diff options
Diffstat (limited to 'fs/xfs/libxfs')
44 files changed, 425 insertions, 347 deletions
diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c index dcd2f93b6a6c..6cab66781d66 100644 --- a/fs/xfs/libxfs/xfs_ag.c +++ b/fs/xfs/libxfs/xfs_ag.c @@ -863,32 +863,30 @@ resv_err: return err2; } -void -xfs_growfs_compute_deltas( +/* + * Return the agcount for the new file system size passed in *nb and adjust *nb + * when it has to be reduced because of maximum AG count or because it would + * create a below minimum size AG. + */ +xfs_agnumber_t +xfs_growfs_compute_agcount( struct xfs_mount *mp, - xfs_rfsblock_t nb, - int64_t *deltap, - xfs_agnumber_t *nagcountp) + xfs_rfsblock_t *nb) { - xfs_rfsblock_t nb_div, nb_mod; - int64_t delta; - xfs_agnumber_t nagcount; - - nb_div = nb; - nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks); - if (nb_mod && nb_mod >= XFS_MIN_AG_BLOCKS) - nb_div++; - else if (nb_mod) - nb = nb_div * mp->m_sb.sb_agblocks; - - if (nb_div > XFS_MAX_AGNUMBER + 1) { - nb_div = XFS_MAX_AGNUMBER + 1; - nb = nb_div * mp->m_sb.sb_agblocks; + uint64_t agcount; /* 64-bits wide to catch overflows */ + xfs_extlen_t remainder; + + agcount = div_u64_rem(*nb, mp->m_sb.sb_agblocks, &remainder); + if (agcount >= XFS_MAX_AGNUMBER + 1) { + agcount = XFS_MAX_AGNUMBER + 1; + remainder = 0; + } + *nb = (xfs_rfsblock_t)agcount * mp->m_sb.sb_agblocks; + if (remainder >= XFS_MIN_AG_BLOCKS) { + *nb += remainder; + agcount++; } - nagcount = nb_div; - delta = nb - mp->m_sb.sb_dblocks; - *deltap = delta; - *nagcountp = nagcount; + return agcount; } /* diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h index 16a9b43a3c27..ee636b66a72f 100644 --- a/fs/xfs/libxfs/xfs_ag.h +++ b/fs/xfs/libxfs/xfs_ag.h @@ -207,7 +207,7 @@ xfs_perag_next( } /* - * Per-ag geometry infomation and validation + * Per-ag geometry information and validation */ xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno); void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno, @@ -329,12 +329,11 @@ struct aghdr_init_data { int xfs_ag_init_headers(struct xfs_mount *mp, struct aghdr_init_data *id); int xfs_ag_shrink_space(struct xfs_perag *pag, struct xfs_trans **tpp, xfs_extlen_t delta); -void -xfs_growfs_compute_deltas(struct xfs_mount *mp, xfs_rfsblock_t nb, - int64_t *deltap, xfs_agnumber_t *nagcountp); int xfs_ag_extend_space(struct xfs_perag *pag, struct xfs_trans *tp, xfs_extlen_t len); int xfs_ag_get_geometry(struct xfs_perag *pag, struct xfs_ag_geometry *ageo); +xfs_agnumber_t xfs_growfs_compute_agcount(struct xfs_mount *mp, + xfs_rfsblock_t *nb); static inline xfs_fsblock_t xfs_agbno_to_fsb( diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index d99602bcc16f..f762dcce8d13 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -3487,7 +3487,7 @@ xfs_alloc_read_agf( } /* - * Pre-proces allocation arguments to set initial state that we don't require + * Pre-process allocation arguments to set initial state that we don't require * callers to set up correctly, as well as bounds check the allocation args * that are set up. */ @@ -3608,7 +3608,7 @@ xfs_alloc_vextent_finish( * ABBA AGF deadlocks because a future allocation attempt in this * transaction may attempt to lock a lower number AGF. * - * We can't release the AGF until the transaction is commited, so at + * We can't release the AGF until the transaction is committed, so at * this point we must update the "first allocation" tracker to point at * this AG if the tracker is empty or points to a lower AG. This allows * the next allocation attempt to be modified appropriately to avoid diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 93caa1dae501..b3f7b2c34ad7 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -276,7 +276,7 @@ xfs_attr_get( return -EIO; if (!args->owner) - args->owner = args->dp->i_ino; + args->owner = I_INO(args->dp); args->geo = args->dp->i_mount->m_attr_geo; args->whichfork = XFS_ATTR_FORK; xfs_attr_sethash(args); diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 2b78041e8672..2c80f4fd0b78 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -325,6 +325,13 @@ xfs_attr3_leaf_verify_entry( */ if (ent->flags & XFS_ATTR_LOCAL) { lentry = xfs_attr3_leaf_name_local(leaf, idx); + + /* Validate lentry pointer is within bounds before field access */ + if ((char *)lentry >= buf_end) + return __this_address; + if ((char *)lentry + offsetof(struct xfs_attr_leaf_name_local, nameval) > buf_end) + return __this_address; + namesize = xfs_attr_leaf_entsize_local(lentry->namelen, be16_to_cpu(lentry->valuelen)); name_end = (char *)lentry + namesize; @@ -332,6 +339,13 @@ xfs_attr3_leaf_verify_entry( return __this_address; } else { rentry = xfs_attr3_leaf_name_remote(leaf, idx); + + /* Validate rentry pointer is within bounds before field access */ + if ((char *)rentry >= buf_end) + return __this_address; + if ((char *)rentry + offsetof(struct xfs_attr_leaf_name_remote, name) > buf_end) + return __this_address; + namesize = xfs_attr_leaf_entsize_remote(rentry->namelen); name_end = (char *)rentry + namesize; if (rentry->namelen == 0) @@ -1429,7 +1443,7 @@ xfs_attr3_leaf_init( struct xfs_da_args args = { .trans = tp, .dp = dp, - .owner = dp->i_ino, + .owner = I_INO(dp), .geo = dp->i_mount->m_attr_geo, }; @@ -1701,7 +1715,7 @@ xfs_attr3_leaf_add_work( /* * This freemap entry starts at the old end of the * leaf entry array, so we need to adjust its base - * upward to accomodate the larger array. + * upward to accommodate the larger array. */ diff = sizeof(struct xfs_attr_leaf_entry); } else if (ichdr->freemap[i].size > 0 && diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 7a4c8f1aa76c..d64defeda645 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -602,7 +602,7 @@ xfs_bmap_btree_to_extents( if ((error = xfs_btree_check_block(cur, cblock, 0, cbp))) return error; - xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork); + xfs_rmap_inode_bmbt_owner(&oinfo, ip, whichfork); error = xfs_free_extent_later(cur->bc_tp, cbno, 1, &oinfo, XFS_AG_RESV_NONE, 0); if (error) @@ -676,13 +676,12 @@ xfs_bmap_extents_to_btree( memset(&args, 0, sizeof(args)); args.tp = tp; args.mp = mp; - xfs_rmap_ino_bmbt_owner(&args.oinfo, ip->i_ino, whichfork); + xfs_rmap_inode_bmbt_owner(&args.oinfo, ip, whichfork); args.minlen = args.maxlen = args.prod = 1; args.wasdel = wasdel; *logflagsp = 0; - error = xfs_alloc_vextent_start_ag(&args, - XFS_INO_TO_FSB(mp, ip->i_ino)); + error = xfs_alloc_vextent_start_ag(&args, XFS_INODE_TO_FSB(ip)); if (error) goto out_root_realloc; @@ -820,7 +819,7 @@ xfs_bmap_local_to_extents( args.mp = ip->i_mount; args.total = total; args.minlen = args.maxlen = args.prod = 1; - xfs_rmap_ino_owner(&args.oinfo, ip->i_ino, whichfork, 0); + xfs_rmap_inode_owner(&args.oinfo, ip, whichfork, 0); /* * Allocate a block. We know we need only one, since the @@ -828,8 +827,7 @@ xfs_bmap_local_to_extents( */ args.total = total; args.minlen = args.maxlen = args.prod = 1; - error = xfs_alloc_vextent_start_ag(&args, - XFS_INO_TO_FSB(args.mp, ip->i_ino)); + error = xfs_alloc_vextent_start_ag(&args, XFS_INODE_TO_FSB(ip)); if (error) goto done; @@ -976,7 +974,7 @@ xfs_bmap_add_attrfork_local( dargs.total = dargs.geo->fsbcount; dargs.whichfork = XFS_DATA_FORK; dargs.trans = tp; - dargs.owner = ip->i_ino; + dargs.owner = I_INO(ip); return xfs_dir2_sf_to_block(&dargs); } @@ -1110,7 +1108,7 @@ xfs_bmap_complain_bad_rec( xfs_warn(mp, "Bmap BTree record corruption in inode 0x%llx %s fork detected at %pS!", - ip->i_ino, forkname, fa); + I_INO(ip), forkname, fa); xfs_warn(mp, "Offset 0x%llx, start block 0x%llx, block count 0x%llx state 0x%x", irec->br_startoff, irec->br_startblock, irec->br_blockcount, @@ -1143,7 +1141,7 @@ xfs_iread_bmbt_block( num_recs = xfs_btree_get_numrecs(block); if (unlikely(ir->loaded + num_recs > ifp->if_nextents)) { xfs_warn(ip->i_mount, "corrupt dinode %llu, (btree extents).", - (unsigned long long)ip->i_ino); + (unsigned long long)I_INO(ip)); xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, block, sizeof(*block), __this_address); xfs_bmap_mark_sick(ip, whichfork); @@ -3590,7 +3588,7 @@ xfs_bmap_btalloc_best_length( xfs_extlen_t blen = 0; int error; - ap->blkno = XFS_INO_TO_FSB(args->mp, ap->ip->i_ino); + ap->blkno = XFS_INODE_TO_FSB(ap->ip); if (!xfs_bmap_adjacent(ap)) ap->eof = false; diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c index 1c7165df483a..758a4b1ccf5b 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.c +++ b/fs/xfs/libxfs/xfs_bmap_btree.c @@ -36,10 +36,10 @@ xfs_bmbt_init_block( { if (bp) xfs_btree_init_buf(ip->i_mount, bp, &xfs_bmbt_ops, level, - numrecs, ip->i_ino); + numrecs, I_INO(ip)); else xfs_btree_init_block(ip->i_mount, buf, &xfs_bmbt_ops, level, - numrecs, ip->i_ino); + numrecs, I_INO(ip)); } /* @@ -217,7 +217,7 @@ xfs_bmbt_alloc_block( memset(&args, 0, sizeof(args)); args.tp = cur->bc_tp; args.mp = cur->bc_mp; - xfs_rmap_ino_bmbt_owner(&args.oinfo, cur->bc_ino.ip->i_ino, + xfs_rmap_inode_bmbt_owner(&args.oinfo, cur->bc_ino.ip, cur->bc_ino.whichfork); args.minlen = args.maxlen = args.prod = 1; args.wasdel = cur->bc_flags & XFS_BTREE_BMBT_WASDEL; @@ -280,7 +280,7 @@ xfs_bmbt_free_block( struct xfs_owner_info oinfo; int error; - xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork); + xfs_rmap_inode_bmbt_owner(&oinfo, ip, cur->bc_ino.whichfork); error = xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo, XFS_AG_RESV_NONE, 0); if (error) diff --git a/fs/xfs/libxfs/xfs_bmap_btree.h b/fs/xfs/libxfs/xfs_bmap_btree.h index b238d559ab03..e0c870beaf67 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.h +++ b/fs/xfs/libxfs/xfs_bmap_btree.h @@ -89,7 +89,7 @@ xfs_bmbt_key_addr( { return (struct xfs_bmbt_key *) ((char *)block + xfs_bmbt_block_len(mp) + - (index - 1) * sizeof(struct xfs_bmbt_key *)); + (index - 1) * sizeof(struct xfs_bmbt_key)); } static inline xfs_bmbt_ptr_t * diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 7012f3570c8d..60ef7f08b1d3 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -371,7 +371,7 @@ xfs_btree_check_ptr( case XFS_BTREE_TYPE_INODE: xfs_err(cur->bc_mp, "Inode %llu fork %d: Corrupt %sbt pointer at level %d index %d.", - cur->bc_ino.ip->i_ino, + I_INO(cur->bc_ino.ip), cur->bc_ino.whichfork, cur->bc_ops->name, level, index); break; @@ -1305,7 +1305,7 @@ xfs_btree_owner( case XFS_BTREE_TYPE_MEM: return cur->bc_mem.xfbtree->owner; case XFS_BTREE_TYPE_INODE: - return cur->bc_ino.ip->i_ino; + return I_INO(cur->bc_ino.ip); case XFS_BTREE_TYPE_AG: return cur->bc_group->xg_gno; default: @@ -3129,7 +3129,7 @@ xfs_btree_promote_leaf_iroot( */ broot = cur->bc_ops->broot_realloc(cur, 1); xfs_btree_init_block(cur->bc_mp, broot, cur->bc_ops, - cur->bc_nlevels - 1, 1, cur->bc_ino.ip->i_ino); + cur->bc_nlevels - 1, 1, I_INO(cur->bc_ino.ip)); pp = xfs_btree_ptr_addr(cur, 1, broot); kp = xfs_btree_key_addr(cur, 1, broot); @@ -3243,8 +3243,7 @@ xfs_btree_new_iroot( if (level > 0) aptr = *xfs_btree_ptr_addr(cur, 1, block); else - aptr.l = cpu_to_be64(XFS_INO_TO_FSB(cur->bc_mp, - cur->bc_ino.ip->i_ino)); + aptr.l = cpu_to_be64(XFS_INODE_TO_FSB(cur->bc_ino.ip)); /* Allocate the new block. If we can't do it, we're toast. Give up. */ error = xfs_btree_alloc_block(cur, &aptr, &nptr, stat); @@ -3827,7 +3826,7 @@ xfs_btree_demote_leaf_child( */ broot = cur->bc_ops->broot_realloc(cur, numrecs); xfs_btree_init_block(cur->bc_mp, broot, cur->bc_ops, 0, numrecs, - cur->bc_ino.ip->i_ino); + I_INO(cur->bc_ino.ip)); rp = xfs_btree_rec_addr(cur, 1, broot); crp = xfs_btree_rec_addr(cur, 1, cblock); @@ -5608,9 +5607,8 @@ xfs_btree_alloc_metafile_block( ASSERT(xfs_is_metadir_inode(ip)); - xfs_rmap_ino_bmbt_owner(&args.oinfo, ip->i_ino, cur->bc_ino.whichfork); - error = xfs_alloc_vextent_start_ag(&args, - XFS_INO_TO_FSB(cur->bc_mp, ip->i_ino)); + xfs_rmap_inode_bmbt_owner(&args.oinfo, ip, cur->bc_ino.whichfork); + error = xfs_alloc_vextent_start_ag(&args, XFS_INODE_TO_FSB(ip)); if (error) return error; if (args.fsbno == NULLFSBLOCK) { @@ -5641,7 +5639,7 @@ xfs_btree_free_metafile_block( ASSERT(xfs_is_metadir_inode(ip)); - xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork); + xfs_rmap_inode_bmbt_owner(&oinfo, ip, cur->bc_ino.whichfork); error = xfs_free_extent_later(tp, fsbno, 1, &oinfo, XFS_AG_RESV_METAFILE, 0); if (error) diff --git a/fs/xfs/libxfs/xfs_btree_mem.c b/fs/xfs/libxfs/xfs_btree_mem.c index 37136a70e56d..1d83a4251cee 100644 --- a/fs/xfs/libxfs/xfs_btree_mem.c +++ b/fs/xfs/libxfs/xfs_btree_mem.c @@ -117,6 +117,7 @@ xfbtree_init( struct xfs_buftarg *btp, const struct xfs_btree_ops *ops) { + unsigned long long owner = xfbt->owner; unsigned int blocklen = xfbtree_rec_bytes(mp, ops); unsigned int keyptr_len; int error; @@ -133,6 +134,7 @@ xfbtree_init( memset(xfbt, 0, sizeof(*xfbt)); xfbt->target = btp; + xfbt->owner = owner; /* Set up min/maxrecs for this btree. */ keyptr_len = ops->key_len + sizeof(__be64); diff --git a/fs/xfs/libxfs/xfs_btree_staging.c b/fs/xfs/libxfs/xfs_btree_staging.c index 4300c058807b..561fd2c2e950 100644 --- a/fs/xfs/libxfs/xfs_btree_staging.c +++ b/fs/xfs/libxfs/xfs_btree_staging.c @@ -248,11 +248,10 @@ xfs_btree_bload_drop_buf( return 0; /* - * Mark this buffer XBF_DONE (i.e. uptodate) so that a subsequent - * xfs_buf_read will not pointlessly reread the contents from the disk. + * Mark this buffer uptodate so that a subsequent xfs_buf_read will + * not pointlessly reread the contents from the disk. */ - bp->b_flags |= XBF_DONE; - + xfs_buf_set_uptodate(bp); xfs_buf_delwri_queue_here(bp, buffers_list); xfs_buf_relse(bp); *bpp = NULL; @@ -309,7 +308,7 @@ xfs_btree_bload_prep_block( /* Initialize it and send it out. */ xfs_btree_init_block(cur->bc_mp, ifp->if_broot, cur->bc_ops, - level, nr_this_block, cur->bc_ino.ip->i_ino); + level, nr_this_block, I_INO(cur->bc_ino.ip)); *bpp = NULL; *blockp = ifp->if_broot; @@ -337,8 +336,10 @@ xfs_btree_bload_prep_block( xfs_btree_set_sibling(cur, *blockp, &new_ptr, XFS_BB_RIGHTSIB); ret = xfs_btree_bload_drop_buf(bbl, buffers_list, bpp); - if (ret) + if (ret) { + xfs_buf_relse(new_bp); return ret; + } /* Initialize the new btree block. */ xfs_btree_init_block_cur(cur, new_bp, level, nr_this_block); diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c index ad801b7bd2dd..3d02a0d7ba44 100644 --- a/fs/xfs/libxfs/xfs_da_btree.c +++ b/fs/xfs/libxfs/xfs_da_btree.c @@ -130,7 +130,7 @@ xfs_da_state_reset( state->mp = state->args->dp->i_mount; } -static inline int xfs_dabuf_nfsb(struct xfs_mount *mp, int whichfork) +inline int xfs_dabuf_nfsb(struct xfs_mount *mp, int whichfork) { if (whichfork == XFS_DATA_FORK) return mp->m_dir_geo->fsbcount; @@ -2354,8 +2354,7 @@ xfs_da_grow_inode_int( * If we didn't get it and the block might work if fragmented, * try without the CONTIG flag. Loop until we get it all. */ - mapp = kmalloc(sizeof(*mapp) * count, - GFP_KERNEL | __GFP_NOFAIL); + mapp = kmalloc_objs(*mapp, count, GFP_KERNEL | __GFP_NOFAIL); for (b = *bno, mapi = 0; b < *bno + count; ) { c = (int)(*bno + count - b); nmap = min(XFS_BMAP_MAX_NMAP, c); @@ -2385,6 +2384,7 @@ xfs_da_grow_inode_int( } /* account for newly allocated blocks in reserved blocks total */ + ASSERT(args->total >= dp->i_nblocks - nblks); args->total -= dp->i_nblocks - nblks; out_free_map: @@ -2747,8 +2747,8 @@ xfs_dabuf_map( * larger one that needs to be free by the caller. */ if (nirecs > 1) { - map = kcalloc(nirecs, sizeof(struct xfs_buf_map), - GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL); + map = kzalloc_objs(struct xfs_buf_map, nirecs, + GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL); *mapp = map; } @@ -2780,7 +2780,7 @@ invalid_mapping: error = -EFSCORRUPTED; if (xfs_error_level >= XFS_ERRLEVEL_LOW) { xfs_alert(mp, "%s: bno %u inode %llu", - __func__, bno, dp->i_ino); + __func__, bno, I_INO(dp)); for (i = 0; i < nirecs; i++) { xfs_alert(mp, diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h index afcf2d3c7a21..a718b1ceb0aa 100644 --- a/fs/xfs/libxfs/xfs_da_btree.h +++ b/fs/xfs/libxfs/xfs_da_btree.h @@ -244,4 +244,6 @@ xfs_failaddr_t xfs_da3_node_header_check(struct xfs_buf *bp, xfs_ino_t owner); extern struct kmem_cache *xfs_da_state_cache; +int xfs_dabuf_nfsb(struct xfs_mount *mp, int whichfork); + #endif /* __XFS_DA_BTREE_H__ */ diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index c6909716b041..3152acdc335d 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -229,6 +229,7 @@ xfs_defer_barrier_cancel_item( } static const struct xfs_defer_op_type xfs_barrier_defer_type = { + .name = "barrier", .max_items = 1, .create_intent = xfs_defer_barrier_create_intent, .abort_intent = xfs_defer_barrier_abort_intent, @@ -583,7 +584,7 @@ xfs_defer_finish_one( const struct xfs_defer_op_type *ops = dfp->dfp_ops; struct xfs_btree_cur *state = NULL; struct list_head *li, *n; - int error; + int error = 0; trace_xfs_defer_pending_finish(tp->t_mountp, dfp); @@ -655,6 +656,7 @@ xfs_defer_finish_noroll( struct xfs_trans **tp) { struct xfs_defer_pending *dfp = NULL; + const char *what = "chain"; int error = 0; LIST_HEAD(dop_pending); LIST_HEAD(dop_paused); @@ -704,9 +706,17 @@ xfs_defer_finish_noroll( struct xfs_defer_pending, dfp_list); if (!dfp) break; + what = dfp->dfp_ops->name; error = xfs_defer_finish_one(*tp, dfp); if (error && error != -EAGAIN) goto out_shutdown; + /* + * A finished item is no longer a candidate for a later + * failure. An -EAGAIN one is not finished, so it keeps the + * attribution across the roll that completes it. + */ + if (!error) + what = "chain"; } /* Requeue the paused items in the outgoing transaction. */ @@ -718,8 +728,12 @@ xfs_defer_finish_noroll( out_shutdown: list_splice_tail_init(&dop_paused, &dop_pending); xfs_defer_trans_abort(*tp, &dop_pending); - xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE); trace_xfs_defer_finish_error(*tp, error); + if (!xfs_is_shutdown((*tp)->t_mountp)) + xfs_alert((*tp)->t_mountp, + "deferred %s work failed, error %d, %u blocks reserved", + what, error, (*tp)->t_blk_res); + xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE); xfs_defer_cancel_list((*tp)->t_mountp, &dop_pending); xfs_defer_cancel(*tp); return error; @@ -878,7 +892,7 @@ xfs_defer_add_barrier( if (dfp) return; - xfs_defer_alloc(&tp->t_dfops, &xfs_barrier_defer_type); + dfp = xfs_defer_alloc(&tp->t_dfops, &xfs_barrier_defer_type); trace_xfs_defer_add_item(tp->t_mountp, dfp, NULL); } diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c index 495620cc001f..0c0402a29b6b 100644 --- a/fs/xfs/libxfs/xfs_dir2.c +++ b/fs/xfs/libxfs/xfs_dir2.c @@ -244,7 +244,7 @@ xfs_dir_init( int error; ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); - error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino); + error = xfs_dir_ino_validate(tp->t_mountp, I_INO(pdp)); if (error) return error; @@ -255,8 +255,8 @@ xfs_dir_init( args->geo = dp->i_mount->m_dir_geo; args->dp = dp; args->trans = tp; - args->owner = dp->i_ino; - error = xfs_dir2_sf_create(args, pdp->i_ino); + args->owner = I_INO(dp); + error = xfs_dir2_sf_create(args, I_INO(pdp)); kfree(args); return error; } @@ -356,7 +356,7 @@ xfs_dir_createname( args->whichfork = XFS_DATA_FORK; args->trans = tp; args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; - args->owner = dp->i_ino; + args->owner = I_INO(dp); rval = xfs_dir_createname_args(args); kfree(args); @@ -447,7 +447,7 @@ xfs_dir_lookup( args->whichfork = XFS_DATA_FORK; args->trans = tp; args->op_flags = XFS_DA_OP_OKNOENT; - args->owner = dp->i_ino; + args->owner = I_INO(dp); if (ci_name) args->op_flags |= XFS_DA_OP_CILOOKUP; @@ -516,7 +516,7 @@ xfs_dir_removename( args->total = total; args->whichfork = XFS_DATA_FORK; args->trans = tp; - args->owner = dp->i_ino; + args->owner = I_INO(dp); rval = xfs_dir_removename_args(args); kfree(args); return rval; @@ -576,7 +576,7 @@ xfs_dir_replace( args->total = total; args->whichfork = XFS_DATA_FORK; args->trans = tp; - args->owner = dp->i_ino; + args->owner = I_INO(dp); rval = xfs_dir_replace_args(args); kfree(args); return rval; @@ -855,7 +855,7 @@ xfs_dir_create_child( xfs_assert_ilocked(ip, XFS_ILOCK_EXCL); xfs_assert_ilocked(dp, XFS_ILOCK_EXCL); - error = xfs_dir_createname(tp, dp, name, ip->i_ino, resblks); + error = xfs_dir_createname(tp, dp, name, I_INO(ip), resblks); if (error) { ASSERT(error != -ENOSPC); return error; @@ -919,14 +919,14 @@ xfs_dir_add_child( if (VFS_I(ip)->i_nlink == 0) { struct xfs_perag *pag; - pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); + pag = xfs_perag_get(mp, XFS_INODE_TO_AGNO(ip)); error = xfs_iunlink_remove(tp, pag, ip); xfs_perag_put(pag); if (error) return error; } - error = xfs_dir_createname(tp, dp, name, ip->i_ino, resblks); + error = xfs_dir_createname(tp, dp, name, I_INO(ip), resblks); if (error) return error; @@ -995,7 +995,7 @@ xfs_dir_remove_child( * get freed before the child directory is closed. If the fs * gets shrunk, this can lead to dirent inode validation errors. */ - if (dp->i_ino != tp->t_mountp->m_sb.sb_rootino) { + if (I_INO(dp) != tp->t_mountp->m_sb.sb_rootino) { error = xfs_dir_replace(tp, ip, &xfs_name_dotdot, tp->t_mountp->m_sb.sb_rootino, 0); if (error) @@ -1016,7 +1016,7 @@ xfs_dir_remove_child( if (error) return error; - error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks); + error = xfs_dir_removename(tp, dp, name, I_INO(ip), resblks); if (error) { ASSERT(error != -ENOENT); return error; @@ -1059,12 +1059,12 @@ xfs_dir_exchange_children( int error; /* Swap inode number for dirent in first parent */ - error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres); + error = xfs_dir_replace(tp, dp1, name1, I_INO(ip2), spaceres); if (error) return error; /* Swap inode number for dirent in second parent */ - error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, spaceres); + error = xfs_dir_replace(tp, dp2, name2, I_INO(ip1), spaceres); if (error) return error; @@ -1078,7 +1078,7 @@ xfs_dir_exchange_children( if (S_ISDIR(VFS_I(ip2)->i_mode)) { error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot, - dp1->i_ino, spaceres); + I_INO(dp1), spaceres); if (error) return error; @@ -1102,7 +1102,7 @@ xfs_dir_exchange_children( if (S_ISDIR(VFS_I(ip1)->i_mode)) { error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot, - dp2->i_ino, spaceres); + I_INO(dp2), spaceres); if (error) return error; @@ -1246,7 +1246,7 @@ xfs_dir_rename_children( ASSERT(VFS_I(du_wip->ip)->i_nlink == 0); - pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, du_wip->ip->i_ino)); + pag = xfs_perag_get(mp, XFS_INODE_TO_AGNO(du_wip->ip)); error = xfs_iunlink_remove(tp, pag, du_wip->ip); xfs_perag_put(pag); if (error) @@ -1265,7 +1265,7 @@ xfs_dir_rename_children( * to account for the ".." reference from the new entry. */ error = xfs_dir_createname(tp, target_dp, target_name, - src_ip->i_ino, spaceres); + I_INO(src_ip), spaceres); if (error) return error; @@ -1286,7 +1286,7 @@ xfs_dir_rename_children( * name at the destination directory, remove it first. */ error = xfs_dir_replace(tp, target_dp, target_name, - src_ip->i_ino, spaceres); + I_INO(src_ip), spaceres); if (error) return error; @@ -1320,7 +1320,7 @@ xfs_dir_rename_children( * directory. */ error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot, - target_dp->i_ino, spaceres); + I_INO(target_dp), spaceres); ASSERT(error != -EEXIST); if (error) return error; @@ -1358,10 +1358,10 @@ xfs_dir_rename_children( * altogether. */ if (du_wip->ip) - error = xfs_dir_replace(tp, src_dp, src_name, du_wip->ip->i_ino, + error = xfs_dir_replace(tp, src_dp, src_name, I_INO(du_wip->ip), spaceres); else - error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino, + error = xfs_dir_removename(tp, src_dp, src_name, I_INO(src_ip), spaceres); if (error) return error; diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c index 80ba94f51e5c..aecbab61014c 100644 --- a/fs/xfs/libxfs/xfs_dir2_data.c +++ b/fs/xfs/libxfs/xfs_dir2_data.c @@ -382,6 +382,7 @@ xfs_dir3_data_write_verify( struct xfs_mount *mp = bp->b_mount; struct xfs_buf_log_item *bip = bp->b_log_item; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; + struct xfs_dir3_data_hdr *datahdr3 = bp->b_addr; xfs_failaddr_t fa; fa = xfs_dir3_data_verify(bp); @@ -396,6 +397,11 @@ xfs_dir3_data_write_verify( if (bip) hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); + /* + * Zero padding that may be stale from old kernels. + */ + datahdr3->pad = 0; + xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); } @@ -728,7 +734,6 @@ xfs_dir3_data_init( struct xfs_dir2_data_unused *dup; struct xfs_dir2_data_free *bf; int error; - int i; /* * Get the buffer set up for the block. @@ -741,13 +746,16 @@ xfs_dir3_data_init( xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_DATA_BUF); /* - * Initialize the header. + * Initialize the whole directory header region to zero + * so that all padding, bestfree entries, and any + * future header fields are clean. */ hdr = bp->b_addr; + memset(hdr, 0, geo->data_entry_offset); + if (xfs_has_crc(mp)) { struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; - memset(hdr3, 0, sizeof(*hdr3)); hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); hdr3->blkno = cpu_to_be64(xfs_buf_daddr(bp)); hdr3->owner = cpu_to_be64(args->owner); @@ -759,10 +767,6 @@ xfs_dir3_data_init( bf = xfs_dir2_data_bestfree_p(mp, hdr); bf[0].offset = cpu_to_be16(geo->data_entry_offset); bf[0].length = cpu_to_be16(geo->blksize - geo->data_entry_offset); - for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { - bf[i].length = 0; - bf[i].offset = 0; - } /* * Set up an unused entry for the block's body. diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c index ed0b5287a44f..19cb536e53ef 100644 --- a/fs/xfs/libxfs/xfs_dir2_node.c +++ b/fs/xfs/libxfs/xfs_dir2_node.c @@ -1739,7 +1739,7 @@ xfs_dir2_node_add_datablk( fbno)) { xfs_alert(mp, "%s: dir ino %llu needed freesp block %lld for data block %lld, got %lld", - __func__, (unsigned long long)dp->i_ino, + __func__, (unsigned long long)I_INO(dp), (long long)xfs_dir2_db_to_fdb(args->geo, *dbno), (long long)*dbno, (long long)fbno); if (fblk) { diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c index 1a67cdd6a707..0567cf8b9c1b 100644 --- a/fs/xfs/libxfs/xfs_dir2_sf.c +++ b/fs/xfs/libxfs/xfs_dir2_sf.c @@ -301,7 +301,7 @@ xfs_dir2_block_to_sf( * Skip . */ if (dep->namelen == 1 && dep->name[0] == '.') - ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino); + ASSERT(be64_to_cpu(dep->inumber) == I_INO(dp)); /* * Skip .., but make sure the inode number is right. */ @@ -863,7 +863,7 @@ xfs_dir2_sf_lookup( * Special case for . */ if (args->namelen == 1 && args->name[0] == '.') { - args->inumber = dp->i_ino; + args->inumber = I_INO(dp); args->cmpresult = XFS_CMP_EXACT; args->filetype = XFS_DIR3_FT_DIR; return -EEXIST; diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c index ce767b40482f..77954d1d924c 100644 --- a/fs/xfs/libxfs/xfs_dquot_buf.c +++ b/fs/xfs/libxfs/xfs_dquot_buf.c @@ -252,8 +252,8 @@ xfs_dquot_buf_read_verify( /* * readahead errors are silent and simply leave the buffer as !done so a real * read will then be run with the xfs_dquot_buf_ops verifier. See - * xfs_inode_buf_verify() for why we use EIO and ~XBF_DONE here rather than - * reporting the failure. + * xfs_inode_buf_verify() for why we use EIO here rather than reporting the + * failure. */ static void xfs_dquot_buf_readahead_verify( @@ -262,10 +262,8 @@ xfs_dquot_buf_readahead_verify( struct xfs_mount *mp = bp->b_mount; if (!xfs_dquot_buf_verify_crc(mp, bp, true) || - xfs_dquot_buf_verify(mp, bp, true) != NULL) { + xfs_dquot_buf_verify(mp, bp, true) != NULL) xfs_buf_ioerror(bp, -EIO); - bp->b_flags &= ~XBF_DONE; - } } /* @@ -416,6 +414,15 @@ xfs_dqinode_load( return 0; } +static int +xfs_dqinode_init( + struct xfs_metadir_update *upd, + void *priv) +{ + xfs_trans_log_inode(upd->tp, upd->ip, XFS_ILOG_CORE); + return 0; +} + /* Create a metadata directory quota inode. */ int xfs_dqinode_metadir_create( @@ -428,25 +435,9 @@ xfs_dqinode_metadir_create( .metafile_type = xfs_dqinode_metafile_type(type), .path = xfs_dqinode_path(type), }; - int error; - - error = xfs_metadir_start_create(&upd); - if (error) - return error; - error = xfs_metadir_create(&upd, S_IFREG); - if (error) - return error; - - xfs_trans_log_inode(upd.tp, upd.ip, XFS_ILOG_CORE); - - error = xfs_metadir_commit(&upd); - if (error) - return error; - - xfs_finish_inode_setup(upd.ip); - *ipp = upd.ip; - return 0; + return xfs_metadir_create_file(&upd, S_IFREG, xfs_dqinode_init, NULL, + ipp); } #ifndef __KERNEL__ diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h index 6de207fed2d8..f0c83f1f0b3b 100644 --- a/fs/xfs/libxfs/xfs_errortag.h +++ b/fs/xfs/libxfs/xfs_errortag.h @@ -83,7 +83,7 @@ #define XFS_RANDOM_DEFAULT 100 /* - * Table of errror injection knobs. The parameters to the XFS_ERRTAG macro are: + * Table of error injection knobs. The parameters to the XFS_ERRTAG macro are: * 1. The XFS_ERRTAG_ flag but without the prefix; * 2. The name of the sysfs knob; and * 3. The default value for the knob. diff --git a/fs/xfs/libxfs/xfs_exchmaps.c b/fs/xfs/libxfs/xfs_exchmaps.c index 5d28f4eac527..6a66b6075e0a 100644 --- a/fs/xfs/libxfs/xfs_exchmaps.c +++ b/fs/xfs/libxfs/xfs_exchmaps.c @@ -395,7 +395,7 @@ xfs_exchmaps_one_step( /* * Re-add both mappings. We exchange the file offsets between the two * maps and add the opposite map, which has the effect of filling the - * logical offsets we just unmapped, but with with the physical mapping + * logical offsets we just unmapped, but with the physical mapping * information exchanged. */ swap(irec1->br_startoff, irec2->br_startoff); @@ -429,7 +429,7 @@ xfs_exchmaps_attr_to_sf( .geo = tp->t_mountp->m_attr_geo, .whichfork = XFS_ATTR_FORK, .trans = tp, - .owner = xmi->xmi_ip2->i_ino, + .owner = I_INO(xmi->xmi_ip2), }; struct xfs_buf *bp; int forkoff; @@ -438,7 +438,7 @@ xfs_exchmaps_attr_to_sf( if (!xfs_attr_is_leaf(xmi->xmi_ip2)) return 0; - error = xfs_attr3_leaf_read(tp, xmi->xmi_ip2, xmi->xmi_ip2->i_ino, 0, + error = xfs_attr3_leaf_read(tp, xmi->xmi_ip2, I_INO(xmi->xmi_ip2), 0, &bp); if (error) return error; @@ -461,7 +461,7 @@ xfs_exchmaps_dir_to_sf( .geo = tp->t_mountp->m_dir_geo, .whichfork = XFS_DATA_FORK, .trans = tp, - .owner = xmi->xmi_ip2->i_ino, + .owner = I_INO(xmi->xmi_ip2), }; struct xfs_dir2_sf_hdr sfh; struct xfs_buf *bp; @@ -471,7 +471,7 @@ xfs_exchmaps_dir_to_sf( if (xfs_dir2_format(&args, &error) != XFS_DIR2_FMT_BLOCK) return error; - error = xfs_dir3_block_read(tp, xmi->xmi_ip2, xmi->xmi_ip2->i_ino, &bp); + error = xfs_dir3_block_read(tp, xmi->xmi_ip2, I_INO(xmi->xmi_ip2), &bp); if (error) return error; @@ -711,7 +711,7 @@ xfs_exchmaps_estimate_overhead( return -ENOSPC; /* Can't actually reserve more than UINT_MAX blocks. */ - if (req->resblks > UINT_MAX) + if (resblks > UINT_MAX) return -ENOSPC; req->resblks = resblks; @@ -959,6 +959,16 @@ xmi_can_exchange_reflink_flags( { struct xfs_mount *mp = req->ip1->i_mount; + /* + * The INO1_WRITTEN optimization can skip exchanging hole and + * unwritten mappings, which means we cannot guarantee that all + * shared extents actually moved to the other file. Clearing the + * reflink flag of an inode that still holds shared extents breaks + * the CoW write path, so refuse to exchange the flags in that case. + */ + if (req->flags & XFS_EXCHMAPS_INO1_WRITTEN) + return false; + if (hweight32(reflink_state) != 1) return false; if (req->startoff1 != 0 || req->startoff2 != 0) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 779dac59b1f3..1a7a7e60a170 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -1051,7 +1051,7 @@ enum xfs_dinode_fmt { * block is 1KB in size. * * With XFS_MAX_EXTCNT_DATA_FORK_SMALL representing maximum extent count and - * with 1KB sized blocks, a file can reach upto, + * with 1KB sized blocks, a file can reach up to, * 1KB * (2^31) = 2TB * * This is much larger than the theoretical maximum size of a directory @@ -1276,8 +1276,12 @@ static inline bool xfs_dinode_is_metadir(const struct xfs_dinode *dip) XFS_INO_AGNO_BITS(mp) + XFS_INO_AGINO_BITS(mp) #define XFS_INO_TO_AGNO(mp,i) \ ((xfs_agnumber_t)((i) >> XFS_INO_AGINO_BITS(mp))) +#define XFS_INODE_TO_AGNO(ip) \ + XFS_INO_TO_AGNO((ip)->i_mount, I_INO(ip)) #define XFS_INO_TO_AGINO(mp,i) \ ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(mp))) +#define XFS_INODE_TO_AGINO(ip) \ + XFS_INO_TO_AGINO((ip)->i_mount, I_INO(ip)) #define XFS_INO_TO_AGBNO(mp,i) \ (((xfs_agblock_t)(i) >> XFS_INO_OFFSET_BITS(mp)) & \ XFS_INO_MASK(XFS_INO_AGBNO_BITS(mp))) @@ -1285,6 +1289,8 @@ static inline bool xfs_dinode_is_metadir(const struct xfs_dinode *dip) ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) #define XFS_INO_TO_FSB(mp,i) \ XFS_AGB_TO_FSB(mp, XFS_INO_TO_AGNO(mp,i), XFS_INO_TO_AGBNO(mp,i)) +#define XFS_INODE_TO_FSB(ip) \ + XFS_INO_TO_FSB((ip)->i_mount, I_INO(ip)) #define XFS_AGINO_TO_INO(mp,a,i) \ (((xfs_ino_t)(a) << XFS_INO_AGINO_BITS(mp)) | (i)) #define XFS_AGINO_TO_AGBNO(mp,i) ((i) >> XFS_INO_OFFSET_BITS(mp)) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index dcef06ec0a02..58dac4d505ba 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -413,7 +413,7 @@ xfs_ialloc_inode_init( xfs_trans_ordered_buf(tp, fbuf); } } else { - fbuf->b_flags |= XBF_DONE; + xfs_buf_set_uptodate(fbuf); xfs_buf_delwri_queue(fbuf, buffer_list); xfs_buf_relse(fbuf); } @@ -1075,7 +1075,7 @@ xfs_dialloc_check_ino( if (error) return -EAGAIN; - error = xfs_imap_to_bp(pag_mount(pag), tp, &imap, &bp); + error = xfs_read_icluster(pag, tp, imap.im_agbno, &bp); if (error) return -EAGAIN; @@ -1870,7 +1870,7 @@ xfs_dialloc_pick_ag( if (S_ISDIR(mode)) return (atomic_inc_return(&mp->m_agirotor) - 1) % mp->m_maxagi; - start_agno = XFS_INO_TO_AGNO(mp, dp->i_ino); + start_agno = XFS_INODE_TO_AGNO(dp); if (start_agno >= mp->m_maxagi) start_agno = 0; @@ -1895,7 +1895,7 @@ xfs_dialloc( struct xfs_perag *pag; struct xfs_ino_geometry *igeo = M_IGEO(mp); xfs_ino_t ino = NULLFSINO; - xfs_ino_t parent = args->pip ? args->pip->i_ino : 0; + xfs_ino_t parent = args->pip ? I_INO(args->pip) : 0; xfs_agnumber_t agno; xfs_agnumber_t start_agno; umode_t mode = args->mode & S_IFMT; @@ -2511,44 +2511,38 @@ xfs_imap( * inodes in stale state on disk. Hence we have to do a btree lookup * in all cases where an untrusted inode number is passed. */ - if (flags & XFS_IGET_UNTRUSTED) { - error = xfs_imap_lookup(pag, tp, agino, agbno, - &chunk_agbno, &offset_agbno, flags); - if (error) - return error; - goto out_map; - } + if (!(flags & XFS_IGET_UNTRUSTED)) { + /* + * If the inode cluster size is the same or smaller than the + * blocksize, get to the buffer by simple arithmetics. + */ + if (M_IGEO(mp)->blocks_per_cluster == 1) { + cluster_agbno = agbno; + offset = XFS_INO_TO_OFFSET(mp, ino); + ASSERT(offset < mp->m_sb.sb_inopblock); + goto out; + } - /* - * If the inode cluster size is the same as the blocksize or - * smaller we get to the buffer by simple arithmetics. - */ - if (M_IGEO(mp)->blocks_per_cluster == 1) { - offset = XFS_INO_TO_OFFSET(mp, ino); - ASSERT(offset < mp->m_sb.sb_inopblock); - - imap->im_blkno = xfs_agbno_to_daddr(pag, agbno); - imap->im_len = XFS_FSB_TO_BB(mp, 1); - imap->im_boffset = (unsigned short)(offset << - mp->m_sb.sb_inodelog); - return 0; - } + /* + * If the inode chunks are aligned, use simple maths to find the + * location. + */ + if (M_IGEO(mp)->inoalign_mask) { + offset_agbno = agbno & M_IGEO(mp)->inoalign_mask; + chunk_agbno = agbno - offset_agbno; + goto out_map; + } - /* - * If the inode chunks are aligned then use simple maths to - * find the location. Otherwise we have to do a btree - * lookup to find the location. - */ - if (M_IGEO(mp)->inoalign_mask) { - offset_agbno = agbno & M_IGEO(mp)->inoalign_mask; - chunk_agbno = agbno - offset_agbno; - } else { - error = xfs_imap_lookup(pag, tp, agino, agbno, - &chunk_agbno, &offset_agbno, flags); - if (error) - return error; + /* + * Otherwise we have to do a btree lookup to find the location. + */ } + error = xfs_imap_lookup(pag, tp, agino, agbno, &chunk_agbno, + &offset_agbno, flags); + if (error) + return error; + out_map: ASSERT(agbno >= chunk_agbno); cluster_agbno = chunk_agbno + @@ -2556,24 +2550,14 @@ out_map: M_IGEO(mp)->blocks_per_cluster); offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + XFS_INO_TO_OFFSET(mp, ino); - - imap->im_blkno = xfs_agbno_to_daddr(pag, cluster_agbno); - imap->im_len = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster); +out: + imap->im_agbno = cluster_agbno; imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog); - - /* - * If the inode number maps to a block outside the bounds - * of the file system then return NULL rather than calling - * read_buf and panicing when we get an error from the - * driver. - */ - if ((imap->im_blkno + imap->im_len) > - XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { - xfs_alert(mp, - "%s: (im_blkno (0x%llx) + im_len (0x%llx)) > sb_dblocks (0x%llx)", - __func__, (unsigned long long) imap->im_blkno, - (unsigned long long) imap->im_len, - XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)); + if (imap->im_agbno + M_IGEO(mp)->blocks_per_cluster > + pag_group(pag)->xg_block_count) { + xfs_alert(mp, "inode cluster out of range: %u/%u > %u", + imap->im_agbno, M_IGEO(mp)->blocks_per_cluster, + pag_group(pag)->xg_block_count); return -EINVAL; } return 0; diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c index 3794e5412eba..0340e2189921 100644 --- a/fs/xfs/libxfs/xfs_inode_buf.c +++ b/fs/xfs/libxfs/xfs_inode_buf.c @@ -29,12 +29,14 @@ * has not had the inode cores stamped into it. Hence for readahead, the buffer * may be potentially invalid. * - * If the readahead buffer is invalid, we need to mark it with an error and - * clear the DONE status of the buffer so that a followup read will re-read it - * from disk. We don't report the error otherwise to avoid warnings during log - * recovery and we don't get unnecessary panics on debug kernels. We use EIO here - * because all we want to do is say readahead failed; there is no-one to report - * the error to, so this will distinguish it from a non-ra verifier failure. + * If the readahead buffer is invalid, we need to mark it with an error so that a + * followup read will re-read it from disk. + * + * We don't report the error otherwise to avoid warnings during log recovery and + * we don't get unnecessary panics on debug kernels. Use EIO here because all + * we want to do is say readahead failed; there is no-one to report the error + * to, so this will distinguish it from a non-ra verifier failure. + * * Changes to this readahead error behaviour also need to be reflected in * xfs_dquot_buf_readahead_verify(). */ @@ -64,7 +66,6 @@ xfs_inode_buf_verify( if (unlikely(!di_ok || XFS_TEST_ERROR(mp, XFS_ERRTAG_ITOBP_INOTOBP))) { if (readahead) { - bp->b_flags &= ~XBF_DONE; xfs_buf_ioerror(bp, -EIO); return; } @@ -123,24 +124,24 @@ const struct xfs_buf_ops xfs_inode_buf_ra_ops = { /* - * This routine is called to map an inode to the buffer containing the on-disk - * version of the inode. It returns a pointer to the buffer containing the - * on-disk inode in the bpp parameter. + * Read the inode cluster at @bno and return it in @bpp. */ int -xfs_imap_to_bp( - struct xfs_mount *mp, +xfs_read_icluster( + struct xfs_perag *pag, struct xfs_trans *tp, - struct xfs_imap *imap, + xfs_agblock_t agbno, struct xfs_buf **bpp) { + struct xfs_mount *mp = pag_mount(pag); int error; - error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, - imap->im_len, 0, bpp, &xfs_inode_buf_ops); + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, + xfs_agbno_to_daddr(pag, agbno), + XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster), + 0, bpp, &xfs_inode_buf_ops); if (xfs_metadata_is_sick(error)) - xfs_agno_mark_sick(mp, xfs_daddr_to_agno(mp, imap->im_blkno), - XFS_SICK_AG_INODES); + xfs_agno_mark_sick(mp, pag_agno(pag), XFS_SICK_AG_INODES); return error; } @@ -185,7 +186,7 @@ xfs_inode_from_disk( ASSERT(ip->i_cowfp == NULL); - fa = xfs_dinode_verify(ip->i_mount, ip->i_ino, from); + fa = xfs_dinode_verify(ip->i_mount, I_INO(ip), from); if (fa) { xfs_inode_verifier_error(ip, -EFSCORRUPTED, "dinode", from, sizeof(*from), fa); @@ -358,7 +359,7 @@ xfs_inode_to_disk( to->di_flags2 = cpu_to_be64(ip->i_diflags2); /* also covers the di_used_blocks union arm: */ to->di_cowextsize = cpu_to_be32(ip->i_cowextsize); - to->di_ino = cpu_to_be64(ip->i_ino); + to->di_ino = cpu_to_be64(I_INO(ip)); to->di_lsn = cpu_to_be64(lsn); memset(to->di_pad2, 0, sizeof(to->di_pad2)); uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid); @@ -625,7 +626,7 @@ xfs_dinode_verify( * have di_nlink track the link count, even if the actual filesystem * only supported V1 inodes (i.e. di_onlink). When writing out the * ondisk inode, it would set both the ondisk di_nlink and di_onlink to - * the the incore di_nlink value, which is why we cannot check for + * the incore di_nlink value, which is why we cannot check for * di_nlink==0 on a V1 inode. V2/3 inodes would get written out with * di_onlink==0, so we can check that. */ diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h index 8d43d2641c73..f3624532b023 100644 --- a/fs/xfs/libxfs/xfs_inode_buf.h +++ b/fs/xfs/libxfs/xfs_inode_buf.h @@ -11,16 +11,15 @@ struct xfs_dinode; /* * Inode location information. Stored in the inode and passed to - * xfs_imap_to_bp() to get a buffer and dinode for a given inode. + * xfs_read_icluster() to get a buffer and dinode for a given inode. */ struct xfs_imap { - xfs_daddr_t im_blkno; /* starting BB of inode chunk */ - unsigned short im_len; /* length in BBs of inode chunk */ - unsigned short im_boffset; /* inode offset in block in bytes */ -}; + xfs_agblock_t im_agbno; /* starting agbno of inode cluster */ + unsigned short im_boffset; /* offset in inode cluster in bytes */ +} __packed; -int xfs_imap_to_bp(struct xfs_mount *mp, struct xfs_trans *tp, - struct xfs_imap *imap, struct xfs_buf **bpp); +int xfs_read_icluster(struct xfs_perag *pag, struct xfs_trans *tp, + xfs_agblock_t agbno, struct xfs_buf **bpp); void xfs_dinode_calc_crc(struct xfs_mount *mp, struct xfs_dinode *dip); void xfs_inode_to_disk(struct xfs_inode *ip, struct xfs_dinode *to, xfs_lsn_t lsn); diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index d14a7f2f4c03..606a36526ce2 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c @@ -87,7 +87,7 @@ xfs_iformat_local( if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { xfs_warn(ip->i_mount, "corrupt inode %llu (bad size %d for local fork, size = %zd).", - (unsigned long long) ip->i_ino, size, + (unsigned long long)I_INO(ip), size, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)); xfs_inode_verifier_error(ip, -EFSCORRUPTED, "xfs_iformat_local", dip, sizeof(*dip), @@ -126,7 +126,7 @@ xfs_iformat_extents( */ if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, mp, whichfork))) { xfs_warn(ip->i_mount, "corrupt inode %llu ((a)extents = %llu).", - ip->i_ino, nex); + I_INO(ip), nex); xfs_inode_verifier_error(ip, -EFSCORRUPTED, "xfs_iformat_extents(1)", dip, sizeof(*dip), __this_address); @@ -205,7 +205,7 @@ xfs_iformat_btree( ifp->if_nextents > ip->i_nblocks) || level == 0 || level > XFS_BM_MAXLEVELS(mp, whichfork)) { xfs_warn(mp, "corrupt inode %llu (btree).", - (unsigned long long) ip->i_ino); + (unsigned long long)I_INO(ip)); xfs_inode_verifier_error(ip, -EFSCORRUPTED, "xfs_iformat_btree", dfp, size, __this_address); diff --git a/fs/xfs/libxfs/xfs_inode_util.c b/fs/xfs/libxfs/xfs_inode_util.c index 551fa51befb6..258ac3d0d486 100644 --- a/fs/xfs/libxfs/xfs_inode_util.c +++ b/fs/xfs/libxfs/xfs_inode_util.c @@ -130,6 +130,8 @@ xfs_ip2xflags( if (xfs_inode_has_attr_fork(ip)) flags |= FS_XFLAG_HASATTR; + if (xfs_has_asciici(ip->i_mount)) + flags |= FS_XFLAG_CASEFOLD; return flags; } @@ -462,10 +464,9 @@ xfs_iunlink_insert_inode( struct xfs_buf *agibp, struct xfs_inode *ip) { - struct xfs_mount *mp = tp->t_mountp; struct xfs_agi *agi = agibp->b_addr; xfs_agino_t next_agino; - xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino); + xfs_agino_t agino = XFS_INODE_TO_AGINO(ip); short bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; int error; @@ -529,7 +530,7 @@ xfs_iunlink( ASSERT(VFS_I(ip)->i_mode != 0); trace_xfs_iunlink(ip); - pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); + pag = xfs_perag_get(mp, XFS_INODE_TO_AGNO(ip)); /* Get the agi buffer first. It ensures lock ordering on the list. */ error = xfs_read_agi(pag, tp, 0, &agibp); @@ -551,7 +552,7 @@ xfs_iunlink_remove_inode( { struct xfs_mount *mp = tp->t_mountp; struct xfs_agi *agi = agibp->b_addr; - xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino); + xfs_agino_t agino = XFS_INODE_TO_AGINO(ip); xfs_agino_t head_agino; short bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; int error; @@ -653,7 +654,7 @@ xfs_droplink( if (inode->i_nlink == 0) { xfs_info_ratelimited(tp->t_mountp, "Inode 0x%llx link count dropped below zero. Pinning link count.", - ip->i_ino); + I_INO(ip)); set_nlink(inode, XFS_NLINK_PINNED); } if (inode->i_nlink != XFS_NLINK_PINNED) @@ -682,7 +683,7 @@ xfs_bumplink( if (inode->i_nlink == XFS_NLINK_PINNED - 1) xfs_info_ratelimited(tp->t_mountp, "Inode 0x%llx link count exceeded maximum. Pinning link count.", - ip->i_ino); + I_INO(ip)); if (inode->i_nlink != XFS_NLINK_PINNED) inc_nlink(inode); @@ -706,7 +707,7 @@ xfs_inode_uninit( * makes the AGI lock -> unlinked list modification order the same as * used in O_TMPFILE creation. */ - error = xfs_difree(tp, pag, ip->i_ino, xic); + error = xfs_difree(tp, pag, I_INO(ip), xic); if (error) return error; diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 3f5a24dda907..a4e1b3eb425c 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -52,6 +52,19 @@ typedef uint32_t xlog_tid_t; #define CYCLE_LSN(lsn) ((uint)((lsn)>>32)) #define BLOCK_LSN(lsn) ((uint)(lsn)) +/* + * By comparing each component, we don't have to worry about extra endian issues + * in treating two 32 bit numbers as one 64 bit number + */ +static inline xfs_lsn_t XFS_LSN_CMP(xfs_lsn_t lsn1, xfs_lsn_t lsn2) +{ + if (CYCLE_LSN(lsn1) != CYCLE_LSN(lsn2)) + return CYCLE_LSN(lsn1) < CYCLE_LSN(lsn2) ? -999 : 999; + if (BLOCK_LSN(lsn1) != BLOCK_LSN(lsn2)) + return BLOCK_LSN(lsn1) < BLOCK_LSN(lsn2) ? -999 : 999; + return 0; +} + /* this is used in a spot where we might otherwise double-endian-flip */ #define CYCLE_LSN_DISK(lsn) (((__be32 *)&(lsn))[0]) diff --git a/fs/xfs/libxfs/xfs_metadir.c b/fs/xfs/libxfs/xfs_metadir.c index 3e5c61188927..7c6b086b73db 100644 --- a/fs/xfs/libxfs/xfs_metadir.c +++ b/fs/xfs/libxfs/xfs_metadir.c @@ -95,7 +95,7 @@ xfs_metadir_lookup( .hashval = xfs_dir2_hashname(mp, xname), .whichfork = XFS_DATA_FORK, .op_flags = XFS_DA_OP_OKNOENT, - .owner = dp->i_ino, + .owner = I_INO(dp), }; int error; @@ -182,7 +182,7 @@ xfs_metadir_teardown( * Begin the process of creating a metadata file by allocating transactions * and taking whatever resources we're going to need. */ -int +static int xfs_metadir_start_create( struct xfs_metadir_update *upd) { @@ -236,7 +236,7 @@ out_teardown: * a negative error code. If an inode is passed back, the caller must finish * setting up the inode before releasing it. */ -int +static int xfs_metadir_create( struct xfs_metadir_update *upd, umode_t mode) @@ -425,7 +425,7 @@ xfs_metadir_commit( } /* Cancel a metadir update and unlock/drop all resources. */ -void +static void xfs_metadir_cancel( struct xfs_metadir_update *upd, int error) @@ -438,48 +438,64 @@ xfs_metadir_cancel( xfs_metadir_teardown(upd, error); } -/* Create a metadata for the last component of the path. */ int -xfs_metadir_mkdir( - struct xfs_inode *dp, - const char *path, +xfs_metadir_create_file( + struct xfs_metadir_update *upd, + umode_t mode, + xfs_metadir_createfn create, + void *priv, struct xfs_inode **ipp) { - struct xfs_metadir_update upd = { - .dp = dp, - .path = path, - .metafile_type = XFS_METAFILE_DIR, - }; int error; - if (xfs_is_shutdown(dp->i_mount)) + if (xfs_is_shutdown(upd->dp->i_mount)) return -EIO; - /* Allocate a transaction to create the last directory. */ - error = xfs_metadir_start_create(&upd); + error = xfs_metadir_start_create(upd); if (error) return error; - /* Create the subdirectory and take our reference. */ - error = xfs_metadir_create(&upd, S_IFDIR); + error = xfs_metadir_create(upd, mode); if (error) goto out_cancel; - error = xfs_metadir_commit(&upd); + if (create) { + error = create(upd, priv); + if (error) + goto out_cancel; + } + + error = xfs_metadir_commit(upd); if (error) goto out_irele; - xfs_finish_inode_setup(upd.ip); - *ipp = upd.ip; + xfs_finish_inode_setup(upd->ip); + *ipp = upd->ip; return 0; out_cancel: - xfs_metadir_cancel(&upd, error); + xfs_metadir_cancel(upd, error); out_irele: /* Have to finish setting up the inode to ensure it's deleted. */ - if (upd.ip) { - xfs_finish_inode_setup(upd.ip); - xfs_irele(upd.ip); + if (upd->ip) { + xfs_finish_inode_setup(upd->ip); + xfs_irele(upd->ip); } return error; } + +/* Create a metadata for the last component of the path. */ +int +xfs_metadir_mkdir( + struct xfs_inode *dp, + const char *path, + struct xfs_inode **ipp) +{ + struct xfs_metadir_update upd = { + .dp = dp, + .path = path, + .metafile_type = XFS_METAFILE_DIR, + }; + + return xfs_metadir_create_file(&upd, S_IFDIR, NULL, NULL, ipp); +} diff --git a/fs/xfs/libxfs/xfs_metadir.h b/fs/xfs/libxfs/xfs_metadir.h index bfecac7d3d14..e434b9d1c932 100644 --- a/fs/xfs/libxfs/xfs_metadir.h +++ b/fs/xfs/libxfs/xfs_metadir.h @@ -32,14 +32,16 @@ int xfs_metadir_load(struct xfs_trans *tp, struct xfs_inode *dp, const char *path, enum xfs_metafile_type metafile_type, struct xfs_inode **ipp); -int xfs_metadir_start_create(struct xfs_metadir_update *upd); -int xfs_metadir_create(struct xfs_metadir_update *upd, umode_t mode); +typedef int (*xfs_metadir_createfn)(struct xfs_metadir_update *upd, void *priv); + +int xfs_metadir_create_file(struct xfs_metadir_update *upd, umode_t mode, + xfs_metadir_createfn create, void *priv, + struct xfs_inode **ipp); int xfs_metadir_start_link(struct xfs_metadir_update *upd); int xfs_metadir_link(struct xfs_metadir_update *upd); int xfs_metadir_commit(struct xfs_metadir_update *upd); -void xfs_metadir_cancel(struct xfs_metadir_update *upd, int error); int xfs_metadir_mkdir(struct xfs_inode *dp, const char *path, struct xfs_inode **ipp); diff --git a/fs/xfs/libxfs/xfs_metafile.c b/fs/xfs/libxfs/xfs_metafile.c index 71f004e9dc64..1f54d39003c2 100644 --- a/fs/xfs/libxfs/xfs_metafile.c +++ b/fs/xfs/libxfs/xfs_metafile.c @@ -297,14 +297,14 @@ xfs_metafile_resv_init( goto out_unlock; /* - * Space taken by the per-AG metadata btrees are accounted on-disk as - * used space. We therefore only hide the space that is reserved but - * not used by the trees. + * Space taken by metadata btrees are accounted on-disk as used space. + * We therefore only hide the space that is reserved but not used by + * the trees. */ if (used > target) target = used; else if (target > dblocks_avail) - target = dblocks_avail; + target = max(dblocks_avail, used); hidden_space = target - used; error = xfs_dec_fdblocks(mp, hidden_space, true); diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 3509cc4b2175..a2f2f5fa640e 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -23,7 +23,6 @@ #include "xfs_attr_sf.h" #include "xfs_bmap.h" #include "xfs_defer.h" -#include "xfs_log.h" #include "xfs_xattr.h" #include "xfs_parent.h" #include "xfs_trans_space.h" @@ -194,7 +193,7 @@ xfs_parent_addname( const struct xfs_name *parent_name, struct xfs_inode *child) { - int error; + int error, local; error = xfs_parent_iread_extents(tp, child); if (error) @@ -202,7 +201,11 @@ xfs_parent_addname( xfs_inode_to_parent_rec(&ppargs->rec, dp); xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, - child->i_ino, parent_name); + I_INO(child), parent_name); + + /* Growing the attr fork needs a real reservation in args->total. */ + ppargs->args.total = xfs_attr_calc_size(&ppargs->args, &local); + ASSERT(local); return xfs_attr_setname(&ppargs->args, 0); } @@ -224,7 +227,7 @@ xfs_parent_removename( xfs_inode_to_parent_rec(&ppargs->rec, dp); xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, - child->i_ino, parent_name); + I_INO(child), parent_name); return xfs_attr_removename(&ppargs->args); } @@ -240,7 +243,7 @@ xfs_parent_replacename( const struct xfs_name *new_name, struct xfs_inode *child) { - int error; + int error, local; error = xfs_parent_iread_extents(tp, child); if (error) @@ -248,7 +251,11 @@ xfs_parent_replacename( xfs_inode_to_parent_rec(&ppargs->rec, old_dp); xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, - child->i_ino, old_name); + I_INO(child), old_name); + + /* Growing the attr fork needs a real reservation in args->total. */ + ppargs->args.total = xfs_attr_calc_size(&ppargs->args, &local); + ASSERT(local); xfs_inode_to_parent_rec(&ppargs->new_rec, new_dp); @@ -312,7 +319,7 @@ xfs_parent_lookup( struct xfs_da_args *scratch) { memset(scratch, 0, sizeof(struct xfs_da_args)); - xfs_parent_da_args_init(scratch, tp, pptr, ip, ip->i_ino, parent_name); + xfs_parent_da_args_init(scratch, tp, pptr, ip, I_INO(ip), parent_name); return xfs_attr_get_ilocked(scratch); } diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index b8036527cdc7..8eb4de9c5f1a 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -34,7 +34,7 @@ xfs_inode_to_parent_rec( struct xfs_parent_rec *rec, const struct xfs_inode *dp) { - xfs_parent_rec_init(rec, dp->i_ino, VFS_IC(dp)->i_generation); + xfs_parent_rec_init(rec, I_INO(dp), VFS_IC(dp)->i_generation); } extern struct kmem_cache *xfs_parent_args_cache; diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c index 40c7f0ff6cf3..0ec6ccd8b4dc 100644 --- a/fs/xfs/libxfs/xfs_refcount.c +++ b/fs/xfs/libxfs/xfs_refcount.c @@ -1414,8 +1414,7 @@ xfs_refcount_finish_one( if (rcur == NULL) { struct xfs_perag *pag = to_perag(ri->ri_group); - error = xfs_alloc_read_agf(pag, tp, - XFS_ALLOC_FLAG_FREEING, &agbp); + error = xfs_alloc_read_agf(pag, tp, 0, &agbp); if (error) return error; diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c index e78133c908ca..34d218de21a9 100644 --- a/fs/xfs/libxfs/xfs_rmap.c +++ b/fs/xfs/libxfs/xfs_rmap.c @@ -2780,7 +2780,7 @@ xfs_rmap_map_extent( if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip)) type = XFS_RMAP_MAP_SHARED; - __xfs_rmap_add(tp, type, ip->i_ino, isrt, whichfork, PREV); + __xfs_rmap_add(tp, type, I_INO(ip), isrt, whichfork, PREV); } /* Unmap an extent out of a file. */ @@ -2800,7 +2800,7 @@ xfs_rmap_unmap_extent( if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip)) type = XFS_RMAP_UNMAP_SHARED; - __xfs_rmap_add(tp, type, ip->i_ino, isrt, whichfork, PREV); + __xfs_rmap_add(tp, type, I_INO(ip), isrt, whichfork, PREV); } /* @@ -2826,7 +2826,7 @@ xfs_rmap_convert_extent( if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip)) type = XFS_RMAP_CONVERT_SHARED; - __xfs_rmap_add(tp, type, ip->i_ino, isrt, whichfork, PREV); + __xfs_rmap_add(tp, type, I_INO(ip), isrt, whichfork, PREV); } /* Schedule the creation of an rmap for non-file data. */ diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h index 5f39f6e53cd1..4afa33575ce2 100644 --- a/fs/xfs/libxfs/xfs_rmap.h +++ b/fs/xfs/libxfs/xfs_rmap.h @@ -21,6 +21,8 @@ xfs_rmap_ino_bmbt_owner( if (whichfork == XFS_ATTR_FORK) oi->oi_flags |= XFS_OWNER_INFO_ATTR_FORK; } +#define xfs_rmap_inode_bmbt_owner(oi, ip, whichfork) \ + xfs_rmap_ino_bmbt_owner(oi, I_INO(ip), whichfork) static inline void xfs_rmap_ino_owner( @@ -35,6 +37,8 @@ xfs_rmap_ino_owner( if (whichfork == XFS_ATTR_FORK) oi->oi_flags |= XFS_OWNER_INFO_ATTR_FORK; } +#define xfs_rmap_inode_owner(oi, ip, whichfork, offset) \ + xfs_rmap_ino_owner(oi, I_INO(ip), whichfork, offset) static inline bool xfs_rmap_should_skip_owner_update( diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c index bc4c0a99f4dd..e62786e90f7b 100644 --- a/fs/xfs/libxfs/xfs_rtbitmap.c +++ b/fs/xfs/libxfs/xfs_rtbitmap.c @@ -214,7 +214,7 @@ xfs_rtbuf_get( if (xfs_has_rtgroups(mp)) { struct xfs_rtbuf_blkinfo *hdr = bp->b_addr; - if (hdr->rt_owner != cpu_to_be64(ip->i_ino)) { + if (hdr->rt_owner != cpu_to_be64(I_INO(ip))) { xfs_buf_mark_corrupt(bp); xfs_trans_brelse(args->tp, bp); xfs_rtginode_mark_sick(args->rtg, type); @@ -1409,7 +1409,7 @@ xfs_rtfile_initialize_block( hdr->rt_magic = cpu_to_be32(XFS_RTBITMAP_MAGIC); else hdr->rt_magic = cpu_to_be32(XFS_RTSUMMARY_MAGIC); - hdr->rt_owner = cpu_to_be64(ip->i_ino); + hdr->rt_owner = cpu_to_be64(I_INO(ip)); hdr->rt_blkno = cpu_to_be64(XFS_FSB_TO_DADDR(mp, fsbno)); hdr->rt_lsn = 0; uuid_copy(&hdr->rt_uuid, &mp->m_sb.sb_meta_uuid); diff --git a/fs/xfs/libxfs/xfs_rtgroup.c b/fs/xfs/libxfs/xfs_rtgroup.c index c85d50953218..fe7222bbe449 100644 --- a/fs/xfs/libxfs/xfs_rtgroup.c +++ b/fs/xfs/libxfs/xfs_rtgroup.c @@ -517,6 +517,25 @@ xfs_rtginode_irele( *ipp = NULL; } +struct xfs_rtginode_create { + struct xfs_rtgroup *rtg; + enum xfs_rtg_inodes type; + bool init; +}; + +static int +xfs_rtginode_init( + struct xfs_metadir_update *upd, + void *priv) +{ + struct xfs_rtginode_create *rc = priv; + const struct xfs_rtginode_ops *ops = &xfs_rtginode_ops[rc->type]; + + xfs_rtginode_lockdep_setup(upd->ip, rtg_rgno(rc->rtg), rc->type); + upd->ip->i_projid = rtg_rgno(rc->rtg); + return ops->create(rc->rtg, upd->ip, upd->tp, rc->init); +} + /* Add a metadata inode for a realtime rmap btree. */ int xfs_rtginode_create( @@ -526,6 +545,11 @@ xfs_rtginode_create( { const struct xfs_rtginode_ops *ops = &xfs_rtginode_ops[type]; struct xfs_mount *mp = rtg_mount(rtg); + struct xfs_rtginode_create rc = { + .rtg = rtg, + .type = type, + .init = init, + }; struct xfs_metadir_update upd = { .dp = mp->m_rtdirip, .metafile_type = ops->metafile_type, @@ -544,38 +568,8 @@ xfs_rtginode_create( if (!upd.path) return -ENOMEM; - error = xfs_metadir_start_create(&upd); - if (error) - goto out_path; - - error = xfs_metadir_create(&upd, S_IFREG); - if (error) - goto out_cancel; - - xfs_rtginode_lockdep_setup(upd.ip, rtg_rgno(rtg), type); - - upd.ip->i_projid = rtg_rgno(rtg); - error = ops->create(rtg, upd.ip, upd.tp, init); - if (error) - goto out_cancel; - - error = xfs_metadir_commit(&upd); - if (error) - goto out_path; - - kfree(upd.path); - xfs_finish_inode_setup(upd.ip); - rtg->rtg_inodes[type] = upd.ip; - return 0; - -out_cancel: - xfs_metadir_cancel(&upd, error); - /* Have to finish setting up the inode to ensure it's deleted. */ - if (upd.ip) { - xfs_finish_inode_setup(upd.ip); - xfs_irele(upd.ip); - } -out_path: + error = xfs_metadir_create_file(&upd, S_IFREG, xfs_rtginode_init, &rc, + &rtg->rtg_inodes[type]); kfree(upd.path); return error; } diff --git a/fs/xfs/libxfs/xfs_rtgroup.h b/fs/xfs/libxfs/xfs_rtgroup.h index c0b9f9f2c413..fca2eb74908c 100644 --- a/fs/xfs/libxfs/xfs_rtgroup.h +++ b/fs/xfs/libxfs/xfs_rtgroup.h @@ -359,7 +359,11 @@ static inline int xfs_initialize_rtgroups(struct xfs_mount *mp, # define xfs_rtgroup_unlock(rtg, gf) ((void)0) # define xfs_rtgroup_trans_join(tp, rtg, gf) ((void)0) # define xfs_update_rtsb(bp, sb_bp) ((void)0) -# define xfs_log_rtsb(tp, sb_bp) (NULL) +static inline struct xfs_buf *xfs_log_rtsb(struct xfs_trans *tp, + const struct xfs_buf *sb_bp) +{ + return NULL; +} # define xfs_rtgroup_get_geometry(rtg, rgeo) (-EOPNOTSUPP) #endif /* CONFIG_XFS_RT */ diff --git a/fs/xfs/libxfs/xfs_rtrefcount_btree.c b/fs/xfs/libxfs/xfs_rtrefcount_btree.c index c1518267eb17..dcc89b8e149b 100644 --- a/fs/xfs/libxfs/xfs_rtrefcount_btree.c +++ b/fs/xfs/libxfs/xfs_rtrefcount_btree.c @@ -201,7 +201,7 @@ xfs_rtrefcountbt_verify( if (fa) return fa; level = be16_to_cpu(block->bb_level); - if (level > mp->m_rtrefc_maxlevels) + if (level >= mp->m_rtrefc_maxlevels) return __this_address; return xfs_btree_fsblock_verify(bp, mp->m_rtrefc_mxr[level != 0]); @@ -489,8 +489,11 @@ xfs_rtrefcountbt_maxlevels_ondisk(void) minrecs[0] = xfs_rtrefcountbt_block_maxrecs(blocklen, true) / 2; minrecs[1] = xfs_rtrefcountbt_block_maxrecs(blocklen, false) / 2; - /* We need at most one record for every block in an rt group. */ - return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_RGBLOCKS); + /* + * We need at most one record for every block in an rt group, and + * one extra level for the inode root. + */ + return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_RGBLOCKS) + 1; } int __init @@ -602,7 +605,7 @@ xfs_rtrefcountbt_from_disk( rblocklen = xfs_rtrefcount_broot_space(mp, dblock); xfs_btree_init_block(mp, rblock, &xfs_rtrefcountbt_ops, 0, 0, - ip->i_ino); + I_INO(ip)); rblock->bb_level = dblock->bb_level; rblock->bb_numrecs = dblock->bb_numrecs; @@ -614,7 +617,7 @@ xfs_rtrefcountbt_from_disk( fpp = xfs_rtrefcount_droot_ptr_addr(dblock, 1, maxrecs); tpp = xfs_rtrefcount_broot_ptr_addr(mp, rblock, 1, rblocklen); numrecs = be16_to_cpu(dblock->bb_numrecs); - memcpy(tkp, fkp, 2 * sizeof(*fkp) * numrecs); + memcpy(tkp, fkp, sizeof(*fkp) * numrecs); memcpy(tpp, fpp, sizeof(*fpp) * numrecs); } else { frp = xfs_rtrefcount_droot_rec_addr(dblock, 1); @@ -651,7 +654,7 @@ xfs_iformat_rtrefcount( numrecs = be16_to_cpu(dfp->bb_numrecs); level = be16_to_cpu(dfp->bb_level); - if (level > mp->m_rtrefc_maxlevels || + if (level >= mp->m_rtrefc_maxlevels || xfs_rtrefcount_droot_space_calc(level, numrecs) > dsize) { xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE); return -EFSCORRUPTED; @@ -700,7 +703,7 @@ xfs_rtrefcountbt_to_disk( fpp = xfs_rtrefcount_broot_ptr_addr(mp, rblock, 1, rblocklen); tpp = xfs_rtrefcount_droot_ptr_addr(dblock, 1, maxrecs); numrecs = be16_to_cpu(rblock->bb_numrecs); - memcpy(tkp, fkp, 2 * sizeof(*fkp) * numrecs); + memcpy(tkp, fkp, sizeof(*fkp) * numrecs); memcpy(tpp, fpp, sizeof(*fpp) * numrecs); } else { frp = xfs_rtrefcount_rec_addr(rblock, 1); @@ -751,7 +754,7 @@ xfs_rtrefcountbt_create( xfs_rtrefcount_broot_space_calc(mp, 0, 0)); if (broot) xfs_btree_init_block(mp, broot, &xfs_rtrefcountbt_ops, 0, 0, - ip->i_ino); + I_INO(ip)); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE | XFS_ILOG_DBROOT); return 0; } diff --git a/fs/xfs/libxfs/xfs_rtrmap_btree.c b/fs/xfs/libxfs/xfs_rtrmap_btree.c index 00557b7ef298..a15e460a1ec7 100644 --- a/fs/xfs/libxfs/xfs_rtrmap_btree.c +++ b/fs/xfs/libxfs/xfs_rtrmap_btree.c @@ -618,7 +618,7 @@ xfs_rtrmapbt_mem_cursor( struct xfs_btree_cur *cur; cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_mem_ops, - mp->m_rtrmap_maxlevels, xfs_rtrmapbt_cur_cache); + xfs_rtrmapbt_maxlevels_ondisk(), xfs_rtrmapbt_cur_cache); cur->bc_mem.xfbtree = xfbt; cur->bc_nlevels = xfbt->nlevels; cur->bc_group = xfs_group_hold(rtg_group(rtg)); @@ -716,10 +716,12 @@ xfs_rtrmapbt_maxlevels_ondisk(void) * happens, which means that we must compute the max height based on * what the btree will look like if it consumes almost all the blocks * in the data device due to maximal sharing factor. + * + * Add one extra level for the inode root. */ max_dblocks = -1U; /* max ag count */ max_dblocks *= XFS_MAX_CRC_AG_BLOCKS; - return xfs_btree_space_to_height(minrecs, max_dblocks); + return xfs_btree_space_to_height(minrecs, max_dblocks) + 1; } int __init @@ -839,7 +841,7 @@ xfs_rtrmapbt_from_disk( unsigned int numrecs; unsigned int maxrecs; - xfs_btree_init_block(mp, rblock, &xfs_rtrmapbt_ops, 0, 0, ip->i_ino); + xfs_btree_init_block(mp, rblock, &xfs_rtrmapbt_ops, 0, 0, I_INO(ip)); rblock->bb_level = dblock->bb_level; rblock->bb_numrecs = dblock->bb_numrecs; @@ -981,7 +983,7 @@ xfs_rtrmapbt_create( broot = xfs_broot_realloc(ifp, xfs_rtrmap_broot_space_calc(mp, 0, 0)); if (broot) xfs_btree_init_block(mp, broot, &xfs_rtrmapbt_ops, 0, 0, - ip->i_ino); + I_INO(ip)); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE | XFS_ILOG_DBROOT); return 0; diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 47322adb7690..f0341adbb879 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -1118,10 +1118,10 @@ xfs_sb_read_verify( * because _verify_common checks the on-disk values. */ __xfs_sb_from_disk(&sb, dsb, false); - error = xfs_validate_sb_common(mp, bp, &sb); + error = xfs_validate_sb_read(mp, &sb); if (error) goto out_error; - error = xfs_validate_sb_read(mp, &sb); + error = xfs_validate_sb_common(mp, bp, &sb); out_error: if (error == -EFSCORRUPTED || error == -EFSBADCRC) @@ -1470,36 +1470,33 @@ xfs_sync_sb_buf( bool update_rtsb) { struct xfs_trans *tp; - struct xfs_buf *bp; - struct xfs_buf *rtsb_bp = NULL; int error; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_sb, 0, 0, 0, &tp); if (error) return error; - bp = xfs_trans_getsb(tp); xfs_log_sb(tp); - xfs_trans_bhold(tp, bp); - if (update_rtsb) { - rtsb_bp = xfs_log_rtsb(tp, bp); - if (rtsb_bp) - xfs_trans_bhold(tp, rtsb_bp); - } + if (update_rtsb) + xfs_log_rtsb(tp, xfs_trans_getsb(tp)); xfs_trans_set_sync(tp); error = xfs_trans_commit(tp); if (error) - goto out; - /* - * write out the sb buffer to get the changes to disk - */ - error = xfs_bwrite(bp); - if (!error && rtsb_bp) - error = xfs_bwrite(rtsb_bp); -out: - if (rtsb_bp) - xfs_buf_relse(rtsb_bp); - xfs_buf_relse(bp); + return error; + + /* Re-acquire and write the sb and rtsb to disk. */ + xfs_buf_lock(mp->m_sb_bp); + error = xfs_bwrite(mp->m_sb_bp); + xfs_buf_unlock(mp->m_sb_bp); + if (error) + return error; + + if (update_rtsb && mp->m_rtsb_bp) { + xfs_buf_lock(mp->m_rtsb_bp); + error = xfs_bwrite(mp->m_rtsb_bp); + xfs_buf_unlock(mp->m_rtsb_bp); + } + return error; } diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c index f9a5966d8048..b0dc3888bf1b 100644 --- a/fs/xfs/libxfs/xfs_symlink_remote.c +++ b/fs/xfs/libxfs/xfs_symlink_remote.c @@ -196,7 +196,7 @@ xfs_symlink_local_to_remote( bp->b_ops = &xfs_symlink_buf_ops; buf = bp->b_addr; - buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); + buf += xfs_symlink_hdr_set(mp, I_INO(ip), 0, ifp->if_bytes, bp); memcpy(buf, ifp->if_data, ifp->if_bytes); xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) + ifp->if_bytes - 1); @@ -277,13 +277,13 @@ xfs_symlink_remote_read( cur_chunk = bp->b_addr; if (xfs_has_crc(mp)) { - if (!xfs_symlink_hdr_ok(ip->i_ino, offset, + if (!xfs_symlink_hdr_ok(I_INO(ip), offset, byte_cnt, bp)) { xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK); error = -EFSCORRUPTED; xfs_alert(mp, "symlink header does not match required off/len/owner (0x%x/0x%x,0x%llx)", - offset, byte_cnt, ip->i_ino); + offset, byte_cnt, I_INO(ip)); xfs_buf_relse(bp); goto out; diff --git a/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c index 9b8f495c9049..c4cd547033e5 100644 --- a/fs/xfs/libxfs/xfs_trans_space.c +++ b/fs/xfs/libxfs/xfs_trans_space.c @@ -22,8 +22,23 @@ xfs_parent_calc_space_res( unsigned int namelen) { /* - * Parent pointers are always the first attr in an attr tree, and never - * larger than a block + * A parent pointer is recorded per dirent, so an inode with N links + * carries N of them and the attr fork can already be in leaf or node + * format when one is added. That does not affect the reservation: + * XFS_DAENTER_SPACE_RES covers a split at every level of a + * maximum-depth attr dabtree, whatever format the fork is in now. + * + * The name is a dirent name and the value is a struct xfs_parent_rec, + * so the leaf entry is always local and never exceeds 272 bytes. + * Parent pointers require V5, hence a 1k minimum block size, so the + * entry always stays under half a block and this needs none of the + * double split allowance that xfs_attr_calc_size() makes. + * + * The second term hands a byte count to a macro whose parameter counts + * mappings, so it asks for more extent-add allowance than the single + * mapping a parent pointer adds - how much more depends on the block + * size. It over-reserves either way, which is why it is left alone: + * correcting the unit would shrink a reservation that is only generous. */ return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_NEXTENTADD_SPACE_RES(mp, namelen, XFS_ATTR_FORK); |
