]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - libxfs/xfs_bmap.c
xfs: perags need atomic operational state
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_bmap.c
index 11f3f5f9d2071a3f5176a413573dd39cb9fbeeb5..badc15054fddf0729d220af005c078ddc42ae395 100644 (file)
 #include "xfs_attr_leaf.h"
 #include "xfs_quota_defs.h"
 #include "xfs_rmap.h"
+#include "xfs_ag.h"
 #include "xfs_ag_resv.h"
 #include "xfs_refcount.h"
 
-
-kmem_zone_t            *xfs_bmap_free_item_zone;
+struct kmem_cache              *xfs_bmap_intent_cache;
 
 /*
  * Miscellaneous helper functions
@@ -45,46 +45,54 @@ xfs_bmap_compute_maxlevels(
        xfs_mount_t     *mp,            /* file system mount structure */
        int             whichfork)      /* data or attr fork */
 {
+       uint64_t        maxblocks;      /* max blocks at this level */
+       xfs_extnum_t    maxleafents;    /* max leaf entries possible */
        int             level;          /* btree level */
-       uint            maxblocks;      /* max blocks at this level */
-       uint            maxleafents;    /* max leaf entries possible */
        int             maxrootrecs;    /* max records in root block */
        int             minleafrecs;    /* min records in leaf block */
        int             minnoderecs;    /* min records in node block */
        int             sz;             /* root block size */
 
        /*
-        * The maximum number of extents in a file, hence the maximum
-        * number of leaf entries, is controlled by the type of di_nextents
-        * (a signed 32-bit number, xfs_extnum_t), or by di_anextents
-        * (a signed 16-bit number, xfs_aextnum_t).
+        * The maximum number of extents in a fork, hence the maximum number of
+        * leaf entries, is controlled by the size of the on-disk extent count.
         *
-        * Note that we can no longer assume that if we are in ATTR1 that
-        * the fork offset of all the inodes will be
-        * (xfs_default_attroffset(ip) >> 3) because we could have mounted
-        * with ATTR2 and then mounted back with ATTR1, keeping the
-        * di_forkoff's fixed but probably at various positions. Therefore,
-        * for both ATTR1 and ATTR2 we have to assume the worst case scenario
-        * of a minimum size available.
+        * Note that we can no longer assume that if we are in ATTR1 that the
+        * fork offset of all the inodes will be
+        * (xfs_default_attroffset(ip) >> 3) because we could have mounted with
+        * ATTR2 and then mounted back with ATTR1, keeping the i_forkoff's fixed
+        * but probably at various positions. Therefore, for both ATTR1 and
+        * ATTR2 we have to assume the worst case scenario of a minimum size
+        * available.
         */
-       if (whichfork == XFS_DATA_FORK) {
-               maxleafents = MAXEXTNUM;
+       maxleafents = xfs_iext_max_nextents(xfs_has_large_extent_counts(mp),
+                               whichfork);
+       if (whichfork == XFS_DATA_FORK)
                sz = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
-       } else {
-               maxleafents = MAXAEXTNUM;
+       else
                sz = XFS_BMDR_SPACE_CALC(MINABTPTRS);
-       }
+
        maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
        minleafrecs = mp->m_bmap_dmnr[0];
        minnoderecs = mp->m_bmap_dmnr[1];
-       maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
+       maxblocks = howmany_64(maxleafents, minleafrecs);
        for (level = 1; maxblocks > 1; level++) {
                if (maxblocks <= maxrootrecs)
                        maxblocks = 1;
                else
-                       maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs;
+                       maxblocks = howmany_64(maxblocks, minnoderecs);
        }
        mp->m_bm_maxlevels[whichfork] = level;
+       ASSERT(mp->m_bm_maxlevels[whichfork] <= xfs_bmbt_maxlevels_ondisk());
+}
+
+unsigned int
+xfs_bmap_compute_attr_offset(
+       struct xfs_mount        *mp)
+{
+       if (mp->m_sb.sb_inodesize == 256)
+               return XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
+       return XFS_BMDR_SPACE_CALC(6 * MINABTPTRS);
 }
 
 STATIC int                             /* error */
@@ -113,10 +121,11 @@ xfs_bmbt_lookup_first(
  */
 static inline bool xfs_bmap_needs_btree(struct xfs_inode *ip, int whichfork)
 {
+       struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
+
        return whichfork != XFS_COW_FORK &&
-               XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
-               XFS_IFORK_NEXTENTS(ip, whichfork) >
-                       XFS_IFORK_MAXEXT(ip, whichfork);
+               ifp->if_format == XFS_DINODE_FMT_EXTENTS &&
+               ifp->if_nextents > XFS_IFORK_MAXEXT(ip, whichfork);
 }
 
 /*
@@ -124,10 +133,11 @@ static inline bool xfs_bmap_needs_btree(struct xfs_inode *ip, int whichfork)
  */
 static inline bool xfs_bmap_wants_extents(struct xfs_inode *ip, int whichfork)
 {
+       struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
+
        return whichfork != XFS_COW_FORK &&
-               XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
-               XFS_IFORK_NEXTENTS(ip, whichfork) <=
-                       XFS_IFORK_MAXEXT(ip, whichfork);
+               ifp->if_format == XFS_DINODE_FMT_BTREE &&
+               ifp->if_nextents <= XFS_IFORK_MAXEXT(ip, whichfork);
 }
 
 /*
@@ -183,22 +193,15 @@ uint
 xfs_default_attroffset(
        struct xfs_inode        *ip)
 {
-       struct xfs_mount        *mp = ip->i_mount;
-       uint                    offset;
-
-       if (mp->m_sb.sb_inodesize == 256)
-               offset = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
-       else
-               offset = XFS_BMDR_SPACE_CALC(6 * MINABTPTRS);
-
-       ASSERT(offset < XFS_LITINO(mp));
-       return offset;
+       if (ip->i_df.if_format == XFS_DINODE_FMT_DEV)
+               return roundup(sizeof(xfs_dev_t), 8);
+       return M_IGEO(ip->i_mount)->attr_fork_offset;
 }
 
 /*
- * Helper routine to reset inode di_forkoff field when switching
- * attribute fork from local to extent format - we reset it where
- * possible to make space available for inline data fork extents.
+ * Helper routine to reset inode i_forkoff field when switching attribute fork
+ * from local to extent format - we reset it where possible to make space
+ * available for inline data fork extents.
  */
 STATIC void
 xfs_bmap_forkoff_reset(
@@ -206,12 +209,12 @@ xfs_bmap_forkoff_reset(
        int             whichfork)
 {
        if (whichfork == XFS_ATTR_FORK &&
-           ip->i_d.di_format != XFS_DINODE_FMT_DEV &&
-           ip->i_d.di_format != XFS_DINODE_FMT_BTREE) {
+           ip->i_df.if_format != XFS_DINODE_FMT_DEV &&
+           ip->i_df.if_format != XFS_DINODE_FMT_BTREE) {
                uint    dfl_forkoff = xfs_default_attroffset(ip) >> 3;
 
-               if (dfl_forkoff > ip->i_d.di_forkoff)
-                       ip->i_d.di_forkoff = dfl_forkoff;
+               if (dfl_forkoff > ip->i_forkoff)
+                       ip->i_forkoff = dfl_forkoff;
        }
 }
 
@@ -227,11 +230,11 @@ xfs_bmap_get_bp(
        if (!cur)
                return NULL;
 
-       for (i = 0; i < XFS_BTREE_MAXLEVELS; i++) {
-               if (!cur->bc_bufs[i])
+       for (i = 0; i < cur->bc_maxlevels; i++) {
+               if (!cur->bc_levels[i].bp)
                        break;
-               if (XFS_BUF_ADDR(cur->bc_bufs[i]) == bno)
-                       return cur->bc_bufs[i];
+               if (xfs_buf_daddr(cur->bc_levels[i].bp) == bno)
+                       return cur->bc_levels[i].bp;
        }
 
        /* Chase down all the log items to see if the bp is there */
@@ -239,7 +242,7 @@ xfs_bmap_get_bp(
                struct xfs_buf_log_item *bip = (struct xfs_buf_log_item *)lip;
 
                if (bip->bli_item.li_type == XFS_LI_BUF &&
-                   XFS_BUF_ADDR(bip->bli_buf) == bno)
+                   xfs_buf_daddr(bip->bli_buf) == bno)
                        return bip->bli_buf;
        }
 
@@ -284,7 +287,7 @@ xfs_check_block(
                        else
                                thispa = XFS_BMBT_PTR_ADDR(mp, block, j, dmxr);
                        if (*thispa == *pp) {
-                               xfs_warn(mp, "%s: thispa(%d) == pp(%d) %Ld",
+                               xfs_warn(mp, "%s: thispa(%d) == pp(%d) %lld",
                                        __func__, j, i,
                                        (unsigned long long)be64_to_cpu(*thispa));
                                xfs_err(mp, "%s: ptrs are equal in node\n",
@@ -304,35 +307,32 @@ xfs_check_block(
  */
 STATIC void
 xfs_bmap_check_leaf_extents(
-       xfs_btree_cur_t         *cur,   /* btree cursor or null */
+       struct xfs_btree_cur    *cur,   /* btree cursor or null */
        xfs_inode_t             *ip,            /* incore inode pointer */
        int                     whichfork)      /* data or attr fork */
 {
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_btree_block  *block; /* current btree block */
        xfs_fsblock_t           bno;    /* block # of "block" */
-       xfs_buf_t               *bp;    /* buffer for "block" */
+       struct xfs_buf          *bp;    /* buffer for "block" */
        int                     error;  /* error return value */
        xfs_extnum_t            i=0, j; /* index into the extents list */
-       struct xfs_ifork        *ifp;   /* fork structure */
        int                     level;  /* btree level, for checking */
-       xfs_mount_t             *mp;    /* file system mount structure */
        __be64                  *pp;    /* pointer to block address */
        xfs_bmbt_rec_t          *ep;    /* pointer to current extent */
        xfs_bmbt_rec_t          last = {0, 0}; /* last extent in prev block */
        xfs_bmbt_rec_t          *nextp; /* pointer to next extent */
        int                     bp_release = 0;
 
-       if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) {
+       if (ifp->if_format != XFS_DINODE_FMT_BTREE)
                return;
-       }
 
        /* skip large extent count inodes */
-       if (ip->i_d.di_nextents > 10000)
+       if (ip->i_df.if_nextents > 10000)
                return;
 
        bno = NULLFSBLOCK;
-       mp = ip->i_mount;
-       ifp = XFS_IFORK_PTR(ip, whichfork);
        block = ifp->if_broot;
        /*
         * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
@@ -459,7 +459,7 @@ error0:
        if (bp_release)
                xfs_trans_brelse(NULL, bp);
 error_norelse:
-       xfs_warn(mp, "%s: BAD after btree leaves for %d extents",
+       xfs_warn(mp, "%s: BAD after btree leaves for %llu extents",
                __func__, i);
        xfs_err(mp, "%s: CORRUPTED BTREE OR SOMETHING", __func__);
        xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
@@ -476,7 +476,7 @@ STATIC void
 xfs_bmap_validate_ret(
        xfs_fileoff_t           bno,
        xfs_filblks_t           len,
-       int                     flags,
+       uint32_t                flags,
        xfs_bmbt_irec_t         *mval,
        int                     nmap,
        int                     ret_nmap)
@@ -512,55 +512,6 @@ xfs_bmap_validate_ret(
 #define        xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap)    do { } while (0)
 #endif /* DEBUG */
 
-/*
- * bmap free list manipulation functions
- */
-
-/*
- * Add the extent to the list of extents to be free at transaction end.
- * The list is maintained sorted (by block number).
- */
-void
-__xfs_bmap_add_free(
-       struct xfs_trans                *tp,
-       xfs_fsblock_t                   bno,
-       xfs_filblks_t                   len,
-       const struct xfs_owner_info     *oinfo,
-       bool                            skip_discard)
-{
-       struct xfs_extent_free_item     *new;           /* new element */
-#ifdef DEBUG
-       struct xfs_mount                *mp = tp->t_mountp;
-       xfs_agnumber_t                  agno;
-       xfs_agblock_t                   agbno;
-
-       ASSERT(bno != NULLFSBLOCK);
-       ASSERT(len > 0);
-       ASSERT(len <= MAXEXTLEN);
-       ASSERT(!isnullstartblock(bno));
-       agno = XFS_FSB_TO_AGNO(mp, bno);
-       agbno = XFS_FSB_TO_AGBNO(mp, bno);
-       ASSERT(agno < mp->m_sb.sb_agcount);
-       ASSERT(agbno < mp->m_sb.sb_agblocks);
-       ASSERT(len < mp->m_sb.sb_agblocks);
-       ASSERT(agbno + len <= mp->m_sb.sb_agblocks);
-#endif
-       ASSERT(xfs_bmap_free_item_zone != NULL);
-
-       new = kmem_zone_alloc(xfs_bmap_free_item_zone, 0);
-       new->xefi_startblock = bno;
-       new->xefi_blockcount = (xfs_extlen_t)len;
-       if (oinfo)
-               new->xefi_oinfo = *oinfo;
-       else
-               new->xefi_oinfo = XFS_RMAP_OINFO_SKIP_UPDATE;
-       new->xefi_skip_discard = skip_discard;
-       trace_xfs_bmap_free_defer(tp->t_mountp,
-                       XFS_FSB_TO_AGNO(tp->t_mountp, bno), 0,
-                       XFS_FSB_TO_AGBNO(tp->t_mountp, bno), len);
-       xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_FREE, &new->xefi_list);
-}
-
 /*
  * Inode fork format manipulation functions
  */
@@ -580,12 +531,12 @@ xfs_bmap_btree_to_extents(
        int                     *logflagsp, /* inode logging flags */
        int                     whichfork)  /* data or attr fork */
 {
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_btree_block  *rblock = ifp->if_broot;
        struct xfs_btree_block  *cblock;/* child btree block */
        xfs_fsblock_t           cbno;   /* child block number */
-       xfs_buf_t               *cbp;   /* child block's buffer */
+       struct xfs_buf          *cbp;   /* child block's buffer */
        int                     error;  /* error return value */
        __be64                  *pp;    /* ptr to block address */
        struct xfs_owner_info   oinfo;
@@ -596,8 +547,7 @@ xfs_bmap_btree_to_extents(
 
        ASSERT(cur);
        ASSERT(whichfork != XFS_COW_FORK);
-       ASSERT(ifp->if_flags & XFS_IFEXTENTS);
-       ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
+       ASSERT(ifp->if_format == XFS_DINODE_FMT_BTREE);
        ASSERT(be16_to_cpu(rblock->bb_level) == 1);
        ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1);
        ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0) == 1);
@@ -616,16 +566,15 @@ 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_bmap_add_free(cur->bc_tp, cbno, 1, &oinfo);
-       ip->i_d.di_nblocks--;
+       xfs_free_extent_later(cur->bc_tp, cbno, 1, &oinfo);
+       ip->i_nblocks--;
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
        xfs_trans_binval(tp, cbp);
-       if (cur->bc_bufs[0] == cbp)
-               cur->bc_bufs[0] = NULL;
+       if (cur->bc_levels[0].bp == cbp)
+               cur->bc_levels[0].bp = NULL;
        xfs_iroot_realloc(ip, -1, whichfork);
        ASSERT(ifp->if_broot == NULL);
-       ASSERT((ifp->if_flags & XFS_IFBROOT) == 0);
-       XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
+       ifp->if_format = XFS_DINODE_FMT_EXTENTS;
        *logflagsp |= XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
        return 0;
 }
@@ -660,15 +609,14 @@ xfs_bmap_extents_to_btree(
 
        mp = ip->i_mount;
        ASSERT(whichfork != XFS_COW_FORK);
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS);
+       ifp = xfs_ifork_ptr(ip, whichfork);
+       ASSERT(ifp->if_format == XFS_DINODE_FMT_EXTENTS);
 
        /*
         * Make space in the inode incore. This needs to be undone if we fail
         * to expand the root.
         */
        xfs_iroot_realloc(ip, 1, whichfork);
-       ifp->if_flags |= XFS_IFBROOT;
 
        /*
         * Fill in the root.
@@ -685,21 +633,14 @@ xfs_bmap_extents_to_btree(
        /*
         * Convert to a btree with two levels, one record in root.
         */
-       XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE);
+       ifp->if_format = XFS_DINODE_FMT_BTREE;
        memset(&args, 0, sizeof(args));
        args.tp = tp;
        args.mp = mp;
        xfs_rmap_ino_bmbt_owner(&args.oinfo, ip->i_ino, whichfork);
-       if (tp->t_firstblock == NULLFSBLOCK) {
-               args.type = XFS_ALLOCTYPE_START_BNO;
-               args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino);
-       } else if (tp->t_flags & XFS_TRANS_LOWMODE) {
-               args.type = XFS_ALLOCTYPE_START_BNO;
-               args.fsbno = tp->t_firstblock;
-       } else {
-               args.type = XFS_ALLOCTYPE_NEAR_BNO;
-               args.fsbno = tp->t_firstblock;
-       }
+
+       args.type = XFS_ALLOCTYPE_START_BNO;
+       args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino);
        args.minlen = args.maxlen = args.prod = 1;
        args.wasdel = wasdel;
        *logflagsp = 0;
@@ -707,19 +648,16 @@ xfs_bmap_extents_to_btree(
        if (error)
                goto out_root_realloc;
 
+       /*
+        * Allocation can't fail, the space was reserved.
+        */
        if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) {
                error = -ENOSPC;
                goto out_root_realloc;
        }
 
-       /*
-        * Allocation can't fail, the space was reserved.
-        */
-       ASSERT(tp->t_firstblock == NULLFSBLOCK ||
-              args.agno >= XFS_FSB_TO_AGNO(mp, tp->t_firstblock));
-       tp->t_firstblock = args.fsbno;
        cur->bc_ino.allocated++;
-       ip->i_d.di_nblocks++;
+       ip->i_nblocks++;
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
        error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
                        XFS_FSB_TO_DADDR(mp, args.fsbno),
@@ -732,7 +670,7 @@ xfs_bmap_extents_to_btree(
         */
        abp->b_ops = &xfs_bmbt_buf_ops;
        ablock = XFS_BUF_TO_BLOCK(abp);
-       xfs_btree_init_block_int(mp, ablock, abp->b_bn,
+       xfs_btree_init_block_int(mp, ablock, xfs_buf_daddr(abp),
                                XFS_BTNUM_BMAP, 0, 0, ip->i_ino,
                                XFS_BTREE_LONG_PTRS);
 
@@ -743,7 +681,7 @@ xfs_bmap_extents_to_btree(
                xfs_bmbt_disk_set_all(arp, &rec);
                cnt++;
        }
-       ASSERT(cnt == XFS_IFORK_NEXTENTS(ip, whichfork));
+       ASSERT(cnt == ifp->if_nextents);
        xfs_btree_set_numrecs(ablock, cnt);
 
        /*
@@ -771,7 +709,7 @@ out_unreserve_dquot:
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
 out_root_realloc:
        xfs_iroot_realloc(ip, -1, whichfork);
-       XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
+       ifp->if_format = XFS_DINODE_FMT_EXTENTS;
        ASSERT(ifp->if_broot == NULL);
        xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
 
@@ -790,19 +728,17 @@ xfs_bmap_local_to_extents_empty(
        struct xfs_inode        *ip,
        int                     whichfork)
 {
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
 
        ASSERT(whichfork != XFS_COW_FORK);
-       ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
+       ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
        ASSERT(ifp->if_bytes == 0);
-       ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
+       ASSERT(ifp->if_nextents == 0);
 
        xfs_bmap_forkoff_reset(ip, whichfork);
-       ifp->if_flags &= ~XFS_IFINLINE;
-       ifp->if_flags |= XFS_IFEXTENTS;
        ifp->if_u1.if_root = NULL;
        ifp->if_height = 0;
-       XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
+       ifp->if_format = XFS_DINODE_FMT_EXTENTS;
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 }
 
@@ -823,7 +759,7 @@ xfs_bmap_local_to_extents(
        int             flags;          /* logging flags returned */
        struct xfs_ifork *ifp;          /* inode fork pointer */
        xfs_alloc_arg_t args;           /* allocation arguments */
-       xfs_buf_t       *bp;            /* buffer for extent block */
+       struct xfs_buf  *bp;            /* buffer for extent block */
        struct xfs_bmbt_irec rec;
        struct xfs_iext_cursor icur;
 
@@ -832,8 +768,8 @@ xfs_bmap_local_to_extents(
         * So sending the data fork of a regular inode is invalid.
         */
        ASSERT(!(S_ISREG(VFS_I(ip)->i_mode) && whichfork == XFS_DATA_FORK));
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
+       ifp = xfs_ifork_ptr(ip, whichfork);
+       ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
 
        if (!ifp->if_bytes) {
                xfs_bmap_local_to_extents_empty(tp, ip, whichfork);
@@ -843,7 +779,6 @@ xfs_bmap_local_to_extents(
 
        flags = 0;
        error = 0;
-       ASSERT((ifp->if_flags & (XFS_IFINLINE|XFS_IFEXTENTS)) == XFS_IFINLINE);
        memset(&args, 0, sizeof(args));
        args.tp = tp;
        args.mp = ip->i_mount;
@@ -852,13 +787,8 @@ xfs_bmap_local_to_extents(
         * Allocate a block.  We know we need only one, since the
         * file currently fits in an inode.
         */
-       if (tp->t_firstblock == NULLFSBLOCK) {
-               args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino);
-               args.type = XFS_ALLOCTYPE_START_BNO;
-       } else {
-               args.fsbno = tp->t_firstblock;
-               args.type = XFS_ALLOCTYPE_NEAR_BNO;
-       }
+       args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino);
+       args.type = XFS_ALLOCTYPE_START_BNO;
        args.total = total;
        args.minlen = args.maxlen = args.prod = 1;
        error = xfs_alloc_vextent(&args);
@@ -868,7 +798,6 @@ xfs_bmap_local_to_extents(
        /* Can't fail, the space was reserved. */
        ASSERT(args.fsbno != NULLFSBLOCK);
        ASSERT(args.len == 1);
-       tp->t_firstblock = args.fsbno;
        error = xfs_trans_get_buf(tp, args.mp->m_ddev_targp,
                        XFS_FSB_TO_DADDR(args.mp, args.fsbno),
                        args.mp->m_bsize, 0, &bp);
@@ -900,10 +829,9 @@ xfs_bmap_local_to_extents(
        xfs_iext_first(ifp, &icur);
        xfs_iext_insert(ip, &icur, &rec, 0);
 
-       XFS_IFORK_NEXT_SET(ip, whichfork, 1);
-       ip->i_d.di_nblocks = 1;
-       xfs_trans_mod_dquot_byino(tp, ip,
-               XFS_TRANS_DQ_BCOUNT, 1L);
+       ifp->if_nextents = 1;
+       ip->i_nblocks = 1;
+       xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
        flags |= xfs_ilog_fext(whichfork);
 
 done:
@@ -920,13 +848,15 @@ xfs_bmap_add_attrfork_btree(
        xfs_inode_t             *ip,            /* incore inode pointer */
        int                     *flags)         /* inode logging flags */
 {
-       xfs_btree_cur_t         *cur;           /* btree cursor */
+       struct xfs_btree_block  *block = ip->i_df.if_broot;
+       struct xfs_btree_cur    *cur;           /* btree cursor */
        int                     error;          /* error return value */
        xfs_mount_t             *mp;            /* file system mount struct */
        int                     stat;           /* newroot status */
 
        mp = ip->i_mount;
-       if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip))
+
+       if (XFS_BMAP_BMDR_SPACE(block) <= xfs_inode_data_fork_size(ip))
                *flags |= XFS_ILOG_DBROOT;
        else {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK);
@@ -962,10 +892,11 @@ xfs_bmap_add_attrfork_extents(
        struct xfs_inode        *ip,            /* incore inode pointer */
        int                     *flags)         /* inode logging flags */
 {
-       xfs_btree_cur_t         *cur;           /* bmap btree cursor */
+       struct xfs_btree_cur    *cur;           /* bmap btree cursor */
        int                     error;          /* error return value */
 
-       if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip))
+       if (ip->i_df.if_nextents * sizeof(struct xfs_bmbt_rec) <=
+           xfs_inode_data_fork_size(ip))
                return 0;
        cur = NULL;
        error = xfs_bmap_extents_to_btree(tp, ip, &cur, 0, flags,
@@ -996,7 +927,7 @@ xfs_bmap_add_attrfork_local(
 {
        struct xfs_da_args      dargs;          /* args for dir/attr code */
 
-       if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip))
+       if (ip->i_df.if_bytes <= xfs_inode_data_fork_size(ip))
                return 0;
 
        if (S_ISDIR(VFS_I(ip)->i_mode)) {
@@ -1019,24 +950,28 @@ xfs_bmap_add_attrfork_local(
        return -EFSCORRUPTED;
 }
 
-/* Set an inode attr fork off based on the format */
-int
+/*
+ * Set an inode attr fork offset based on the format of the data fork.
+ */
+static int
 xfs_bmap_set_attrforkoff(
        struct xfs_inode        *ip,
        int                     size,
        int                     *version)
 {
-       switch (ip->i_d.di_format) {
+       int                     default_size = xfs_default_attroffset(ip) >> 3;
+
+       switch (ip->i_df.if_format) {
        case XFS_DINODE_FMT_DEV:
-               ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
+               ip->i_forkoff = default_size;
                break;
        case XFS_DINODE_FMT_LOCAL:
        case XFS_DINODE_FMT_EXTENTS:
        case XFS_DINODE_FMT_BTREE:
-               ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
-               if (!ip->i_d.di_forkoff)
-                       ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
-               else if ((ip->i_mount->m_flags & XFS_MOUNT_ATTR2) && version)
+               ip->i_forkoff = xfs_attr_shortform_bytesfit(ip, size);
+               if (!ip->i_forkoff)
+                       ip->i_forkoff = default_size;
+               else if (xfs_has_attr2(ip->i_mount) && version)
                        *version = 2;
                break;
        default:
@@ -1064,48 +999,28 @@ xfs_bmap_add_attrfork(
        int                     logflags;       /* logging flags */
        int                     error;          /* error return value */
 
-       ASSERT(XFS_IFORK_Q(ip) == 0);
+       ASSERT(xfs_inode_has_attr_fork(ip) == 0);
 
        mp = ip->i_mount;
        ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
 
        blks = XFS_ADDAFORK_SPACE_RES(mp);
 
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_addafork, blks, 0,
-                       rsvd ? XFS_TRANS_RESERVE : 0, &tp);
+       error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_addafork, blks, 0,
+                       rsvd, &tp);
        if (error)
                return error;
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ?
-                       XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
-                       XFS_QMOPT_RES_REGBLKS);
-       if (error)
-               goto trans_cancel;
-       if (XFS_IFORK_Q(ip))
+       if (xfs_inode_has_attr_fork(ip))
                goto trans_cancel;
-       if (XFS_IS_CORRUPT(mp, ip->i_d.di_anextents != 0)) {
-               error = -EFSCORRUPTED;
-               goto trans_cancel;
-       }
-       if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) {
-               /*
-                * For inodes coming from pre-6.2 filesystems.
-                */
-               ASSERT(ip->i_d.di_aformat == 0);
-               ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
-       }
 
-       xfs_trans_ijoin(tp, ip, 0);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        error = xfs_bmap_set_attrforkoff(ip, size, &version);
        if (error)
                goto trans_cancel;
-       ASSERT(ip->i_afp == NULL);
-       ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
-       ip->i_afp->if_flags = XFS_IFEXTENTS;
+
+       xfs_ifork_init_attr(ip, XFS_DINODE_FMT_EXTENTS, 0);
        logflags = 0;
-       switch (ip->i_d.di_format) {
+       switch (ip->i_df.if_format) {
        case XFS_DINODE_FMT_LOCAL:
                error = xfs_bmap_add_attrfork_local(tp, ip, &logflags);
                break;
@@ -1123,17 +1038,17 @@ xfs_bmap_add_attrfork(
                xfs_trans_log_inode(tp, ip, logflags);
        if (error)
                goto trans_cancel;
-       if (!xfs_sb_version_hasattr(&mp->m_sb) ||
-          (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2)) {
+       if (!xfs_has_attr(mp) ||
+          (!xfs_has_attr2(mp) && version == 2)) {
                bool log_sb = false;
 
                spin_lock(&mp->m_sb_lock);
-               if (!xfs_sb_version_hasattr(&mp->m_sb)) {
-                       xfs_sb_version_addattr(&mp->m_sb);
+               if (!xfs_has_attr(mp)) {
+                       xfs_add_attr(mp);
                        log_sb = true;
                }
-               if (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2) {
-                       xfs_sb_version_addattr2(&mp->m_sb);
+               if (!xfs_has_attr2(mp) && version == 2) {
+                       xfs_add_attr2(mp);
                        log_sb = true;
                }
                spin_unlock(&mp->m_sb_lock);
@@ -1176,13 +1091,13 @@ xfs_iread_bmbt_block(
        xfs_extnum_t            num_recs;
        xfs_extnum_t            j;
        int                     whichfork = cur->bc_ino.whichfork;
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
 
        block = xfs_btree_get_block(cur, level, &bp);
 
        /* Abort if we find more records than nextents. */
        num_recs = xfs_btree_get_numrecs(block);
-       if (unlikely(ir->loaded + num_recs >
-                    XFS_IFORK_NEXTENTS(ip, whichfork))) {
+       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);
                xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, block,
@@ -1208,7 +1123,7 @@ xfs_iread_bmbt_block(
                                xfs_bmap_fork_to_state(whichfork));
                trace_xfs_read_extent(ip, &ir->icur,
                                xfs_bmap_fork_to_state(whichfork), _THIS_IP_);
-               xfs_iext_next(XFS_IFORK_PTR(ip, whichfork), &ir->icur);
+               xfs_iext_next(ifp, &ir->icur);
        }
 
        return 0;
@@ -1224,19 +1139,15 @@ xfs_iread_extents(
        int                     whichfork)
 {
        struct xfs_iread_state  ir;
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_btree_cur    *cur;
        int                     error;
 
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+       if (!xfs_need_iread_extents(ifp))
+               return 0;
 
-       if (XFS_IS_CORRUPT(mp,
-                          XFS_IFORK_FORMAT(ip, whichfork) !=
-                          XFS_DINODE_FMT_BTREE)) {
-               error = -EFSCORRUPTED;
-               goto out;
-       }
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
        ir.loaded = 0;
        xfs_iext_first(ifp, &ir.icur);
@@ -1247,14 +1158,11 @@ xfs_iread_extents(
        if (error)
                goto out;
 
-       if (XFS_IS_CORRUPT(mp,
-                          ir.loaded != XFS_IFORK_NEXTENTS(ip, whichfork))) {
+       if (XFS_IS_CORRUPT(mp, ir.loaded != ifp->if_nextents)) {
                error = -EFSCORRUPTED;
                goto out;
        }
        ASSERT(ir.loaded == xfs_iext_count(ifp));
-
-       ifp->if_flags |= XFS_IFEXTENTS;
        return 0;
 out:
        xfs_iext_destroy(ifp);
@@ -1275,26 +1183,23 @@ xfs_bmap_first_unused(
        xfs_fileoff_t           *first_unused,  /* unused block */
        int                     whichfork)      /* data or attr fork */
 {
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_bmbt_irec    got;
        struct xfs_iext_cursor  icur;
        xfs_fileoff_t           lastaddr = 0;
        xfs_fileoff_t           lowest, max;
        int                     error;
 
-       ASSERT(xfs_ifork_has_extents(ip, whichfork) ||
-              XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
-
-       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
+       if (ifp->if_format == XFS_DINODE_FMT_LOCAL) {
                *first_unused = 0;
                return 0;
        }
 
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               error = xfs_iread_extents(tp, ip, whichfork);
-               if (error)
-                       return error;
-       }
+       ASSERT(xfs_ifork_has_extents(ifp));
+
+       error = xfs_iread_extents(tp, ip, whichfork);
+       if (error)
+               return error;
 
        lowest = max = *first_unused;
        for_each_xfs_iext(ifp, &icur, &got) {
@@ -1325,12 +1230,12 @@ xfs_bmap_last_before(
        xfs_fileoff_t           *last_block,    /* last block */
        int                     whichfork)      /* data or attr fork */
 {
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_bmbt_irec    got;
        struct xfs_iext_cursor  icur;
        int                     error;
 
-       switch (XFS_IFORK_FORMAT(ip, whichfork)) {
+       switch (ifp->if_format) {
        case XFS_DINODE_FMT_LOCAL:
                *last_block = 0;
                return 0;
@@ -1342,11 +1247,9 @@ xfs_bmap_last_before(
                return -EFSCORRUPTED;
        }
 
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               error = xfs_iread_extents(tp, ip, whichfork);
-               if (error)
-                       return error;
-       }
+       error = xfs_iread_extents(tp, ip, whichfork);
+       if (error)
+               return error;
 
        if (!xfs_iext_lookup_extent_before(ip, ifp, last_block, &icur, &got))
                *last_block = 0;
@@ -1361,15 +1264,13 @@ xfs_bmap_last_extent(
        struct xfs_bmbt_irec    *rec,
        int                     *is_empty)
 {
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_iext_cursor  icur;
        int                     error;
 
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               error = xfs_iread_extents(tp, ip, whichfork);
-               if (error)
-                       return error;
-       }
+       error = xfs_iread_extents(tp, ip, whichfork);
+       if (error)
+               return error;
 
        xfs_iext_last(ifp, &icur);
        if (!xfs_iext_get_extent(ifp, &icur, rec))
@@ -1429,16 +1330,17 @@ xfs_bmap_last_offset(
        xfs_fileoff_t           *last_block,
        int                     whichfork)
 {
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_bmbt_irec    rec;
        int                     is_empty;
        int                     error;
 
        *last_block = 0;
 
-       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL)
+       if (ifp->if_format == XFS_DINODE_FMT_LOCAL)
                return 0;
 
-       if (XFS_IS_CORRUPT(ip->i_mount, !xfs_ifork_has_extents(ip, whichfork)))
+       if (XFS_IS_CORRUPT(ip->i_mount, !xfs_ifork_has_extents(ifp)))
                return -EFSCORRUPTED;
 
        error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
@@ -1449,39 +1351,6 @@ xfs_bmap_last_offset(
        return 0;
 }
 
-/*
- * Returns whether the selected fork of the inode has exactly one
- * block or not.  For the data fork we check this matches di_size,
- * implying the file's range is 0..bsize-1.
- */
-int                                    /* 1=>1 block, 0=>otherwise */
-xfs_bmap_one_block(
-       xfs_inode_t     *ip,            /* incore inode */
-       int             whichfork)      /* data or attr fork */
-{
-       struct xfs_ifork *ifp;          /* inode fork pointer */
-       int             rval;           /* return value */
-       xfs_bmbt_irec_t s;              /* internal version of extent */
-       struct xfs_iext_cursor icur;
-
-#ifndef DEBUG
-       if (whichfork == XFS_DATA_FORK)
-               return XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize;
-#endif /* !DEBUG */
-       if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1)
-               return 0;
-       if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
-               return 0;
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       ASSERT(ifp->if_flags & XFS_IFEXTENTS);
-       xfs_iext_first(ifp, &icur);
-       xfs_iext_get_extent(ifp, &icur, &s);
-       rval = s.br_startoff == 0 && s.br_blockcount == 1;
-       if (rval && whichfork == XFS_DATA_FORK)
-               ASSERT(XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize);
-       return rval;
-}
-
 /*
  * Extent tree manipulation functions used during allocation.
  */
@@ -1494,29 +1363,23 @@ xfs_bmap_add_extent_delay_real(
        struct xfs_bmalloca     *bma,
        int                     whichfork)
 {
+       struct xfs_mount        *mp = bma->ip->i_mount;
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(bma->ip, whichfork);
        struct xfs_bmbt_irec    *new = &bma->got;
        int                     error;  /* error return value */
        int                     i;      /* temp state */
-       struct xfs_ifork        *ifp;   /* inode fork pointer */
        xfs_fileoff_t           new_endoff;     /* end offset of new entry */
        xfs_bmbt_irec_t         r[3];   /* neighbor extent entries */
                                        /* left is 0, right is 1, prev is 2 */
        int                     rval=0; /* return value (logging flags) */
-       int                     state = xfs_bmap_fork_to_state(whichfork);
+       uint32_t                state = xfs_bmap_fork_to_state(whichfork);
        xfs_filblks_t           da_new; /* new count del alloc blocks used */
        xfs_filblks_t           da_old; /* old count del alloc blocks used */
        xfs_filblks_t           temp=0; /* value for da_new calculations */
        int                     tmp_rval;       /* partial logging flags */
-       struct xfs_mount        *mp;
-       xfs_extnum_t            *nextents;
        struct xfs_bmbt_irec    old;
 
-       mp = bma->ip->i_mount;
-       ifp = XFS_IFORK_PTR(bma->ip, whichfork);
        ASSERT(whichfork != XFS_ATTR_FORK);
-       nextents = (whichfork == XFS_COW_FORK ? &bma->ip->i_cnextents :
-                                               &bma->ip->i_d.di_nextents);
-
        ASSERT(!isnullstartblock(new->br_startblock));
        ASSERT(!bma->cur ||
               (bma->cur->bc_ino.flags & XFS_BTCUR_BMBT_WASDEL));
@@ -1562,7 +1425,7 @@ xfs_bmap_add_extent_delay_real(
            LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff &&
            LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock &&
            LEFT.br_state == new->br_state &&
-           LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN)
+           LEFT.br_blockcount + new->br_blockcount <= XFS_MAX_BMBT_EXTLEN)
                state |= BMAP_LEFT_CONTIG;
 
        /*
@@ -1580,13 +1443,13 @@ xfs_bmap_add_extent_delay_real(
            new_endoff == RIGHT.br_startoff &&
            new->br_startblock + new->br_blockcount == RIGHT.br_startblock &&
            new->br_state == RIGHT.br_state &&
-           new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN &&
+           new->br_blockcount + RIGHT.br_blockcount <= XFS_MAX_BMBT_EXTLEN &&
            ((state & (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING |
                       BMAP_RIGHT_FILLING)) !=
                      (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING |
                       BMAP_RIGHT_FILLING) ||
             LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount
-                       <= MAXEXTLEN))
+                       <= XFS_MAX_BMBT_EXTLEN))
                state |= BMAP_RIGHT_CONTIG;
 
        error = 0;
@@ -1607,7 +1470,7 @@ xfs_bmap_add_extent_delay_real(
                xfs_iext_remove(bma->ip, &bma->icur, state);
                xfs_iext_prev(ifp, &bma->icur);
                xfs_iext_update_extent(bma->ip, state, &bma->icur, &LEFT);
-               (*nextents)--;
+               ifp->if_nextents--;
 
                if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -1711,8 +1574,8 @@ xfs_bmap_add_extent_delay_real(
                PREV.br_startblock = new->br_startblock;
                PREV.br_state = new->br_state;
                xfs_iext_update_extent(bma->ip, state, &bma->icur, &PREV);
+               ifp->if_nextents++;
 
-               (*nextents)++;
                if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
@@ -1777,7 +1640,8 @@ xfs_bmap_add_extent_delay_real(
                 * The left neighbor is not contiguous.
                 */
                xfs_iext_update_extent(bma->ip, state, &bma->icur, new);
-               (*nextents)++;
+               ifp->if_nextents++;
+
                if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
@@ -1863,7 +1727,8 @@ xfs_bmap_add_extent_delay_real(
                 * The right neighbor is not contiguous.
                 */
                xfs_iext_update_extent(bma->ip, state, &bma->icur, new);
-               (*nextents)++;
+               ifp->if_nextents++;
+
                if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
@@ -1948,7 +1813,7 @@ xfs_bmap_add_extent_delay_real(
                xfs_iext_next(ifp, &bma->icur);
                xfs_iext_insert(bma->ip, &bma->icur, &RIGHT, state);
                xfs_iext_insert(bma->ip, &bma->icur, &LEFT, state);
-               (*nextents)++;
+               ifp->if_nextents++;
 
                if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -2046,11 +1911,11 @@ xfs_bmap_add_extent_unwritten_real(
        xfs_inode_t             *ip,    /* incore inode pointer */
        int                     whichfork,
        struct xfs_iext_cursor  *icur,
-       xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
+       struct xfs_btree_cur    **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp) /* inode logging flags */
 {
-       xfs_btree_cur_t         *cur;   /* btree cursor */
+       struct xfs_btree_cur    *cur;   /* btree cursor */
        int                     error;  /* error return value */
        int                     i;      /* temp state */
        struct xfs_ifork        *ifp;   /* inode fork pointer */
@@ -2058,14 +1923,14 @@ xfs_bmap_add_extent_unwritten_real(
        xfs_bmbt_irec_t         r[3];   /* neighbor extent entries */
                                        /* left is 0, right is 1, prev is 2 */
        int                     rval=0; /* return value (logging flags) */
-       int                     state = xfs_bmap_fork_to_state(whichfork);
+       uint32_t                state = xfs_bmap_fork_to_state(whichfork);
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_bmbt_irec    old;
 
        *logflagsp = 0;
 
        cur = *curp;
-       ifp = XFS_IFORK_PTR(ip, whichfork);
+       ifp = xfs_ifork_ptr(ip, whichfork);
 
        ASSERT(!isnullstartblock(new->br_startblock));
 
@@ -2108,7 +1973,7 @@ xfs_bmap_add_extent_unwritten_real(
            LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff &&
            LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock &&
            LEFT.br_state == new->br_state &&
-           LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN)
+           LEFT.br_blockcount + new->br_blockcount <= XFS_MAX_BMBT_EXTLEN)
                state |= BMAP_LEFT_CONTIG;
 
        /*
@@ -2126,13 +1991,13 @@ xfs_bmap_add_extent_unwritten_real(
            new_endoff == RIGHT.br_startoff &&
            new->br_startblock + new->br_blockcount == RIGHT.br_startblock &&
            new->br_state == RIGHT.br_state &&
-           new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN &&
+           new->br_blockcount + RIGHT.br_blockcount <= XFS_MAX_BMBT_EXTLEN &&
            ((state & (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING |
                       BMAP_RIGHT_FILLING)) !=
                      (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING |
                       BMAP_RIGHT_FILLING) ||
             LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount
-                       <= MAXEXTLEN))
+                       <= XFS_MAX_BMBT_EXTLEN))
                state |= BMAP_RIGHT_CONTIG;
 
        /*
@@ -2152,8 +2017,7 @@ xfs_bmap_add_extent_unwritten_real(
                xfs_iext_remove(ip, icur, state);
                xfs_iext_prev(ifp, icur);
                xfs_iext_update_extent(ip, state, icur, &LEFT);
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                               XFS_IFORK_NEXTENTS(ip, whichfork) - 2);
+               ifp->if_nextents -= 2;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
@@ -2205,8 +2069,7 @@ xfs_bmap_add_extent_unwritten_real(
                xfs_iext_remove(ip, icur, state);
                xfs_iext_prev(ifp, icur);
                xfs_iext_update_extent(ip, state, icur, &LEFT);
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                               XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
+               ifp->if_nextents--;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
@@ -2248,9 +2111,8 @@ xfs_bmap_add_extent_unwritten_real(
                xfs_iext_remove(ip, icur, state);
                xfs_iext_prev(ifp, icur);
                xfs_iext_update_extent(ip, state, icur, &PREV);
+               ifp->if_nextents--;
 
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                               XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
@@ -2357,8 +2219,8 @@ xfs_bmap_add_extent_unwritten_real(
 
                xfs_iext_update_extent(ip, state, icur, &PREV);
                xfs_iext_insert(ip, icur, new, state);
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                               XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
+               ifp->if_nextents++;
+
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
@@ -2433,9 +2295,8 @@ xfs_bmap_add_extent_unwritten_real(
                xfs_iext_update_extent(ip, state, icur, &PREV);
                xfs_iext_next(ifp, icur);
                xfs_iext_insert(ip, icur, new, state);
+               ifp->if_nextents++;
 
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                               XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
@@ -2486,9 +2347,8 @@ xfs_bmap_add_extent_unwritten_real(
                xfs_iext_next(ifp, icur);
                xfs_iext_insert(ip, icur, &r[1], state);
                xfs_iext_insert(ip, icur, &r[0], state);
+               ifp->if_nextents += 2;
 
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                               XFS_IFORK_NEXTENTS(ip, whichfork) + 2);
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
@@ -2592,10 +2452,10 @@ xfs_bmap_add_extent_hole_delay(
        xfs_filblks_t           newlen=0;       /* new indirect size */
        xfs_filblks_t           oldlen=0;       /* old indirect size */
        xfs_bmbt_irec_t         right;  /* right neighbor extent entry */
-       int                     state = xfs_bmap_fork_to_state(whichfork);
+       uint32_t                state = xfs_bmap_fork_to_state(whichfork);
        xfs_filblks_t           temp;    /* temp for indirect calculations */
 
-       ifp = XFS_IFORK_PTR(ip, whichfork);
+       ifp = xfs_ifork_ptr(ip, whichfork);
        ASSERT(isnullstartblock(new->br_startblock));
 
        /*
@@ -2623,15 +2483,15 @@ xfs_bmap_add_extent_hole_delay(
         */
        if ((state & BMAP_LEFT_VALID) && (state & BMAP_LEFT_DELAY) &&
            left.br_startoff + left.br_blockcount == new->br_startoff &&
-           left.br_blockcount + new->br_blockcount <= MAXEXTLEN)
+           left.br_blockcount + new->br_blockcount <= XFS_MAX_BMBT_EXTLEN)
                state |= BMAP_LEFT_CONTIG;
 
        if ((state & BMAP_RIGHT_VALID) && (state & BMAP_RIGHT_DELAY) &&
            new->br_startoff + new->br_blockcount == right.br_startoff &&
-           new->br_blockcount + right.br_blockcount <= MAXEXTLEN &&
+           new->br_blockcount + right.br_blockcount <= XFS_MAX_BMBT_EXTLEN &&
            (!(state & BMAP_LEFT_CONTIG) ||
             (left.br_blockcount + new->br_blockcount +
-             right.br_blockcount <= MAXEXTLEN)))
+             right.br_blockcount <= XFS_MAX_BMBT_EXTLEN)))
                state |= BMAP_RIGHT_CONTIG;
 
        /*
@@ -2729,9 +2589,9 @@ xfs_bmap_add_extent_hole_real(
        struct xfs_btree_cur    **curp,
        struct xfs_bmbt_irec    *new,
        int                     *logflagsp,
-       int                     flags)
+       uint32_t                flags)
 {
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_btree_cur    *cur = *curp;
        int                     error;  /* error return value */
@@ -2739,7 +2599,7 @@ xfs_bmap_add_extent_hole_real(
        xfs_bmbt_irec_t         left;   /* left neighbor extent entry */
        xfs_bmbt_irec_t         right;  /* right neighbor extent entry */
        int                     rval=0; /* return value (logging flags) */
-       int                     state = xfs_bmap_fork_to_state(whichfork);
+       uint32_t                state = xfs_bmap_fork_to_state(whichfork);
        struct xfs_bmbt_irec    old;
 
        ASSERT(!isnullstartblock(new->br_startblock));
@@ -2774,17 +2634,17 @@ xfs_bmap_add_extent_hole_real(
            left.br_startoff + left.br_blockcount == new->br_startoff &&
            left.br_startblock + left.br_blockcount == new->br_startblock &&
            left.br_state == new->br_state &&
-           left.br_blockcount + new->br_blockcount <= MAXEXTLEN)
+           left.br_blockcount + new->br_blockcount <= XFS_MAX_BMBT_EXTLEN)
                state |= BMAP_LEFT_CONTIG;
 
        if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) &&
            new->br_startoff + new->br_blockcount == right.br_startoff &&
            new->br_startblock + new->br_blockcount == right.br_startblock &&
            new->br_state == right.br_state &&
-           new->br_blockcount + right.br_blockcount <= MAXEXTLEN &&
+           new->br_blockcount + right.br_blockcount <= XFS_MAX_BMBT_EXTLEN &&
            (!(state & BMAP_LEFT_CONTIG) ||
             left.br_blockcount + new->br_blockcount +
-            right.br_blockcount <= MAXEXTLEN))
+            right.br_blockcount <= XFS_MAX_BMBT_EXTLEN))
                state |= BMAP_RIGHT_CONTIG;
 
        error = 0;
@@ -2803,9 +2663,8 @@ xfs_bmap_add_extent_hole_real(
                xfs_iext_remove(ip, icur, state);
                xfs_iext_prev(ifp, icur);
                xfs_iext_update_extent(ip, state, icur, &left);
+               ifp->if_nextents--;
 
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                       XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
                if (cur == NULL) {
                        rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
                } else {
@@ -2903,8 +2762,8 @@ xfs_bmap_add_extent_hole_real(
                 * Insert a new entry.
                 */
                xfs_iext_insert(ip, icur, new, state);
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                       XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
+               ifp->if_nextents++;
+
                if (cur == NULL) {
                        rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
                } else {
@@ -2959,7 +2818,7 @@ done:
  */
 
 /*
- * Adjust the size of the new extent based on di_extsize and rt extsize.
+ * Adjust the size of the new extent based on i_extsize and rt extsize.
  */
 int
 xfs_bmap_extsize_align(
@@ -3020,15 +2879,15 @@ xfs_bmap_extsize_align(
 
        /*
         * For large extent hint sizes, the aligned extent might be larger than
-        * MAXEXTLEN. In that case, reduce the size by an extsz so that it pulls
-        * the length back under MAXEXTLEN. The outer allocation loops handle
-        * short allocation just fine, so it is safe to do this. We only want to
-        * do it when we are forced to, though, because it means more allocation
-        * operations are required.
+        * XFS_BMBT_MAX_EXTLEN. In that case, reduce the size by an extsz so
+        * that it pulls the length back under XFS_BMBT_MAX_EXTLEN. The outer
+        * allocation loops handle short allocation just fine, so it is safe to
+        * do this. We only want to do it when we are forced to, though, because
+        * it means more allocation operations are required.
         */
-       while (align_alen > MAXEXTLEN)
+       while (align_alen > XFS_MAX_BMBT_EXTLEN)
                align_alen -= extsz;
-       ASSERT(align_alen <= MAXEXTLEN);
+       ASSERT(align_alen <= XFS_MAX_BMBT_EXTLEN);
 
        /*
         * If the previous block overlaps with this proposed allocation
@@ -3118,9 +2977,9 @@ xfs_bmap_extsize_align(
                        return -EINVAL;
        } else {
                ASSERT(orig_off >= align_off);
-               /* see MAXEXTLEN handling above */
+               /* see XFS_BMBT_MAX_EXTLEN handling above */
                ASSERT(orig_end <= align_off + align_alen ||
-                      align_alen + extsz > MAXEXTLEN);
+                      align_alen + extsz > XFS_MAX_BMBT_EXTLEN);
        }
 
 #ifdef DEBUG
@@ -3142,9 +3001,7 @@ xfs_bmap_adjacent(
        struct xfs_bmalloca     *ap)    /* bmap alloc argument struct */
 {
        xfs_fsblock_t   adjust;         /* adjustment to block numbers */
-       xfs_agnumber_t  fb_agno;        /* ag number of ap->firstblock */
        xfs_mount_t     *mp;            /* mount point structure */
-       int             nullfb;         /* true if ap->firstblock isn't set */
        int             rt;             /* true if inode is realtime */
 
 #define        ISVALID(x,y)    \
@@ -3155,11 +3012,8 @@ xfs_bmap_adjacent(
                XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks)
 
        mp = ap->ip->i_mount;
-       nullfb = ap->tp->t_firstblock == NULLFSBLOCK;
        rt = XFS_IS_REALTIME_INODE(ap->ip) &&
                (ap->datatype & XFS_ALLOC_USERDATA);
-       fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp,
-                                                       ap->tp->t_firstblock);
        /*
         * If allocating at eof, and there's a previous real block,
         * try to use its last block as our starting point.
@@ -3218,13 +3072,6 @@ xfs_bmap_adjacent(
                                prevbno += adjust;
                        else
                                prevdiff += adjust;
-                       /*
-                        * If the firstblock forbids it, can't use it,
-                        * must use default.
-                        */
-                       if (!rt && !nullfb &&
-                           XFS_FSB_TO_AGNO(mp, prevbno) != fb_agno)
-                               prevbno = NULLFSBLOCK;
                }
                /*
                 * No previous block or can't follow it, just default.
@@ -3260,13 +3107,6 @@ xfs_bmap_adjacent(
                                gotdiff += adjust - ap->length;
                        } else
                                gotdiff += adjust;
-                       /*
-                        * If the firstblock forbids it, can't use it,
-                        * must use default.
-                        */
-                       if (!rt && !nullfb &&
-                           XFS_FSB_TO_AGNO(mp, gotbno) != fb_agno)
-                               gotbno = NULLFSBLOCK;
                }
                /*
                 * No next block, just default.
@@ -3300,8 +3140,9 @@ xfs_bmap_longest_free_extent(
        int                     error = 0;
 
        pag = xfs_perag_get(mp, ag);
-       if (!pag->pagf_init) {
-               error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK);
+       if (!xfs_perag_initialised_agf(pag)) {
+               error = xfs_alloc_read_agf(pag, tp, XFS_ALLOC_FLAG_TRYLOCK,
+                               NULL);
                if (error) {
                        /* Couldn't lock the AGF, so skip this AG. */
                        if (error == -EAGAIN) {
@@ -3352,7 +3193,7 @@ xfs_bmap_select_minlen(
 }
 
 STATIC int
-xfs_bmap_btalloc_nullfb(
+xfs_bmap_btalloc_select_lengths(
        struct xfs_bmalloca     *ap,
        struct xfs_alloc_arg    *args,
        xfs_extlen_t            *blen)
@@ -3363,8 +3204,13 @@ xfs_bmap_btalloc_nullfb(
        int                     error;
 
        args->type = XFS_ALLOCTYPE_START_BNO;
-       args->total = ap->total;
+       if (ap->tp->t_flags & XFS_TRANS_LOWMODE) {
+               args->total = ap->minlen;
+               args->minlen = ap->minlen;
+               return 0;
+       }
 
+       args->total = ap->total;
        startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno);
        if (startag == NULLAGNUMBER)
                startag = ag = 0;
@@ -3396,6 +3242,13 @@ xfs_bmap_btalloc_filestreams(
        int                     notinit = 0;
        int                     error;
 
+       if (ap->tp->t_flags & XFS_TRANS_LOWMODE) {
+               args->type = XFS_ALLOCTYPE_FIRST_AG;
+               args->total = ap->minlen;
+               args->minlen = ap->minlen;
+               return 0;
+       }
+
        args->type = XFS_ALLOCTYPE_NEAR_BNO;
        args->total = ap->total;
 
@@ -3465,7 +3318,7 @@ xfs_bmap_btalloc_accounting(
        }
 
        /* data/attr fork only */
-       ap->ip->i_d.di_nblocks += args->len;
+       ap->ip->i_nblocks += args->len;
        xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
        if (ap->wasdel) {
                ap->ip->i_delayed_blks -= args->len;
@@ -3476,35 +3329,17 @@ xfs_bmap_btalloc_accounting(
                args->len);
 }
 
-STATIC int
-xfs_bmap_btalloc(
-       struct xfs_bmalloca     *ap)    /* bmap alloc argument struct */
+static int
+xfs_bmap_compute_alignments(
+       struct xfs_bmalloca     *ap,
+       struct xfs_alloc_arg    *args)
 {
-       xfs_mount_t     *mp;            /* mount point structure */
-       xfs_alloctype_t atype = 0;      /* type for allocation routines */
-       xfs_extlen_t    align = 0;      /* minimum allocation alignment */
-       xfs_agnumber_t  fb_agno;        /* ag number of ap->firstblock */
-       xfs_agnumber_t  ag;
-       xfs_alloc_arg_t args;
-       xfs_fileoff_t   orig_offset;
-       xfs_extlen_t    orig_length;
-       xfs_extlen_t    blen;
-       xfs_extlen_t    nextminlen = 0;
-       int             nullfb;         /* true if ap->firstblock isn't set */
-       int             isaligned;
-       int             tryagain;
-       int             error;
-       int             stripe_align;
-
-       ASSERT(ap->length);
-       orig_offset = ap->offset;
-       orig_length = ap->length;
-
-       mp = ap->ip->i_mount;
+       struct xfs_mount        *mp = args->mp;
+       xfs_extlen_t            align = 0; /* minimum allocation alignment */
+       int                     stripe_align = 0;
 
        /* stripe alignment for allocation is determined by mount parameters */
-       stripe_align = 0;
-       if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC))
+       if (mp->m_swidth && xfs_has_swalloc(mp))
                stripe_align = mp->m_swidth;
        else if (mp->m_dalign)
                stripe_align = mp->m_dalign;
@@ -3514,91 +3349,185 @@ xfs_bmap_btalloc(
        else if (ap->datatype & XFS_ALLOC_USERDATA)
                align = xfs_get_extsz_hint(ap->ip);
        if (align) {
-               error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
-                                               align, 0, ap->eof, 0, ap->conv,
-                                               &ap->offset, &ap->length);
-               ASSERT(!error);
+               if (xfs_bmap_extsize_align(mp, &ap->got, &ap->prev, align, 0,
+                                       ap->eof, 0, ap->conv, &ap->offset,
+                                       &ap->length))
+                       ASSERT(0);
                ASSERT(ap->length);
        }
 
+       /* apply extent size hints if obtained earlier */
+       if (align) {
+               args->prod = align;
+               div_u64_rem(ap->offset, args->prod, &args->mod);
+               if (args->mod)
+                       args->mod = args->prod - args->mod;
+       } else if (mp->m_sb.sb_blocksize >= PAGE_SIZE) {
+               args->prod = 1;
+               args->mod = 0;
+       } else {
+               args->prod = PAGE_SIZE >> mp->m_sb.sb_blocklog;
+               div_u64_rem(ap->offset, args->prod, &args->mod);
+               if (args->mod)
+                       args->mod = args->prod - args->mod;
+       }
 
-       nullfb = ap->tp->t_firstblock == NULLFSBLOCK;
-       fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp,
-                                                       ap->tp->t_firstblock);
-       if (nullfb) {
-               if ((ap->datatype & XFS_ALLOC_USERDATA) &&
-                   xfs_inode_is_filestream(ap->ip)) {
-                       ag = xfs_filestream_lookup_ag(ap->ip);
-                       ag = (ag != NULLAGNUMBER) ? ag : 0;
-                       ap->blkno = XFS_AGB_TO_FSB(mp, ag, 0);
-               } else {
-                       ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
-               }
-       } else
-               ap->blkno = ap->tp->t_firstblock;
-
-       xfs_bmap_adjacent(ap);
+       return stripe_align;
+}
 
+static void
+xfs_bmap_process_allocated_extent(
+       struct xfs_bmalloca     *ap,
+       struct xfs_alloc_arg    *args,
+       xfs_fileoff_t           orig_offset,
+       xfs_extlen_t            orig_length)
+{
+       ap->blkno = args->fsbno;
+       ap->length = args->len;
        /*
-        * If allowed, use ap->blkno; otherwise must use firstblock since
-        * it's in the right allocation group.
+        * If the extent size hint is active, we tried to round the
+        * caller's allocation request offset down to extsz and the
+        * length up to another extsz boundary.  If we found a free
+        * extent we mapped it in starting at this new offset.  If the
+        * newly mapped space isn't long enough to cover any of the
+        * range of offsets that was originally requested, move the
+        * mapping up so that we can fill as much of the caller's
+        * original request as possible.  Free space is apparently
+        * very fragmented so we're unlikely to be able to satisfy the
+        * hints anyway.
         */
-       if (nullfb || XFS_FSB_TO_AGNO(mp, ap->blkno) == fb_agno)
-               ;
-       else
-               ap->blkno = ap->tp->t_firstblock;
+       if (ap->length <= orig_length)
+               ap->offset = orig_offset;
+       else if (ap->offset + ap->length < orig_offset + orig_length)
+               ap->offset = orig_offset + orig_length - ap->length;
+       xfs_bmap_btalloc_accounting(ap, args);
+}
+
+#ifdef DEBUG
+static int
+xfs_bmap_exact_minlen_extent_alloc(
+       struct xfs_bmalloca     *ap)
+{
+       struct xfs_mount        *mp = ap->ip->i_mount;
+       struct xfs_alloc_arg    args = { .tp = ap->tp, .mp = mp };
+       xfs_fileoff_t           orig_offset;
+       xfs_extlen_t            orig_length;
+       int                     error;
+
+       ASSERT(ap->length);
+
+       if (ap->minlen != 1) {
+               ap->blkno = NULLFSBLOCK;
+               ap->length = 0;
+               return 0;
+       }
+
+       orig_offset = ap->offset;
+       orig_length = ap->length;
+
+       args.alloc_minlen_only = 1;
+
+       xfs_bmap_compute_alignments(ap, &args);
+
        /*
-        * Normal allocation, done through xfs_alloc_vextent.
+        * Unlike the longest extent available in an AG, we don't track
+        * the length of an AG's shortest extent.
+        * XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT is a debug only knob and
+        * hence we can afford to start traversing from the 0th AG since
+        * we need not be concerned about a drop in performance in
+        * "debug only" code paths.
         */
-       tryagain = isaligned = 0;
-       memset(&args, 0, sizeof(args));
-       args.tp = ap->tp;
-       args.mp = mp;
+       ap->blkno = XFS_AGB_TO_FSB(mp, 0, 0);
+
        args.fsbno = ap->blkno;
        args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE;
+       args.type = XFS_ALLOCTYPE_FIRST_AG;
+       args.minlen = args.maxlen = ap->minlen;
+       args.total = ap->total;
 
-       /* Trim the allocation back to the maximum an AG can fit. */
-       args.maxlen = min(ap->length, mp->m_ag_max_usable);
-       blen = 0;
-       if (nullfb) {
-               /*
-                * Search for an allocation group with a single extent large
-                * enough for the request.  If one isn't found, then adjust
-                * the minimum allocation size to the largest space found.
-                */
-               if ((ap->datatype & XFS_ALLOC_USERDATA) &&
-                   xfs_inode_is_filestream(ap->ip))
-                       error = xfs_bmap_btalloc_filestreams(ap, &args, &blen);
-               else
-                       error = xfs_bmap_btalloc_nullfb(ap, &args, &blen);
-               if (error)
-                       return error;
-       } else if (ap->tp->t_flags & XFS_TRANS_LOWMODE) {
-               if (xfs_inode_is_filestream(ap->ip))
-                       args.type = XFS_ALLOCTYPE_FIRST_AG;
-               else
-                       args.type = XFS_ALLOCTYPE_START_BNO;
-               args.total = args.minlen = ap->minlen;
+       args.alignment = 1;
+       args.minalignslop = 0;
+
+       args.minleft = ap->minleft;
+       args.wasdel = ap->wasdel;
+       args.resv = XFS_AG_RESV_NONE;
+       args.datatype = ap->datatype;
+
+       error = xfs_alloc_vextent(&args);
+       if (error)
+               return error;
+
+       if (args.fsbno != NULLFSBLOCK) {
+               xfs_bmap_process_allocated_extent(ap, &args, orig_offset,
+                       orig_length);
        } else {
-               args.type = XFS_ALLOCTYPE_NEAR_BNO;
-               args.total = ap->total;
-               args.minlen = ap->minlen;
+               ap->blkno = NULLFSBLOCK;
+               ap->length = 0;
        }
-       /* apply extent size hints if obtained earlier */
-       if (align) {
-               args.prod = align;
-               div_u64_rem(ap->offset, args.prod, &args.mod);
-               if (args.mod)
-                       args.mod = args.prod - args.mod;
-       } else if (mp->m_sb.sb_blocksize >= PAGE_SIZE) {
-               args.prod = 1;
-               args.mod = 0;
+
+       return 0;
+}
+#else
+
+#define xfs_bmap_exact_minlen_extent_alloc(bma) (-EFSCORRUPTED)
+
+#endif
+
+STATIC int
+xfs_bmap_btalloc(
+       struct xfs_bmalloca     *ap)
+{
+       struct xfs_mount        *mp = ap->ip->i_mount;
+       struct xfs_alloc_arg    args = { .tp = ap->tp, .mp = mp };
+       xfs_alloctype_t         atype = 0;
+       xfs_agnumber_t          ag;
+       xfs_fileoff_t           orig_offset;
+       xfs_extlen_t            orig_length;
+       xfs_extlen_t            blen;
+       xfs_extlen_t            nextminlen = 0;
+       int                     isaligned;
+       int                     tryagain;
+       int                     error;
+       int                     stripe_align;
+
+       ASSERT(ap->length);
+       orig_offset = ap->offset;
+       orig_length = ap->length;
+
+       stripe_align = xfs_bmap_compute_alignments(ap, &args);
+
+       if ((ap->datatype & XFS_ALLOC_USERDATA) &&
+           xfs_inode_is_filestream(ap->ip)) {
+               ag = xfs_filestream_lookup_ag(ap->ip);
+               ag = (ag != NULLAGNUMBER) ? ag : 0;
+               ap->blkno = XFS_AGB_TO_FSB(mp, ag, 0);
        } else {
-               args.prod = PAGE_SIZE >> mp->m_sb.sb_blocklog;
-               div_u64_rem(ap->offset, args.prod, &args.mod);
-               if (args.mod)
-                       args.mod = args.prod - args.mod;
+               ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
        }
+
+       xfs_bmap_adjacent(ap);
+
+       tryagain = isaligned = 0;
+       args.fsbno = ap->blkno;
+       args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE;
+
+       /* Trim the allocation back to the maximum an AG can fit. */
+       args.maxlen = min(ap->length, mp->m_ag_max_usable);
+       blen = 0;
+
+       /*
+        * Search for an allocation group with a single extent large
+        * enough for the request.  If one isn't found, then adjust
+        * the minimum allocation size to the largest space found.
+        */
+       if ((ap->datatype & XFS_ALLOC_USERDATA) &&
+           xfs_inode_is_filestream(ap->ip))
+               error = xfs_bmap_btalloc_filestreams(ap, &args, &blen);
+       else
+               error = xfs_bmap_btalloc_select_lengths(ap, &args, &blen);
+       if (error)
+               return error;
+
        /*
         * If we are not low on available data blocks, and the underlying
         * logical volume manager is a stripe, and the file offset is zero then
@@ -3684,7 +3613,7 @@ xfs_bmap_btalloc(
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
        }
-       if (args.fsbno == NULLFSBLOCK && nullfb &&
+       if (args.fsbno == NULLFSBLOCK &&
            args.minlen > ap->minlen) {
                args.minlen = ap->minlen;
                args.type = XFS_ALLOCTYPE_START_BNO;
@@ -3692,7 +3621,7 @@ xfs_bmap_btalloc(
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
        }
-       if (args.fsbno == NULLFSBLOCK && nullfb) {
+       if (args.fsbno == NULLFSBLOCK) {
                args.fsbno = 0;
                args.type = XFS_ALLOCTYPE_FIRST_AG;
                args.total = ap->minlen;
@@ -3700,37 +3629,10 @@ xfs_bmap_btalloc(
                        return error;
                ap->tp->t_flags |= XFS_TRANS_LOWMODE;
        }
+
        if (args.fsbno != NULLFSBLOCK) {
-               /*
-                * check the allocation happened at the same or higher AG than
-                * the first block that was allocated.
-                */
-               ASSERT(ap->tp->t_firstblock == NULLFSBLOCK ||
-                      XFS_FSB_TO_AGNO(mp, ap->tp->t_firstblock) <=
-                      XFS_FSB_TO_AGNO(mp, args.fsbno));
-
-               ap->blkno = args.fsbno;
-               if (ap->tp->t_firstblock == NULLFSBLOCK)
-                       ap->tp->t_firstblock = args.fsbno;
-               ASSERT(nullfb || fb_agno <= args.agno);
-               ap->length = args.len;
-               /*
-                * If the extent size hint is active, we tried to round the
-                * caller's allocation request offset down to extsz and the
-                * length up to another extsz boundary.  If we found a free
-                * extent we mapped it in starting at this new offset.  If the
-                * newly mapped space isn't long enough to cover any of the
-                * range of offsets that was originally requested, move the
-                * mapping up so that we can fill as much of the caller's
-                * original request as possible.  Free space is apparently
-                * very fragmented so we're unlikely to be able to satisfy the
-                * hints anyway.
-                */
-               if (ap->length <= orig_length)
-                       ap->offset = orig_offset;
-               else if (ap->offset + ap->length < orig_offset + orig_length)
-                       ap->offset = orig_offset + orig_length - ap->length;
-               xfs_bmap_btalloc_accounting(ap, &args);
+               xfs_bmap_process_allocated_extent(ap, &args, orig_offset,
+                       orig_length);
        } else {
                ap->blkno = NULLFSBLOCK;
                ap->length = 0;
@@ -3783,7 +3685,7 @@ xfs_bmapi_trim_map(
        xfs_fileoff_t           obno,
        xfs_fileoff_t           end,
        int                     n,
-       int                     flags)
+       uint32_t                flags)
 {
        if ((flags & XFS_BMAPI_ENTIRE) ||
            got->br_startoff + got->br_blockcount <= obno) {
@@ -3828,7 +3730,7 @@ xfs_bmapi_update_map(
        xfs_fileoff_t           obno,
        xfs_fileoff_t           end,
        int                     *n,
-       int                     flags)
+       uint32_t                flags)
 {
        xfs_bmbt_irec_t *mval = *map;
 
@@ -3881,10 +3783,11 @@ xfs_bmapi_read(
        xfs_filblks_t           len,
        struct xfs_bmbt_irec    *mval,
        int                     *nmap,
-       int                     flags)
+       uint32_t                flags)
 {
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_ifork        *ifp;
+       int                     whichfork = xfs_bmapi_whichfork(flags);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_bmbt_irec    got;
        xfs_fileoff_t           obno;
        xfs_fileoff_t           end;
@@ -3892,53 +3795,26 @@ xfs_bmapi_read(
        int                     error;
        bool                    eof = false;
        int                     n = 0;
-       int                     whichfork = xfs_bmapi_whichfork(flags);
 
        ASSERT(*nmap >= 1);
-       ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK|XFS_BMAPI_ENTIRE|
-                          XFS_BMAPI_COWFORK)));
+       ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK | XFS_BMAPI_ENTIRE)));
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED|XFS_ILOCK_EXCL));
 
-       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
-           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+       if (WARN_ON_ONCE(!ifp))
+               return -EFSCORRUPTED;
+
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
+           XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT))
                return -EFSCORRUPTED;
-       }
 
-       if (XFS_FORCED_SHUTDOWN(mp))
+       if (xfs_is_shutdown(mp))
                return -EIO;
 
        XFS_STATS_INC(mp, xs_blk_mapr);
 
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (!ifp) {
-               /* No CoW fork?  Return a hole. */
-               if (whichfork == XFS_COW_FORK) {
-                       mval->br_startoff = bno;
-                       mval->br_startblock = HOLESTARTBLOCK;
-                       mval->br_blockcount = len;
-                       mval->br_state = XFS_EXT_NORM;
-                       *nmap = 1;
-                       return 0;
-               }
-
-               /*
-                * A missing attr ifork implies that the inode says we're in
-                * extents or btree format but failed to pass the inode fork
-                * verifier while trying to load it.  Treat that as a file
-                * corruption too.
-                */
-#ifdef DEBUG
-               xfs_alert(mp, "%s: inode %llu missing fork %d",
-                               __func__, ip->i_ino, whichfork);
-#endif /* DEBUG */
-               return -EFSCORRUPTED;
-       }
-
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               error = xfs_iread_extents(NULL, ip, whichfork);
-               if (error)
-                       return error;
-       }
+       error = xfs_iread_extents(NULL, ip, whichfork);
+       if (error)
+               return error;
 
        if (!xfs_iext_lookup_extent(ip, ifp, bno, &icur, &got))
                eof = true;
@@ -4004,7 +3880,7 @@ xfs_bmapi_reserve_delalloc(
        int                     eof)
 {
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        xfs_extlen_t            alen;
        xfs_extlen_t            indlen;
        int                     error;
@@ -4014,7 +3890,7 @@ xfs_bmapi_reserve_delalloc(
         * Cap the alloc length. Keep track of prealloc so we know whether to
         * tag the inode before we return.
         */
-       alen = XFS_FILBLKS_MIN(len + prealloc, MAXEXTLEN);
+       alen = XFS_FILBLKS_MIN(len + prealloc, XFS_MAX_BMBT_EXTLEN);
        if (!eof)
                alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff);
        if (prealloc && alen >= len)
@@ -4038,8 +3914,7 @@ xfs_bmapi_reserve_delalloc(
         * blocks.  This number gets adjusted later.  We return if we haven't
         * allocated blocks already inside this loop.
         */
-       error = xfs_trans_reserve_quota_nblks(NULL, ip, (long)alen, 0,
-                                               XFS_QMOPT_RES_REGBLKS);
+       error = xfs_quota_reserve_blkres(ip, alen);
        if (error)
                return error;
 
@@ -4085,8 +3960,7 @@ out_unreserve_blocks:
        xfs_mod_fdblocks(mp, alen, false);
 out_unreserve_quota:
        if (XFS_IS_QUOTA_ON(mp))
-               xfs_trans_unreserve_quota_nblks(NULL, ip, (long)alen, 0,
-                                               XFS_QMOPT_RES_REGBLKS);
+               xfs_quota_unreserve_blkres(ip, alen);
        return error;
 }
 
@@ -4105,7 +3979,7 @@ xfs_bmap_alloc_userdata(
         * the busy list.
         */
        bma->datatype = XFS_ALLOC_NOBUSY;
-       if (whichfork == XFS_DATA_FORK) {
+       if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK) {
                bma->datatype |= XFS_ALLOC_USERDATA;
                if (bma->offset == 0)
                        bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA;
@@ -4120,6 +3994,10 @@ xfs_bmap_alloc_userdata(
                        return xfs_bmap_rtalloc(bma);
        }
 
+       if (unlikely(XFS_TEST_ERROR(false, mp,
+                       XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
+               return xfs_bmap_exact_minlen_extent_alloc(bma);
+
        return xfs_bmap_btalloc(bma);
 }
 
@@ -4129,7 +4007,7 @@ xfs_bmapi_allocate(
 {
        struct xfs_mount        *mp = bma->ip->i_mount;
        int                     whichfork = xfs_bmapi_whichfork(bma->flags);
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(bma->ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(bma->ip, whichfork);
        int                     tmp_logflags = 0;
        int                     error;
 
@@ -4145,7 +4023,7 @@ xfs_bmapi_allocate(
                if (!xfs_iext_peek_prev_extent(ifp, &bma->icur, &bma->prev))
                        bma->prev.br_startoff = NULLFILEOFF;
        } else {
-               bma->length = XFS_FILBLKS_MIN(bma->length, MAXEXTLEN);
+               bma->length = XFS_FILBLKS_MIN(bma->length, XFS_MAX_BMBT_EXTLEN);
                if (!bma->eof)
                        bma->length = XFS_FILBLKS_MIN(bma->length,
                                        bma->got.br_startoff - bma->offset);
@@ -4156,10 +4034,15 @@ xfs_bmapi_allocate(
        else
                bma->minlen = 1;
 
-       if (bma->flags & XFS_BMAPI_METADATA)
-               error = xfs_bmap_btalloc(bma);
-       else
+       if (bma->flags & XFS_BMAPI_METADATA) {
+               if (unlikely(XFS_TEST_ERROR(false, mp,
+                               XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
+                       error = xfs_bmap_exact_minlen_extent_alloc(bma);
+               else
+                       error = xfs_bmap_btalloc(bma);
+       } else {
                error = xfs_bmap_alloc_userdata(bma);
+       }
        if (error || bma->blkno == NULLFSBLOCK)
                return error;
 
@@ -4169,7 +4052,7 @@ xfs_bmapi_allocate(
                        return error;
        }
 
-       if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur)
+       if (ifp->if_format == XFS_DINODE_FMT_BTREE && !bma->cur)
                bma->cur = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork);
        /*
         * Bump the number of extents we've allocated
@@ -4186,17 +4069,7 @@ xfs_bmapi_allocate(
        bma->got.br_blockcount = bma->length;
        bma->got.br_state = XFS_EXT_NORM;
 
-       /*
-        * In the data fork, a wasdelay extent has been initialized, so
-        * shouldn't be flagged as unwritten.
-        *
-        * For the cow fork, however, we convert delalloc reservations
-        * (extents allocated for speculative preallocation) to
-        * allocated unwritten extents, and only convert the unwritten
-        * extents to real extents when we're about to write the data.
-        */
-       if ((!bma->wasdel || (bma->flags & XFS_BMAPI_COWFORK)) &&
-           (bma->flags & XFS_BMAPI_PREALLOC))
+       if (bma->flags & XFS_BMAPI_PREALLOC)
                bma->got.br_state = XFS_EXT_UNWRITTEN;
 
        if (bma->wasdel)
@@ -4230,10 +4103,10 @@ xfs_bmapi_convert_unwritten(
        struct xfs_bmalloca     *bma,
        struct xfs_bmbt_irec    *mval,
        xfs_filblks_t           len,
-       int                     flags)
+       uint32_t                flags)
 {
        int                     whichfork = xfs_bmapi_whichfork(flags);
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(bma->ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(bma->ip, whichfork);
        int                     tmp_logflags = 0;
        int                     error;
 
@@ -4252,7 +4125,7 @@ xfs_bmapi_convert_unwritten(
         * Modify (by adding) the state flag, if writing.
         */
        ASSERT(mval->br_blockcount <= len);
-       if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) {
+       if (ifp->if_format == XFS_DINODE_FMT_BTREE && !bma->cur) {
                bma->cur = xfs_bmbt_init_cursor(bma->ip->i_mount, bma->tp,
                                        bma->ip, whichfork);
        }
@@ -4304,17 +4177,19 @@ xfs_bmapi_convert_unwritten(
        return 0;
 }
 
-static inline xfs_extlen_t
+xfs_extlen_t
 xfs_bmapi_minleft(
        struct xfs_trans        *tp,
        struct xfs_inode        *ip,
        int                     fork)
 {
-       if (tp && tp->t_firstblock != NULLFSBLOCK)
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, fork);
+
+       if (tp && tp->t_highest_agno != NULLAGNUMBER)
                return 0;
-       if (XFS_IFORK_FORMAT(ip, fork) != XFS_DINODE_FMT_BTREE)
+       if (ifp->if_format != XFS_DINODE_FMT_BTREE)
                return 1;
-       return be16_to_cpu(XFS_IFORK_PTR(ip, fork)->if_broot->bb_level) + 1;
+       return be16_to_cpu(ifp->if_broot->bb_level) + 1;
 }
 
 /*
@@ -4329,11 +4204,13 @@ xfs_bmapi_finish(
        int                     whichfork,
        int                     error)
 {
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(bma->ip, whichfork);
+
        if ((bma->logflags & xfs_ilog_fext(whichfork)) &&
-           XFS_IFORK_FORMAT(bma->ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
+           ifp->if_format != XFS_DINODE_FMT_EXTENTS)
                bma->logflags &= ~xfs_ilog_fext(whichfork);
        else if ((bma->logflags & xfs_ilog_fbroot(whichfork)) &&
-                XFS_IFORK_FORMAT(bma->ip, whichfork) != XFS_DINODE_FMT_BTREE)
+                ifp->if_format != XFS_DINODE_FMT_BTREE)
                bma->logflags &= ~xfs_ilog_fbroot(whichfork);
 
        if (bma->logflags)
@@ -4354,7 +4231,7 @@ xfs_bmapi_write(
        struct xfs_inode        *ip,            /* incore inode */
        xfs_fileoff_t           bno,            /* starting file offs. mapped */
        xfs_filblks_t           len,            /* length to map in file */
-       int                     flags,          /* XFS_BMAPI_... */
+       uint32_t                flags,          /* XFS_BMAPI_... */
        xfs_extlen_t            total,          /* total blocks needed */
        struct xfs_bmbt_irec    *mval,          /* output: map values */
        int                     *nmap)          /* i/o: mval size/count */
@@ -4365,13 +4242,13 @@ xfs_bmapi_write(
                .total          = total,
        };
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_ifork        *ifp;
+       int                     whichfork = xfs_bmapi_whichfork(flags);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        xfs_fileoff_t           end;            /* end of mapped file region */
        bool                    eof = false;    /* after the end of extents */
        int                     error;          /* error return */
        int                     n;              /* current extent index */
        xfs_fileoff_t           obno;           /* old block number (offset) */
-       int                     whichfork;      /* data or attr fork */
 
 #ifdef DEBUG
        xfs_fileoff_t           orig_bno;       /* original block number value */
@@ -4386,13 +4263,12 @@ xfs_bmapi_write(
        orig_mval = mval;
        orig_nmap = *nmap;
 #endif
-       whichfork = xfs_bmapi_whichfork(flags);
 
        ASSERT(*nmap >= 1);
        ASSERT(*nmap <= XFS_BMAP_MAX_NMAP);
        ASSERT(tp != NULL);
        ASSERT(len > 0);
-       ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL);
+       ASSERT(ifp->if_format != XFS_DINODE_FMT_LOCAL);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
        ASSERT(!(flags & XFS_BMAPI_REMAP));
 
@@ -4408,23 +4284,19 @@ xfs_bmapi_write(
        ASSERT((flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)) !=
                        (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO));
 
-       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
-       if (XFS_FORCED_SHUTDOWN(mp))
+       if (xfs_is_shutdown(mp))
                return -EIO;
 
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-
        XFS_STATS_INC(mp, xs_blk_mapw);
 
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               error = xfs_iread_extents(tp, ip, whichfork);
-               if (error)
-                       goto error0;
-       }
+       error = xfs_iread_extents(tp, ip, whichfork);
+       if (error)
+               goto error0;
 
        if (!xfs_iext_lookup_extent(ip, ifp, bno, &bma.icur, &bma.got))
                eof = true;
@@ -4471,8 +4343,8 @@ xfs_bmapi_write(
                         * xfs_extlen_t and therefore 32 bits. Hence we have to
                         * check for 32-bit overflows and handle them here.
                         */
-                       if (len > (xfs_filblks_t)MAXEXTLEN)
-                               bma.length = MAXEXTLEN;
+                       if (len > (xfs_filblks_t)XFS_MAX_BMBT_EXTLEN)
+                               bma.length = XFS_MAX_BMBT_EXTLEN;
                        else
                                bma.length = len;
 
@@ -4527,9 +4399,8 @@ xfs_bmapi_write(
        if (error)
                goto error0;
 
-       ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE ||
-              XFS_IFORK_NEXTENTS(ip, whichfork) >
-               XFS_IFORK_MAXEXT(ip, whichfork));
+       ASSERT(ifp->if_format != XFS_DINODE_FMT_BTREE ||
+              ifp->if_nextents > XFS_IFORK_MAXEXT(ip, whichfork));
        xfs_bmapi_finish(&bma, whichfork, 0);
        xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval,
                orig_nmap, *nmap);
@@ -4553,7 +4424,7 @@ xfs_bmapi_convert_delalloc(
        struct iomap            *iomap,
        unsigned int            *seq)
 {
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_mount        *mp = ip->i_mount;
        xfs_fileoff_t           offset_fsb = XFS_B_TO_FSBT(mp, offset);
        struct xfs_bmalloca     bma = { NULL };
@@ -4576,6 +4447,14 @@ xfs_bmapi_convert_delalloc(
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, 0);
 
+       error = xfs_iext_count_may_overflow(ip, whichfork,
+                       XFS_IEXT_ADD_NOSPLIT_CNT);
+       if (error == -EFBIG)
+               error = xfs_iext_count_upgrade(tp, ip,
+                               XFS_IEXT_ADD_NOSPLIT_CNT);
+       if (error)
+               goto out_trans_cancel;
+
        if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &bma.icur, &bma.got) ||
            bma.got.br_startoff > offset_fsb) {
                /*
@@ -4593,7 +4472,8 @@ xfs_bmapi_convert_delalloc(
         * the extent.  Just return the real extent at this offset.
         */
        if (!isnullstartblock(bma.got.br_startblock)) {
-               xfs_bmbt_to_iomap(ip, iomap, &bma.got, flags);
+               xfs_bmbt_to_iomap(ip, iomap, &bma.got, 0, flags,
+                               xfs_iomap_inode_sequence(ip, flags));
                *seq = READ_ONCE(ifp->if_seq);
                goto out_trans_cancel;
        }
@@ -4602,10 +4482,26 @@ xfs_bmapi_convert_delalloc(
        bma.ip = ip;
        bma.wasdel = true;
        bma.offset = bma.got.br_startoff;
-       bma.length = max_t(xfs_filblks_t, bma.got.br_blockcount, MAXEXTLEN);
+       bma.length = max_t(xfs_filblks_t, bma.got.br_blockcount,
+                       XFS_MAX_BMBT_EXTLEN);
        bma.minleft = xfs_bmapi_minleft(tp, ip, whichfork);
+
+       /*
+        * When we're converting the delalloc reservations backing dirty pages
+        * in the page cache, we must be careful about how we create the new
+        * extents:
+        *
+        * New CoW fork extents are created unwritten, turned into real extents
+        * when we're about to write the data to disk, and mapped into the data
+        * fork after the write finishes.  End of story.
+        *
+        * New data fork extents must be mapped in as unwritten and converted
+        * to real extents after the write succeeds to avoid exposing stale
+        * disk contents if we crash.
+        */
+       bma.flags = XFS_BMAPI_PREALLOC;
        if (whichfork == XFS_COW_FORK)
-               bma.flags = XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC;
+               bma.flags |= XFS_BMAPI_COWFORK;
 
        if (!xfs_iext_peek_prev_extent(ifp, &bma.icur, &bma.prev))
                bma.prev.br_startoff = NULLFILEOFF;
@@ -4625,7 +4521,8 @@ xfs_bmapi_convert_delalloc(
        XFS_STATS_INC(mp, xs_xstrat_quick);
 
        ASSERT(!isnullstartblock(bma.got.br_startblock));
-       xfs_bmbt_to_iomap(ip, iomap, &bma.got, flags);
+       xfs_bmbt_to_iomap(ip, iomap, &bma.got, 0, flags,
+                               xfs_iomap_inode_sequence(ip, flags));
        *seq = READ_ONCE(ifp->if_seq);
 
        if (whichfork == XFS_COW_FORK)
@@ -4656,7 +4553,7 @@ xfs_bmapi_remap(
        xfs_fileoff_t           bno,
        xfs_filblks_t           len,
        xfs_fsblock_t           startblock,
-       int                     flags)
+       uint32_t                flags)
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_ifork        *ifp;
@@ -4666,28 +4563,26 @@ xfs_bmapi_remap(
        int                     whichfork = xfs_bmapi_whichfork(flags);
        int                     logflags = 0, error;
 
-       ifp = XFS_IFORK_PTR(ip, whichfork);
+       ifp = xfs_ifork_ptr(ip, whichfork);
        ASSERT(len > 0);
-       ASSERT(len <= (xfs_filblks_t)MAXEXTLEN);
+       ASSERT(len <= (xfs_filblks_t)XFS_MAX_BMBT_EXTLEN);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
        ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK | XFS_BMAPI_PREALLOC |
                           XFS_BMAPI_NORMAP)));
        ASSERT((flags & (XFS_BMAPI_ATTRFORK | XFS_BMAPI_PREALLOC)) !=
                        (XFS_BMAPI_ATTRFORK | XFS_BMAPI_PREALLOC));
 
-       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
-       if (XFS_FORCED_SHUTDOWN(mp))
+       if (xfs_is_shutdown(mp))
                return -EIO;
 
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               error = xfs_iread_extents(tp, ip, whichfork);
-               if (error)
-                       return error;
-       }
+       error = xfs_iread_extents(tp, ip, whichfork);
+       if (error)
+               return error;
 
        if (xfs_iext_lookup_extent(ip, ifp, bno, &icur, &got)) {
                /* make sure we only reflink into a hole. */
@@ -4695,10 +4590,10 @@ xfs_bmapi_remap(
                ASSERT(got.br_startoff - bno >= len);
        }
 
-       ip->i_d.di_nblocks += len;
+       ip->i_nblocks += len;
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
-       if (ifp->if_flags & XFS_IFBROOT) {
+       if (ifp->if_format == XFS_DINODE_FMT_BTREE) {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_ino.flags = 0;
        }
@@ -4719,9 +4614,9 @@ xfs_bmapi_remap(
        error = xfs_bmap_btree_to_extents(tp, ip, cur, &logflags, whichfork);
 
 error0:
-       if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS)
+       if (ip->i_df.if_format != XFS_DINODE_FMT_EXTENTS)
                logflags &= ~XFS_ILOG_DEXT;
-       else if (ip->i_d.di_format != XFS_DINODE_FMT_BTREE)
+       else if (ip->i_df.if_format != XFS_DINODE_FMT_BTREE)
                logflags &= ~XFS_ILOG_DBROOT;
 
        if (logflags)
@@ -4825,12 +4720,12 @@ xfs_bmap_del_extent_delay(
        struct xfs_bmbt_irec    *del)
 {
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_bmbt_irec    new;
        int64_t                 da_old, da_new, da_diff = 0;
        xfs_fileoff_t           del_endoff, got_endoff;
        xfs_filblks_t           got_indlen, new_indlen, stolen;
-       int                     state = xfs_bmap_fork_to_state(whichfork);
+       uint32_t                state = xfs_bmap_fork_to_state(whichfork);
        int                     error = 0;
        bool                    isrt;
 
@@ -4858,9 +4753,8 @@ xfs_bmap_del_extent_delay(
         * sb counters as we might have to borrow some blocks for the
         * indirect block accounting.
         */
-       error = xfs_trans_reserve_quota_nblks(NULL, ip,
-                       -((long)del->br_blockcount), 0,
-                       isrt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+       ASSERT(!isrt);
+       error = xfs_quota_unreserve_blkres(ip, del->br_blockcount);
        if (error)
                return error;
        ip->i_delayed_blks -= del->br_blockcount;
@@ -4953,10 +4847,10 @@ xfs_bmap_del_extent_cow(
        struct xfs_bmbt_irec    *del)
 {
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, XFS_COW_FORK);
        struct xfs_bmbt_irec    new;
        xfs_fileoff_t           del_endoff, got_endoff;
-       int                     state = BMAP_COWFORK;
+       uint32_t                state = BMAP_COWFORK;
 
        XFS_STATS_INC(mp, xs_del_exlist);
 
@@ -5025,11 +4919,11 @@ xfs_bmap_del_extent_real(
        xfs_inode_t             *ip,    /* incore inode pointer */
        xfs_trans_t             *tp,    /* current transaction pointer */
        struct xfs_iext_cursor  *icur,
-       xfs_btree_cur_t         *cur,   /* if null, not a btree */
+       struct xfs_btree_cur    *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *del,   /* data to remove from extents */
        int                     *logflagsp, /* inode logging flags */
        int                     whichfork, /* data or attr fork */
-       int                     bflags) /* bmapi flags */
+       uint32_t                bflags) /* bmapi flags */
 {
        xfs_fsblock_t           del_endblock=0; /* first block past del */
        xfs_fileoff_t           del_endoff;     /* first offset past del */
@@ -5045,13 +4939,13 @@ xfs_bmap_del_extent_real(
        xfs_bmbt_irec_t         new;    /* new record to be inserted */
        /* REFERENCED */
        uint                    qfield; /* quota field to update */
-       int                     state = xfs_bmap_fork_to_state(whichfork);
+       uint32_t                state = xfs_bmap_fork_to_state(whichfork);
        struct xfs_bmbt_irec    old;
 
        mp = ip->i_mount;
        XFS_STATS_INC(mp, xs_del_exlist);
 
-       ifp = XFS_IFORK_PTR(ip, whichfork);
+       ifp = xfs_ifork_ptr(ip, whichfork);
        ASSERT(del->br_blockcount > 0);
        xfs_iext_get_extent(ifp, icur, &got);
        ASSERT(got.br_startoff <= del->br_startoff);
@@ -5071,28 +4965,32 @@ xfs_bmap_del_extent_real(
         * conversion to btree format, since the transaction will be dirty then.
         */
        if (tp->t_blk_res == 0 &&
-           XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(ip, whichfork) >=
-                       XFS_IFORK_MAXEXT(ip, whichfork) &&
+           ifp->if_format == XFS_DINODE_FMT_EXTENTS &&
+           ifp->if_nextents >= XFS_IFORK_MAXEXT(ip, whichfork) &&
            del->br_startoff > got.br_startoff && del_endoff < got_endoff)
                return -ENOSPC;
 
        flags = XFS_ILOG_CORE;
        if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) {
-               xfs_fsblock_t   bno;
                xfs_filblks_t   len;
                xfs_extlen_t    mod;
 
-               bno = div_u64_rem(del->br_startblock, mp->m_sb.sb_rextsize,
-                                 &mod);
-               ASSERT(mod == 0);
                len = div_u64_rem(del->br_blockcount, mp->m_sb.sb_rextsize,
                                  &mod);
                ASSERT(mod == 0);
 
-               error = xfs_rtfree_extent(tp, bno, (xfs_extlen_t)len);
-               if (error)
-                       goto done;
+               if (!(bflags & XFS_BMAPI_REMAP)) {
+                       xfs_fsblock_t   bno;
+
+                       bno = div_u64_rem(del->br_startblock,
+                                       mp->m_sb.sb_rextsize, &mod);
+                       ASSERT(mod == 0);
+
+                       error = xfs_rtfree_extent(tp, bno, (xfs_extlen_t)len);
+                       if (error)
+                               goto done;
+               }
+
                do_fx = 0;
                nblks = len * mp->m_sb.sb_rextsize;
                qfield = XFS_TRANS_DQ_RTBCOUNT;
@@ -5125,8 +5023,8 @@ xfs_bmap_del_extent_real(
                 */
                xfs_iext_remove(ip, icur, state);
                xfs_iext_prev(ifp, icur);
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                       XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
+               ifp->if_nextents--;
+
                flags |= XFS_ILOG_CORE;
                if (!cur) {
                        flags |= xfs_ilog_fext(whichfork);
@@ -5173,6 +5071,7 @@ xfs_bmap_del_extent_real(
                /*
                 * Deleting the middle of the extent.
                 */
+
                old = got;
 
                got.br_blockcount = del->br_startoff - got.br_startoff;
@@ -5234,8 +5133,8 @@ xfs_bmap_del_extent_real(
                        }
                } else
                        flags |= xfs_ilog_fext(whichfork);
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                       XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
+
+               ifp->if_nextents++;
                xfs_iext_next(ifp, icur);
                xfs_iext_insert(ip, icur, &new, state);
                break;
@@ -5251,7 +5150,7 @@ xfs_bmap_del_extent_real(
                if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) {
                        xfs_refcount_decrease_extent(tp, del);
                } else {
-                       __xfs_bmap_add_free(tp, del->br_startblock,
+                       __xfs_free_extent_later(tp, del->br_startblock,
                                        del->br_blockcount, NULL,
                                        (bflags & XFS_BMAPI_NODISCARD) ||
                                        del->br_state == XFS_EXT_UNWRITTEN);
@@ -5262,7 +5161,7 @@ xfs_bmap_del_extent_real(
         * Adjust inode # blocks in the file.
         */
        if (nblks)
-               ip->i_d.di_nblocks -= nblks;
+               ip->i_nblocks -= nblks;
        /*
         * Adjust quota data.
         */
@@ -5286,7 +5185,7 @@ __xfs_bunmapi(
        struct xfs_inode        *ip,            /* incore inode */
        xfs_fileoff_t           start,          /* first file offset deleted */
        xfs_filblks_t           *rlen,          /* i/o: amount remaining */
-       int                     flags,          /* misc flags */
+       uint32_t                flags,          /* misc flags */
        xfs_extnum_t            nexts)          /* number of extents max */
 {
        struct xfs_btree_cur    *cur;           /* bmap btree cursor */
@@ -5304,8 +5203,6 @@ __xfs_bunmapi(
        int                     whichfork;      /* data or attribute fork */
        xfs_fsblock_t           sum;
        xfs_filblks_t           len = *rlen;    /* length to unmap in file */
-       xfs_fileoff_t           max_len;
-       xfs_agnumber_t          prev_agno = NULLAGNUMBER, agno;
        xfs_fileoff_t           end;
        struct xfs_iext_cursor  icur;
        bool                    done = false;
@@ -5314,29 +5211,20 @@ __xfs_bunmapi(
 
        whichfork = xfs_bmapi_whichfork(flags);
        ASSERT(whichfork != XFS_COW_FORK);
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)))
+       ifp = xfs_ifork_ptr(ip, whichfork);
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)))
                return -EFSCORRUPTED;
-       if (XFS_FORCED_SHUTDOWN(mp))
+       if (xfs_is_shutdown(mp))
                return -EIO;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
        ASSERT(len > 0);
        ASSERT(nexts >= 0);
 
-       /*
-        * Guesstimate how many blocks we can unmap without running the risk of
-        * blowing out the transaction with a mix of EFIs and reflink
-        * adjustments.
-        */
-       if (tp && xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK)
-               max_len = min(len, xfs_refcount_max_unmap(tp->t_log_res));
-       else
-               max_len = len;
-
-       if (!(ifp->if_flags & XFS_IFEXTENTS) &&
-           (error = xfs_iread_extents(tp, ip, whichfork)))
+       error = xfs_iread_extents(tp, ip, whichfork);
+       if (error)
                return error;
+
        if (xfs_iext_count(ifp) == 0) {
                *rlen = 0;
                return 0;
@@ -5352,8 +5240,8 @@ __xfs_bunmapi(
        end--;
 
        logflags = 0;
-       if (ifp->if_flags & XFS_IFBROOT) {
-               ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
+       if (ifp->if_format == XFS_DINODE_FMT_BTREE) {
+               ASSERT(ifp->if_format == XFS_DINODE_FMT_BTREE);
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_ino.flags = 0;
        } else
@@ -5371,7 +5259,7 @@ __xfs_bunmapi(
 
        extno = 0;
        while (end != (xfs_fileoff_t)-1 && end >= start &&
-              (nexts == 0 || extno < nexts) && max_len > 0) {
+              (nexts == 0 || extno < nexts)) {
                /*
                 * Is the found extent after a hole in which end lives?
                 * Just back up to the previous extent, if so.
@@ -5396,16 +5284,6 @@ __xfs_bunmapi(
                del = got;
                wasdel = isnullstartblock(del.br_startblock);
 
-               /*
-                * Make sure we don't touch multiple AGF headers out of order
-                * in a single transaction, as that could cause AB-BA deadlocks.
-                */
-               if (!wasdel && !isrt) {
-                       agno = XFS_FSB_TO_AGNO(mp, del.br_startblock);
-                       if (prev_agno != NULLAGNUMBER && prev_agno > agno)
-                               break;
-                       prev_agno = agno;
-               }
                if (got.br_startoff < start) {
                        del.br_startoff = start;
                        del.br_blockcount -= start - got.br_startoff;
@@ -5415,14 +5293,6 @@ __xfs_bunmapi(
                if (del.br_startoff + del.br_blockcount > end + 1)
                        del.br_blockcount = end + 1 - del.br_startoff;
 
-               /* How much can we safely unmap? */
-               if (max_len < del.br_blockcount) {
-                       del.br_startoff += del.br_blockcount - max_len;
-                       if (!wasdel)
-                               del.br_startblock += del.br_blockcount - max_len;
-                       del.br_blockcount = max_len;
-               }
-
                if (!isrt)
                        goto delete;
 
@@ -5558,7 +5428,6 @@ delete:
                if (error)
                        goto error0;
 
-               max_len -= del.br_blockcount;
                end = del.br_startoff - 1;
 nodelete:
                /*
@@ -5598,10 +5467,10 @@ error0:
         * logging the extent records if we've converted to btree format.
         */
        if ((logflags & xfs_ilog_fext(whichfork)) &&
-           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
+           ifp->if_format != XFS_DINODE_FMT_EXTENTS)
                logflags &= ~xfs_ilog_fext(whichfork);
        else if ((logflags & xfs_ilog_fbroot(whichfork)) &&
-                XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)
+                ifp->if_format != XFS_DINODE_FMT_BTREE)
                logflags &= ~xfs_ilog_fbroot(whichfork);
        /*
         * Log inode even in the error case, if the transaction
@@ -5624,7 +5493,7 @@ xfs_bunmapi(
        struct xfs_inode        *ip,
        xfs_fileoff_t           bno,
        xfs_filblks_t           len,
-       int                     flags,
+       uint32_t                flags,
        xfs_extnum_t            nexts,
        int                     *done)
 {
@@ -5656,7 +5525,7 @@ xfs_bmse_can_merge(
        if ((left->br_startoff + left->br_blockcount != startoff) ||
            (left->br_startblock + left->br_blockcount != got->br_startblock) ||
            (left->br_state != got->br_state) ||
-           (left->br_blockcount + got->br_blockcount > MAXEXTLEN))
+           (left->br_blockcount + got->br_blockcount > XFS_MAX_BMBT_EXTLEN))
                return false;
 
        return true;
@@ -5683,6 +5552,7 @@ xfs_bmse_merge(
        struct xfs_btree_cur            *cur,
        int                             *logflags)      /* output */
 {
+       struct xfs_ifork                *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_bmbt_irec            new;
        xfs_filblks_t                   blockcount;
        int                             error, i;
@@ -5701,8 +5571,7 @@ xfs_bmse_merge(
         * Update the on-disk extent count, the btree if necessary and log the
         * inode.
         */
-       XFS_IFORK_NEXT_SET(ip, whichfork,
-                          XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
+       ifp->if_nextents--;
        *logflags |= XFS_ILOG_CORE;
        if (!cur) {
                *logflags |= XFS_ILOG_DEXT;
@@ -5740,7 +5609,7 @@ xfs_bmse_merge(
 
 done:
        xfs_iext_remove(ip, icur, 0);
-       xfs_iext_prev(XFS_IFORK_PTR(ip, whichfork), icur);
+       xfs_iext_prev(ifp, icur);
        xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork), icur,
                        &new);
 
@@ -5804,7 +5673,7 @@ xfs_bmap_collapse_extents(
 {
        int                     whichfork = XFS_DATA_FORK;
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_btree_cur    *cur = NULL;
        struct xfs_bmbt_irec    got, prev;
        struct xfs_iext_cursor  icur;
@@ -5812,23 +5681,21 @@ xfs_bmap_collapse_extents(
        int                     error = 0;
        int                     logflags = 0;
 
-       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
-       if (XFS_FORCED_SHUTDOWN(mp))
+       if (xfs_is_shutdown(mp))
                return -EIO;
 
        ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL));
 
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               error = xfs_iread_extents(tp, ip, whichfork);
-               if (error)
-                       return error;
-       }
+       error = xfs_iread_extents(tp, ip, whichfork);
+       if (error)
+               return error;
 
-       if (ifp->if_flags & XFS_IFBROOT) {
+       if (ifp->if_format == XFS_DINODE_FMT_BTREE) {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_ino.flags = 0;
        }
@@ -5897,7 +5764,7 @@ xfs_bmap_can_insert_extents(
 
        ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
 
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+       if (xfs_is_shutdown(ip->i_mount))
                return -EIO;
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -5921,7 +5788,7 @@ xfs_bmap_insert_extents(
 {
        int                     whichfork = XFS_DATA_FORK;
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_btree_cur    *cur = NULL;
        struct xfs_bmbt_irec    got, next;
        struct xfs_iext_cursor  icur;
@@ -5929,23 +5796,21 @@ xfs_bmap_insert_extents(
        int                     error = 0;
        int                     logflags = 0;
 
-       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
-       if (XFS_FORCED_SHUTDOWN(mp))
+       if (xfs_is_shutdown(mp))
                return -EIO;
 
        ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL));
 
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               error = xfs_iread_extents(tp, ip, whichfork);
-               if (error)
-                       return error;
-       }
+       error = xfs_iread_extents(tp, ip, whichfork);
+       if (error)
+               return error;
 
-       if (ifp->if_flags & XFS_IFBROOT) {
+       if (ifp->if_format == XFS_DINODE_FMT_BTREE) {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_ino.flags = 0;
        }
@@ -6023,32 +5888,29 @@ xfs_bmap_split_extent(
        xfs_fileoff_t           split_fsb)
 {
        int                             whichfork = XFS_DATA_FORK;
+       struct xfs_ifork                *ifp = xfs_ifork_ptr(ip, whichfork);
        struct xfs_btree_cur            *cur = NULL;
        struct xfs_bmbt_irec            got;
        struct xfs_bmbt_irec            new; /* split extent */
        struct xfs_mount                *mp = ip->i_mount;
-       struct xfs_ifork                *ifp;
        xfs_fsblock_t                   gotblkcnt; /* new block count for got */
        struct xfs_iext_cursor          icur;
        int                             error = 0;
        int                             logflags = 0;
        int                             i = 0;
 
-       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
                return -EFSCORRUPTED;
        }
 
-       if (XFS_FORCED_SHUTDOWN(mp))
+       if (xfs_is_shutdown(mp))
                return -EIO;
 
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               /* Read in all the extents */
-               error = xfs_iread_extents(tp, ip, whichfork);
-               if (error)
-                       return error;
-       }
+       /* Read in all the extents */
+       error = xfs_iread_extents(tp, ip, whichfork);
+       if (error)
+               return error;
 
        /*
         * If there are not extents, or split_fsb lies in a hole we are done.
@@ -6063,7 +5925,7 @@ xfs_bmap_split_extent(
        new.br_blockcount = got.br_blockcount - gotblkcnt;
        new.br_state = got.br_state;
 
-       if (ifp->if_flags & XFS_IFBROOT) {
+       if (ifp->if_format == XFS_DINODE_FMT_BTREE) {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_ino.flags = 0;
                error = xfs_bmbt_lookup_eq(cur, &got, &i);
@@ -6090,8 +5952,7 @@ xfs_bmap_split_extent(
        /* Add new extent */
        xfs_iext_next(ifp, &icur);
        xfs_iext_insert(ip, &icur, &new, 0);
-       XFS_IFORK_NEXT_SET(ip, whichfork,
-                          XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
+       ifp->if_nextents++;
 
        if (cur) {
                error = xfs_bmbt_lookup_eq(cur, &new, &i);
@@ -6162,7 +6023,7 @@ __xfs_bmap_add(
                        bmap->br_blockcount,
                        bmap->br_state);
 
-       bi = kmem_alloc(sizeof(struct xfs_bmap_intent), KM_NOFS);
+       bi = kmem_cache_alloc(xfs_bmap_intent_cache, GFP_NOFS | __GFP_NOFAIL);
        INIT_LIST_HEAD(&bi->bi_list);
        bi->bi_type = type;
        bi->bi_owner = ip;
@@ -6206,39 +6067,37 @@ xfs_bmap_unmap_extent(
 int
 xfs_bmap_finish_one(
        struct xfs_trans                *tp,
-       struct xfs_inode                *ip,
-       enum xfs_bmap_intent_type       type,
-       int                             whichfork,
-       xfs_fileoff_t                   startoff,
-       xfs_fsblock_t                   startblock,
-       xfs_filblks_t                   *blockcount,
-       xfs_exntst_t                    state)
+       struct xfs_bmap_intent          *bi)
 {
+       struct xfs_bmbt_irec            *bmap = &bi->bi_bmap;
        int                             error = 0;
 
-       ASSERT(tp->t_firstblock == NULLFSBLOCK);
+       ASSERT(tp->t_highest_agno == NULLAGNUMBER);
 
        trace_xfs_bmap_deferred(tp->t_mountp,
-                       XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type,
-                       XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),
-                       ip->i_ino, whichfork, startoff, *blockcount, state);
+                       XFS_FSB_TO_AGNO(tp->t_mountp, bmap->br_startblock),
+                       bi->bi_type,
+                       XFS_FSB_TO_AGBNO(tp->t_mountp, bmap->br_startblock),
+                       bi->bi_owner->i_ino, bi->bi_whichfork,
+                       bmap->br_startoff, bmap->br_blockcount,
+                       bmap->br_state);
 
-       if (WARN_ON_ONCE(whichfork != XFS_DATA_FORK))
+       if (WARN_ON_ONCE(bi->bi_whichfork != XFS_DATA_FORK))
                return -EFSCORRUPTED;
 
        if (XFS_TEST_ERROR(false, tp->t_mountp,
                        XFS_ERRTAG_BMAP_FINISH_ONE))
                return -EIO;
 
-       switch (type) {
+       switch (bi->bi_type) {
        case XFS_BMAP_MAP:
-               error = xfs_bmapi_remap(tp, ip, startoff, *blockcount,
-                               startblock, 0);
-               *blockcount = 0;
+               error = xfs_bmapi_remap(tp, bi->bi_owner, bmap->br_startoff,
+                               bmap->br_blockcount, bmap->br_startblock, 0);
+               bmap->br_blockcount = 0;
                break;
        case XFS_BMAP_UNMAP:
-               error = __xfs_bunmapi(tp, ip, startoff, blockcount,
-                               XFS_BMAPI_REMAP, 1);
+               error = __xfs_bunmapi(tp, bi->bi_owner, bmap->br_startoff,
+                               &bmap->br_blockcount, XFS_BMAPI_REMAP, 1);
                break;
        default:
                ASSERT(0);
@@ -6256,26 +6115,37 @@ xfs_bmap_validate_extent(
        struct xfs_bmbt_irec    *irec)
 {
        struct xfs_mount        *mp = ip->i_mount;
-       xfs_fsblock_t           endfsb;
-       bool                    isrt;
 
-       isrt = XFS_IS_REALTIME_INODE(ip);
-       endfsb = irec->br_startblock + irec->br_blockcount - 1;
-       if (isrt) {
-               if (!xfs_verify_rtbno(mp, irec->br_startblock))
-                       return __this_address;
-               if (!xfs_verify_rtbno(mp, endfsb))
+       if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount))
+               return __this_address;
+
+       if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) {
+               if (!xfs_verify_rtext(mp, irec->br_startblock,
+                                         irec->br_blockcount))
                        return __this_address;
        } else {
-               if (!xfs_verify_fsbno(mp, irec->br_startblock))
-                       return __this_address;
-               if (!xfs_verify_fsbno(mp, endfsb))
-                       return __this_address;
-               if (XFS_FSB_TO_AGNO(mp, irec->br_startblock) !=
-                   XFS_FSB_TO_AGNO(mp, endfsb))
+               if (!xfs_verify_fsbext(mp, irec->br_startblock,
+                                          irec->br_blockcount))
                        return __this_address;
        }
        if (irec->br_state != XFS_EXT_NORM && whichfork != XFS_DATA_FORK)
                return __this_address;
        return NULL;
 }
+
+int __init
+xfs_bmap_intent_init_cache(void)
+{
+       xfs_bmap_intent_cache = kmem_cache_create("xfs_bmap_intent",
+                       sizeof(struct xfs_bmap_intent),
+                       0, 0, NULL);
+
+       return xfs_bmap_intent_cache != NULL ? 0 : -ENOMEM;
+}
+
+void
+xfs_bmap_intent_destroy_cache(void)
+{
+       kmem_cache_destroy(xfs_bmap_intent_cache);
+       xfs_bmap_intent_cache = NULL;
+}