Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
authorAlex Elder <aelder@sgi.com>
Mon, 17 Oct 2011 20:42:02 +0000 (15:42 -0500)
committerAlex Elder <aelder@sgi.com>
Mon, 17 Oct 2011 20:42:02 +0000 (15:42 -0500)
Resolved conflicts:
  fs/xfs/xfs_trans_priv.h:
    - deleted struct xfs_ail field xa_flags
    - kept field xa_log_flush in struct xfs_ail
  fs/xfs/xfs_trans_ail.c:
    - in xfsaild_push(), in XFS_ITEM_PUSHBUF case, replaced
      "flush_log = 1" with "ailp->xa_log_flush++"

Signed-off-by: Alex Elder <aelder@sgi.com>
47 files changed:
fs/xfs/xfs_alloc.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_aops.h
fs/xfs/xfs_attr.c
fs/xfs/xfs_attr_leaf.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_btree.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_dfrag.c
fs/xfs/xfs_dir2_leaf.c
fs/xfs/xfs_discard.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_export.c
fs/xfs/xfs_file.c
fs/xfs/xfs_filestream.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_rename.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rw.c
fs/xfs/xfs_rw.h
fs/xfs/xfs_super.c
fs/xfs/xfs_sync.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_inode.c
fs/xfs/xfs_trans_priv.h
fs/xfs/xfs_vnodeops.c

index bdd9cb5..ce84ffd 100644 (file)
@@ -452,7 +452,7 @@ xfs_alloc_read_agfl(
        if (error)
                return error;
        ASSERT(!xfs_buf_geterror(bp));
-       XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGFL, XFS_AGFL_REF);
+       xfs_buf_set_ref(bp, XFS_AGFL_REF);
        *bpp = bp;
        return 0;
 }
@@ -2139,7 +2139,7 @@ xfs_read_agf(
                xfs_trans_brelse(tp, *bpp);
                return XFS_ERROR(EFSCORRUPTED);
        }
-       XFS_BUF_SET_VTYPE_REF(*bpp, B_FS_AGF, XFS_AGF_REF);
+       xfs_buf_set_ref(*bpp, XFS_AGF_REF);
        return 0;
 }
 
index 8c37dde..11b2aad 100644 (file)
 #include <linux/pagevec.h>
 #include <linux/writeback.h>
 
-
-/*
- * Prime number of hash buckets since address is used as the key.
- */
-#define NVSYNC         37
-#define to_ioend_wq(v) (&xfs_ioend_wq[((unsigned long)v) % NVSYNC])
-static wait_queue_head_t xfs_ioend_wq[NVSYNC];
-
-void __init
-xfs_ioend_init(void)
-{
-       int i;
-
-       for (i = 0; i < NVSYNC; i++)
-               init_waitqueue_head(&xfs_ioend_wq[i]);
-}
-
-void
-xfs_ioend_wait(
-       xfs_inode_t     *ip)
-{
-       wait_queue_head_t *wq = to_ioend_wq(ip);
-
-       wait_event(*wq, (atomic_read(&ip->i_iocount) == 0));
-}
-
-STATIC void
-xfs_ioend_wake(
-       xfs_inode_t     *ip)
-{
-       if (atomic_dec_and_test(&ip->i_iocount))
-               wake_up(to_ioend_wq(ip));
-}
-
 void
 xfs_count_page_state(
        struct page             *page,
@@ -115,25 +81,20 @@ xfs_destroy_ioend(
        xfs_ioend_t             *ioend)
 {
        struct buffer_head      *bh, *next;
-       struct xfs_inode        *ip = XFS_I(ioend->io_inode);
 
        for (bh = ioend->io_buffer_head; bh; bh = next) {
                next = bh->b_private;
                bh->b_end_io(bh, !ioend->io_error);
        }
 
-       /*
-        * Volume managers supporting multiple paths can send back ENODEV
-        * when the final path disappears.  In this case continuing to fill
-        * the page cache with dirty data which cannot be written out is
-        * evil, so prevent that.
-        */
-       if (unlikely(ioend->io_error == -ENODEV)) {
-               xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ,
-                                     __FILE__, __LINE__);
+       if (ioend->io_iocb) {
+               if (ioend->io_isasync) {
+                       aio_complete(ioend->io_iocb, ioend->io_error ?
+                                       ioend->io_error : ioend->io_result, 0);
+               }
+               inode_dio_done(ioend->io_inode);
        }
 
-       xfs_ioend_wake(ip);
        mempool_free(ioend, xfs_ioend_pool);
 }
 
@@ -156,6 +117,15 @@ xfs_ioend_new_eof(
 }
 
 /*
+ * Fast and loose check if this write could update the on-disk inode size.
+ */
+static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend)
+{
+       return ioend->io_offset + ioend->io_size >
+               XFS_I(ioend->io_inode)->i_d.di_size;
+}
+
+/*
  * Update on-disk file size now that data has been written to disk.  The
  * current in-memory file size is i_size.  If a write is beyond eof i_new_size
  * will be the intended file size until i_size is updated.  If this write does
@@ -173,9 +143,6 @@ xfs_setfilesize(
        xfs_inode_t             *ip = XFS_I(ioend->io_inode);
        xfs_fsize_t             isize;
 
-       if (unlikely(ioend->io_error))
-               return 0;
-
        if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL))
                return EAGAIN;
 
@@ -192,6 +159,9 @@ xfs_setfilesize(
 
 /*
  * Schedule IO completion handling on the final put of an ioend.
+ *
+ * If there is no work to do we might as well call it a day and free the
+ * ioend right now.
  */
 STATIC void
 xfs_finish_ioend(
@@ -200,8 +170,10 @@ xfs_finish_ioend(
        if (atomic_dec_and_test(&ioend->io_remaining)) {
                if (ioend->io_type == IO_UNWRITTEN)
                        queue_work(xfsconvertd_workqueue, &ioend->io_work);
-               else
+               else if (xfs_ioend_is_append(ioend))
                        queue_work(xfsdatad_workqueue, &ioend->io_work);
+               else
+                       xfs_destroy_ioend(ioend);
        }
 }
 
@@ -216,17 +188,24 @@ xfs_end_io(
        struct xfs_inode *ip = XFS_I(ioend->io_inode);
        int             error = 0;
 
+       if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+               error = -EIO;
+               goto done;
+       }
+       if (ioend->io_error)
+               goto done;
+
        /*
         * For unwritten extents we need to issue transactions to convert a
         * range to normal written extens after the data I/O has finished.
         */
-       if (ioend->io_type == IO_UNWRITTEN &&
-           likely(!ioend->io_error && !XFS_FORCED_SHUTDOWN(ip->i_mount))) {
-
+       if (ioend->io_type == IO_UNWRITTEN) {
                error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
                                                 ioend->io_size);
-               if (error)
-                       ioend->io_error = error;
+               if (error) {
+                       ioend->io_error = -error;
+                       goto done;
+               }
        }
 
        /*
@@ -236,6 +215,7 @@ xfs_end_io(
        error = xfs_setfilesize(ioend);
        ASSERT(!error || error == EAGAIN);
 
+done:
        /*
         * If we didn't complete processing of the ioend, requeue it to the
         * tail of the workqueue for another attempt later. Otherwise destroy
@@ -247,8 +227,6 @@ xfs_end_io(
                /* ensure we don't spin on blocked ioends */
                delay(1);
        } else {
-               if (ioend->io_iocb)
-                       aio_complete(ioend->io_iocb, ioend->io_result, 0);
                xfs_destroy_ioend(ioend);
        }
 }
@@ -285,13 +263,13 @@ xfs_alloc_ioend(
         * all the I/O from calling the completion routine too early.
         */
        atomic_set(&ioend->io_remaining, 1);
+       ioend->io_isasync = 0;
        ioend->io_error = 0;
        ioend->io_list = NULL;
        ioend->io_type = type;
        ioend->io_inode = inode;
        ioend->io_buffer_head = NULL;
        ioend->io_buffer_tail = NULL;
-       atomic_inc(&XFS_I(ioend->io_inode)->i_iocount);
        ioend->io_offset = 0;
        ioend->io_size = 0;
        ioend->io_iocb = NULL;
@@ -337,8 +315,8 @@ xfs_map_blocks(
                count = mp->m_maxioffset - offset;
        end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
-       error = xfs_bmapi(NULL, ip, offset_fsb, end_fsb - offset_fsb,
-                         bmapi_flags,  NULL, 0, imap, &nimaps, NULL);
+       error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
+                               imap, &nimaps, bmapi_flags);
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
        if (error)
@@ -551,7 +529,6 @@ xfs_cancel_ioend(
                        unlock_buffer(bh);
                } while ((bh = next_bh) != NULL);
 
-               xfs_ioend_wake(XFS_I(ioend->io_inode));
                mempool_free(ioend, xfs_ioend_pool);
        } while ((ioend = next) != NULL);
 }
@@ -1161,8 +1138,8 @@ __xfs_get_blocks(
        end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
 
-       error = xfs_bmapi(NULL, ip, offset_fsb, end_fsb - offset_fsb,
-                         XFS_BMAPI_ENTIRE,  NULL, 0, &imap, &nimaps, NULL);
+       error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
+                               &imap, &nimaps, XFS_BMAPI_ENTIRE);
        if (error)
                goto out_unlock;
 
@@ -1300,7 +1277,6 @@ xfs_end_io_direct_write(
        bool                    is_async)
 {
        struct xfs_ioend        *ioend = iocb->private;
-       struct inode            *inode = ioend->io_inode;
 
        /*
         * blockdev_direct_IO can return an error even after the I/O
@@ -1311,28 +1287,17 @@ xfs_end_io_direct_write(
 
        ioend->io_offset = offset;
        ioend->io_size = size;
+       ioend->io_iocb = iocb;
+       ioend->io_result = ret;
        if (private && size > 0)
                ioend->io_type = IO_UNWRITTEN;
 
        if (is_async) {
-               /*
-                * If we are converting an unwritten extent we need to delay
-                * the AIO completion until after the unwrittent extent
-                * conversion has completed, otherwise do it ASAP.
-                */
-               if (ioend->io_type == IO_UNWRITTEN) {
-                       ioend->io_iocb = iocb;
-                       ioend->io_result = ret;
-               } else {
-                       aio_complete(iocb, ret, 0);
-               }
+               ioend->io_isasync = 1;
                xfs_finish_ioend(ioend);
        } else {
                xfs_finish_ioend_sync(ioend);
        }
-
-       /* XXX: probably should move into the real I/O completion handler */
-       inode_dio_done(inode);
 }
 
 STATIC ssize_t
index 71f721e..116dd5c 100644 (file)
@@ -47,6 +47,7 @@ typedef struct xfs_ioend {
        unsigned int            io_type;        /* delalloc / unwritten */
        int                     io_error;       /* I/O error code */
        atomic_t                io_remaining;   /* hold count */
+       unsigned int            io_isasync : 1; /* needs aio_complete */
        struct inode            *io_inode;      /* file being written to */
        struct buffer_head      *io_buffer_head;/* buffer linked list head */
        struct buffer_head      *io_buffer_tail;/* buffer linked list tail */
@@ -60,9 +61,6 @@ typedef struct xfs_ioend {
 extern const struct address_space_operations xfs_address_space_operations;
 extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int);
 
-extern void xfs_ioend_init(void);
-extern void xfs_ioend_wait(struct xfs_inode *);
-
 extern void xfs_count_page_state(struct page *, int *, int *);
 
 #endif /* __XFS_AOPS_H__ */
index 160bcdc..1e5d97f 100644 (file)
@@ -319,7 +319,7 @@ xfs_attr_set_int(
                return (error);
        }
 
-       xfs_trans_ijoin(args.trans, dp);
+       xfs_trans_ijoin(args.trans, dp, 0);
 
        /*
         * If the attribute list is non-existent or a shortform list,
@@ -389,7 +389,7 @@ xfs_attr_set_int(
                 * a new one.  We need the inode to be in all transactions.
                 */
                if (committed)
-                       xfs_trans_ijoin(args.trans, dp);
+                       xfs_trans_ijoin(args.trans, dp, 0);
 
                /*
                 * Commit the leaf transformation.  We'll need another (linked)
@@ -537,7 +537,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
         * No need to make quota reservations here. We expect to release some
         * blocks not allocate in the common case.
         */
-       xfs_trans_ijoin(args.trans, dp);
+       xfs_trans_ijoin(args.trans, dp, 0);
 
        /*
         * Decide on what work routines to call based on the inode size.
@@ -809,7 +809,7 @@ xfs_attr_inactive(xfs_inode_t *dp)
         * No need to make quota reservations here. We expect to release some
         * blocks, not allocate, in the common case.
         */
-       xfs_trans_ijoin(trans, dp);
+       xfs_trans_ijoin(trans, dp, 0);
 
        /*
         * Decide on what work routines to call based on the inode size.
@@ -823,18 +823,6 @@ xfs_attr_inactive(xfs_inode_t *dp)
        if (error)
                goto out;
 
-       /*
-        * Signal synchronous inactive transactions unless this is a
-        * synchronous mount filesystem in which case we know that we're here
-        * because we've been called out of xfs_inactive which means that the
-        * last reference is gone and the unlink transaction has already hit
-        * the disk so async inactive transactions are safe.
-        */
-       if (!(mp->m_flags & XFS_MOUNT_WSYNC)) {
-               if (dp->i_d.di_anextents > 0)
-                       xfs_trans_set_sync(trans);
-       }
-
        error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
        if (error)
                goto out;
@@ -973,7 +961,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                 * a new one.  We need the inode to be in all transactions.
                 */
                if (committed)
-                       xfs_trans_ijoin(args->trans, dp);
+                       xfs_trans_ijoin(args->trans, dp, 0);
 
                /*
                 * Commit the current trans (including the inode) and start
@@ -1075,7 +1063,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                         * in all transactions.
                         */
                        if (committed)
-                               xfs_trans_ijoin(args->trans, dp);
+                               xfs_trans_ijoin(args->trans, dp, 0);
                } else
                        xfs_da_buf_done(bp);
 
@@ -1149,7 +1137,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
                 * a new one.  We need the inode to be in all transactions.
                 */
                if (committed)
-                       xfs_trans_ijoin(args->trans, dp);
+                       xfs_trans_ijoin(args->trans, dp, 0);
        } else
                xfs_da_buf_done(bp);
        return(0);
@@ -1303,7 +1291,7 @@ restart:
                         * in all transactions.
                         */
                        if (committed)
-                               xfs_trans_ijoin(args->trans, dp);
+                               xfs_trans_ijoin(args->trans, dp, 0);
 
                        /*
                         * Commit the node conversion and start the next
@@ -1340,7 +1328,7 @@ restart:
                 * a new one.  We need the inode to be in all transactions.
                 */
                if (committed)
-                       xfs_trans_ijoin(args->trans, dp);
+                       xfs_trans_ijoin(args->trans, dp, 0);
        } else {
                /*
                 * Addition succeeded, update Btree hashvals.
@@ -1452,7 +1440,7 @@ restart:
                         * in all transactions.
                         */
                        if (committed)
-                               xfs_trans_ijoin(args->trans, dp);
+                               xfs_trans_ijoin(args->trans, dp, 0);
                }
 
                /*
@@ -1584,7 +1572,7 @@ xfs_attr_node_removename(xfs_da_args_t *args)
                 * a new one.  We need the inode to be in all transactions.
                 */
                if (committed)
-                       xfs_trans_ijoin(args->trans, dp);
+                       xfs_trans_ijoin(args->trans, dp, 0);
 
                /*
                 * Commit the Btree join operation and start a new trans.
@@ -1635,7 +1623,7 @@ xfs_attr_node_removename(xfs_da_args_t *args)
                         * in all transactions.
                         */
                        if (committed)
-                               xfs_trans_ijoin(args->trans, dp);
+                               xfs_trans_ijoin(args->trans, dp, 0);
                } else
                        xfs_da_brelse(args->trans, bp);
        }
@@ -1975,10 +1963,9 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
        lblkno = args->rmtblkno;
        while (valuelen > 0) {
                nmap = ATTR_RMTVALUE_MAPSIZE;
-               error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno,
-                                 args->rmtblkcnt,
-                                 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                 NULL, 0, map, &nmap, NULL);
+               error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
+                                      args->rmtblkcnt, map, &nmap,
+                                      XFS_BMAPI_ATTRFORK);
                if (error)
                        return(error);
                ASSERT(nmap >= 1);
@@ -2052,10 +2039,9 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                 */
                xfs_bmap_init(args->flist, args->firstblock);
                nmap = 1;
-               error = xfs_bmapi(args->trans, dp, (xfs_fileoff_t)lblkno,
+               error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
                                  blkcnt,
-                                 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA |
-                                                       XFS_BMAPI_WRITE,
+                                 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
                                  args->firstblock, args->total, &map, &nmap,
                                  args->flist);
                if (!error) {
@@ -2074,7 +2060,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                 * a new one.  We need the inode to be in all transactions.
                 */
                if (committed)
-                       xfs_trans_ijoin(args->trans, dp);
+                       xfs_trans_ijoin(args->trans, dp, 0);
 
                ASSERT(nmap == 1);
                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
@@ -2104,14 +2090,11 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                 */
                xfs_bmap_init(args->flist, args->firstblock);
                nmap = 1;
-               error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno,
-                                 args->rmtblkcnt,
-                                 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                 args->firstblock, 0, &map, &nmap,
-                                 NULL);
-               if (error) {
+               error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
+                                      args->rmtblkcnt, &map, &nmap,
+                                      XFS_BMAPI_ATTRFORK);
+               if (error)
                        return(error);
-               }
                ASSERT(nmap == 1);
                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
                       (map.br_startblock != HOLESTARTBLOCK));
@@ -2121,16 +2104,17 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
 
                bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt,
                                 XBF_LOCK | XBF_DONT_BLOCK);
-               ASSERT(!xfs_buf_geterror(bp));
-
+               if (!bp)
+                       return ENOMEM;
                tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
                                                        XFS_BUF_SIZE(bp);
                xfs_buf_iomove(bp, 0, tmp, src, XBRW_WRITE);
                if (tmp < XFS_BUF_SIZE(bp))
                        xfs_buf_zero(bp, tmp, XFS_BUF_SIZE(bp) - tmp);
-               if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */
-                       return (error);
-               }
+               error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
+               xfs_buf_relse(bp);
+               if (error)
+                       return error;
                src += tmp;
                valuelen -= tmp;
 
@@ -2166,16 +2150,12 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                /*
                 * Try to remember where we decided to put the value.
                 */
-               xfs_bmap_init(args->flist, args->firstblock);
                nmap = 1;
-               error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno,
-                                       args->rmtblkcnt,
-                                       XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                       args->firstblock, 0, &map, &nmap,
-                                       args->flist);
-               if (error) {
+               error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
+                                      args->rmtblkcnt, &map, &nmap,
+                                      XFS_BMAPI_ATTRFORK);
+               if (error)
                        return(error);
-               }
                ASSERT(nmap == 1);
                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
                       (map.br_startblock != HOLESTARTBLOCK));
@@ -2188,8 +2168,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                 */
                bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, XBF_TRYLOCK);
                if (bp) {
-                       XFS_BUF_STALE(bp);
-                       XFS_BUF_UNDELAYWRITE(bp);
+                       xfs_buf_stale(bp);
                        xfs_buf_relse(bp);
                        bp = NULL;
                }
@@ -2227,7 +2206,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                 * a new one.  We need the inode to be in all transactions.
                 */
                if (committed)
-                       xfs_trans_ijoin(args->trans, args->dp);
+                       xfs_trans_ijoin(args->trans, args->dp, 0);
 
                /*
                 * Close out trans and start the next one in the chain.
index 8fad960..d4906e7 100644 (file)
@@ -2926,9 +2926,8 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
                 * Try to remember where we decided to put the value.
                 */
                nmap = 1;
-               error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt,
-                                       XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                       NULL, 0, &map, &nmap, NULL);
+               error = xfs_bmapi_read(dp, (xfs_fileoff_t)tblkno, tblkcnt,
+                                      &map, &nmap, XFS_BMAPI_ATTRFORK);
                if (error) {
                        return(error);
                }
@@ -2948,6 +2947,8 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
                        bp = xfs_trans_get_buf(*trans,
                                        dp->i_mount->m_ddev_targp,
                                        dblkno, dblkcnt, XBF_LOCK);
+                       if (!bp)
+                               return ENOMEM;
                        xfs_trans_binval(*trans, bp);
                        /*
                         * Roll to next transaction.
index 452a291..c68baeb 100644 (file)
 #include "xfs_trace.h"
 
 
-#ifdef DEBUG
-STATIC void
-xfs_bmap_check_leaf_extents(xfs_btree_cur_t *cur, xfs_inode_t *ip, int whichfork);
-#endif
-
 kmem_zone_t            *xfs_bmap_free_item_zone;
 
 /*
  * Prototypes for internal bmap routines.
  */
 
+#ifdef DEBUG
+STATIC void
+xfs_bmap_check_leaf_extents(
+       struct xfs_btree_cur    *cur,
+       struct xfs_inode        *ip,
+       int                     whichfork);
+#else
+#define xfs_bmap_check_leaf_extents(cur, ip, whichfork)                do { } while (0)
+#endif
+
 
 /*
  * Called from xfs_bmap_add_attrfork to handle extents format files.
@@ -85,58 +90,6 @@ xfs_bmap_add_attrfork_local(
        int                     *flags);        /* inode logging flags */
 
 /*
- * Called by xfs_bmap_add_extent to handle cases converting a delayed
- * allocation to a real allocation.
- */
-STATIC int                             /* error */
-xfs_bmap_add_extent_delay_real(
-       struct xfs_trans        *tp,    /* transaction pointer */
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            *idx,   /* extent number to update/insert */
-       xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       xfs_filblks_t           *dnew,  /* new delayed-alloc indirect blocks */
-       xfs_fsblock_t           *first, /* pointer to firstblock variable */
-       xfs_bmap_free_t         *flist, /* list of extents to be freed */
-       int                     *logflagsp); /* inode logging flags */
-
-/*
- * Called by xfs_bmap_add_extent to handle cases converting a hole
- * to a delayed allocation.
- */
-STATIC int                             /* error */
-xfs_bmap_add_extent_hole_delay(
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            *idx,   /* extent number to update/insert */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp); /* inode logging flags */
-
-/*
- * Called by xfs_bmap_add_extent to handle cases converting a hole
- * to a real allocation.
- */
-STATIC int                             /* error */
-xfs_bmap_add_extent_hole_real(
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            *idx,   /* extent number to update/insert */
-       xfs_btree_cur_t         *cur,   /* if null, not a btree */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp, /* inode logging flags */
-       int                     whichfork); /* data or attr fork */
-
-/*
- * Called by xfs_bmap_add_extent to handle cases converting an unwritten
- * allocation to a real allocation or vice versa.
- */
-STATIC int                             /* error */
-xfs_bmap_add_extent_unwritten_real(
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            *idx,   /* extent number to update/insert */
-       xfs_btree_cur_t         **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_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
  * It figures out where to ask the underlying allocator to put the new extent.
  */
@@ -215,19 +168,6 @@ xfs_bmap_search_extents(
        xfs_bmbt_irec_t *prevp);        /* out: previous extent entry found */
 
 /*
- * Check the last inode extent to determine whether this allocation will result
- * in blocks being allocated at the end of the file. When we allocate new data
- * blocks at the end of the file which do not start at the previous data block,
- * we will try to align the new blocks at stripe unit boundaries.
- */
-STATIC int                             /* error */
-xfs_bmap_isaeof(
-       xfs_inode_t     *ip,            /* incore inode pointer */
-       xfs_fileoff_t   off,            /* file offset in fsblocks */
-       int             whichfork,      /* data or attribute fork */
-       char            *aeof);         /* return value */
-
-/*
  * Compute the worst-case number of indirect blocks that will be used
  * for ip's delayed extent of length "len".
  */
@@ -431,188 +371,13 @@ xfs_bmap_add_attrfork_local(
 }
 
 /*
- * Called by xfs_bmapi to update file extent records and the btree
- * after allocating space (or doing a delayed allocation).
- */
-STATIC int                             /* error */
-xfs_bmap_add_extent(
-       struct xfs_trans        *tp,    /* transaction pointer */
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            *idx,   /* extent number to update/insert */
-       xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       xfs_fsblock_t           *first, /* pointer to firstblock variable */
-       xfs_bmap_free_t         *flist, /* list of extents to be freed */
-       int                     *logflagsp, /* inode logging flags */
-       int                     whichfork) /* data or attr fork */
-{
-       xfs_btree_cur_t         *cur;   /* btree cursor or null */
-       xfs_filblks_t           da_new; /* new count del alloc blocks used */
-       xfs_filblks_t           da_old; /* old count del alloc blocks used */
-       int                     error;  /* error return value */
-       xfs_ifork_t             *ifp;   /* inode fork ptr */
-       int                     logflags; /* returned value */
-       xfs_extnum_t            nextents; /* number of extents in file now */
-
-       XFS_STATS_INC(xs_add_exlist);
-
-       cur = *curp;
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       da_old = da_new = 0;
-       error = 0;
-
-       ASSERT(*idx >= 0);
-       ASSERT(*idx <= nextents);
-
-       /*
-        * This is the first extent added to a new/empty file.
-        * Special case this one, so other routines get to assume there are
-        * already extents in the list.
-        */
-       if (nextents == 0) {
-               xfs_iext_insert(ip, *idx, 1, new,
-                               whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0);
-
-               ASSERT(cur == NULL);
-
-               if (!isnullstartblock(new->br_startblock)) {
-                       XFS_IFORK_NEXT_SET(ip, whichfork, 1);
-                       logflags = XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
-               } else
-                       logflags = 0;
-       }
-       /*
-        * Any kind of new delayed allocation goes here.
-        */
-       else if (isnullstartblock(new->br_startblock)) {
-               if (cur)
-                       ASSERT((cur->bc_private.b.flags &
-                               XFS_BTCUR_BPRV_WASDEL) == 0);
-               error = xfs_bmap_add_extent_hole_delay(ip, idx, new,
-                                                      &logflags);
-       }
-       /*
-        * Real allocation off the end of the file.
-        */
-       else if (*idx == nextents) {
-               if (cur)
-                       ASSERT((cur->bc_private.b.flags &
-                               XFS_BTCUR_BPRV_WASDEL) == 0);
-               error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,
-                               &logflags, whichfork);
-       } else {
-               xfs_bmbt_irec_t prev;   /* old extent at offset idx */
-
-               /*
-                * Get the record referred to by idx.
-                */
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &prev);
-               /*
-                * If it's a real allocation record, and the new allocation ends
-                * after the start of the referred to record, then we're filling
-                * in a delayed or unwritten allocation with a real one, or
-                * converting real back to unwritten.
-                */
-               if (!isnullstartblock(new->br_startblock) &&
-                   new->br_startoff + new->br_blockcount > prev.br_startoff) {
-                       if (prev.br_state != XFS_EXT_UNWRITTEN &&
-                           isnullstartblock(prev.br_startblock)) {
-                               da_old = startblockval(prev.br_startblock);
-                               if (cur)
-                                       ASSERT(cur->bc_private.b.flags &
-                                               XFS_BTCUR_BPRV_WASDEL);
-                               error = xfs_bmap_add_extent_delay_real(tp, ip,
-                                               idx, &cur, new, &da_new,
-                                               first, flist, &logflags);
-                       } else {
-                               ASSERT(new->br_state == XFS_EXT_NORM ||
-                                      new->br_state == XFS_EXT_UNWRITTEN);
-
-                               error = xfs_bmap_add_extent_unwritten_real(ip,
-                                               idx, &cur, new, &logflags);
-                               if (error)
-                                       goto done;
-                       }
-               }
-               /*
-                * Otherwise we're filling in a hole with an allocation.
-                */
-               else {
-                       if (cur)
-                               ASSERT((cur->bc_private.b.flags &
-                                       XFS_BTCUR_BPRV_WASDEL) == 0);
-                       error = xfs_bmap_add_extent_hole_real(ip, idx, cur,
-                                       new, &logflags, whichfork);
-               }
-       }
-
-       if (error)
-               goto done;
-       ASSERT(*curp == cur || *curp == NULL);
-
-       /*
-        * Convert to a btree if necessary.
-        */
-       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) {
-               int     tmp_logflags;   /* partial log flag return val */
-
-               ASSERT(cur == NULL);
-               error = xfs_bmap_extents_to_btree(tp, ip, first,
-                       flist, &cur, da_old > 0, &tmp_logflags, whichfork);
-               logflags |= tmp_logflags;
-               if (error)
-                       goto done;
-       }
-       /*
-        * Adjust for changes in reserved delayed indirect blocks.
-        * Nothing to do for disk quotas here.
-        */
-       if (da_old || da_new) {
-               xfs_filblks_t   nblks;
-
-               nblks = da_new;
-               if (cur)
-                       nblks += cur->bc_private.b.allocated;
-               ASSERT(nblks <= da_old);
-               if (nblks < da_old)
-                       xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
-                               (int64_t)(da_old - nblks), 0);
-       }
-       /*
-        * Clear out the allocated field, done with it now in any case.
-        */
-       if (cur) {
-               cur->bc_private.b.allocated = 0;
-               *curp = cur;
-       }
-done:
-#ifdef DEBUG
-       if (!error)
-               xfs_bmap_check_leaf_extents(*curp, ip, whichfork);
-#endif
-       *logflagsp = logflags;
-       return error;
-}
-
-/*
- * Called by xfs_bmap_add_extent to handle cases converting a delayed
- * allocation to a real allocation.
+ * Convert a delayed allocation to a real allocation.
  */
 STATIC int                             /* error */
 xfs_bmap_add_extent_delay_real(
-       struct xfs_trans        *tp,    /* transaction pointer */
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            *idx,   /* extent number to update/insert */
-       xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       xfs_filblks_t           *dnew,  /* new delayed-alloc indirect blocks */
-       xfs_fsblock_t           *first, /* pointer to firstblock variable */
-       xfs_bmap_free_t         *flist, /* list of extents to be freed */
-       int                     *logflagsp) /* inode logging flags */
+       struct xfs_bmalloca     *bma)
 {
-       xfs_btree_cur_t         *cur;   /* btree cursor */
+       struct xfs_bmbt_irec    *new = &bma->got;
        int                     diff;   /* temp value */
        xfs_bmbt_rec_host_t     *ep;    /* extent entry for idx */
        int                     error;  /* error return value */
@@ -623,10 +388,22 @@ xfs_bmap_add_extent_delay_real(
                                        /* left is 0, right is 1, prev is 2 */
        int                     rval=0; /* return value (logging flags) */
        int                     state = 0;/* state bits, accessed thru macros */
-       xfs_filblks_t           temp=0; /* value for dnew calculations */
-       xfs_filblks_t           temp2=0;/* value for dnew calculations */
+       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 */
+       xfs_filblks_t           temp2=0;/* value for da_new calculations */
        int                     tmp_rval;       /* partial logging flags */
 
+       ifp = XFS_IFORK_PTR(bma->ip, XFS_DATA_FORK);
+
+       ASSERT(bma->idx >= 0);
+       ASSERT(bma->idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
+       ASSERT(!isnullstartblock(new->br_startblock));
+       ASSERT(!bma->cur ||
+              (bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
+
+       XFS_STATS_INC(xs_add_exlist);
+
 #define        LEFT            r[0]
 #define        RIGHT           r[1]
 #define        PREV            r[2]
@@ -634,14 +411,15 @@ xfs_bmap_add_extent_delay_real(
        /*
         * Set up a bunch of variables to make the tests simpler.
         */
-       cur = *curp;
-       ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
-       ep = xfs_iext_get_ext(ifp, *idx);
+       ep = xfs_iext_get_ext(ifp, bma->idx);
        xfs_bmbt_get_all(ep, &PREV);
        new_endoff = new->br_startoff + new->br_blockcount;
        ASSERT(PREV.br_startoff <= new->br_startoff);
        ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);
 
+       da_old = startblockval(PREV.br_startblock);
+       da_new = 0;
+
        /*
         * Set flags determining what part of the previous delayed allocation
         * extent is being replaced by a real allocation.
@@ -655,9 +433,9 @@ xfs_bmap_add_extent_delay_real(
         * Check and set flags if this segment has a left neighbor.
         * Don't set contiguous if the combined extent would be too large.
         */
-       if (*idx > 0) {
+       if (bma->idx > 0) {
                state |= BMAP_LEFT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &LEFT);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), &LEFT);
 
                if (isnullstartblock(LEFT.br_startblock))
                        state |= BMAP_LEFT_DELAY;
@@ -675,9 +453,9 @@ xfs_bmap_add_extent_delay_real(
         * Don't set contiguous if the combined extent would be too large.
         * Also check for all-three-contiguous being too large.
         */
-       if (*idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) {
+       if (bma->idx < bma->ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) {
                state |= BMAP_RIGHT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx + 1), &RIGHT);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx + 1), &RIGHT);
 
                if (isnullstartblock(RIGHT.br_startblock))
                        state |= BMAP_RIGHT_DELAY;
@@ -708,38 +486,41 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in all of a previously delayed allocation extent.
                 * The left and right neighbors are both contiguous with new.
                 */
-               --*idx;
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
+               bma->idx--;
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx),
                        LEFT.br_blockcount + PREV.br_blockcount +
                        RIGHT.br_blockcount);
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               xfs_iext_remove(ip, *idx + 1, 2, state);
-               ip->i_d.di_nextents--;
-               if (cur == NULL)
+               xfs_iext_remove(bma->ip, bma->idx + 1, 2, state);
+               bma->ip->i_d.di_nextents--;
+               if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
                        rval = XFS_ILOG_CORE;
-                       if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff,
+                       error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff,
                                        RIGHT.br_startblock,
-                                       RIGHT.br_blockcount, &i)))
+                                       RIGHT.br_blockcount, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_btree_delete(cur, &i)))
+                       error = xfs_btree_delete(bma->cur, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_btree_decrement(cur, 0, &i)))
+                       error = xfs_btree_decrement(bma->cur, 0, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
+                       error = xfs_bmbt_update(bma->cur, LEFT.br_startoff,
                                        LEFT.br_startblock,
                                        LEFT.br_blockcount +
                                        PREV.br_blockcount +
-                                       RIGHT.br_blockcount, LEFT.br_state)))
+                                       RIGHT.br_blockcount, LEFT.br_state);
+                       if (error)
                                goto done;
                }
-               *dnew = 0;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
@@ -747,30 +528,31 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in all of a previously delayed allocation extent.
                 * The left neighbor is contiguous, the right is not.
                 */
-               --*idx;
+               bma->idx--;
 
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx),
                        LEFT.br_blockcount + PREV.br_blockcount);
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               xfs_iext_remove(ip, *idx + 1, 1, state);
-               if (cur == NULL)
+               xfs_iext_remove(bma->ip, bma->idx + 1, 1, state);
+               if (bma->cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
                        rval = 0;
-                       if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff,
+                       error = xfs_bmbt_lookup_eq(bma->cur, LEFT.br_startoff,
                                        LEFT.br_startblock, LEFT.br_blockcount,
-                                       &i)))
+                                       &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
+                       error = xfs_bmbt_update(bma->cur, LEFT.br_startoff,
                                        LEFT.br_startblock,
                                        LEFT.br_blockcount +
-                                       PREV.br_blockcount, LEFT.br_state)))
+                                       PREV.br_blockcount, LEFT.br_state);
+                       if (error)
                                goto done;
                }
-               *dnew = 0;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -778,30 +560,30 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in all of a previously delayed allocation extent.
                 * The right neighbor is contiguous, the left is not.
                 */
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
                xfs_bmbt_set_startblock(ep, new->br_startblock);
                xfs_bmbt_set_blockcount(ep,
                        PREV.br_blockcount + RIGHT.br_blockcount);
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               xfs_iext_remove(ip, *idx + 1, 1, state);
-               if (cur == NULL)
+               xfs_iext_remove(bma->ip, bma->idx + 1, 1, state);
+               if (bma->cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
                        rval = 0;
-                       if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff,
+                       error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff,
                                        RIGHT.br_startblock,
-                                       RIGHT.br_blockcount, &i)))
+                                       RIGHT.br_blockcount, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
+                       error = xfs_bmbt_update(bma->cur, PREV.br_startoff,
                                        new->br_startblock,
                                        PREV.br_blockcount +
-                                       RIGHT.br_blockcount, PREV.br_state)))
+                                       RIGHT.br_blockcount, PREV.br_state);
+                       if (error)
                                goto done;
                }
-
-               *dnew = 0;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
@@ -810,27 +592,27 @@ xfs_bmap_add_extent_delay_real(
                 * Neither the left nor right neighbors are contiguous with
                 * the new one.
                 */
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
                xfs_bmbt_set_startblock(ep, new->br_startblock);
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               ip->i_d.di_nextents++;
-               if (cur == NULL)
+               bma->ip->i_d.di_nextents++;
+               if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
                        rval = XFS_ILOG_CORE;
-                       if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
+                       error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff,
                                        new->br_startblock, new->br_blockcount,
-                                       &i)))
+                                       &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 0, done);
-                       cur->bc_rec.b.br_state = XFS_EXT_NORM;
-                       if ((error = xfs_btree_insert(cur, &i)))
+                       bma->cur->bc_rec.b.br_state = XFS_EXT_NORM;
+                       error = xfs_btree_insert(bma->cur, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-
-               *dnew = 0;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
@@ -838,39 +620,40 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in the first part of a previous delayed allocation.
                 * The left neighbor is contiguous.
                 */
-               trace_xfs_bmap_pre_update(ip, *idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx - 1),
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx - 1, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx - 1),
                        LEFT.br_blockcount + new->br_blockcount);
                xfs_bmbt_set_startoff(ep,
                        PREV.br_startoff + new->br_blockcount);
-               trace_xfs_bmap_post_update(ip, *idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(bma->ip, bma->idx - 1, state, _THIS_IP_);
 
                temp = PREV.br_blockcount - new->br_blockcount;
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);
-               if (cur == NULL)
+               if (bma->cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
                        rval = 0;
-                       if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff,
+                       error = xfs_bmbt_lookup_eq(bma->cur, LEFT.br_startoff,
                                        LEFT.br_startblock, LEFT.br_blockcount,
-                                       &i)))
+                                       &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
+                       error = xfs_bmbt_update(bma->cur, LEFT.br_startoff,
                                        LEFT.br_startblock,
                                        LEFT.br_blockcount +
                                        new->br_blockcount,
-                                       LEFT.br_state)))
+                                       LEFT.br_state);
+                       if (error)
                                goto done;
                }
-               temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
+               da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp),
                        startblockval(PREV.br_startblock));
-               xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               --*idx;
-               *dnew = temp;
+               bma->idx--;
                break;
 
        case BMAP_LEFT_FILLING:
@@ -878,43 +661,43 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in the first part of a previous delayed allocation.
                 * The left neighbor is not contiguous.
                 */
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
                xfs_bmbt_set_startoff(ep, new_endoff);
                temp = PREV.br_blockcount - new->br_blockcount;
                xfs_bmbt_set_blockcount(ep, temp);
-               xfs_iext_insert(ip, *idx, 1, new, state);
-               ip->i_d.di_nextents++;
-               if (cur == NULL)
+               xfs_iext_insert(bma->ip, bma->idx, 1, new, state);
+               bma->ip->i_d.di_nextents++;
+               if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
                        rval = XFS_ILOG_CORE;
-                       if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
+                       error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff,
                                        new->br_startblock, new->br_blockcount,
-                                       &i)))
+                                       &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 0, done);
-                       cur->bc_rec.b.br_state = XFS_EXT_NORM;
-                       if ((error = xfs_btree_insert(cur, &i)))
+                       bma->cur->bc_rec.b.br_state = XFS_EXT_NORM;
+                       error = xfs_btree_insert(bma->cur, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-                   ip->i_d.di_nextents > ip->i_df.if_ext_max) {
-                       error = xfs_bmap_extents_to_btree(tp, ip,
-                                       first, flist, &cur, 1, &tmp_rval,
-                                       XFS_DATA_FORK);
+               if (bma->ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
+                   bma->ip->i_d.di_nextents > bma->ip->i_df.if_ext_max) {
+                       error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
+                                       bma->firstblock, bma->flist,
+                                       &bma->cur, 1, &tmp_rval, XFS_DATA_FORK);
                        rval |= tmp_rval;
                        if (error)
                                goto done;
                }
-               temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
+               da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp),
                        startblockval(PREV.br_startblock) -
-                       (cur ? cur->bc_private.b.allocated : 0));
-               ep = xfs_iext_get_ext(ifp, *idx + 1);
-               xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_);
-
-               *dnew = temp;
+                       (bma->cur ? bma->cur->bc_private.b.allocated : 0));
+               ep = xfs_iext_get_ext(ifp, bma->idx + 1);
+               xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
+               trace_xfs_bmap_post_update(bma->ip, bma->idx + 1, state, _THIS_IP_);
                break;
 
        case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -923,38 +706,39 @@ xfs_bmap_add_extent_delay_real(
                 * The right neighbor is contiguous with the new allocation.
                 */
                temp = PREV.br_blockcount - new->br_blockcount;
-               trace_xfs_bmap_pre_update(ip, *idx + 1, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx + 1, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);
-               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx + 1),
+               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, bma->idx + 1),
                        new->br_startoff, new->br_startblock,
                        new->br_blockcount + RIGHT.br_blockcount,
                        RIGHT.br_state);
-               trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_);
-               if (cur == NULL)
+               trace_xfs_bmap_post_update(bma->ip, bma->idx + 1, state, _THIS_IP_);
+               if (bma->cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
                        rval = 0;
-                       if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff,
+                       error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff,
                                        RIGHT.br_startblock,
-                                       RIGHT.br_blockcount, &i)))
+                                       RIGHT.br_blockcount, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_bmbt_update(cur, new->br_startoff,
+                       error = xfs_bmbt_update(bma->cur, new->br_startoff,
                                        new->br_startblock,
                                        new->br_blockcount +
                                        RIGHT.br_blockcount,
-                                       RIGHT.br_state)))
+                                       RIGHT.br_state);
+                       if (error)
                                goto done;
                }
 
-               temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
+               da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp),
                        startblockval(PREV.br_startblock));
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
-               xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
+               xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               ++*idx;
-               *dnew = temp;
+               bma->idx++;
                break;
 
        case BMAP_RIGHT_FILLING:
@@ -963,42 +747,43 @@ xfs_bmap_add_extent_delay_real(
                 * The right neighbor is not contiguous.
                 */
                temp = PREV.br_blockcount - new->br_blockcount;
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);
-               xfs_iext_insert(ip, *idx + 1, 1, new, state);
-               ip->i_d.di_nextents++;
-               if (cur == NULL)
+               xfs_iext_insert(bma->ip, bma->idx + 1, 1, new, state);
+               bma->ip->i_d.di_nextents++;
+               if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
                        rval = XFS_ILOG_CORE;
-                       if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
+                       error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff,
                                        new->br_startblock, new->br_blockcount,
-                                       &i)))
+                                       &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 0, done);
-                       cur->bc_rec.b.br_state = XFS_EXT_NORM;
-                       if ((error = xfs_btree_insert(cur, &i)))
+                       bma->cur->bc_rec.b.br_state = XFS_EXT_NORM;
+                       error = xfs_btree_insert(bma->cur, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-                   ip->i_d.di_nextents > ip->i_df.if_ext_max) {
-                       error = xfs_bmap_extents_to_btree(tp, ip,
-                               first, flist, &cur, 1, &tmp_rval,
-                               XFS_DATA_FORK);
+               if (bma->ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
+                   bma->ip->i_d.di_nextents > bma->ip->i_df.if_ext_max) {
+                       error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
+                               bma->firstblock, bma->flist, &bma->cur, 1,
+                               &tmp_rval, XFS_DATA_FORK);
                        rval |= tmp_rval;
                        if (error)
                                goto done;
                }
-               temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
+               da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp),
                        startblockval(PREV.br_startblock) -
-                       (cur ? cur->bc_private.b.allocated : 0));
-               ep = xfs_iext_get_ext(ifp, *idx);
-               xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+                       (bma->cur ? bma->cur->bc_private.b.allocated : 0));
+               ep = xfs_iext_get_ext(ifp, bma->idx);
+               xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               ++*idx;
-               *dnew = temp;
+               bma->idx++;
                break;
 
        case 0:
@@ -1024,82 +809,65 @@ xfs_bmap_add_extent_delay_real(
                 */
                temp = new->br_startoff - PREV.br_startoff;
                temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff;
-               trace_xfs_bmap_pre_update(ip, *idx, 0, _THIS_IP_);
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, 0, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);      /* truncate PREV */
                LEFT = *new;
                RIGHT.br_state = PREV.br_state;
                RIGHT.br_startblock = nullstartblock(
-                               (int)xfs_bmap_worst_indlen(ip, temp2));
+                               (int)xfs_bmap_worst_indlen(bma->ip, temp2));
                RIGHT.br_startoff = new_endoff;
                RIGHT.br_blockcount = temp2;
                /* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */
-               xfs_iext_insert(ip, *idx + 1, 2, &LEFT, state);
-               ip->i_d.di_nextents++;
-               if (cur == NULL)
+               xfs_iext_insert(bma->ip, bma->idx + 1, 2, &LEFT, state);
+               bma->ip->i_d.di_nextents++;
+               if (bma->cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
                else {
                        rval = XFS_ILOG_CORE;
-                       if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
+                       error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff,
                                        new->br_startblock, new->br_blockcount,
-                                       &i)))
+                                       &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 0, done);
-                       cur->bc_rec.b.br_state = XFS_EXT_NORM;
-                       if ((error = xfs_btree_insert(cur, &i)))
+                       bma->cur->bc_rec.b.br_state = XFS_EXT_NORM;
+                       error = xfs_btree_insert(bma->cur, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-                   ip->i_d.di_nextents > ip->i_df.if_ext_max) {
-                       error = xfs_bmap_extents_to_btree(tp, ip,
-                                       first, flist, &cur, 1, &tmp_rval,
-                                       XFS_DATA_FORK);
+               if (bma->ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
+                   bma->ip->i_d.di_nextents > bma->ip->i_df.if_ext_max) {
+                       error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
+                                       bma->firstblock, bma->flist, &bma->cur,
+                                       1, &tmp_rval, XFS_DATA_FORK);
                        rval |= tmp_rval;
                        if (error)
                                goto done;
                }
-               temp = xfs_bmap_worst_indlen(ip, temp);
-               temp2 = xfs_bmap_worst_indlen(ip, temp2);
+               temp = xfs_bmap_worst_indlen(bma->ip, temp);
+               temp2 = xfs_bmap_worst_indlen(bma->ip, temp2);
                diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) -
-                       (cur ? cur->bc_private.b.allocated : 0));
-               if (diff > 0 &&
-                   xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
-                                            -((int64_t)diff), 0)) {
-                       /*
-                        * Ick gross gag me with a spoon.
-                        */
-                       ASSERT(0);      /* want to see if this ever happens! */
-                       while (diff > 0) {
-                               if (temp) {
-                                       temp--;
-                                       diff--;
-                                       if (!diff ||
-                                           !xfs_icsb_modify_counters(ip->i_mount,
-                                                   XFS_SBS_FDBLOCKS,
-                                                   -((int64_t)diff), 0))
-                                               break;
-                               }
-                               if (temp2) {
-                                       temp2--;
-                                       diff--;
-                                       if (!diff ||
-                                           !xfs_icsb_modify_counters(ip->i_mount,
-                                                   XFS_SBS_FDBLOCKS,
-                                                   -((int64_t)diff), 0))
-                                               break;
-                               }
-                       }
+                       (bma->cur ? bma->cur->bc_private.b.allocated : 0));
+               if (diff > 0) {
+                       error = xfs_icsb_modify_counters(bma->ip->i_mount,
+                                       XFS_SBS_FDBLOCKS,
+                                       -((int64_t)diff), 0);
+                       ASSERT(!error);
+                       if (error)
+                               goto done;
                }
-               ep = xfs_iext_get_ext(ifp, *idx);
+
+               ep = xfs_iext_get_ext(ifp, bma->idx);
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
-               trace_xfs_bmap_pre_update(ip, *idx + 2, state, _THIS_IP_);
-               xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx + 2),
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx + 2, state, _THIS_IP_);
+               xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, bma->idx + 2),
                        nullstartblock((int)temp2));
-               trace_xfs_bmap_post_update(ip, *idx + 2, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(bma->ip, bma->idx + 2, state, _THIS_IP_);
 
-               ++*idx;
-               *dnew = temp + temp2;
+               bma->idx++;
+               da_new = temp + temp2;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
@@ -1114,9 +882,40 @@ xfs_bmap_add_extent_delay_real(
                 */
                ASSERT(0);
        }
-       *curp = cur;
+
+       /* convert to a btree if necessary */
+       if (XFS_IFORK_FORMAT(bma->ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS &&
+           XFS_IFORK_NEXTENTS(bma->ip, XFS_DATA_FORK) > ifp->if_ext_max) {
+               int     tmp_logflags;   /* partial log flag return val */
+
+               ASSERT(bma->cur == NULL);
+               error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
+                               bma->firstblock, bma->flist, &bma->cur,
+                               da_old > 0, &tmp_logflags, XFS_DATA_FORK);
+               bma->logflags |= tmp_logflags;
+               if (error)
+                       goto done;
+       }
+
+       /* adjust for changes in reserved delayed indirect blocks */
+       if (da_old || da_new) {
+               temp = da_new;
+               if (bma->cur)
+                       temp += bma->cur->bc_private.b.allocated;
+               ASSERT(temp <= da_old);
+               if (temp < da_old)
+                       xfs_icsb_modify_counters(bma->ip->i_mount,
+                                       XFS_SBS_FDBLOCKS,
+                                       (int64_t)(da_old - temp), 0);
+       }
+
+       /* clear out the allocated field, done with it now in any case. */
+       if (bma->cur)
+               bma->cur->bc_private.b.allocated = 0;
+
+       xfs_bmap_check_leaf_extents(bma->cur, bma->ip, XFS_DATA_FORK);
 done:
-       *logflagsp = rval;
+       bma->logflags |= rval;
        return error;
 #undef LEFT
 #undef RIGHT
@@ -1124,15 +923,17 @@ done:
 }
 
 /*
- * Called by xfs_bmap_add_extent to handle cases converting an unwritten
- * allocation to a real allocation or vice versa.
+ * Convert an unwritten allocation to a real allocation or vice versa.
  */
 STATIC int                             /* error */
 xfs_bmap_add_extent_unwritten_real(
+       struct xfs_trans        *tp,
        xfs_inode_t             *ip,    /* incore inode pointer */
        xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
+       xfs_fsblock_t           *first, /* pointer to firstblock variable */
+       xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp) /* inode logging flags */
 {
        xfs_btree_cur_t         *cur;   /* btree cursor */
@@ -1148,15 +949,25 @@ xfs_bmap_add_extent_unwritten_real(
        int                     rval=0; /* return value (logging flags) */
        int                     state = 0;/* state bits, accessed thru macros */
 
+       *logflagsp = 0;
+
+       cur = *curp;
+       ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+
+       ASSERT(*idx >= 0);
+       ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
+       ASSERT(!isnullstartblock(new->br_startblock));
+
+       XFS_STATS_INC(xs_add_exlist);
+
 #define        LEFT            r[0]
 #define        RIGHT           r[1]
 #define        PREV            r[2]
+
        /*
         * Set up a bunch of variables to make the tests simpler.
         */
        error = 0;
-       cur = *curp;
-       ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
        ep = xfs_iext_get_ext(ifp, *idx);
        xfs_bmbt_get_all(ep, &PREV);
        newext = new->br_state;
@@ -1406,10 +1217,11 @@ xfs_bmap_add_extent_unwritten_real(
                                goto done;
                        if ((error = xfs_btree_decrement(cur, 0, &i)))
                                goto done;
-                       if (xfs_bmbt_update(cur, LEFT.br_startoff,
+                       error = xfs_bmbt_update(cur, LEFT.br_startoff,
                                LEFT.br_startblock,
                                LEFT.br_blockcount + new->br_blockcount,
-                               LEFT.br_state))
+                               LEFT.br_state);
+                       if (error)
                                goto done;
                }
                break;
@@ -1607,9 +1419,29 @@ xfs_bmap_add_extent_unwritten_real(
                 */
                ASSERT(0);
        }
-       *curp = cur;
+
+       /* convert to a btree if necessary */
+       if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS &&
+           XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > ifp->if_ext_max) {
+               int     tmp_logflags;   /* partial log flag return val */
+
+               ASSERT(cur == NULL);
+               error = xfs_bmap_extents_to_btree(tp, ip, first, flist, &cur,
+                               0, &tmp_logflags, XFS_DATA_FORK);
+               *logflagsp |= tmp_logflags;
+               if (error)
+                       goto done;
+       }
+
+       /* clear out the allocated field, done with it now in any case. */
+       if (cur) {
+               cur->bc_private.b.allocated = 0;
+               *curp = cur;
+       }
+
+       xfs_bmap_check_leaf_extents(*curp, ip, XFS_DATA_FORK);
 done:
-       *logflagsp = rval;
+       *logflagsp |= rval;
        return error;
 #undef LEFT
 #undef RIGHT
@@ -1617,16 +1449,13 @@ done:
 }
 
 /*
- * Called by xfs_bmap_add_extent to handle cases converting a hole
- * to a delayed allocation.
+ * Convert a hole to a delayed allocation.
  */
-/*ARGSUSED*/
-STATIC int                             /* error */
+STATIC void
 xfs_bmap_add_extent_hole_delay(
        xfs_inode_t             *ip,    /* incore inode pointer */
        xfs_extnum_t            *idx,   /* extent number to update/insert */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp) /* inode logging flags */
+       xfs_bmbt_irec_t         *new)   /* new data to add to file extents */
 {
        xfs_ifork_t             *ifp;   /* inode fork pointer */
        xfs_bmbt_irec_t         left;   /* left neighbor extent entry */
@@ -1761,23 +1590,17 @@ xfs_bmap_add_extent_hole_delay(
                 * Nothing to do for disk quota accounting here.
                 */
        }
-       *logflagsp = 0;
-       return 0;
 }
 
 /*
- * Called by xfs_bmap_add_extent to handle cases converting a hole
- * to a real allocation.
+ * Convert a hole to a real allocation.
  */
 STATIC int                             /* error */
 xfs_bmap_add_extent_hole_real(
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            *idx,   /* extent number to update/insert */
-       xfs_btree_cur_t         *cur,   /* if null, not a btree */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp, /* inode logging flags */
-       int                     whichfork) /* data or attr fork */
+       struct xfs_bmalloca     *bma,
+       int                     whichfork)
 {
+       struct xfs_bmbt_irec    *new = &bma->got;
        int                     error;  /* error return value */
        int                     i;      /* temp state */
        xfs_ifork_t             *ifp;   /* inode fork pointer */
@@ -1786,19 +1609,26 @@ xfs_bmap_add_extent_hole_real(
        int                     rval=0; /* return value (logging flags) */
        int                     state;  /* state bits, accessed thru macros */
 
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       ASSERT(*idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
-       state = 0;
+       ifp = XFS_IFORK_PTR(bma->ip, whichfork);
+
+       ASSERT(bma->idx >= 0);
+       ASSERT(bma->idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
+       ASSERT(!isnullstartblock(new->br_startblock));
+       ASSERT(!bma->cur ||
+              !(bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
 
+       XFS_STATS_INC(xs_add_exlist);
+
+       state = 0;
        if (whichfork == XFS_ATTR_FORK)
                state |= BMAP_ATTRFORK;
 
        /*
         * Check and set flags if this segment has a left neighbor.
         */
-       if (*idx > 0) {
+       if (bma->idx > 0) {
                state |= BMAP_LEFT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &left);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), &left);
                if (isnullstartblock(left.br_startblock))
                        state |= BMAP_LEFT_DELAY;
        }
@@ -1807,9 +1637,9 @@ xfs_bmap_add_extent_hole_real(
         * Check and set flags if this segment has a current value.
         * Not true if we're inserting into the "hole" at eof.
         */
-       if (*idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) {
+       if (bma->idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) {
                state |= BMAP_RIGHT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &right);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx), &right);
                if (isnullstartblock(right.br_startblock))
                        state |= BMAP_RIGHT_DELAY;
        }
@@ -1846,39 +1676,42 @@ xfs_bmap_add_extent_hole_real(
                 * left and on the right.
                 * Merge all three into a single extent record.
                 */
-               --*idx;
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
+               --bma->idx;
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx),
                        left.br_blockcount + new->br_blockcount +
                        right.br_blockcount);
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               xfs_iext_remove(ip, *idx + 1, 1, state);
+               xfs_iext_remove(bma->ip, bma->idx + 1, 1, state);
 
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                       XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
-               if (cur == NULL) {
+               XFS_IFORK_NEXT_SET(bma->ip, whichfork,
+                       XFS_IFORK_NEXTENTS(bma->ip, whichfork) - 1);
+               if (bma->cur == NULL) {
                        rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
                } else {
                        rval = XFS_ILOG_CORE;
-                       if ((error = xfs_bmbt_lookup_eq(cur,
-                                       right.br_startoff,
-                                       right.br_startblock,
-                                       right.br_blockcount, &i)))
+                       error = xfs_bmbt_lookup_eq(bma->cur, right.br_startoff,
+                                       right.br_startblock, right.br_blockcount,
+                                       &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_btree_delete(cur, &i)))
+                       error = xfs_btree_delete(bma->cur, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_btree_decrement(cur, 0, &i)))
+                       error = xfs_btree_decrement(bma->cur, 0, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_bmbt_update(cur, left.br_startoff,
+                       error = xfs_bmbt_update(bma->cur, left.br_startoff,
                                        left.br_startblock,
                                        left.br_blockcount +
                                                new->br_blockcount +
                                                right.br_blockcount,
-                                       left.br_state)))
+                                       left.br_state);
+                       if (error)
                                goto done;
                }
                break;
@@ -1889,27 +1722,28 @@ xfs_bmap_add_extent_hole_real(
                 * on the left.
                 * Merge the new allocation with the left neighbor.
                 */
-               --*idx;
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
+               --bma->idx;
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx),
                        left.br_blockcount + new->br_blockcount);
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               if (cur == NULL) {
+               if (bma->cur == NULL) {
                        rval = xfs_ilog_fext(whichfork);
                } else {
                        rval = 0;
-                       if ((error = xfs_bmbt_lookup_eq(cur,
-                                       left.br_startoff,
-                                       left.br_startblock,
-                                       left.br_blockcount, &i)))
+                       error = xfs_bmbt_lookup_eq(bma->cur, left.br_startoff,
+                                       left.br_startblock, left.br_blockcount,
+                                       &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_bmbt_update(cur, left.br_startoff,
+                       error = xfs_bmbt_update(bma->cur, left.br_startoff,
                                        left.br_startblock,
                                        left.br_blockcount +
                                                new->br_blockcount,
-                                       left.br_state)))
+                                       left.br_state);
+                       if (error)
                                goto done;
                }
                break;
@@ -1920,28 +1754,30 @@ xfs_bmap_add_extent_hole_real(
                 * on the right.
                 * Merge the new allocation with the right neighbor.
                 */
-               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
-               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx),
+               trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_);
+               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, bma->idx),
                        new->br_startoff, new->br_startblock,
                        new->br_blockcount + right.br_blockcount,
                        right.br_state);
-               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_);
 
-               if (cur == NULL) {
+               if (bma->cur == NULL) {
                        rval = xfs_ilog_fext(whichfork);
                } else {
                        rval = 0;
-                       if ((error = xfs_bmbt_lookup_eq(cur,
+                       error = xfs_bmbt_lookup_eq(bma->cur,
                                        right.br_startoff,
                                        right.br_startblock,
-                                       right.br_blockcount, &i)))
+                                       right.br_blockcount, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
-                       if ((error = xfs_bmbt_update(cur, new->br_startoff,
+                       error = xfs_bmbt_update(bma->cur, new->br_startoff,
                                        new->br_startblock,
                                        new->br_blockcount +
                                                right.br_blockcount,
-                                       right.br_state)))
+                                       right.br_state);
+                       if (error)
                                goto done;
                }
                break;
@@ -1952,28 +1788,50 @@ xfs_bmap_add_extent_hole_real(
                 * real allocation.
                 * Insert a new entry.
                 */
-               xfs_iext_insert(ip, *idx, 1, new, state);
-               XFS_IFORK_NEXT_SET(ip, whichfork,
-                       XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
-               if (cur == NULL) {
+               xfs_iext_insert(bma->ip, bma->idx, 1, new, state);
+               XFS_IFORK_NEXT_SET(bma->ip, whichfork,
+                       XFS_IFORK_NEXTENTS(bma->ip, whichfork) + 1);
+               if (bma->cur == NULL) {
                        rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
                } else {
                        rval = XFS_ILOG_CORE;
-                       if ((error = xfs_bmbt_lookup_eq(cur,
+                       error = xfs_bmbt_lookup_eq(bma->cur,
                                        new->br_startoff,
                                        new->br_startblock,
-                                       new->br_blockcount, &i)))
+                                       new->br_blockcount, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 0, done);
-                       cur->bc_rec.b.br_state = new->br_state;
-                       if ((error = xfs_btree_insert(cur, &i)))
+                       bma->cur->bc_rec.b.br_state = new->br_state;
+                       error = xfs_btree_insert(bma->cur, &i);
+                       if (error)
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
                break;
        }
+
+       /* convert to a btree if necessary */
+       if (XFS_IFORK_FORMAT(bma->ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
+           XFS_IFORK_NEXTENTS(bma->ip, whichfork) > ifp->if_ext_max) {
+               int     tmp_logflags;   /* partial log flag return val */
+
+               ASSERT(bma->cur == NULL);
+               error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
+                               bma->firstblock, bma->flist, &bma->cur,
+                               0, &tmp_logflags, whichfork);
+               bma->logflags |= tmp_logflags;
+               if (error)
+                       goto done;
+       }
+
+       /* clear out the allocated field, done with it now in any case. */
+       if (bma->cur)
+               bma->cur->bc_private.b.allocated = 0;
+
+       xfs_bmap_check_leaf_extents(bma->cur, bma->ip, whichfork);
 done:
-       *logflagsp = rval;
+       bma->logflags |= rval;
        return error;
 }
 
@@ -2160,26 +2018,26 @@ xfs_bmap_adjacent(
                XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks)
 
        mp = ap->ip->i_mount;
-       nullfb = ap->firstblock == NULLFSBLOCK;
+       nullfb = *ap->firstblock == NULLFSBLOCK;
        rt = XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata;
-       fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock);
+       fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, *ap->firstblock);
        /*
         * If allocating at eof, and there's a previous real block,
         * try to use its last block as our starting point.
         */
-       if (ap->eof && ap->prevp->br_startoff != NULLFILEOFF &&
-           !isnullstartblock(ap->prevp->br_startblock) &&
-           ISVALID(ap->prevp->br_startblock + ap->prevp->br_blockcount,
-                   ap->prevp->br_startblock)) {
-               ap->rval = ap->prevp->br_startblock + ap->prevp->br_blockcount;
+       if (ap->eof && ap->prev.br_startoff != NULLFILEOFF &&
+           !isnullstartblock(ap->prev.br_startblock) &&
+           ISVALID(ap->prev.br_startblock + ap->prev.br_blockcount,
+                   ap->prev.br_startblock)) {
+               ap->blkno = ap->prev.br_startblock + ap->prev.br_blockcount;
                /*
                 * Adjust for the gap between prevp and us.
                 */
-               adjust = ap->off -
-                       (ap->prevp->br_startoff + ap->prevp->br_blockcount);
+               adjust = ap->offset -
+                       (ap->prev.br_startoff + ap->prev.br_blockcount);
                if (adjust &&
-                   ISVALID(ap->rval + adjust, ap->prevp->br_startblock))
-                       ap->rval += adjust;
+                   ISVALID(ap->blkno + adjust, ap->prev.br_startblock))
+                       ap->blkno += adjust;
        }
        /*
         * If not at eof, then compare the two neighbor blocks.
@@ -2196,17 +2054,17 @@ xfs_bmap_adjacent(
                 * If there's a previous (left) block, select a requested
                 * start block based on it.
                 */
-               if (ap->prevp->br_startoff != NULLFILEOFF &&
-                   !isnullstartblock(ap->prevp->br_startblock) &&
-                   (prevbno = ap->prevp->br_startblock +
-                              ap->prevp->br_blockcount) &&
-                   ISVALID(prevbno, ap->prevp->br_startblock)) {
+               if (ap->prev.br_startoff != NULLFILEOFF &&
+                   !isnullstartblock(ap->prev.br_startblock) &&
+                   (prevbno = ap->prev.br_startblock +
+                              ap->prev.br_blockcount) &&
+                   ISVALID(prevbno, ap->prev.br_startblock)) {
                        /*
                         * Calculate gap to end of previous block.
                         */
-                       adjust = prevdiff = ap->off -
-                               (ap->prevp->br_startoff +
-                                ap->prevp->br_blockcount);
+                       adjust = prevdiff = ap->offset -
+                               (ap->prev.br_startoff +
+                                ap->prev.br_blockcount);
                        /*
                         * Figure the startblock based on the previous block's
                         * end and the gap size.
@@ -2215,9 +2073,9 @@ xfs_bmap_adjacent(
                         * allocating, or using it gives us an invalid block
                         * number, then just use the end of the previous block.
                         */
-                       if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->alen &&
+                       if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->length &&
                            ISVALID(prevbno + prevdiff,
-                                   ap->prevp->br_startblock))
+                                   ap->prev.br_startblock))
                                prevbno += adjust;
                        else
                                prevdiff += adjust;
@@ -2238,16 +2096,16 @@ xfs_bmap_adjacent(
                 * If there's a following (right) block, select a requested
                 * start block based on it.
                 */
-               if (!isnullstartblock(ap->gotp->br_startblock)) {
+               if (!isnullstartblock(ap->got.br_startblock)) {
                        /*
                         * Calculate gap to start of next block.
                         */
-                       adjust = gotdiff = ap->gotp->br_startoff - ap->off;
+                       adjust = gotdiff = ap->got.br_startoff - ap->offset;
                        /*
                         * Figure the startblock based on the next block's
                         * start and the gap size.
                         */
-                       gotbno = ap->gotp->br_startblock;
+                       gotbno = ap->got.br_startblock;
                        /*
                         * Heuristic!
                         * If the gap is large relative to the piece we're
@@ -2255,12 +2113,12 @@ xfs_bmap_adjacent(
                         * number, then just use the start of the next block
                         * offset by our length.
                         */
-                       if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->alen &&
+                       if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->length &&
                            ISVALID(gotbno - gotdiff, gotbno))
                                gotbno -= adjust;
-                       else if (ISVALID(gotbno - ap->alen, gotbno)) {
-                               gotbno -= ap->alen;
-                               gotdiff += adjust - ap->alen;
+                       else if (ISVALID(gotbno - ap->length, gotbno)) {
+                               gotbno -= ap->length;
+                               gotdiff += adjust - ap->length;
                        } else
                                gotdiff += adjust;
                        /*
@@ -2278,14 +2136,14 @@ xfs_bmap_adjacent(
                        gotbno = NULLFSBLOCK;
                /*
                 * If both valid, pick the better one, else the only good
-                * one, else ap->rval is already set (to 0 or the inode block).
+                * one, else ap->blkno is already set (to 0 or the inode block).
                 */
                if (prevbno != NULLFSBLOCK && gotbno != NULLFSBLOCK)
-                       ap->rval = prevdiff <= gotdiff ? prevbno : gotbno;
+                       ap->blkno = prevdiff <= gotdiff ? prevbno : gotbno;
                else if (prevbno != NULLFSBLOCK)
-                       ap->rval = prevbno;
+                       ap->blkno = prevbno;
                else if (gotbno != NULLFSBLOCK)
-                       ap->rval = gotbno;
+                       ap->blkno = gotbno;
        }
 #undef ISVALID
 }
@@ -2305,24 +2163,24 @@ xfs_bmap_rtalloc(
        mp = ap->ip->i_mount;
        align = xfs_get_extsz_hint(ap->ip);
        prod = align / mp->m_sb.sb_rextsize;
-       error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp,
+       error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
                                        align, 1, ap->eof, 0,
-                                       ap->conv, &ap->off, &ap->alen);
+                                       ap->conv, &ap->offset, &ap->length);
        if (error)
                return error;
-       ASSERT(ap->alen);
-       ASSERT(ap->alen % mp->m_sb.sb_rextsize == 0);
+       ASSERT(ap->length);
+       ASSERT(ap->length % mp->m_sb.sb_rextsize == 0);
 
        /*
         * If the offset & length are not perfectly aligned
         * then kill prod, it will just get us in trouble.
         */
-       if (do_mod(ap->off, align) || ap->alen % align)
+       if (do_mod(ap->offset, align) || ap->length % align)
                prod = 1;
        /*
         * Set ralen to be the actual requested length in rtextents.
         */
-       ralen = ap->alen / mp->m_sb.sb_rextsize;
+       ralen = ap->length / mp->m_sb.sb_rextsize;
        /*
         * If the old value was close enough to MAXEXTLEN that
         * we rounded up to it, cut it back so it's valid again.
@@ -2337,21 +2195,21 @@ xfs_bmap_rtalloc(
         * Lock out other modifications to the RT bitmap inode.
         */
        xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin_ref(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
 
        /*
         * If it's an allocation to an empty file at offset 0,
         * pick an extent that will space things out in the rt area.
         */
-       if (ap->eof && ap->off == 0) {
+       if (ap->eof && ap->offset == 0) {
                xfs_rtblock_t uninitialized_var(rtx); /* realtime extent no */
 
                error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx);
                if (error)
                        return error;
-               ap->rval = rtx * mp->m_sb.sb_rextsize;
+               ap->blkno = rtx * mp->m_sb.sb_rextsize;
        } else {
-               ap->rval = 0;
+               ap->blkno = 0;
        }
 
        xfs_bmap_adjacent(ap);
@@ -2359,23 +2217,23 @@ xfs_bmap_rtalloc(
        /*
         * Realtime allocation, done through xfs_rtallocate_extent.
         */
-       atype = ap->rval == 0 ?  XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO;
-       do_div(ap->rval, mp->m_sb.sb_rextsize);
-       rtb = ap->rval;
-       ap->alen = ralen;
-       if ((error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, ap->alen,
+       atype = ap->blkno == 0 ?  XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO;
+       do_div(ap->blkno, mp->m_sb.sb_rextsize);
+       rtb = ap->blkno;
+       ap->length = ralen;
+       if ((error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1, ap->length,
                                &ralen, atype, ap->wasdel, prod, &rtb)))
                return error;
        if (rtb == NULLFSBLOCK && prod > 1 &&
-           (error = xfs_rtallocate_extent(ap->tp, ap->rval, 1,
-                                          ap->alen, &ralen, atype,
+           (error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1,
+                                          ap->length, &ralen, atype,
                                           ap->wasdel, 1, &rtb)))
                return error;
-       ap->rval = rtb;
-       if (ap->rval != NULLFSBLOCK) {
-               ap->rval *= mp->m_sb.sb_rextsize;
+       ap->blkno = rtb;
+       if (ap->blkno != NULLFSBLOCK) {
+               ap->blkno *= mp->m_sb.sb_rextsize;
                ralen *= mp->m_sb.sb_rextsize;
-               ap->alen = ralen;
+               ap->length = ralen;
                ap->ip->i_d.di_nblocks += ralen;
                xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
                if (ap->wasdel)
@@ -2388,7 +2246,7 @@ xfs_bmap_rtalloc(
                        ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
                                        XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
        } else {
-               ap->alen = 0;
+               ap->length = 0;
        }
        return 0;
 }
@@ -2503,7 +2361,7 @@ xfs_bmap_btalloc_nullfb(
         * AG as the stream may have moved.
         */
        if (xfs_inode_is_filestream(ap->ip))
-               ap->rval = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0);
+               ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0);
 
        return 0;
 }
@@ -2528,52 +2386,52 @@ xfs_bmap_btalloc(
        mp = ap->ip->i_mount;
        align = ap->userdata ? xfs_get_extsz_hint(ap->ip) : 0;
        if (unlikely(align)) {
-               error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp,
+               error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
                                                align, 0, ap->eof, 0, ap->conv,
-                                               &ap->off, &ap->alen);
+                                               &ap->offset, &ap->length);
                ASSERT(!error);
-               ASSERT(ap->alen);
+               ASSERT(ap->length);
        }
-       nullfb = ap->firstblock == NULLFSBLOCK;
-       fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock);
+       nullfb = *ap->firstblock == NULLFSBLOCK;
+       fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, *ap->firstblock);
        if (nullfb) {
                if (ap->userdata && xfs_inode_is_filestream(ap->ip)) {
                        ag = xfs_filestream_lookup_ag(ap->ip);
                        ag = (ag != NULLAGNUMBER) ? ag : 0;
-                       ap->rval = XFS_AGB_TO_FSB(mp, ag, 0);
+                       ap->blkno = XFS_AGB_TO_FSB(mp, ag, 0);
                } else {
-                       ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
+                       ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
                }
        } else
-               ap->rval = ap->firstblock;
+               ap->blkno = *ap->firstblock;
 
        xfs_bmap_adjacent(ap);
 
        /*
-        * If allowed, use ap->rval; otherwise must use firstblock since
+        * If allowed, use ap->blkno; otherwise must use firstblock since
         * it's in the right allocation group.
         */
-       if (nullfb || XFS_FSB_TO_AGNO(mp, ap->rval) == fb_agno)
+       if (nullfb || XFS_FSB_TO_AGNO(mp, ap->blkno) == fb_agno)
                ;
        else
-               ap->rval = ap->firstblock;
+               ap->blkno = *ap->firstblock;
        /*
         * Normal allocation, done through xfs_alloc_vextent.
         */
        tryagain = isaligned = 0;
        args.tp = ap->tp;
        args.mp = mp;
-       args.fsbno = ap->rval;
+       args.fsbno = ap->blkno;
 
        /* Trim the allocation back to the maximum an AG can fit. */
-       args.maxlen = MIN(ap->alen, XFS_ALLOC_AG_MAX_USABLE(mp));
-       args.firstblock = ap->firstblock;
+       args.maxlen = MIN(ap->length, XFS_ALLOC_AG_MAX_USABLE(mp));
+       args.firstblock = *ap->firstblock;
        blen = 0;
        if (nullfb) {
                error = xfs_bmap_btalloc_nullfb(ap, &args, &blen);
                if (error)
                        return error;
-       } else if (ap->low) {
+       } else if (ap->flist->xbf_low) {
                if (xfs_inode_is_filestream(ap->ip))
                        args.type = XFS_ALLOCTYPE_FIRST_AG;
                else
@@ -2587,14 +2445,14 @@ xfs_bmap_btalloc(
        /* apply extent size hints if obtained earlier */
        if (unlikely(align)) {
                args.prod = align;
-               if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod)))
+               if ((args.mod = (xfs_extlen_t)do_mod(ap->offset, args.prod)))
                        args.mod = (xfs_extlen_t)(args.prod - args.mod);
        } else if (mp->m_sb.sb_blocksize >= PAGE_CACHE_SIZE) {
                args.prod = 1;
                args.mod = 0;
        } else {
                args.prod = PAGE_CACHE_SIZE >> mp->m_sb.sb_blocklog;
-               if ((args.mod = (xfs_extlen_t)(do_mod(ap->off, args.prod))))
+               if ((args.mod = (xfs_extlen_t)(do_mod(ap->offset, args.prod))))
                        args.mod = (xfs_extlen_t)(args.prod - args.mod);
        }
        /*
@@ -2606,8 +2464,8 @@ xfs_bmap_btalloc(
         * is >= the stripe unit and the allocation offset is
         * at the end of file.
         */
-       if (!ap->low && ap->aeof) {
-               if (!ap->off) {
+       if (!ap->flist->xbf_low && ap->aeof) {
+               if (!ap->offset) {
                        args.alignment = mp->m_dalign;
                        atype = args.type;
                        isaligned = 1;
@@ -2660,7 +2518,7 @@ xfs_bmap_btalloc(
                 * turned on.
                 */
                args.type = atype;
-               args.fsbno = ap->rval;
+               args.fsbno = ap->blkno;
                args.alignment = mp->m_dalign;
                args.minlen = nextminlen;
                args.minalignslop = 0;
@@ -2674,7 +2532,7 @@ xfs_bmap_btalloc(
                 * try again.
                 */
                args.type = atype;
-               args.fsbno = ap->rval;
+               args.fsbno = ap->blkno;
                args.alignment = 0;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
@@ -2683,7 +2541,7 @@ xfs_bmap_btalloc(
            args.minlen > ap->minlen) {
                args.minlen = ap->minlen;
                args.type = XFS_ALLOCTYPE_START_BNO;
-               args.fsbno = ap->rval;
+               args.fsbno = ap->blkno;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
        }
@@ -2694,13 +2552,26 @@ xfs_bmap_btalloc(
                args.minleft = 0;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
-               ap->low = 1;
+               ap->flist->xbf_low = 1;
        }
        if (args.fsbno != NULLFSBLOCK) {
-               ap->firstblock = ap->rval = args.fsbno;
+               /*
+                * check the allocation happened at the same or higher AG than
+                * the first block that was allocated.
+                */
+               ASSERT(*ap->firstblock == NULLFSBLOCK ||
+                      XFS_FSB_TO_AGNO(mp, *ap->firstblock) ==
+                      XFS_FSB_TO_AGNO(mp, args.fsbno) ||
+                      (ap->flist->xbf_low &&
+                       XFS_FSB_TO_AGNO(mp, *ap->firstblock) <
+                       XFS_FSB_TO_AGNO(mp, args.fsbno)));
+
+               ap->blkno = args.fsbno;
+               if (*ap->firstblock == NULLFSBLOCK)
+                       *ap->firstblock = args.fsbno;
                ASSERT(nullfb || fb_agno == args.agno ||
-                      (ap->low && fb_agno < args.agno));
-               ap->alen = args.len;
+                      (ap->flist->xbf_low && fb_agno < args.agno));
+               ap->length = args.len;
                ap->ip->i_d.di_nblocks += args.len;
                xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
                if (ap->wasdel)
@@ -2714,8 +2585,8 @@ xfs_bmap_btalloc(
                                        XFS_TRANS_DQ_BCOUNT,
                        (long) args.len);
        } else {
-               ap->rval = NULLFSBLOCK;
-               ap->alen = 0;
+               ap->blkno = NULLFSBLOCK;
+               ap->length = 0;
        }
        return 0;
 }
@@ -3589,7 +3460,7 @@ xfs_bmap_add_attrfork(
        }
        ASSERT(ip->i_d.di_anextents == 0);
 
-       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
        switch (ip->i_d.di_format) {
@@ -3782,19 +3653,11 @@ xfs_bmap_compute_maxlevels(
  * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
  * caller.  Frees all the extents that need freeing, which must be done
  * last due to locking considerations.  We never free any extents in
- * the first transaction.  This is to allow the caller to make the first
- * transaction a synchronous one so that the pointers to the data being
- * broken in this transaction will be permanent before the data is actually
- * freed.  This is necessary to prevent blocks from being reallocated
- * and written to before the free and reallocation are actually permanent.
- * We do not just make the first transaction synchronous here, because
- * there are more efficient ways to gain the same protection in some cases
- * (see the file truncation code).
+ * the first transaction.
  *
  * Return 1 if the given transaction was committed and a new one
  * started, and 0 otherwise in the committed parameter.
  */
-/*ARGSUSED*/
 int                                            /* error */
 xfs_bmap_finish(
        xfs_trans_t             **tp,           /* transaction pointer addr */
@@ -3994,42 +3857,122 @@ xfs_bmap_last_before(
        return 0;
 }
 
+STATIC int
+xfs_bmap_last_extent(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       int                     whichfork,
+       struct xfs_bmbt_irec    *rec,
+       int                     *is_empty)
+{
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       int                     error;
+       int                     nextents;
+
+       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+               error = xfs_iread_extents(tp, ip, whichfork);
+               if (error)
+                       return error;
+       }
+
+       nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);
+       if (nextents == 0) {
+               *is_empty = 1;
+               return 0;
+       }
+
+       xfs_bmbt_get_all(xfs_iext_get_ext(ifp, nextents - 1), rec);
+       *is_empty = 0;
+       return 0;
+}
+
+/*
+ * Check the last inode extent to determine whether this allocation will result
+ * in blocks being allocated at the end of the file. When we allocate new data
+ * blocks at the end of the file which do not start at the previous data block,
+ * we will try to align the new blocks at stripe unit boundaries.
+ *
+ * Returns 0 in bma->aeof if the file (fork) is empty as any new write will be
+ * at, or past the EOF.
+ */
+STATIC int
+xfs_bmap_isaeof(
+       struct xfs_bmalloca     *bma,
+       int                     whichfork)
+{
+       struct xfs_bmbt_irec    rec;
+       int                     is_empty;
+       int                     error;
+
+       bma->aeof = 0;
+       error = xfs_bmap_last_extent(NULL, bma->ip, whichfork, &rec,
+                                    &is_empty);
+       if (error || is_empty)
+               return error;
+
+       /*
+        * Check if we are allocation or past the last extent, or at least into
+        * the last delayed allocated extent.
+        */
+       bma->aeof = bma->offset >= rec.br_startoff + rec.br_blockcount ||
+               (bma->offset >= rec.br_startoff &&
+                isnullstartblock(rec.br_startblock));
+       return 0;
+}
+
+/*
+ * Check if the endoff is outside the last extent. If so the caller will grow
+ * the allocation to a stripe unit boundary.  All offsets are considered outside
+ * the end of file for an empty fork, so 1 is returned in *eof in that case.
+ */
+int
+xfs_bmap_eof(
+       struct xfs_inode        *ip,
+       xfs_fileoff_t           endoff,
+       int                     whichfork,
+       int                     *eof)
+{
+       struct xfs_bmbt_irec    rec;
+       int                     error;
+
+       error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, eof);
+       if (error || *eof)
+               return error;
+
+       *eof = endoff >= rec.br_startoff + rec.br_blockcount;
+       return 0;
+}
+
 /*
  * Returns the file-relative block number of the first block past eof in
  * the file.  This is not based on i_size, it is based on the extent records.
  * Returns 0 for local files, as they do not have extent records.
  */
-int                                            /* error */
+int
 xfs_bmap_last_offset(
-       xfs_trans_t     *tp,                    /* transaction pointer */
-       xfs_inode_t     *ip,                    /* incore inode */
-       xfs_fileoff_t   *last_block,            /* last block */
-       int             whichfork)              /* data or attr fork */
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       xfs_fileoff_t           *last_block,
+       int                     whichfork)
 {
-       xfs_bmbt_rec_host_t *ep;                /* pointer to last extent */
-       int             error;                  /* error return value */
-       xfs_ifork_t     *ifp;                   /* inode fork pointer */
-       xfs_extnum_t    nextents;               /* number of extent entries */
+       struct xfs_bmbt_irec    rec;
+       int                     is_empty;
+       int                     error;
+
+       *last_block = 0;
+
+       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL)
+               return 0;
 
        if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
-           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
+           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
               return XFS_ERROR(EIO);
-       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
-               *last_block = 0;
-               return 0;
-       }
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (!(ifp->if_flags & XFS_IFEXTENTS) &&
-           (error = xfs_iread_extents(tp, ip, whichfork)))
+
+       error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
+       if (error || is_empty)
                return error;
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       if (!nextents) {
-               *last_block = 0;
-               return 0;
-       }
-       ep = xfs_iext_get_ext(ifp, nextents - 1);
-       *last_block = xfs_bmbt_get_startoff(ep) + xfs_bmbt_get_blockcount(ep);
+
+       *last_block = rec.br_startoff + rec.br_blockcount;
        return 0;
 }
 
@@ -4159,7 +4102,6 @@ xfs_bmap_read_extents(
                xfs_extnum_t    num_recs;
                xfs_extnum_t    start;
 
-
                num_recs = xfs_btree_get_numrecs(block);
                if (unlikely(i + num_recs > room)) {
                        ASSERT(i + num_recs <= room);
@@ -4282,9 +4224,8 @@ xfs_bmap_validate_ret(
                ASSERT(i == 0 ||
                       mval[i - 1].br_startoff + mval[i - 1].br_blockcount ==
                       mval[i].br_startoff);
-               if ((flags & XFS_BMAPI_WRITE) && !(flags & XFS_BMAPI_DELAY))
-                       ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK &&
-                              mval[i].br_startblock != HOLESTARTBLOCK);
+               ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK &&
+                      mval[i].br_startblock != HOLESTARTBLOCK);
                ASSERT(mval[i].br_state == XFS_EXT_NORM ||
                       mval[i].br_state == XFS_EXT_UNWRITTEN);
        }
@@ -4293,66 +4234,609 @@ xfs_bmap_validate_ret(
 
 
 /*
- * Map file blocks to filesystem blocks.
- * File range is given by the bno/len pair.
- * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set)
- * into a hole or past eof.
- * Only allocates blocks from a single allocation group,
- * to avoid locking problems.
+ * Trim the returned map to the required bounds
+ */
+STATIC void
+xfs_bmapi_trim_map(
+       struct xfs_bmbt_irec    *mval,
+       struct xfs_bmbt_irec    *got,
+       xfs_fileoff_t           *bno,
+       xfs_filblks_t           len,
+       xfs_fileoff_t           obno,
+       xfs_fileoff_t           end,
+       int                     n,
+       int                     flags)
+{
+       if ((flags & XFS_BMAPI_ENTIRE) ||
+           got->br_startoff + got->br_blockcount <= obno) {
+               *mval = *got;
+               if (isnullstartblock(got->br_startblock))
+                       mval->br_startblock = DELAYSTARTBLOCK;
+               return;
+       }
+
+       if (obno > *bno)
+               *bno = obno;
+       ASSERT((*bno >= obno) || (n == 0));
+       ASSERT(*bno < end);
+       mval->br_startoff = *bno;
+       if (isnullstartblock(got->br_startblock))
+               mval->br_startblock = DELAYSTARTBLOCK;
+       else
+               mval->br_startblock = got->br_startblock +
+                                       (*bno - got->br_startoff);
+       /*
+        * Return the minimum of what we got and what we asked for for
+        * the length.  We can use the len variable here because it is
+        * modified below and we could have been there before coming
+        * here if the first part of the allocation didn't overlap what
+        * was asked for.
+        */
+       mval->br_blockcount = XFS_FILBLKS_MIN(end - *bno,
+                       got->br_blockcount - (*bno - got->br_startoff));
+       mval->br_state = got->br_state;
+       ASSERT(mval->br_blockcount <= len);
+       return;
+}
+
+/*
+ * Update and validate the extent map to return
+ */
+STATIC void
+xfs_bmapi_update_map(
+       struct xfs_bmbt_irec    **map,
+       xfs_fileoff_t           *bno,
+       xfs_filblks_t           *len,
+       xfs_fileoff_t           obno,
+       xfs_fileoff_t           end,
+       int                     *n,
+       int                     flags)
+{
+       xfs_bmbt_irec_t *mval = *map;
+
+       ASSERT((flags & XFS_BMAPI_ENTIRE) ||
+              ((mval->br_startoff + mval->br_blockcount) <= end));
+       ASSERT((flags & XFS_BMAPI_ENTIRE) || (mval->br_blockcount <= *len) ||
+              (mval->br_startoff < obno));
+
+       *bno = mval->br_startoff + mval->br_blockcount;
+       *len = end - *bno;
+       if (*n > 0 && mval->br_startoff == mval[-1].br_startoff) {
+               /* update previous map with new information */
+               ASSERT(mval->br_startblock == mval[-1].br_startblock);
+               ASSERT(mval->br_blockcount > mval[-1].br_blockcount);
+               ASSERT(mval->br_state == mval[-1].br_state);
+               mval[-1].br_blockcount = mval->br_blockcount;
+               mval[-1].br_state = mval->br_state;
+       } else if (*n > 0 && mval->br_startblock != DELAYSTARTBLOCK &&
+                  mval[-1].br_startblock != DELAYSTARTBLOCK &&
+                  mval[-1].br_startblock != HOLESTARTBLOCK &&
+                  mval->br_startblock == mval[-1].br_startblock +
+                                         mval[-1].br_blockcount &&
+                  ((flags & XFS_BMAPI_IGSTATE) ||
+                       mval[-1].br_state == mval->br_state)) {
+               ASSERT(mval->br_startoff ==
+                      mval[-1].br_startoff + mval[-1].br_blockcount);
+               mval[-1].br_blockcount += mval->br_blockcount;
+       } else if (*n > 0 &&
+                  mval->br_startblock == DELAYSTARTBLOCK &&
+                  mval[-1].br_startblock == DELAYSTARTBLOCK &&
+                  mval->br_startoff ==
+                  mval[-1].br_startoff + mval[-1].br_blockcount) {
+               mval[-1].br_blockcount += mval->br_blockcount;
+               mval[-1].br_state = mval->br_state;
+       } else if (!((*n == 0) &&
+                    ((mval->br_startoff + mval->br_blockcount) <=
+                     obno))) {
+               mval++;
+               (*n)++;
+       }
+       *map = mval;
+}
+
+/*
+ * Map file blocks to filesystem blocks without allocation.
+ */
+int
+xfs_bmapi_read(
+       struct xfs_inode        *ip,
+       xfs_fileoff_t           bno,
+       xfs_filblks_t           len,
+       struct xfs_bmbt_irec    *mval,
+       int                     *nmap,
+       int                     flags)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_ifork        *ifp;
+       struct xfs_bmbt_irec    got;
+       struct xfs_bmbt_irec    prev;
+       xfs_fileoff_t           obno;
+       xfs_fileoff_t           end;
+       xfs_extnum_t            lastx;
+       int                     error;
+       int                     eof;
+       int                     n = 0;
+       int                     whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
+                                               XFS_ATTR_FORK : XFS_DATA_FORK;
+
+       ASSERT(*nmap >= 1);
+       ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK|XFS_BMAPI_ENTIRE|
+                          XFS_BMAPI_IGSTATE)));
+
+       if (unlikely(XFS_TEST_ERROR(
+           (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
+            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
+            mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
+               XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+
+       XFS_STATS_INC(xs_blk_mapr);
+
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       ASSERT(ifp->if_ext_max ==
+              XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
+
+       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+               error = xfs_iread_extents(NULL, ip, whichfork);
+               if (error)
+                       return error;
+       }
+
+       xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev);
+       end = bno + len;
+       obno = bno;
+
+       while (bno < end && n < *nmap) {
+               /* Reading past eof, act as though there's a hole up to end. */
+               if (eof)
+                       got.br_startoff = end;
+               if (got.br_startoff > bno) {
+                       /* Reading in a hole.  */
+                       mval->br_startoff = bno;
+                       mval->br_startblock = HOLESTARTBLOCK;
+                       mval->br_blockcount =
+                               XFS_FILBLKS_MIN(len, got.br_startoff - bno);
+                       mval->br_state = XFS_EXT_NORM;
+                       bno += mval->br_blockcount;
+                       len -= mval->br_blockcount;
+                       mval++;
+                       n++;
+                       continue;
+               }
+
+               /* set up the extent map to return. */
+               xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags);
+               xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags);
+
+               /* If we're done, stop now. */
+               if (bno >= end || n >= *nmap)
+                       break;
+
+               /* Else go on to the next record. */
+               if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t))
+                       xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got);
+               else
+                       eof = 1;
+       }
+       *nmap = n;
+       return 0;
+}
+
+STATIC int
+xfs_bmapi_reserve_delalloc(
+       struct xfs_inode        *ip,
+       xfs_fileoff_t           aoff,
+       xfs_filblks_t           len,
+       struct xfs_bmbt_irec    *got,
+       struct xfs_bmbt_irec    *prev,
+       xfs_extnum_t            *lastx,
+       int                     eof)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+       xfs_extlen_t            alen;
+       xfs_extlen_t            indlen;
+       char                    rt = XFS_IS_REALTIME_INODE(ip);
+       xfs_extlen_t            extsz;
+       int                     error;
+
+       alen = XFS_FILBLKS_MIN(len, MAXEXTLEN);
+       if (!eof)
+               alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff);
+
+       /* Figure out the extent size, adjust alen */
+       extsz = xfs_get_extsz_hint(ip);
+       if (extsz) {
+               /*
+                * Make sure we don't exceed a single extent length when we
+                * align the extent by reducing length we are going to
+                * allocate by the maximum amount extent size aligment may
+                * require.
+                */
+               alen = XFS_FILBLKS_MIN(len, MAXEXTLEN - (2 * extsz - 1));
+               error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof,
+                                              1, 0, &aoff, &alen);
+               ASSERT(!error);
+       }
+
+       if (rt)
+               extsz = alen / mp->m_sb.sb_rextsize;
+
+       /*
+        * Make a transaction-less quota reservation for delayed allocation
+        * 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,
+                       rt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+       if (error)
+               return error;
+
+       /*
+        * Split changing sb for alen and indlen since they could be coming
+        * from different places.
+        */
+       indlen = (xfs_extlen_t)xfs_bmap_worst_indlen(ip, alen);
+       ASSERT(indlen > 0);
+
+       if (rt) {
+               error = xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS,
+                                         -((int64_t)extsz), 0);
+       } else {
+               error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
+                                                -((int64_t)alen), 0);
+       }
+
+       if (error)
+               goto out_unreserve_quota;
+
+       error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
+                                        -((int64_t)indlen), 0);
+       if (error)
+               goto out_unreserve_blocks;
+
+
+       ip->i_delayed_blks += alen;
+
+       got->br_startoff = aoff;
+       got->br_startblock = nullstartblock(indlen);
+       got->br_blockcount = alen;
+       got->br_state = XFS_EXT_NORM;
+       xfs_bmap_add_extent_hole_delay(ip, lastx, got);
+
+       /*
+        * Update our extent pointer, given that xfs_bmap_add_extent_hole_delay
+        * might have merged it into one of the neighbouring ones.
+        */
+       xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), got);
+
+       ASSERT(got->br_startoff <= aoff);
+       ASSERT(got->br_startoff + got->br_blockcount >= aoff + alen);
+       ASSERT(isnullstartblock(got->br_startblock));
+       ASSERT(got->br_state == XFS_EXT_NORM);
+       return 0;
+
+out_unreserve_blocks:
+       if (rt)
+               xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, extsz, 0);
+       else
+               xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, alen, 0);
+out_unreserve_quota:
+       if (XFS_IS_QUOTA_ON(mp))
+               xfs_trans_unreserve_quota_nblks(NULL, ip, alen, 0, rt ?
+                               XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+       return error;
+}
+
+/*
+ * Map file blocks to filesystem blocks, adding delayed allocations as needed.
+ */
+int
+xfs_bmapi_delay(
+       struct xfs_inode        *ip,    /* incore inode */
+       xfs_fileoff_t           bno,    /* starting file offs. mapped */
+       xfs_filblks_t           len,    /* length to map in file */
+       struct xfs_bmbt_irec    *mval,  /* output: map values */
+       int                     *nmap,  /* i/o: mval size/count */
+       int                     flags)  /* XFS_BMAPI_... */
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+       struct xfs_bmbt_irec    got;    /* current file extent record */
+       struct xfs_bmbt_irec    prev;   /* previous file extent record */
+       xfs_fileoff_t           obno;   /* old block number (offset) */
+       xfs_fileoff_t           end;    /* end of mapped file region */
+       xfs_extnum_t            lastx;  /* last useful extent number */
+       int                     eof;    /* we've hit the end of extents */
+       int                     n = 0;  /* current extent index */
+       int                     error = 0;
+
+       ASSERT(*nmap >= 1);
+       ASSERT(*nmap <= XFS_BMAP_MAX_NMAP);
+       ASSERT(!(flags & ~XFS_BMAPI_ENTIRE));
+
+       if (unlikely(XFS_TEST_ERROR(
+           (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS &&
+            XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE),
+            mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
+               XFS_ERROR_REPORT("xfs_bmapi_delay", XFS_ERRLEVEL_LOW, mp);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+
+       XFS_STATS_INC(xs_blk_mapw);
+
+       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+               error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
+               if (error)
+                       return error;
+       }
+
+       xfs_bmap_search_extents(ip, bno, XFS_DATA_FORK, &eof, &lastx, &got, &prev);
+       end = bno + len;
+       obno = bno;
+
+       while (bno < end && n < *nmap) {
+               if (eof || got.br_startoff > bno) {
+                       error = xfs_bmapi_reserve_delalloc(ip, bno, len, &got,
+                                                          &prev, &lastx, eof);
+                       if (error) {
+                               if (n == 0) {
+                                       *nmap = 0;
+                                       return error;
+                               }
+                               break;
+                       }
+               }
+
+               /* set up the extent map to return. */
+               xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags);
+               xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags);
+
+               /* If we're done, stop now. */
+               if (bno >= end || n >= *nmap)
+                       break;
+
+               /* Else go on to the next record. */
+               prev = got;
+               if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t))
+                       xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got);
+               else
+                       eof = 1;
+       }
+
+       *nmap = n;
+       return 0;
+}
+
+
+STATIC int
+xfs_bmapi_allocate(
+       struct xfs_bmalloca     *bma,
+       int                     flags)
+{
+       struct xfs_mount        *mp = bma->ip->i_mount;
+       int                     whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
+                                               XFS_ATTR_FORK : XFS_DATA_FORK;
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(bma->ip, whichfork);
+       int                     tmp_logflags = 0;
+       int                     error;
+       int                     rt;
+
+       rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(bma->ip);
+
+       /*
+        * For the wasdelay case, we could also just allocate the stuff asked
+        * for in this bmap call but that wouldn't be as good.
+        */
+       if (bma->wasdel) {
+               bma->length = (xfs_extlen_t)bma->got.br_blockcount;
+               bma->offset = bma->got.br_startoff;
+               if (bma->idx != NULLEXTNUM && bma->idx) {
+                       xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1),
+                                        &bma->prev);
+               }
+       } else {
+               bma->length = XFS_FILBLKS_MIN(bma->length, MAXEXTLEN);
+               if (!bma->eof)
+                       bma->length = XFS_FILBLKS_MIN(bma->length,
+                                       bma->got.br_startoff - bma->offset);
+       }
+
+       /*
+        * Indicate if this is the first user data in the file, or just any
+        * user data.
+        */
+       if (!(flags & XFS_BMAPI_METADATA)) {
+               bma->userdata = (bma->offset == 0) ?
+                       XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA;
+       }
+
+       bma->minlen = (flags & XFS_BMAPI_CONTIG) ? bma->length : 1;
+
+       /*
+        * Only want to do the alignment at the eof if it is userdata and
+        * allocation length is larger than a stripe unit.
+        */
+       if (mp->m_dalign && bma->length >= mp->m_dalign &&
+           !(flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) {
+               error = xfs_bmap_isaeof(bma, whichfork);
+               if (error)
+                       return error;
+       }
+
+       error = xfs_bmap_alloc(bma);
+       if (error)
+               return error;
+
+       if (bma->flist->xbf_low)
+               bma->minleft = 0;
+       if (bma->cur)
+               bma->cur->bc_private.b.firstblock = *bma->firstblock;
+       if (bma->blkno == NULLFSBLOCK)
+               return 0;
+       if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) {
+               bma->cur = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork);
+               bma->cur->bc_private.b.firstblock = *bma->firstblock;
+               bma->cur->bc_private.b.flist = bma->flist;
+       }
+       /*
+        * Bump the number of extents we've allocated
+        * in this call.
+        */
+       bma->nallocs++;
+
+       if (bma->cur)
+               bma->cur->bc_private.b.flags =
+                       bma->wasdel ? XFS_BTCUR_BPRV_WASDEL : 0;
+
+       bma->got.br_startoff = bma->offset;
+       bma->got.br_startblock = bma->blkno;
+       bma->got.br_blockcount = bma->length;
+       bma->got.br_state = XFS_EXT_NORM;
+
+       /*
+        * A wasdelay extent has been initialized, so shouldn't be flagged
+        * as unwritten.
+        */
+       if (!bma->wasdel && (flags & XFS_BMAPI_PREALLOC) &&
+           xfs_sb_version_hasextflgbit(&mp->m_sb))
+               bma->got.br_state = XFS_EXT_UNWRITTEN;
+
+       if (bma->wasdel)
+               error = xfs_bmap_add_extent_delay_real(bma);
+       else
+               error = xfs_bmap_add_extent_hole_real(bma, whichfork);
+
+       bma->logflags |= tmp_logflags;
+       if (error)
+               return error;
+
+       /*
+        * Update our extent pointer, given that xfs_bmap_add_extent_delay_real
+        * or xfs_bmap_add_extent_hole_real might have merged it into one of
+        * the neighbouring ones.
+        */
+       xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx), &bma->got);
+
+       ASSERT(bma->got.br_startoff <= bma->offset);
+       ASSERT(bma->got.br_startoff + bma->got.br_blockcount >=
+              bma->offset + bma->length);
+       ASSERT(bma->got.br_state == XFS_EXT_NORM ||
+              bma->got.br_state == XFS_EXT_UNWRITTEN);
+       return 0;
+}
+
+STATIC int
+xfs_bmapi_convert_unwritten(
+       struct xfs_bmalloca     *bma,
+       struct xfs_bmbt_irec    *mval,
+       xfs_filblks_t           len,
+       int                     flags)
+{
+       int                     whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
+                                               XFS_ATTR_FORK : XFS_DATA_FORK;
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(bma->ip, whichfork);
+       int                     tmp_logflags = 0;
+       int                     error;
+
+       /* check if we need to do unwritten->real conversion */
+       if (mval->br_state == XFS_EXT_UNWRITTEN &&
+           (flags & XFS_BMAPI_PREALLOC))
+               return 0;
+
+       /* check if we need to do real->unwritten conversion */
+       if (mval->br_state == XFS_EXT_NORM &&
+           (flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT)) !=
+                       (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT))
+               return 0;
+
+       /*
+        * Modify (by adding) the state flag, if writing.
+        */
+       ASSERT(mval->br_blockcount <= len);
+       if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) {
+               bma->cur = xfs_bmbt_init_cursor(bma->ip->i_mount, bma->tp,
+                                       bma->ip, whichfork);
+               bma->cur->bc_private.b.firstblock = *bma->firstblock;
+               bma->cur->bc_private.b.flist = bma->flist;
+       }
+       mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
+                               ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
+
+       error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, &bma->idx,
+                       &bma->cur, mval, bma->firstblock, bma->flist,
+                       &tmp_logflags);
+       bma->logflags |= tmp_logflags;
+       if (error)
+               return error;
+
+       /*
+        * Update our extent pointer, given that
+        * xfs_bmap_add_extent_unwritten_real might have merged it into one
+        * of the neighbouring ones.
+        */
+       xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx), &bma->got);
+
+       /*
+        * We may have combined previously unwritten space with written space,
+        * so generate another request.
+        */
+       if (mval->br_blockcount < len)
+               return EAGAIN;
+       return 0;
+}
+
+/*
+ * Map file blocks to filesystem blocks, and allocate blocks or convert the
+ * extent state if necessary.  Details behaviour is controlled by the flags
+ * parameter.  Only allocates blocks from a single allocation group, to avoid
+ * locking problems.
+ *
  * The returned value in "firstblock" from the first call in a transaction
  * must be remembered and presented to subsequent calls in "firstblock".
  * An upper bound for the number of blocks to be allocated is supplied to
  * the first call in "total"; if no allocation group has that many free
  * blocks then the call will fail (return NULLFSBLOCK in "firstblock").
  */
-int                                    /* error */
-xfs_bmapi(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *ip,            /* incore inode */
-       xfs_fileoff_t   bno,            /* starting file offs. mapped */
-       xfs_filblks_t   len,            /* length to map in file */
-       int             flags,          /* XFS_BMAPI_... */
-       xfs_fsblock_t   *firstblock,    /* first allocated block
-                                          controls a.g. for allocs */
-       xfs_extlen_t    total,          /* total blocks needed */
-       xfs_bmbt_irec_t *mval,          /* output: map values */
-       int             *nmap,          /* i/o: mval size/count */
-       xfs_bmap_free_t *flist)         /* i/o: list extents to free */
+int
+xfs_bmapi_write(
+       struct xfs_trans        *tp,            /* transaction pointer */
+       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_... */
+       xfs_fsblock_t           *firstblock,    /* first allocated block
+                                                  controls a.g. for allocs */
+       xfs_extlen_t            total,          /* total blocks needed */
+       struct xfs_bmbt_irec    *mval,          /* output: map values */
+       int                     *nmap,          /* i/o: mval size/count */
+       struct xfs_bmap_free    *flist)         /* i/o: list extents to free */
 {
-       xfs_fsblock_t   abno;           /* allocated block number */
-       xfs_extlen_t    alen;           /* allocated extent length */
-       xfs_fileoff_t   aoff;           /* allocated file offset */
-       xfs_bmalloca_t  bma = { 0 };    /* args for xfs_bmap_alloc */
-       xfs_btree_cur_t *cur;           /* bmap btree cursor */
-       xfs_fileoff_t   end;            /* end of mapped file region */
-       int             eof;            /* we've hit the end of extents */
-       xfs_bmbt_rec_host_t *ep;        /* extent record pointer */
-       int             error;          /* error return */
-       xfs_bmbt_irec_t got;            /* current file extent record */
-       xfs_ifork_t     *ifp;           /* inode fork pointer */
-       xfs_extlen_t    indlen;         /* indirect blocks length */
-       xfs_extnum_t    lastx;          /* last useful extent number */
-       int             logflags;       /* flags for transaction logging */
-       xfs_extlen_t    minleft;        /* min blocks left after allocation */
-       xfs_extlen_t    minlen;         /* min allocation size */
-       xfs_mount_t     *mp;            /* xfs mount structure */
-       int             n;              /* current extent index */
-       int             nallocs;        /* number of extents alloc'd */
-       xfs_extnum_t    nextents;       /* number of extents in file */
-       xfs_fileoff_t   obno;           /* old block number (offset) */
-       xfs_bmbt_irec_t prev;           /* previous file extent record */
-       int             tmp_logflags;   /* temp flags holder */
-       int             whichfork;      /* data or attr fork */
-       char            inhole;         /* current location is hole in file */
-       char            wasdelay;       /* old extent was delayed */
-       char            wr;             /* this is a write request */
-       char            rt;             /* this is a realtime file */
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_ifork        *ifp;
+       struct xfs_bmalloca     bma = { 0 };    /* args for xfs_bmap_alloc */
+       xfs_fileoff_t           end;            /* end of mapped file region */
+       int                     eof;            /* 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 */
+       char                    inhole;         /* current location is hole in file */
+       char                    wasdelay;       /* old extent was delayed */
+
 #ifdef DEBUG
-       xfs_fileoff_t   orig_bno;       /* original block number value */
-       int             orig_flags;     /* original flags arg value */
-       xfs_filblks_t   orig_len;       /* original value of len arg */
-       xfs_bmbt_irec_t *orig_mval;     /* original value of mval */
-       int             orig_nmap;      /* original value of *nmap */
+       xfs_fileoff_t           orig_bno;       /* original block number value */
+       int                     orig_flags;     /* original flags arg value */
+       xfs_filblks_t           orig_len;       /* original value of len arg */
+       struct xfs_bmbt_irec    *orig_mval;     /* original value of mval */
+       int                     orig_nmap;      /* original value of *nmap */
 
        orig_bno = bno;
        orig_len = len;
@@ -4360,488 +4844,133 @@ xfs_bmapi(
        orig_mval = mval;
        orig_nmap = *nmap;
 #endif
+
        ASSERT(*nmap >= 1);
-       ASSERT(*nmap <= XFS_BMAP_MAX_NMAP || !(flags & XFS_BMAPI_WRITE));
+       ASSERT(*nmap <= XFS_BMAP_MAX_NMAP);
+       ASSERT(!(flags & XFS_BMAPI_IGSTATE));
+       ASSERT(tp != NULL);
+
        whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
                XFS_ATTR_FORK : XFS_DATA_FORK;
-       mp = ip->i_mount;
+
        if (unlikely(XFS_TEST_ERROR(
            (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
             XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
             XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),
             mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
-               XFS_ERROR_REPORT("xfs_bmapi", XFS_ERRLEVEL_LOW, mp);
+               XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp);
                return XFS_ERROR(EFSCORRUPTED);
        }
+
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
-       rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
+
        ifp = XFS_IFORK_PTR(ip, whichfork);
        ASSERT(ifp->if_ext_max ==
               XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
-       if ((wr = (flags & XFS_BMAPI_WRITE)) != 0)
-               XFS_STATS_INC(xs_blk_mapw);
-       else
-               XFS_STATS_INC(xs_blk_mapr);
-       /*
-        * IGSTATE flag is used to combine extents which
-        * differ only due to the state of the extents.
-        * This technique is used from xfs_getbmap()
-        * when the caller does not wish to see the
-        * separation (which is the default).
-        *
-        * This technique is also used when writing a
-        * buffer which has been partially written,
-        * (usually by being flushed during a chunkread),
-        * to ensure one write takes place. This also
-        * prevents a change in the xfs inode extents at
-        * this time, intentionally. This change occurs
-        * on completion of the write operation, in
-        * xfs_strat_comp(), where the xfs_bmapi() call
-        * is transactioned, and the extents combined.
-        */
-       if ((flags & XFS_BMAPI_IGSTATE) && wr)  /* if writing unwritten space */
-               wr = 0;                         /* no allocations are allowed */
-       ASSERT(wr || !(flags & XFS_BMAPI_DELAY));
-       logflags = 0;
-       nallocs = 0;
-       cur = NULL;
+
+       XFS_STATS_INC(xs_blk_mapw);
+
        if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
-               ASSERT(wr && tp);
-               if ((error = xfs_bmap_local_to_extents(tp, ip,
-                               firstblock, total, &logflags, whichfork)))
+               error = xfs_bmap_local_to_extents(tp, ip, firstblock, total,
+                                                 &bma.logflags, whichfork);
+               if (error)
                        goto error0;
        }
-       if (wr && *firstblock == NULLFSBLOCK) {
+
+       if (*firstblock == NULLFSBLOCK) {
                if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE)
-                       minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1;
+                       bma.minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1;
                else
-                       minleft = 1;
-       } else
-               minleft = 0;
-       if (!(ifp->if_flags & XFS_IFEXTENTS) &&
-           (error = xfs_iread_extents(tp, ip, whichfork)))
-               goto error0;
-       ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
-               &prev);
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+                       bma.minleft = 1;
+       } else {
+               bma.minleft = 0;
+       }
+
+       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+               error = xfs_iread_extents(tp, ip, whichfork);
+               if (error)
+                       goto error0;
+       }
+
+       xfs_bmap_search_extents(ip, bno, whichfork, &eof, &bma.idx, &bma.got,
+                               &bma.prev);
        n = 0;
        end = bno + len;
        obno = bno;
-       bma.ip = NULL;
+
+       bma.tp = tp;
+       bma.ip = ip;
+       bma.total = total;
+       bma.userdata = 0;
+       bma.flist = flist;
+       bma.firstblock = firstblock;
 
        while (bno < end && n < *nmap) {
-               /*
-                * Reading past eof, act as though there's a hole
-                * up to end.
-                */
-               if (eof && !wr)
-                       got.br_startoff = end;
-               inhole = eof || got.br_startoff > bno;
-               wasdelay = wr && !inhole && !(flags & XFS_BMAPI_DELAY) &&
-                       isnullstartblock(got.br_startblock);
+               inhole = eof || bma.got.br_startoff > bno;
+               wasdelay = !inhole && isnullstartblock(bma.got.br_startblock);
+
                /*
                 * First, deal with the hole before the allocated space
                 * that we found, if any.
                 */
-               if (wr && (inhole || wasdelay)) {
-                       /*
-                        * For the wasdelay case, we could also just
-                        * allocate the stuff asked for in this bmap call
-                        * but that wouldn't be as good.
-                        */
-                       if (wasdelay) {
-                               alen = (xfs_extlen_t)got.br_blockcount;
-                               aoff = got.br_startoff;
-                               if (lastx != NULLEXTNUM && lastx) {
-                                       ep = xfs_iext_get_ext(ifp, lastx - 1);
-                                       xfs_bmbt_get_all(ep, &prev);
-                               }
-                       } else {
-                               alen = (xfs_extlen_t)
-                                       XFS_FILBLKS_MIN(len, MAXEXTLEN);
-                               if (!eof)
-                                       alen = (xfs_extlen_t)
-                                               XFS_FILBLKS_MIN(alen,
-                                                       got.br_startoff - bno);
-                               aoff = bno;
-                       }
-                       minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1;
-                       if (flags & XFS_BMAPI_DELAY) {
-                               xfs_extlen_t    extsz;
-
-                               /* Figure out the extent size, adjust alen */
-                               extsz = xfs_get_extsz_hint(ip);
-                               if (extsz) {
-                                       /*
-                                        * make sure we don't exceed a single
-                                        * extent length when we align the
-                                        * extent by reducing length we are
-                                        * going to allocate by the maximum
-                                        * amount extent size aligment may
-                                        * require.
-                                        */
-                                       alen = XFS_FILBLKS_MIN(len,
-                                                  MAXEXTLEN - (2 * extsz - 1));
-                                       error = xfs_bmap_extsize_align(mp,
-                                                       &got, &prev, extsz,
-                                                       rt, eof,
-                                                       flags&XFS_BMAPI_DELAY,
-                                                       flags&XFS_BMAPI_CONVERT,
-                                                       &aoff, &alen);
-                                       ASSERT(!error);
-                               }
-
-                               if (rt)
-                                       extsz = alen / mp->m_sb.sb_rextsize;
-
-                               /*
-                                * Make a transaction-less quota reservation for
-                                * delayed allocation 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,
-                                               rt ? XFS_QMOPT_RES_RTBLKS :
-                                                    XFS_QMOPT_RES_REGBLKS);
-                               if (error) {
-                                       if (n == 0) {
-                                               *nmap = 0;
-                                               ASSERT(cur == NULL);
-                                               return error;
-                                       }
-                                       break;
-                               }
-
-                               /*
-                                * Split changing sb for alen and indlen since
-                                * they could be coming from different places.
-                                */
-                               indlen = (xfs_extlen_t)
-                                       xfs_bmap_worst_indlen(ip, alen);
-                               ASSERT(indlen > 0);
-
-                               if (rt) {
-                                       error = xfs_mod_incore_sb(mp,
-                                                       XFS_SBS_FREXTENTS,
-                                                       -((int64_t)extsz), 0);
-                               } else {
-                                       error = xfs_icsb_modify_counters(mp,
-                                                       XFS_SBS_FDBLOCKS,
-                                                       -((int64_t)alen), 0);
-                               }
-                               if (!error) {
-                                       error = xfs_icsb_modify_counters(mp,
-                                                       XFS_SBS_FDBLOCKS,
-                                                       -((int64_t)indlen), 0);
-                                       if (error && rt)
-                                               xfs_mod_incore_sb(mp,
-                                                       XFS_SBS_FREXTENTS,
-                                                       (int64_t)extsz, 0);
-                                       else if (error)
-                                               xfs_icsb_modify_counters(mp,
-                                                       XFS_SBS_FDBLOCKS,
-                                                       (int64_t)alen, 0);
-                               }
-
-                               if (error) {
-                                       if (XFS_IS_QUOTA_ON(mp))
-                                               /* unreserve the blocks now */
-                                               (void)
-                                               xfs_trans_unreserve_quota_nblks(
-                                                       NULL, ip,
-                                                       (long)alen, 0, rt ?
-                                                       XFS_QMOPT_RES_RTBLKS :
-                                                       XFS_QMOPT_RES_REGBLKS);
-                                       break;
-                               }
-
-                               ip->i_delayed_blks += alen;
-                               abno = nullstartblock(indlen);
-                       } else {
-                               /*
-                                * If first time, allocate and fill in
-                                * once-only bma fields.
-                                */
-                               if (bma.ip == NULL) {
-                                       bma.tp = tp;
-                                       bma.ip = ip;
-                                       bma.prevp = &prev;
-                                       bma.gotp = &got;
-                                       bma.total = total;
-                                       bma.userdata = 0;
-                               }
-                               /* Indicate if this is the first user data
-                                * in the file, or just any user data.
-                                */
-                               if (!(flags & XFS_BMAPI_METADATA)) {
-                                       bma.userdata = (aoff == 0) ?
-                                               XFS_ALLOC_INITIAL_USER_DATA :
-                                               XFS_ALLOC_USERDATA;
-                               }
-                               /*
-                                * Fill in changeable bma fields.
-                                */
-                               bma.eof = eof;
-                               bma.firstblock = *firstblock;
-                               bma.alen = alen;
-                               bma.off = aoff;
-                               bma.conv = !!(flags & XFS_BMAPI_CONVERT);
-                               bma.wasdel = wasdelay;
-                               bma.minlen = minlen;
-                               bma.low = flist->xbf_low;
-                               bma.minleft = minleft;
-                               /*
-                                * Only want to do the alignment at the
-                                * eof if it is userdata and allocation length
-                                * is larger than a stripe unit.
-                                */
-                               if (mp->m_dalign && alen >= mp->m_dalign &&
-                                   (!(flags & XFS_BMAPI_METADATA)) &&
-                                   (whichfork == XFS_DATA_FORK)) {
-                                       if ((error = xfs_bmap_isaeof(ip, aoff,
-                                                       whichfork, &bma.aeof)))
-                                               goto error0;
-                               } else
-                                       bma.aeof = 0;
-                               /*
-                                * Call allocator.
-                                */
-                               if ((error = xfs_bmap_alloc(&bma)))
-                                       goto error0;
-                               /*
-                                * Copy out result fields.
-                                */
-                               abno = bma.rval;
-                               if ((flist->xbf_low = bma.low))
-                                       minleft = 0;
-                               alen = bma.alen;
-                               aoff = bma.off;
-                               ASSERT(*firstblock == NULLFSBLOCK ||
-                                      XFS_FSB_TO_AGNO(mp, *firstblock) ==
-                                      XFS_FSB_TO_AGNO(mp, bma.firstblock) ||
-                                      (flist->xbf_low &&
-                                       XFS_FSB_TO_AGNO(mp, *firstblock) <
-                                       XFS_FSB_TO_AGNO(mp, bma.firstblock)));
-                               *firstblock = bma.firstblock;
-                               if (cur)
-                                       cur->bc_private.b.firstblock =
-                                               *firstblock;
-                               if (abno == NULLFSBLOCK)
-                                       break;
-                               if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
-                                       cur = xfs_bmbt_init_cursor(mp, tp,
-                                               ip, whichfork);
-                                       cur->bc_private.b.firstblock =
-                                               *firstblock;
-                                       cur->bc_private.b.flist = flist;
-                               }
-                               /*
-                                * Bump the number of extents we've allocated
-                                * in this call.
-                                */
-                               nallocs++;
-                       }
-                       if (cur)
-                               cur->bc_private.b.flags =
-                                       wasdelay ? XFS_BTCUR_BPRV_WASDEL : 0;
-                       got.br_startoff = aoff;
-                       got.br_startblock = abno;
-                       got.br_blockcount = alen;
-                       got.br_state = XFS_EXT_NORM;    /* assume normal */
-                       /*
-                        * Determine state of extent, and the filesystem.
-                        * A wasdelay extent has been initialized, so
-                        * shouldn't be flagged as unwritten.
-                        */
-                       if (wr && xfs_sb_version_hasextflgbit(&mp->m_sb)) {
-                               if (!wasdelay && (flags & XFS_BMAPI_PREALLOC))
-                                       got.br_state = XFS_EXT_UNWRITTEN;
-                       }
-                       error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, &got,
-                               firstblock, flist, &tmp_logflags,
-                               whichfork);
-                       logflags |= tmp_logflags;
+               if (inhole || wasdelay) {
+                       bma.eof = eof;
+                       bma.conv = !!(flags & XFS_BMAPI_CONVERT);
+                       bma.wasdel = wasdelay;
+                       bma.length = len;
+                       bma.offset = bno;
+
+                       error = xfs_bmapi_allocate(&bma, flags);
                        if (error)
                                goto error0;
-                       ep = xfs_iext_get_ext(ifp, lastx);
-                       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-                       xfs_bmbt_get_all(ep, &got);
-                       ASSERT(got.br_startoff <= aoff);
-                       ASSERT(got.br_startoff + got.br_blockcount >=
-                               aoff + alen);
-#ifdef DEBUG
-                       if (flags & XFS_BMAPI_DELAY) {
-                               ASSERT(isnullstartblock(got.br_startblock));
-                               ASSERT(startblockval(got.br_startblock) > 0);
-                       }
-                       ASSERT(got.br_state == XFS_EXT_NORM ||
-                              got.br_state == XFS_EXT_UNWRITTEN);
-#endif
-                       /*
-                        * Fall down into the found allocated space case.
-                        */
-               } else if (inhole) {
-                       /*
-                        * Reading in a hole.
-                        */
-                       mval->br_startoff = bno;
-                       mval->br_startblock = HOLESTARTBLOCK;
-                       mval->br_blockcount =
-                               XFS_FILBLKS_MIN(len, got.br_startoff - bno);
-                       mval->br_state = XFS_EXT_NORM;
-                       bno += mval->br_blockcount;
-                       len -= mval->br_blockcount;
-                       mval++;
-                       n++;
-                       continue;
-               }
-               /*
-                * Then deal with the allocated space we found.
-                */
-               ASSERT(ep != NULL);
-               if (!(flags & XFS_BMAPI_ENTIRE) &&
-                   (got.br_startoff + got.br_blockcount > obno)) {
-                       if (obno > bno)
-                               bno = obno;
-                       ASSERT((bno >= obno) || (n == 0));
-                       ASSERT(bno < end);
-                       mval->br_startoff = bno;
-                       if (isnullstartblock(got.br_startblock)) {
-                               ASSERT(!wr || (flags & XFS_BMAPI_DELAY));
-                               mval->br_startblock = DELAYSTARTBLOCK;
-                       } else
-                               mval->br_startblock =
-                                       got.br_startblock +
-                                       (bno - got.br_startoff);
-                       /*
-                        * Return the minimum of what we got and what we
-                        * asked for for the length.  We can use the len
-                        * variable here because it is modified below
-                        * and we could have been there before coming
-                        * here if the first part of the allocation
-                        * didn't overlap what was asked for.
-                        */
-                       mval->br_blockcount =
-                               XFS_FILBLKS_MIN(end - bno, got.br_blockcount -
-                                       (bno - got.br_startoff));
-                       mval->br_state = got.br_state;
-                       ASSERT(mval->br_blockcount <= len);
-               } else {
-                       *mval = got;
-                       if (isnullstartblock(mval->br_startblock)) {
-                               ASSERT(!wr || (flags & XFS_BMAPI_DELAY));
-                               mval->br_startblock = DELAYSTARTBLOCK;
-                       }
+                       if (bma.blkno == NULLFSBLOCK)
+                               break;
                }
 
-               /*
-                * Check if writing previously allocated but
-                * unwritten extents.
-                */
-               if (wr &&
-                   ((mval->br_state == XFS_EXT_UNWRITTEN &&
-                     ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) ||
-                    (mval->br_state == XFS_EXT_NORM &&
-                     ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT)) ==
-                               (XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT))))) {
-                       /*
-                        * Modify (by adding) the state flag, if writing.
-                        */
-                       ASSERT(mval->br_blockcount <= len);
-                       if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
-                               cur = xfs_bmbt_init_cursor(mp,
-                                       tp, ip, whichfork);
-                               cur->bc_private.b.firstblock =
-                                       *firstblock;
-                               cur->bc_private.b.flist = flist;
-                       }
-                       mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
-                                               ? XFS_EXT_NORM
-                                               : XFS_EXT_UNWRITTEN;
-                       error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, mval,
-                               firstblock, flist, &tmp_logflags,
-                               whichfork);
-                       logflags |= tmp_logflags;
-                       if (error)
-                               goto error0;
-                       ep = xfs_iext_get_ext(ifp, lastx);
-                       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-                       xfs_bmbt_get_all(ep, &got);
-                       /*
-                        * We may have combined previously unwritten
-                        * space with written space, so generate
-                        * another request.
-                        */
-                       if (mval->br_blockcount < len)
-                               continue;
-               }
+               /* Deal with the allocated space we found.  */
+               xfs_bmapi_trim_map(mval, &bma.got, &bno, len, obno,
+                                                       end, n, flags);
+
+               /* Execute unwritten extent conversion if necessary */
+               error = xfs_bmapi_convert_unwritten(&bma, mval, len, flags);
+               if (error == EAGAIN)
+                       continue;
+               if (error)
+                       goto error0;
+
+               /* update the extent map to return */
+               xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags);
 
-               ASSERT((flags & XFS_BMAPI_ENTIRE) ||
-                      ((mval->br_startoff + mval->br_blockcount) <= end));
-               ASSERT((flags & XFS_BMAPI_ENTIRE) ||
-                      (mval->br_blockcount <= len) ||
-                      (mval->br_startoff < obno));
-               bno = mval->br_startoff + mval->br_blockcount;
-               len = end - bno;
-               if (n > 0 && mval->br_startoff == mval[-1].br_startoff) {
-                       ASSERT(mval->br_startblock == mval[-1].br_startblock);
-                       ASSERT(mval->br_blockcount > mval[-1].br_blockcount);
-                       ASSERT(mval->br_state == mval[-1].br_state);
-                       mval[-1].br_blockcount = mval->br_blockcount;
-                       mval[-1].br_state = mval->br_state;
-               } else if (n > 0 && mval->br_startblock != DELAYSTARTBLOCK &&
-                          mval[-1].br_startblock != DELAYSTARTBLOCK &&
-                          mval[-1].br_startblock != HOLESTARTBLOCK &&
-                          mval->br_startblock ==
-                          mval[-1].br_startblock + mval[-1].br_blockcount &&
-                          ((flags & XFS_BMAPI_IGSTATE) ||
-                               mval[-1].br_state == mval->br_state)) {
-                       ASSERT(mval->br_startoff ==
-                              mval[-1].br_startoff + mval[-1].br_blockcount);
-                       mval[-1].br_blockcount += mval->br_blockcount;
-               } else if (n > 0 &&
-                          mval->br_startblock == DELAYSTARTBLOCK &&
-                          mval[-1].br_startblock == DELAYSTARTBLOCK &&
-                          mval->br_startoff ==
-                          mval[-1].br_startoff + mval[-1].br_blockcount) {
-                       mval[-1].br_blockcount += mval->br_blockcount;
-                       mval[-1].br_state = mval->br_state;
-               } else if (!((n == 0) &&
-                            ((mval->br_startoff + mval->br_blockcount) <=
-                             obno))) {
-                       mval++;
-                       n++;
-               }
                /*
                 * If we're done, stop now.  Stop when we've allocated
                 * XFS_BMAP_MAX_NMAP extents no matter what.  Otherwise
                 * the transaction may get too big.
                 */
-               if (bno >= end || n >= *nmap || nallocs >= *nmap)
+               if (bno >= end || n >= *nmap || bma.nallocs >= *nmap)
                        break;
-               /*
-                * Else go on to the next record.
-                */
-               prev = got;
-               if (++lastx < nextents) {
-                       ep = xfs_iext_get_ext(ifp, lastx);
-                       xfs_bmbt_get_all(ep, &got);
-               } else {
+
+               /* Else go on to the next record. */
+               bma.prev = bma.got;
+               if (++bma.idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) {
+                       xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma.idx),
+                                        &bma.got);
+               } else
                        eof = 1;
-               }
        }
        *nmap = n;
+
        /*
         * Transform from btree to extents, give it cur.
         */
-       if (tp && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
+       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
            XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) {
-               ASSERT(wr && cur);
-               error = xfs_bmap_btree_to_extents(tp, ip, cur,
+               int             tmp_logflags = 0;
+
+               ASSERT(bma.cur);
+               error = xfs_bmap_btree_to_extents(tp, ip, bma.cur,
                        &tmp_logflags, whichfork);
-               logflags |= tmp_logflags;
+               bma.logflags |= tmp_logflags;
                if (error)
                        goto error0;
        }
@@ -4855,34 +4984,33 @@ error0:
         * Log everything.  Do this after conversion, there's no point in
         * logging the extent records if we've converted to btree format.
         */
-       if ((logflags & xfs_ilog_fext(whichfork)) &&
+       if ((bma.logflags & xfs_ilog_fext(whichfork)) &&
            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
-               logflags &= ~xfs_ilog_fext(whichfork);
-       else if ((logflags & xfs_ilog_fbroot(whichfork)) &&
+               bma.logflags &= ~xfs_ilog_fext(whichfork);
+       else if ((bma.logflags & xfs_ilog_fbroot(whichfork)) &&
                 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)
-               logflags &= ~xfs_ilog_fbroot(whichfork);
+               bma.logflags &= ~xfs_ilog_fbroot(whichfork);
        /*
         * Log whatever the flags say, even if error.  Otherwise we might miss
         * detecting a case where the data is changed, there's an error,
         * and it's not logged so we don't shutdown when we should.
         */
-       if (logflags) {
-               ASSERT(tp && wr);
-               xfs_trans_log_inode(tp, ip, logflags);
-       }
-       if (cur) {
+       if (bma.logflags)
+               xfs_trans_log_inode(tp, ip, bma.logflags);
+
+       if (bma.cur) {
                if (!error) {
                        ASSERT(*firstblock == NULLFSBLOCK ||
                               XFS_FSB_TO_AGNO(mp, *firstblock) ==
                               XFS_FSB_TO_AGNO(mp,
-                                      cur->bc_private.b.firstblock) ||
+                                      bma.cur->bc_private.b.firstblock) ||
                               (flist->xbf_low &&
                                XFS_FSB_TO_AGNO(mp, *firstblock) <
                                XFS_FSB_TO_AGNO(mp,
-                                       cur->bc_private.b.firstblock)));
-                       *firstblock = cur->bc_private.b.firstblock;
+                                       bma.cur->bc_private.b.firstblock)));
+                       *firstblock = bma.cur->bc_private.b.firstblock;
                }
-               xfs_btree_del_cursor(cur,
+               xfs_btree_del_cursor(bma.cur,
                        error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
        }
        if (!error)
@@ -4892,58 +5020,6 @@ error0:
 }
 
 /*
- * Map file blocks to filesystem blocks, simple version.
- * One block (extent) only, read-only.
- * For flags, only the XFS_BMAPI_ATTRFORK flag is examined.
- * For the other flag values, the effect is as if XFS_BMAPI_METADATA
- * was set and all the others were clear.
- */
-int                                            /* error */
-xfs_bmapi_single(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *ip,            /* incore inode */
-       int             whichfork,      /* data or attr fork */
-       xfs_fsblock_t   *fsb,           /* output: mapped block */
-       xfs_fileoff_t   bno)            /* starting file offs. mapped */
-{
-       int             eof;            /* we've hit the end of extents */
-       int             error;          /* error return */
-       xfs_bmbt_irec_t got;            /* current file extent record */
-       xfs_ifork_t     *ifp;           /* inode fork pointer */
-       xfs_extnum_t    lastx;          /* last useful extent number */
-       xfs_bmbt_irec_t prev;           /* previous file extent record */
-
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (unlikely(
-           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
-           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)) {
-              XFS_ERROR_REPORT("xfs_bmapi_single", XFS_ERRLEVEL_LOW,
-                               ip->i_mount);
-              return XFS_ERROR(EFSCORRUPTED);
-       }
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
-               return XFS_ERROR(EIO);
-       XFS_STATS_INC(xs_blk_mapr);
-       if (!(ifp->if_flags & XFS_IFEXTENTS) &&
-           (error = xfs_iread_extents(tp, ip, whichfork)))
-               return error;
-       (void)xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
-               &prev);
-       /*
-        * Reading past eof, act as though there's a hole
-        * up to end.
-        */
-       if (eof || got.br_startoff > bno) {
-               *fsb = NULLFSBLOCK;
-               return 0;
-       }
-       ASSERT(!isnullstartblock(got.br_startblock));
-       ASSERT(bno < got.br_startoff + got.br_blockcount);
-       *fsb = got.br_startblock + (bno - got.br_startoff);
-       return 0;
-}
-
-/*
  * Unmap (remove) blocks from a file.
  * If nexts is nonzero then the number of extents to remove is limited to
  * that value.  If not all extents in the block range can be removed then
@@ -5114,9 +5190,9 @@ xfs_bunmapi(
                                del.br_blockcount = mod;
                        }
                        del.br_state = XFS_EXT_UNWRITTEN;
-                       error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, &del,
-                               firstblock, flist, &logflags,
-                               XFS_DATA_FORK);
+                       error = xfs_bmap_add_extent_unwritten_real(tp, ip,
+                                       &lastx, &cur, &del, firstblock, flist,
+                                       &logflags);
                        if (error)
                                goto error0;
                        goto nodelete;
@@ -5172,18 +5248,18 @@ xfs_bunmapi(
                                }
                                prev.br_state = XFS_EXT_UNWRITTEN;
                                lastx--;
-                               error = xfs_bmap_add_extent(tp, ip, &lastx,
-                                               &cur, &prev, firstblock, flist,
-                                               &logflags, XFS_DATA_FORK);
+                               error = xfs_bmap_add_extent_unwritten_real(tp,
+                                               ip, &lastx, &cur, &prev,
+                                               firstblock, flist, &logflags);
                                if (error)
                                        goto error0;
                                goto nodelete;
                        } else {
                                ASSERT(del.br_state == XFS_EXT_NORM);
                                del.br_state = XFS_EXT_UNWRITTEN;
-                               error = xfs_bmap_add_extent(tp, ip, &lastx,
-                                               &cur, &del, firstblock, flist,
-                                               &logflags, XFS_DATA_FORK);
+                               error = xfs_bmap_add_extent_unwritten_real(tp,
+                                               ip, &lastx, &cur, &del,
+                                               firstblock, flist, &logflags);
                                if (error)
                                        goto error0;
                                goto nodelete;
@@ -5505,10 +5581,9 @@ xfs_getbmap(
 
        do {
                nmap = (nexleft > subnex) ? subnex : nexleft;
-               error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
-                                 XFS_BB_TO_FSB(mp, bmv->bmv_length),
-                                 bmapi_flags, NULL, 0, map, &nmap,
-                                 NULL);
+               error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
+                                      XFS_BB_TO_FSB(mp, bmv->bmv_length),
+                                      map, &nmap, bmapi_flags);
                if (error)
                        goto out_free_map;
                ASSERT(nmap <= subnex);
@@ -5582,89 +5657,6 @@ xfs_getbmap(
        return error;
 }
 
-/*
- * Check the last inode extent to determine whether this allocation will result
- * in blocks being allocated at the end of the file. When we allocate new data
- * blocks at the end of the file which do not start at the previous data block,
- * we will try to align the new blocks at stripe unit boundaries.
- */
-STATIC int                             /* error */
-xfs_bmap_isaeof(
-       xfs_inode_t     *ip,            /* incore inode pointer */
-       xfs_fileoff_t   off,            /* file offset in fsblocks */
-       int             whichfork,      /* data or attribute fork */
-       char            *aeof)          /* return value */
-{
-       int             error;          /* error return value */
-       xfs_ifork_t     *ifp;           /* inode fork pointer */
-       xfs_bmbt_rec_host_t *lastrec;   /* extent record pointer */
-       xfs_extnum_t    nextents;       /* number of file extents */
-       xfs_bmbt_irec_t s;              /* expanded extent record */
-
-       ASSERT(whichfork == XFS_DATA_FORK);
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (!(ifp->if_flags & XFS_IFEXTENTS) &&
-           (error = xfs_iread_extents(NULL, ip, whichfork)))
-               return error;
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       if (nextents == 0) {
-               *aeof = 1;
-               return 0;
-       }
-       /*
-        * Go to the last extent
-        */
-       lastrec = xfs_iext_get_ext(ifp, nextents - 1);
-       xfs_bmbt_get_all(lastrec, &s);
-       /*
-        * Check we are allocating in the last extent (for delayed allocations)
-        * or past the last extent for non-delayed allocations.
-        */
-       *aeof = (off >= s.br_startoff &&
-                off < s.br_startoff + s.br_blockcount &&
-                isnullstartblock(s.br_startblock)) ||
-               off >= s.br_startoff + s.br_blockcount;
-       return 0;
-}
-
-/*
- * Check if the endoff is outside the last extent. If so the caller will grow
- * the allocation to a stripe unit boundary.
- */
-int                                    /* error */
-xfs_bmap_eof(
-       xfs_inode_t     *ip,            /* incore inode pointer */
-       xfs_fileoff_t   endoff,         /* file offset in fsblocks */
-       int             whichfork,      /* data or attribute fork */
-       int             *eof)           /* result value */
-{
-       xfs_fsblock_t   blockcount;     /* extent block count */
-       int             error;          /* error return value */
-       xfs_ifork_t     *ifp;           /* inode fork pointer */
-       xfs_bmbt_rec_host_t *lastrec;   /* extent record pointer */
-       xfs_extnum_t    nextents;       /* number of file extents */
-       xfs_fileoff_t   startoff;       /* extent starting file offset */
-
-       ASSERT(whichfork == XFS_DATA_FORK);
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (!(ifp->if_flags & XFS_IFEXTENTS) &&
-           (error = xfs_iread_extents(NULL, ip, whichfork)))
-               return error;
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       if (nextents == 0) {
-               *eof = 1;
-               return 0;
-       }
-       /*
-        * Go to the last extent
-        */
-       lastrec = xfs_iext_get_ext(ifp, nextents - 1);
-       startoff = xfs_bmbt_get_startoff(lastrec);
-       blockcount = xfs_bmbt_get_blockcount(lastrec);
-       *eof = endoff >= startoff + blockcount;
-       return 0;
-}
-
 #ifdef DEBUG
 STATIC struct xfs_buf *
 xfs_bmap_get_bp(
@@ -6099,9 +6091,8 @@ xfs_bmap_punch_delalloc_range(
                 * trying to remove a real extent (which requires a
                 * transaction) or a hole, which is probably a bad idea...
                 */
-               error = xfs_bmapi(NULL, ip, start_fsb, 1,
-                               XFS_BMAPI_ENTIRE,  NULL, 0, &imap,
-                               &nimaps, NULL);
+               error = xfs_bmapi_read(ip, start_fsb, 1, &imap, &nimaps,
+                                      XFS_BMAPI_ENTIRE);
 
                if (error) {
                        /* something screwed, just bail */
index c62234b..89ee672 100644 (file)
@@ -62,27 +62,23 @@ typedef     struct xfs_bmap_free
 #define        XFS_BMAP_MAX_NMAP       4
 
 /*
- * Flags for xfs_bmapi
+ * Flags for xfs_bmapi_*
  */
-#define        XFS_BMAPI_WRITE         0x001   /* write operation: allocate space */
-#define XFS_BMAPI_DELAY                0x002   /* delayed write operation */
-#define XFS_BMAPI_ENTIRE       0x004   /* return entire extent, not trimmed */
-#define XFS_BMAPI_METADATA     0x008   /* mapping metadata not user data */
-#define XFS_BMAPI_ATTRFORK     0x010   /* use attribute fork not data */
-#define        XFS_BMAPI_PREALLOC      0x040   /* preallocation op: unwritten space */
-#define        XFS_BMAPI_IGSTATE       0x080   /* Ignore state - */
+#define XFS_BMAPI_ENTIRE       0x001   /* return entire extent, not trimmed */
+#define XFS_BMAPI_METADATA     0x002   /* mapping metadata not user data */
+#define XFS_BMAPI_ATTRFORK     0x004   /* use attribute fork not data */
+#define XFS_BMAPI_PREALLOC     0x008   /* preallocation op: unwritten space */
+#define XFS_BMAPI_IGSTATE      0x010   /* Ignore state - */
                                        /* combine contig. space */
-#define        XFS_BMAPI_CONTIG        0x100   /* must allocate only one extent */
+#define XFS_BMAPI_CONTIG       0x020   /* must allocate only one extent */
 /*
  * unwritten extent conversion - this needs write cache flushing and no additional
  * allocation alignments. When specified with XFS_BMAPI_PREALLOC it converts
  * from written to unwritten, otherwise convert from unwritten to written.
  */
-#define XFS_BMAPI_CONVERT      0x200
+#define XFS_BMAPI_CONVERT      0x040
 
 #define XFS_BMAPI_FLAGS \
-       { XFS_BMAPI_WRITE,      "WRITE" }, \
-       { XFS_BMAPI_DELAY,      "DELAY" }, \
        { XFS_BMAPI_ENTIRE,     "ENTIRE" }, \
        { XFS_BMAPI_METADATA,   "METADATA" }, \
        { XFS_BMAPI_ATTRFORK,   "ATTRFORK" }, \
@@ -113,21 +109,28 @@ static inline void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp)
  * Argument structure for xfs_bmap_alloc.
  */
 typedef struct xfs_bmalloca {
-       xfs_fsblock_t           firstblock; /* i/o first block allocated */
-       xfs_fsblock_t           rval;   /* starting block of new extent */
-       xfs_fileoff_t           off;    /* offset in file filling in */
+       xfs_fsblock_t           *firstblock; /* i/o first block allocated */
+       struct xfs_bmap_free    *flist; /* bmap freelist */
        struct xfs_trans        *tp;    /* transaction pointer */
        struct xfs_inode        *ip;    /* incore inode pointer */
-       struct xfs_bmbt_irec    *prevp; /* extent before the new one */
-       struct xfs_bmbt_irec    *gotp;  /* extent after, or delayed */
-       xfs_extlen_t            alen;   /* i/o length asked/allocated */
+       struct xfs_bmbt_irec    prev;   /* extent before the new one */
+       struct xfs_bmbt_irec    got;    /* extent after, or delayed */
+
+       xfs_fileoff_t           offset; /* offset in file filling in */
+       xfs_extlen_t            length; /* i/o length asked/allocated */
+       xfs_fsblock_t           blkno;  /* starting block of new extent */
+
+       struct xfs_btree_cur    *cur;   /* btree cursor */
+       xfs_extnum_t            idx;    /* current extent index */
+       int                     nallocs;/* number of extents alloc'd */
+       int                     logflags;/* flags for transaction logging */
+
        xfs_extlen_t            total;  /* total blocks needed for xaction */
        xfs_extlen_t            minlen; /* minimum allocation size (blocks) */
        xfs_extlen_t            minleft; /* amount must be left after alloc */
        char                    eof;    /* set if allocating past last extent */
        char                    wasdel; /* replacing a delayed allocation */
        char                    userdata;/* set if is user data */
-       char                    low;    /* low on space, using seq'l ags */
        char                    aeof;   /* allocated space at eof */
        char                    conv;   /* overwriting unwritten extents */
 } xfs_bmalloca_t;
@@ -152,251 +155,62 @@ typedef struct xfs_bmalloca {
        { BMAP_RIGHT_FILLING,   "RF" }, \
        { BMAP_ATTRFORK,        "ATTR" }
 
-/*
- * Add bmap trace insert entries for all the contents of the extent list.
- *
- * Quite excessive tracing.  Only do this for debug builds.
- */
 #if defined(__KERNEL) && defined(DEBUG)
-void
-xfs_bmap_trace_exlist(
-       struct xfs_inode        *ip,            /* incore inode pointer */
-       xfs_extnum_t            cnt,            /* count of entries in list */
-       int                     whichfork,
-       unsigned long           caller_ip);     /* data or attr fork */
+void   xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,
+               int whichfork, unsigned long caller_ip);
 #define        XFS_BMAP_TRACE_EXLIST(ip,c,w)   \
        xfs_bmap_trace_exlist(ip,c,w, _THIS_IP_)
 #else
 #define        XFS_BMAP_TRACE_EXLIST(ip,c,w)
 #endif
 
-/*
- * Convert inode from non-attributed to attributed.
- * Must not be in a transaction, ip must not be locked.
- */
-int                                    /* error code */
-xfs_bmap_add_attrfork(
-       struct xfs_inode        *ip,    /* incore inode pointer */
-       int                     size,   /* space needed for new attribute */
-       int                     rsvd);  /* flag for reserved block allocation */
-
-/*
- * 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(
-       xfs_fsblock_t           bno,            /* fs block number of extent */
-       xfs_filblks_t           len,            /* length of extent */
-       xfs_bmap_free_t         *flist,         /* list of extents */
-       struct xfs_mount        *mp);           /* mount point structure */
-
-/*
- * Routine to clean up the free list data structure when
- * an error occurs during a transaction.
- */
-void
-xfs_bmap_cancel(
-       xfs_bmap_free_t         *flist);        /* free list to clean up */
-
-/*
- * Compute and fill in the value of the maximum depth of a bmap btree
- * in this filesystem.  Done once, during mount.
- */
-void
-xfs_bmap_compute_maxlevels(
-       struct xfs_mount        *mp,    /* file system mount structure */
-       int                     whichfork);     /* data or attr fork */
-
-/*
- * Returns the file-relative block number of the first unused block in the file.
- * This is the lowest-address hole if the file has holes, else the first block
- * past the end of file.
- */
-int                                            /* error */
-xfs_bmap_first_unused(
-       struct xfs_trans        *tp,            /* transaction pointer */
-       struct xfs_inode        *ip,            /* incore inode */
-       xfs_extlen_t            len,            /* size of hole to find */
-       xfs_fileoff_t           *unused,        /* unused block num */
-       int                     whichfork);     /* data or attr fork */
-
-/*
- * Returns the file-relative block number of the last block + 1 before
- * last_block (input value) in the file.
- * This is not based on i_size, it is based on the extent list.
- * Returns 0 for local files, as they do not have an extent list.
- */
-int                                            /* error */
-xfs_bmap_last_before(
-       struct xfs_trans        *tp,            /* transaction pointer */
-       struct xfs_inode        *ip,            /* incore inode */
-       xfs_fileoff_t           *last_block,    /* last block */
-       int                     whichfork);     /* data or attr fork */
-
-/*
- * Returns the file-relative block number of the first block past eof in
- * the file.  This is not based on i_size, it is based on the extent list.
- * Returns 0 for local files, as they do not have an extent list.
- */
-int                                            /* error */
-xfs_bmap_last_offset(
-       struct xfs_trans        *tp,            /* transaction pointer */
-       struct xfs_inode        *ip,            /* incore inode */
-       xfs_fileoff_t           *unused,        /* last block num */
-       int                     whichfork);     /* data or attr fork */
-
-/*
- * 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
-xfs_bmap_one_block(
-       struct xfs_inode        *ip,            /* incore inode */
-       int                     whichfork);     /* data or attr fork */
-
-/*
- * Read in the extents to iu_extents.
- * All inode fields are set up by caller, we just traverse the btree
- * and copy the records in.
- */
-int                                            /* error */
-xfs_bmap_read_extents(
-       struct xfs_trans        *tp,            /* transaction pointer */
-       struct xfs_inode        *ip,            /* incore inode */
-       int                     whichfork);     /* data or attr fork */
-
-/*
- * Map file blocks to filesystem blocks.
- * File range is given by the bno/len pair.
- * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set)
- * into a hole or past eof.
- * Only allocates blocks from a single allocation group,
- * to avoid locking problems.
- * The returned value in "firstblock" from the first call in a transaction
- * must be remembered and presented to subsequent calls in "firstblock".
- * An upper bound for the number of blocks to be allocated is supplied to
- * the first call in "total"; if no allocation group has that many free
- * blocks then the call will fail (return NULLFSBLOCK in "firstblock").
- */
-int                                            /* error */
-xfs_bmapi(
-       struct xfs_trans        *tp,            /* transaction pointer */
-       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_... */
-       xfs_fsblock_t           *firstblock,    /* first allocated block
-                                                  controls a.g. for allocs */
-       xfs_extlen_t            total,          /* total blocks needed */
-       struct xfs_bmbt_irec    *mval,          /* output: map values */
-       int                     *nmap,          /* i/o: mval size/count */
-       xfs_bmap_free_t         *flist);        /* i/o: list extents to free */
-
-/*
- * Map file blocks to filesystem blocks, simple version.
- * One block only, read-only.
- * For flags, only the XFS_BMAPI_ATTRFORK flag is examined.
- * For the other flag values, the effect is as if XFS_BMAPI_METADATA
- * was set and all the others were clear.
- */
-int                                            /* error */
-xfs_bmapi_single(
-       struct xfs_trans        *tp,            /* transaction pointer */
-       struct xfs_inode        *ip,            /* incore inode */
-       int                     whichfork,      /* data or attr fork */
-       xfs_fsblock_t           *fsb,           /* output: mapped block */
-       xfs_fileoff_t           bno);           /* starting file offs. mapped */
-
-/*
- * Unmap (remove) blocks from a file.
- * If nexts is nonzero then the number of extents to remove is limited to
- * that value.  If not all extents in the block range can be removed then
- * *done is set.
- */
-int                                            /* error */
-xfs_bunmapi(
-       struct xfs_trans        *tp,            /* transaction pointer */
-       struct xfs_inode        *ip,            /* incore inode */
-       xfs_fileoff_t           bno,            /* starting offset to unmap */
-       xfs_filblks_t           len,            /* length to unmap in file */
-       int                     flags,          /* XFS_BMAPI_... */
-       xfs_extnum_t            nexts,          /* number of extents max */
-       xfs_fsblock_t           *firstblock,    /* first allocated block
-                                                  controls a.g. for allocs */
-       xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
-       int                     *done);         /* set if not done yet */
-
-/*
- * Check an extent list, which has just been read, for
- * any bit in the extent flag field.
- */
-int
-xfs_check_nostate_extents(
-       struct xfs_ifork        *ifp,
-       xfs_extnum_t            idx,
-       xfs_extnum_t            num);
-
-uint
-xfs_default_attroffset(
-       struct xfs_inode        *ip);
+int    xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
+void   xfs_bmap_add_free(xfs_fsblock_t bno, xfs_filblks_t len,
+               struct xfs_bmap_free *flist, struct xfs_mount *mp);
+void   xfs_bmap_cancel(struct xfs_bmap_free *flist);
+void   xfs_bmap_compute_maxlevels(struct xfs_mount *mp, int whichfork);
+int    xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip,
+               xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork);
+int    xfs_bmap_last_before(struct xfs_trans *tp, struct xfs_inode *ip,
+               xfs_fileoff_t *last_block, int whichfork);
+int    xfs_bmap_last_offset(struct xfs_trans *tp, struct xfs_inode *ip,
+               xfs_fileoff_t *unused, int whichfork);
+int    xfs_bmap_one_block(struct xfs_inode *ip, int whichfork);
+int    xfs_bmap_read_extents(struct xfs_trans *tp, struct xfs_inode *ip,
+               int whichfork);
+int    xfs_bmapi_read(struct xfs_inode *ip, xfs_fileoff_t bno,
+               xfs_filblks_t len, struct xfs_bmbt_irec *mval,
+               int *nmap, int flags);
+int    xfs_bmapi_delay(struct xfs_inode *ip, xfs_fileoff_t bno,
+               xfs_filblks_t len, struct xfs_bmbt_irec *mval,
+               int *nmap, int flags);
+int    xfs_bmapi_write(struct xfs_trans *tp, struct xfs_inode *ip,
+               xfs_fileoff_t bno, xfs_filblks_t len, int flags,
+               xfs_fsblock_t *firstblock, xfs_extlen_t total,
+               struct xfs_bmbt_irec *mval, int *nmap,
+               struct xfs_bmap_free *flist);
+int    xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip,
+               xfs_fileoff_t bno, xfs_filblks_t len, int flags,
+               xfs_extnum_t nexts, xfs_fsblock_t *firstblock,
+               struct xfs_bmap_free *flist, int *done);
+int    xfs_check_nostate_extents(struct xfs_ifork *ifp, xfs_extnum_t idx,
+               xfs_extnum_t num);
+uint   xfs_default_attroffset(struct xfs_inode *ip);
 
 #ifdef __KERNEL__
-
-/*
- * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
- * caller.  Frees all the extents that need freeing, which must be done
- * last due to locking considerations.
- *
- * Return 1 if the given transaction was committed and a new one allocated,
- * and 0 otherwise.
- */
-int                                            /* error */
-xfs_bmap_finish(
-       struct xfs_trans        **tp,           /* transaction pointer addr */
-       xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
-       int                     *committed);    /* xact committed or not */
-
 /* bmap to userspace formatter - copy to user & advance pointer */
 typedef int (*xfs_bmap_format_t)(void **, struct getbmapx *, int *);
 
-/*
- * Get inode's extents as described in bmv, and format for output.
- */
-int                                            /* error code */
-xfs_getbmap(
-       xfs_inode_t             *ip,
-       struct getbmapx         *bmv,           /* user bmap structure */
-       xfs_bmap_format_t       formatter,      /* format to user */
-       void                    *arg);          /* formatter arg */
-
-/*
- * Check if the endoff is outside the last extent. If so the caller will grow
- * the allocation to a stripe unit boundary
- */
-int
-xfs_bmap_eof(
-       struct xfs_inode        *ip,
-       xfs_fileoff_t           endoff,
-       int                     whichfork,
-       int                     *eof);
-
-/*
- * Count fsblocks of the given fork.
- */
-int
-xfs_bmap_count_blocks(
-       xfs_trans_t             *tp,
-       struct xfs_inode        *ip,
-       int                     whichfork,
-       int                     *count);
-
-int
-xfs_bmap_punch_delalloc_range(
-       struct xfs_inode        *ip,
-       xfs_fileoff_t           start_fsb,
-       xfs_fileoff_t           length);
+int    xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist,
+               int *committed);
+int    xfs_getbmap(struct xfs_inode *ip, struct getbmapx *bmv,
+               xfs_bmap_format_t formatter, void *arg);
+int    xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff,
+               int whichfork, int *eof);
+int    xfs_bmap_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
+               int whichfork, int *count);
+int    xfs_bmap_punch_delalloc_range(struct xfs_inode *ip,
+               xfs_fileoff_t start_fsb, xfs_fileoff_t length);
 #endif /* __KERNEL__ */
 
 #endif /* __XFS_BMAP_H__ */
index 2b9fd38..1f19f03 100644 (file)
@@ -631,7 +631,7 @@ xfs_btree_read_bufl(
        }
        ASSERT(!xfs_buf_geterror(bp));
        if (bp)
-               XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval);
+               xfs_buf_set_ref(bp, refval);
        *bpp = bp;
        return 0;
 }
@@ -939,13 +939,13 @@ xfs_btree_set_refs(
        switch (cur->bc_btnum) {
        case XFS_BTNUM_BNO:
        case XFS_BTNUM_CNT:
-               XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, XFS_ALLOC_BTREE_REF);
+               xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF);
                break;
        case XFS_BTNUM_INO:
-               XFS_BUF_SET_VTYPE_REF(bp, B_FS_INOMAP, XFS_INO_BTREE_REF);
+               xfs_buf_set_ref(bp, XFS_INO_BTREE_REF);
                break;
        case XFS_BTNUM_BMAP:
-               XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, XFS_BMAP_BTREE_REF);
+               xfs_buf_set_ref(bp, XFS_BMAP_BTREE_REF);
                break;
        default:
                ASSERT(0);
@@ -970,7 +970,8 @@ xfs_btree_get_buf_block(
        *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
                                 mp->m_bsize, flags);
 
-       ASSERT(!xfs_buf_geterror(*bpp));
+       if (!*bpp)
+               return ENOMEM;
 
        *block = XFS_BUF_TO_BLOCK(*bpp);
        return 0;
index c57836d..cf0ac05 100644 (file)
@@ -43,7 +43,6 @@
 
 static kmem_zone_t *xfs_buf_zone;
 STATIC int xfsbufd(void *);
-STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int);
 
 static struct workqueue_struct *xfslogd_workqueue;
 struct workqueue_struct *xfsdatad_workqueue;
@@ -66,10 +65,6 @@ struct workqueue_struct *xfsconvertd_workqueue;
 #define xb_to_km(flags) \
         (((flags) & XBF_DONT_BLOCK) ? KM_NOFS : KM_SLEEP)
 
-#define xfs_buf_allocate(flags) \
-       kmem_zone_alloc(xfs_buf_zone, xb_to_km(flags))
-#define xfs_buf_deallocate(bp) \
-       kmem_zone_free(xfs_buf_zone, (bp));
 
 static inline int
 xfs_buf_is_vmapped(
@@ -152,6 +147,7 @@ xfs_buf_stale(
        struct xfs_buf  *bp)
 {
        bp->b_flags |= XBF_STALE;
+       xfs_buf_delwri_dequeue(bp);
        atomic_set(&(bp)->b_lru_ref, 0);
        if (!list_empty(&bp->b_lru)) {
                struct xfs_buftarg *btp = bp->b_target;
@@ -167,14 +163,19 @@ xfs_buf_stale(
        ASSERT(atomic_read(&bp->b_hold) >= 1);
 }
 
-STATIC void
-_xfs_buf_initialize(
-       xfs_buf_t               *bp,
-       xfs_buftarg_t           *target,
+struct xfs_buf *
+xfs_buf_alloc(
+       struct xfs_buftarg      *target,
        xfs_off_t               range_base,
        size_t                  range_length,
        xfs_buf_flags_t         flags)
 {
+       struct xfs_buf          *bp;
+
+       bp = kmem_zone_alloc(xfs_buf_zone, xb_to_km(flags));
+       if (unlikely(!bp))
+               return NULL;
+
        /*
         * We don't want certain flags to appear in b_flags.
         */
@@ -203,8 +204,9 @@ _xfs_buf_initialize(
        init_waitqueue_head(&bp->b_waiters);
 
        XFS_STATS_INC(xb_create);
-
        trace_xfs_buf_init(bp, _RET_IP_);
+
+       return bp;
 }
 
 /*
@@ -277,7 +279,7 @@ xfs_buf_free(
        } else if (bp->b_flags & _XBF_KMEM)
                kmem_free(bp->b_addr);
        _xfs_buf_free_pages(bp);
-       xfs_buf_deallocate(bp);
+       kmem_zone_free(xfs_buf_zone, bp);
 }
 
 /*
@@ -416,10 +418,7 @@ _xfs_buf_map_pages(
 /*
  *     Look up, and creates if absent, a lockable buffer for
  *     a given range of an inode.  The buffer is returned
- *     locked.  If other overlapping buffers exist, they are
- *     released before the new buffer is created and locked,
- *     which may imply that this call will block until those buffers
- *     are unlocked.  No I/O is implied by this call.
+ *     locked. No I/O is implied by this call.
  */
 xfs_buf_t *
 _xfs_buf_find(
@@ -481,8 +480,6 @@ _xfs_buf_find(
 
        /* No match found */
        if (new_bp) {
-               _xfs_buf_initialize(new_bp, btp, range_base,
-                               range_length, flags);
                rb_link_node(&new_bp->b_rbnode, parent, rbp);
                rb_insert_color(&new_bp->b_rbnode, &pag->pag_buf_tree);
                /* the buffer keeps the perag reference until it is freed */
@@ -525,35 +522,51 @@ found:
 }
 
 /*
- *     Assembles a buffer covering the specified range.
- *     Storage in memory for all portions of the buffer will be allocated,
- *     although backing storage may not be.
+ * Assembles a buffer covering the specified range. The code is optimised for
+ * cache hits, as metadata intensive workloads will see 3 orders of magnitude
+ * more hits than misses.
  */
-xfs_buf_t *
+struct xfs_buf *
 xfs_buf_get(
        xfs_buftarg_t           *target,/* target for buffer            */
        xfs_off_t               ioff,   /* starting offset of range     */
        size_t                  isize,  /* length of range              */
        xfs_buf_flags_t         flags)
 {
-       xfs_buf_t               *bp, *new_bp;
+       struct xfs_buf          *bp;
+       struct xfs_buf          *new_bp;
        int                     error = 0;
 
-       new_bp = xfs_buf_allocate(flags);
+       bp = _xfs_buf_find(target, ioff, isize, flags, NULL);
+       if (likely(bp))
+               goto found;
+
+       new_bp = xfs_buf_alloc(target, ioff << BBSHIFT, isize << BBSHIFT,
+                              flags);
        if (unlikely(!new_bp))
                return NULL;
 
        bp = _xfs_buf_find(target, ioff, isize, flags, new_bp);
+       if (!bp) {
+               kmem_zone_free(xfs_buf_zone, new_bp);
+               return NULL;
+       }
+
        if (bp == new_bp) {
                error = xfs_buf_allocate_memory(bp, flags);
                if (error)
                        goto no_buffer;
-       } else {
-               xfs_buf_deallocate(new_bp);
-               if (unlikely(bp == NULL))
-                       return NULL;
-       }
+       } else
+               kmem_zone_free(xfs_buf_zone, new_bp);
 
+       /*
+        * Now we have a workable buffer, fill in the block number so
+        * that we can do IO on it.
+        */
+       bp->b_bn = ioff;
+       bp->b_count_desired = bp->b_buffer_length;
+
+found:
        if (!(bp->b_flags & XBF_MAPPED)) {
                error = _xfs_buf_map_pages(bp, flags);
                if (unlikely(error)) {
@@ -564,18 +577,10 @@ xfs_buf_get(
        }
 
        XFS_STATS_INC(xb_get);
-
-       /*
-        * Always fill in the block number now, the mapped cases can do
-        * their own overlay of this later.
-        */
-       bp->b_bn = ioff;
-       bp->b_count_desired = bp->b_buffer_length;
-
        trace_xfs_buf_get(bp, flags, _RET_IP_);
        return bp;
 
- no_buffer:
+no_buffer:
        if (flags & (XBF_LOCK | XBF_TRYLOCK))
                xfs_buf_unlock(bp);
        xfs_buf_rele(bp);
@@ -689,19 +694,6 @@ xfs_buf_read_uncached(
        return bp;
 }
 
-xfs_buf_t *
-xfs_buf_get_empty(
-       size_t                  len,
-       xfs_buftarg_t           *target)
-{
-       xfs_buf_t               *bp;
-
-       bp = xfs_buf_allocate(0);
-       if (bp)
-               _xfs_buf_initialize(bp, target, 0, len, 0);
-       return bp;
-}
-
 /*
  * Return a buffer allocated as an empty buffer and associated to external
  * memory via xfs_buf_associate_memory() back to it's empty state.
@@ -787,10 +779,9 @@ xfs_buf_get_uncached(
        int                     error, i;
        xfs_buf_t               *bp;
 
-       bp = xfs_buf_allocate(0);
+       bp = xfs_buf_alloc(target, 0, len, 0);
        if (unlikely(bp == NULL))
                goto fail;
-       _xfs_buf_initialize(bp, target, 0, len, 0);
 
        error = _xfs_buf_get_pages(bp, page_count, 0);
        if (error)
@@ -818,7 +809,7 @@ xfs_buf_get_uncached(
                __free_page(bp->b_pages[i]);
        _xfs_buf_free_pages(bp);
  fail_free_buf:
-       xfs_buf_deallocate(bp);
+       kmem_zone_free(xfs_buf_zone, bp);
  fail:
        return NULL;
 }
@@ -937,12 +928,6 @@ void
 xfs_buf_unlock(
        struct xfs_buf          *bp)
 {
-       if ((bp->b_flags & (XBF_DELWRI|_XBF_DELWRI_Q)) == XBF_DELWRI) {
-               atomic_inc(&bp->b_hold);
-               bp->b_flags |= XBF_ASYNC;
-               xfs_buf_delwri_queue(bp, 0);
-       }
-
        XB_CLEAR_OWNER(bp);
        up(&bp->b_sema);
 
@@ -1019,9 +1004,19 @@ xfs_buf_ioerror(
        trace_xfs_buf_ioerror(bp, error, _RET_IP_);
 }
 
+void
+xfs_buf_ioerror_alert(
+       struct xfs_buf          *bp,
+       const char              *func)
+{
+       xfs_alert(bp->b_target->bt_mount,
+"metadata I/O error: block 0x%llx (\"%s\") error %d buf count %zd",
+               (__uint64_t)XFS_BUF_ADDR(bp), func,
+               bp->b_error, XFS_BUF_COUNT(bp));
+}
+
 int
 xfs_bwrite(
-       struct xfs_mount        *mp,
        struct xfs_buf          *bp)
 {
        int                     error;
@@ -1033,25 +1028,13 @@ xfs_bwrite(
        xfs_bdstrat_cb(bp);
 
        error = xfs_buf_iowait(bp);
-       if (error)
-               xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
-       xfs_buf_relse(bp);
+       if (error) {
+               xfs_force_shutdown(bp->b_target->bt_mount,
+                                  SHUTDOWN_META_IO_ERROR);
+       }
        return error;
 }
 
-void
-xfs_bdwrite(
-       void                    *mp,
-       struct xfs_buf          *bp)
-{
-       trace_xfs_buf_bdwrite(bp, _RET_IP_);
-
-       bp->b_flags &= ~XBF_READ;
-       bp->b_flags |= (XBF_DELWRI | XBF_ASYNC);
-
-       xfs_buf_delwri_queue(bp, 1);
-}
-
 /*
  * Called when we want to stop a buffer from getting written or read.
  * We attach the EIO error, muck with its flags, and call xfs_buf_ioend
@@ -1074,9 +1057,8 @@ xfs_bioerror(
         * We're calling xfs_buf_ioend, so delete XBF_DONE flag.
         */
        XFS_BUF_UNREAD(bp);
-       XFS_BUF_UNDELAYWRITE(bp);
        XFS_BUF_UNDONE(bp);
-       XFS_BUF_STALE(bp);
+       xfs_buf_stale(bp);
 
        xfs_buf_ioend(bp, 0);
 
@@ -1103,9 +1085,8 @@ xfs_bioerror_relse(
         * change that interface.
         */
        XFS_BUF_UNREAD(bp);
-       XFS_BUF_UNDELAYWRITE(bp);
        XFS_BUF_DONE(bp);
-       XFS_BUF_STALE(bp);
+       xfs_buf_stale(bp);
        bp->b_iodone = NULL;
        if (!(fl & XBF_ASYNC)) {
                /*
@@ -1115,7 +1096,7 @@ xfs_bioerror_relse(
                 * ASYNC buffers.
                 */
                xfs_buf_ioerror(bp, EIO);
-               XFS_BUF_FINISH_IOWAIT(bp);
+               complete(&bp->b_iowait);
        } else {
                xfs_buf_relse(bp);
        }
@@ -1275,15 +1256,10 @@ xfs_buf_iorequest(
 {
        trace_xfs_buf_iorequest(bp, _RET_IP_);
 
-       if (bp->b_flags & XBF_DELWRI) {
-               xfs_buf_delwri_queue(bp, 1);
-               return 0;
-       }
+       ASSERT(!(bp->b_flags & XBF_DELWRI));
 
-       if (bp->b_flags & XBF_WRITE) {
+       if (bp->b_flags & XBF_WRITE)
                xfs_buf_wait_unpin(bp);
-       }
-
        xfs_buf_hold(bp);
 
        /* Set the count to 1 initially, this will stop an I/O
@@ -1481,9 +1457,13 @@ xfs_setsize_buftarg_flags(
        btp->bt_smask = sectorsize - 1;
 
        if (set_blocksize(btp->bt_bdev, sectorsize)) {
+               char name[BDEVNAME_SIZE];
+
+               bdevname(btp->bt_bdev, name);
+
                xfs_warn(btp->bt_mount,
                        "Cannot set_blocksize to %u on device %s\n",
-                       sectorsize, xfs_buf_target_name(btp));
+                       sectorsize, name);
                return EINVAL;
        }
 
@@ -1514,12 +1494,12 @@ xfs_setsize_buftarg(
 }
 
 STATIC int
-xfs_alloc_delwrite_queue(
+xfs_alloc_delwri_queue(
        xfs_buftarg_t           *btp,
        const char              *fsname)
 {
-       INIT_LIST_HEAD(&btp->bt_delwrite_queue);
-       spin_lock_init(&btp->bt_delwrite_lock);
+       INIT_LIST_HEAD(&btp->bt_delwri_queue);
+       spin_lock_init(&btp->bt_delwri_lock);
        btp->bt_flags = 0;
        btp->bt_task = kthread_run(xfsbufd, btp, "xfsbufd/%s", fsname);
        if (IS_ERR(btp->bt_task))
@@ -1549,7 +1529,7 @@ xfs_alloc_buftarg(
        spin_lock_init(&btp->bt_lru_lock);
        if (xfs_setsize_buftarg_early(btp, bdev))
                goto error;
-       if (xfs_alloc_delwrite_queue(btp, fsname))
+       if (xfs_alloc_delwri_queue(btp, fsname))
                goto error;
        btp->bt_shrinker.shrink = xfs_buftarg_shrink;
        btp->bt_shrinker.seeks = DEFAULT_SEEKS;
@@ -1565,56 +1545,48 @@ error:
 /*
  *     Delayed write buffer handling
  */
-STATIC void
+void
 xfs_buf_delwri_queue(
-       xfs_buf_t               *bp,
-       int                     unlock)
+       xfs_buf_t               *bp)
 {
-       struct list_head        *dwq = &bp->b_target->bt_delwrite_queue;
-       spinlock_t              *dwlk = &bp->b_target->bt_delwrite_lock;
+       struct xfs_buftarg      *btp = bp->b_target;
 
        trace_xfs_buf_delwri_queue(bp, _RET_IP_);
 
-       ASSERT((bp->b_flags&(XBF_DELWRI|XBF_ASYNC)) == (XBF_DELWRI|XBF_ASYNC));
+       ASSERT(!(bp->b_flags & XBF_READ));
 
-       spin_lock(dwlk);
-       /* If already in the queue, dequeue and place at tail */
+       spin_lock(&btp->bt_delwri_lock);
        if (!list_empty(&bp->b_list)) {
+               /* if already in the queue, move it to the tail */
                ASSERT(bp->b_flags & _XBF_DELWRI_Q);
-               if (unlock)
-                       atomic_dec(&bp->b_hold);
-               list_del(&bp->b_list);
-       }
-
-       if (list_empty(dwq)) {
+               list_move_tail(&bp->b_list, &btp->bt_delwri_queue);
+       } else {
                /* start xfsbufd as it is about to have something to do */
-               wake_up_process(bp->b_target->bt_task);
-       }
+               if (list_empty(&btp->bt_delwri_queue))
+                       wake_up_process(bp->b_target->bt_task);
 
-       bp->b_flags |= _XBF_DELWRI_Q;
-       list_add_tail(&bp->b_list, dwq);
+               atomic_inc(&bp->b_hold);
+               bp->b_flags |= XBF_DELWRI | _XBF_DELWRI_Q | XBF_ASYNC;
+               list_add_tail(&bp->b_list, &btp->bt_delwri_queue);
+       }
        bp->b_queuetime = jiffies;
-       spin_unlock(dwlk);
-
-       if (unlock)
-               xfs_buf_unlock(bp);
+       spin_unlock(&btp->bt_delwri_lock);
 }
 
 void
 xfs_buf_delwri_dequeue(
        xfs_buf_t               *bp)
 {
-       spinlock_t              *dwlk = &bp->b_target->bt_delwrite_lock;
        int                     dequeued = 0;
 
-       spin_lock(dwlk);
+       spin_lock(&bp->b_target->bt_delwri_lock);
        if ((bp->b_flags & XBF_DELWRI) && !list_empty(&bp->b_list)) {
                ASSERT(bp->b_flags & _XBF_DELWRI_Q);
                list_del_init(&bp->b_list);
                dequeued = 1;
        }
        bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q);
-       spin_unlock(dwlk);
+       spin_unlock(&bp->b_target->bt_delwri_lock);
 
        if (dequeued)
                xfs_buf_rele(bp);
@@ -1646,16 +1618,9 @@ xfs_buf_delwri_promote(
        if (bp->b_queuetime < jiffies - age)
                return;
        bp->b_queuetime = jiffies - age;
-       spin_lock(&btp->bt_delwrite_lock);
-       list_move(&bp->b_list, &btp->bt_delwrite_queue);
-       spin_unlock(&btp->bt_delwrite_lock);
-}
-
-STATIC void
-xfs_buf_runall_queues(
-       struct workqueue_struct *queue)
-{
-       flush_workqueue(queue);
+       spin_lock(&btp->bt_delwri_lock);
+       list_move(&bp->b_list, &btp->bt_delwri_queue);
+       spin_unlock(&btp->bt_delwri_lock);
 }
 
 /*
@@ -1669,15 +1634,13 @@ xfs_buf_delwri_split(
        unsigned long   age)
 {
        xfs_buf_t       *bp, *n;
-       struct list_head *dwq = &target->bt_delwrite_queue;
-       spinlock_t      *dwlk = &target->bt_delwrite_lock;
        int             skipped = 0;
        int             force;
 
        force = test_and_clear_bit(XBT_FORCE_FLUSH, &target->bt_flags);
        INIT_LIST_HEAD(list);
-       spin_lock(dwlk);
-       list_for_each_entry_safe(bp, n, dwq, b_list) {
+       spin_lock(&target->bt_delwri_lock);
+       list_for_each_entry_safe(bp, n, &target->bt_delwri_queue, b_list) {
                ASSERT(bp->b_flags & XBF_DELWRI);
 
                if (!xfs_buf_ispinned(bp) && xfs_buf_trylock(bp)) {
@@ -1694,10 +1657,9 @@ xfs_buf_delwri_split(
                } else
                        skipped++;
        }
-       spin_unlock(dwlk);
 
+       spin_unlock(&target->bt_delwri_lock);
        return skipped;
-
 }
 
 /*
@@ -1747,7 +1709,7 @@ xfsbufd(
                }
 
                /* sleep for a long time if there is nothing to do. */
-               if (list_empty(&target->bt_delwrite_queue))
+               if (list_empty(&target->bt_delwri_queue))
                        tout = MAX_SCHEDULE_TIMEOUT;
                schedule_timeout_interruptible(tout);
 
@@ -1783,9 +1745,7 @@ xfs_flush_buftarg(
        LIST_HEAD(wait_list);
        struct blk_plug plug;
 
-       xfs_buf_runall_queues(xfsconvertd_workqueue);
-       xfs_buf_runall_queues(xfsdatad_workqueue);
-       xfs_buf_runall_queues(xfslogd_workqueue);
+       flush_workqueue(xfslogd_workqueue);
 
        set_bit(XBT_FORCE_FLUSH, &target->bt_flags);
        pincount = xfs_buf_delwri_split(target, &tmp_list, 0);
@@ -1866,11 +1826,3 @@ xfs_buf_terminate(void)
        destroy_workqueue(xfslogd_workqueue);
        kmem_zone_destroy(xfs_buf_zone);
 }
-
-#ifdef CONFIG_KDB_MODULES
-struct list_head *
-xfs_get_buftarg_list(void)
-{
-       return &xfs_buftarg_list;
-}
-#endif
index 620972b..5bab046 100644 (file)
@@ -105,8 +105,8 @@ typedef struct xfs_buftarg {
 
        /* per device delwri queue */
        struct task_struct      *bt_task;
-       struct list_head        bt_delwrite_queue;
-       spinlock_t              bt_delwrite_lock;
+       struct list_head        bt_delwri_queue;
+       spinlock_t              bt_delwri_lock;
        unsigned long           bt_flags;
 
        /* LRU control structures */
@@ -175,7 +175,8 @@ extern xfs_buf_t *xfs_buf_get(xfs_buftarg_t *, xfs_off_t, size_t,
 extern xfs_buf_t *xfs_buf_read(xfs_buftarg_t *, xfs_off_t, size_t,
                                xfs_buf_flags_t);
 
-extern xfs_buf_t *xfs_buf_get_empty(size_t, xfs_buftarg_t *);
+struct xfs_buf *xfs_buf_alloc(struct xfs_buftarg *, xfs_off_t, size_t,
+                             xfs_buf_flags_t);
 extern void xfs_buf_set_empty(struct xfs_buf *bp, size_t len);
 extern xfs_buf_t *xfs_buf_get_uncached(struct xfs_buftarg *, size_t, int);
 extern int xfs_buf_associate_memory(xfs_buf_t *, void *, size_t);
@@ -197,14 +198,14 @@ extern void xfs_buf_unlock(xfs_buf_t *);
        ((bp)->b_sema.count <= 0)
 
 /* Buffer Read and Write Routines */
-extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp);
-extern void xfs_bdwrite(void *mp, xfs_buf_t *bp);
+extern int xfs_bwrite(struct xfs_buf *bp);
 
 extern void xfsbdstrat(struct xfs_mount *, struct xfs_buf *);
 extern int xfs_bdstrat_cb(struct xfs_buf *);
 
 extern void xfs_buf_ioend(xfs_buf_t *, int);
 extern void xfs_buf_ioerror(xfs_buf_t *, int);
+extern void xfs_buf_ioerror_alert(struct xfs_buf *, const char *func);
 extern int xfs_buf_iorequest(xfs_buf_t *);
 extern int xfs_buf_iowait(xfs_buf_t *);
 extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
@@ -221,38 +222,22 @@ static inline int xfs_buf_geterror(xfs_buf_t *bp)
 extern xfs_caddr_t xfs_buf_offset(xfs_buf_t *, size_t);
 
 /* Delayed Write Buffer Routines */
-extern void xfs_buf_delwri_dequeue(xfs_buf_t *);
-extern void xfs_buf_delwri_promote(xfs_buf_t *);
+extern void xfs_buf_delwri_queue(struct xfs_buf *);
+extern void xfs_buf_delwri_dequeue(struct xfs_buf *);
+extern void xfs_buf_delwri_promote(struct xfs_buf *);
 
 /* Buffer Daemon Setup Routines */
 extern int xfs_buf_init(void);
 extern void xfs_buf_terminate(void);
 
-static inline const char *
-xfs_buf_target_name(struct xfs_buftarg *target)
-{
-       static char __b[BDEVNAME_SIZE];
-
-       return bdevname(target->bt_bdev, __b);
-}
-
-
 #define XFS_BUF_ZEROFLAGS(bp) \
        ((bp)->b_flags &= ~(XBF_READ|XBF_WRITE|XBF_ASYNC|XBF_DELWRI| \
                            XBF_SYNCIO|XBF_FUA|XBF_FLUSH))
 
 void xfs_buf_stale(struct xfs_buf *bp);
-#define XFS_BUF_STALE(bp)      xfs_buf_stale(bp);
 #define XFS_BUF_UNSTALE(bp)    ((bp)->b_flags &= ~XBF_STALE)
 #define XFS_BUF_ISSTALE(bp)    ((bp)->b_flags & XBF_STALE)
-#define XFS_BUF_SUPER_STALE(bp)        do {                            \
-                                       XFS_BUF_STALE(bp);      \
-                                       xfs_buf_delwri_dequeue(bp);     \
-                                       XFS_BUF_DONE(bp);       \
-                               } while (0)
-
-#define XFS_BUF_DELAYWRITE(bp)         ((bp)->b_flags |= XBF_DELWRI)
-#define XFS_BUF_UNDELAYWRITE(bp)       xfs_buf_delwri_dequeue(bp)
+
 #define XFS_BUF_ISDELAYWRITE(bp)       ((bp)->b_flags & XBF_DELWRI)
 
 #define XFS_BUF_DONE(bp)       ((bp)->b_flags |= XBF_DONE)
@@ -280,23 +265,16 @@ void xfs_buf_stale(struct xfs_buf *bp);
 #define XFS_BUF_SIZE(bp)               ((bp)->b_buffer_length)
 #define XFS_BUF_SET_SIZE(bp, cnt)      ((bp)->b_buffer_length = (cnt))
 
-static inline void
-xfs_buf_set_ref(
-       struct xfs_buf  *bp,
-       int             lru_ref)
+static inline void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref)
 {
        atomic_set(&bp->b_lru_ref, lru_ref);
 }
-#define XFS_BUF_SET_VTYPE_REF(bp, type, ref)   xfs_buf_set_ref(bp, ref)
-#define XFS_BUF_SET_VTYPE(bp, type)            do { } while (0)
 
 static inline int xfs_buf_ispinned(struct xfs_buf *bp)
 {
        return atomic_read(&bp->b_pin_count);
 }
 
-#define XFS_BUF_FINISH_IOWAIT(bp)      complete(&bp->b_iowait);
-
 static inline void xfs_buf_relse(xfs_buf_t *bp)
 {
        xfs_buf_unlock(bp);
@@ -313,14 +291,7 @@ extern void xfs_wait_buftarg(xfs_buftarg_t *);
 extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
 extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
 
-#ifdef CONFIG_KDB_MODULES
-extern struct list_head *xfs_get_buftarg_list(void);
-#endif
-
 #define xfs_getsize_buftarg(buftarg)   block_size((buftarg)->bt_bdev)
 #define xfs_readonly_buftarg(buftarg)  bdev_read_only((buftarg)->bt_bdev)
 
-#define xfs_binval(buftarg)            xfs_flush_buftarg(buftarg, 1)
-#define XFS_bflush(buftarg)            xfs_flush_buftarg(buftarg, 1)
-
 #endif /* __XFS_BUF_H__ */
index ef43fce..1a35138 100644 (file)
@@ -967,7 +967,8 @@ xfs_buf_iodone_callbacks(
         * I/O errors, there's no point in giving this a retry.
         */
        if (XFS_FORCED_SHUTDOWN(mp)) {
-               XFS_BUF_SUPER_STALE(bp);
+               xfs_buf_stale(bp);
+               XFS_BUF_DONE(bp);
                trace_xfs_buf_item_iodone(bp, _RET_IP_);
                goto do_callbacks;
        }
@@ -975,9 +976,7 @@ xfs_buf_iodone_callbacks(
        if (bp->b_target != lasttarg ||
            time_after(jiffies, (lasttime + 5*HZ))) {
                lasttime = jiffies;
-               xfs_alert(mp, "Device %s: metadata write error block 0x%llx",
-                       xfs_buf_target_name(bp->b_target),
-                     (__uint64_t)XFS_BUF_ADDR(bp));
+               xfs_buf_ioerror_alert(bp, __func__);
        }
        lasttarg = bp->b_target;
 
@@ -993,7 +992,7 @@ xfs_buf_iodone_callbacks(
                xfs_buf_ioerror(bp, 0); /* errno of 0 unsets the flag */
 
                if (!XFS_BUF_ISSTALE(bp)) {
-                       XFS_BUF_DELAYWRITE(bp);
+                       xfs_buf_delwri_queue(bp);
                        XFS_BUF_DONE(bp);
                }
                ASSERT(bp->b_iodone != NULL);
@@ -1006,9 +1005,8 @@ xfs_buf_iodone_callbacks(
         * If the write of the buffer was synchronous, we want to make
         * sure to return the error to the caller of xfs_bwrite().
         */
-       XFS_BUF_STALE(bp);
+       xfs_buf_stale(bp);
        XFS_BUF_DONE(bp);
-       XFS_BUF_UNDELAYWRITE(bp);
 
        trace_xfs_buf_error_relse(bp, _RET_IP_);
 
index ee9d542..77c7425 100644 (file)
@@ -1578,9 +1578,8 @@ xfs_da_grow_inode_int(
         */
        nmap = 1;
        ASSERT(args->firstblock != NULL);
-       error = xfs_bmapi(tp, dp, *bno, count,
-                       xfs_bmapi_aflag(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|
-                       XFS_BMAPI_CONTIG,
+       error = xfs_bmapi_write(tp, dp, *bno, count,
+                       xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
                        args->firstblock, args->total, &map, &nmap,
                        args->flist);
        if (error)
@@ -1602,9 +1601,8 @@ xfs_da_grow_inode_int(
                for (b = *bno, mapi = 0; b < *bno + count; ) {
                        nmap = MIN(XFS_BMAP_MAX_NMAP, count);
                        c = (int)(*bno + count - b);
-                       error = xfs_bmapi(tp, dp, b, c,
-                                       xfs_bmapi_aflag(w)|XFS_BMAPI_WRITE|
-                                       XFS_BMAPI_METADATA,
+                       error = xfs_bmapi_write(tp, dp, b, c,
+                                       xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA,
                                        args->firstblock, args->total,
                                        &mapp[mapi], &nmap, args->flist);
                        if (error)
@@ -1975,33 +1973,16 @@ xfs_da_do_buf(
                /*
                 * Optimize the one-block case.
                 */
-               if (nfsb == 1) {
-                       xfs_fsblock_t   fsb;
-
-                       if ((error =
-                           xfs_bmapi_single(trans, dp, whichfork, &fsb,
-                                   (xfs_fileoff_t)bno))) {
-                               return error;
-                       }
+               if (nfsb == 1)
                        mapp = &map;
-                       if (fsb == NULLFSBLOCK) {
-                               nmap = 0;
-                       } else {
-                               map.br_startblock = fsb;
-                               map.br_startoff = (xfs_fileoff_t)bno;
-                               map.br_blockcount = 1;
-                               nmap = 1;
-                       }
-               } else {
+               else
                        mapp = kmem_alloc(sizeof(*mapp) * nfsb, KM_SLEEP);
-                       nmap = nfsb;
-                       if ((error = xfs_bmapi(trans, dp, (xfs_fileoff_t)bno,
-                                       nfsb,
-                                       XFS_BMAPI_METADATA |
-                                               xfs_bmapi_aflag(whichfork),
-                                       NULL, 0, mapp, &nmap, NULL)))
-                               goto exit0;
-               }
+
+               nmap = nfsb;
+               error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, mapp,
+                                      &nmap, xfs_bmapi_aflag(whichfork));
+               if (error)
+                       goto exit0;
        } else {
                map.br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno);
                map.br_startoff = (xfs_fileoff_t)bno;
@@ -2072,13 +2053,10 @@ xfs_da_do_buf(
                if (!bp)
                        continue;
                if (caller == 1) {
-                       if (whichfork == XFS_ATTR_FORK) {
-                               XFS_BUF_SET_VTYPE_REF(bp, B_FS_ATTR_BTREE,
-                                               XFS_ATTR_BTREE_REF);
-                       } else {
-                               XFS_BUF_SET_VTYPE_REF(bp, B_FS_DIR_BTREE,
-                                               XFS_DIR_BTREE_REF);
-                       }
+                       if (whichfork == XFS_ATTR_FORK)
+                               xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF);
+                       else
+                               xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF);
                }
                if (bplist) {
                        bplist[nbplist++] = bp;
index 9a84a85..654dc6f 100644 (file)
@@ -425,8 +425,8 @@ xfs_swap_extents(
        }
 
 
-       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       xfs_trans_ijoin_ref(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 
        xfs_trans_log_inode(tp, ip,  ilf_fields);
        xfs_trans_log_inode(tp, tip, tilf_fields);
@@ -438,7 +438,7 @@ xfs_swap_extents(
        if (mp->m_flags & XFS_MOUNT_WSYNC)
                xfs_trans_set_sync(tp);
 
-       error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT);
+       error = xfs_trans_commit(tp, 0);
 
        trace_xfs_swap_extent_after(ip, 0);
        trace_xfs_swap_extent_after(tip, 1);
index ca2386d..66e108f 100644 (file)
@@ -888,12 +888,10 @@ xfs_dir2_leaf_getdents(
                                 * we already have in the table.
                                 */
                                nmap = map_size - map_valid;
-                               error = xfs_bmapi(NULL, dp,
-                                       map_off,
+                               error = xfs_bmapi_read(dp, map_off,
                                        xfs_dir2_byte_to_da(mp,
                                                XFS_DIR2_LEAF_OFFSET) - map_off,
-                                       XFS_BMAPI_METADATA, NULL, 0,
-                                       &map[map_valid], &nmap, NULL);
+                                       &map[map_valid], &nmap, 0);
                                /*
                                 * Don't know if we should ignore this or
                                 * try to return an error.
index 244e797..8a24f0c 100644 (file)
@@ -38,7 +38,7 @@ xfs_trim_extents(
        struct xfs_mount        *mp,
        xfs_agnumber_t          agno,
        xfs_fsblock_t           start,
-       xfs_fsblock_t           len,
+       xfs_fsblock_t           end,
        xfs_fsblock_t           minlen,
        __uint64_t              *blocks_trimmed)
 {
@@ -100,7 +100,7 @@ xfs_trim_extents(
                 * down partially overlapping ranges for now.
                 */
                if (XFS_AGB_TO_FSB(mp, agno, fbno) + flen < start ||
-                   XFS_AGB_TO_FSB(mp, agno, fbno) >= start + len) {
+                   XFS_AGB_TO_FSB(mp, agno, fbno) > end) {
                        trace_xfs_discard_exclude(mp, agno, fbno, flen);
                        goto next_extent;
                }
@@ -145,7 +145,7 @@ xfs_ioc_trim(
        struct request_queue    *q = mp->m_ddev_targp->bt_bdev->bd_disk->queue;
        unsigned int            granularity = q->limits.discard_granularity;
        struct fstrim_range     range;
-       xfs_fsblock_t           start, len, minlen;
+       xfs_fsblock_t           start, end, minlen;
        xfs_agnumber_t          start_agno, end_agno, agno;
        __uint64_t              blocks_trimmed = 0;
        int                     error, last_error = 0;
@@ -165,19 +165,19 @@ xfs_ioc_trim(
         * matter as trimming blocks is an advisory interface.
         */
        start = XFS_B_TO_FSBT(mp, range.start);
-       len = XFS_B_TO_FSBT(mp, range.len);
+       end = start + XFS_B_TO_FSBT(mp, range.len) - 1;
        minlen = XFS_B_TO_FSB(mp, max_t(u64, granularity, range.minlen));
 
-       start_agno = XFS_FSB_TO_AGNO(mp, start);
-       if (start_agno >= mp->m_sb.sb_agcount)
+       if (start >= mp->m_sb.sb_dblocks)
                return -XFS_ERROR(EINVAL);
+       if (end > mp->m_sb.sb_dblocks - 1)
+               end = mp->m_sb.sb_dblocks - 1;
 
-       end_agno = XFS_FSB_TO_AGNO(mp, start + len);
-       if (end_agno >= mp->m_sb.sb_agcount)
-               end_agno = mp->m_sb.sb_agcount - 1;
+       start_agno = XFS_FSB_TO_AGNO(mp, start);
+       end_agno = XFS_FSB_TO_AGNO(mp, end);
 
        for (agno = start_agno; agno <= end_agno; agno++) {
-               error = -xfs_trim_extents(mp, agno, start, len, minlen,
+               error = -xfs_trim_extents(mp, agno, start, end, minlen,
                                          &blocks_trimmed);
                if (error)
                        last_error = error;
index db62959..25d7280 100644 (file)
@@ -377,16 +377,14 @@ xfs_qm_dqalloc(
                return (ESRCH);
        }
 
-       xfs_trans_ijoin_ref(tp, quotip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
        nmaps = 1;
-       if ((error = xfs_bmapi(tp, quotip,
-                             offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB,
-                             XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,
-                             &firstblock,
-                             XFS_QM_DQALLOC_SPACE_RES(mp),
-                             &map, &nmaps, &flist))) {
+       error = xfs_bmapi_write(tp, quotip, offset_fsb,
+                               XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA,
+                               &firstblock, XFS_QM_DQALLOC_SPACE_RES(mp),
+                               &map, &nmaps, &flist);
+       if (error)
                goto error0;
-       }
        ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
        ASSERT(nmaps == 1);
        ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
@@ -402,8 +400,11 @@ xfs_qm_dqalloc(
                               dqp->q_blkno,
                               mp->m_quotainfo->qi_dqchunklen,
                               0);
-       if (!bp || (error = xfs_buf_geterror(bp)))
+
+       error = xfs_buf_geterror(bp);
+       if (error)
                goto error1;
+
        /*
         * Make a chunk of dquots out of this buffer and log
         * the entire thing.
@@ -485,9 +486,8 @@ xfs_qm_dqtobp(
        /*
         * Find the block map; no allocations yet
         */
-       error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
-                         XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA,
-                         NULL, 0, &map, &nmaps, NULL);
+       error = xfs_bmapi_read(quotip, dqp->q_fileoffset,
+                              XFS_DQUOT_CLUSTER_SIZE_FSB, &map, &nmaps, 0);
 
        xfs_iunlock(quotip, XFS_ILOCK_SHARED);
        if (error)
@@ -605,7 +605,7 @@ xfs_qm_dqread(
        dqp->q_res_rtbcount = be64_to_cpu(ddqp->d_rtbcount);
 
        /* Mark the buf so that this will stay incore a little longer */
-       XFS_BUF_SET_VTYPE_REF(bp, B_FS_DQUOT, XFS_DQUOT_REF);
+       xfs_buf_set_ref(bp, XFS_DQUOT_REF);
 
        /*
         * We got the buffer with a xfs_trans_read_buf() (in dqtobp())
@@ -1242,9 +1242,11 @@ xfs_qm_dqflush(
        }
 
        if (flags & SYNC_WAIT)
-               error = xfs_bwrite(mp, bp);
+               error = xfs_bwrite(bp);
        else
-               xfs_bdwrite(mp, bp);
+               xfs_buf_delwri_queue(bp);
+
+       xfs_buf_relse(bp);
 
        trace_xfs_dqflush_done(dqp);
 
index 75e5d32..da10897 100644 (file)
@@ -229,16 +229,16 @@ xfs_fs_nfs_commit_metadata(
 {
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
-       int                     error = 0;
+       xfs_lsn_t               lsn = 0;
 
        xfs_ilock(ip, XFS_ILOCK_SHARED);
-       if (xfs_ipincount(ip)) {
-               error = _xfs_log_force_lsn(mp, ip->i_itemp->ili_last_lsn,
-                               XFS_LOG_SYNC, NULL);
-       }
+       if (xfs_ipincount(ip))
+               lsn = ip->i_itemp->ili_last_lsn;
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
-       return error;
+       if (!lsn)
+               return 0;
+       return _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
 }
 
 const struct export_operations xfs_export_operations = {
index 7f7b424..753ed9b 100644 (file)
@@ -124,6 +124,35 @@ xfs_iozero(
        return (-status);
 }
 
+/*
+ * Fsync operations on directories are much simpler than on regular files,
+ * as there is no file data to flush, and thus also no need for explicit
+ * cache flush operations, and there are no non-transaction metadata updates
+ * on directories either.
+ */
+STATIC int
+xfs_dir_fsync(
+       struct file             *file,
+       loff_t                  start,
+       loff_t                  end,
+       int                     datasync)
+{
+       struct xfs_inode        *ip = XFS_I(file->f_mapping->host);
+       struct xfs_mount        *mp = ip->i_mount;
+       xfs_lsn_t               lsn = 0;
+
+       trace_xfs_dir_fsync(ip);
+
+       xfs_ilock(ip, XFS_ILOCK_SHARED);
+       if (xfs_ipincount(ip))
+               lsn = ip->i_itemp->ili_last_lsn;
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+
+       if (!lsn)
+               return 0;
+       return _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
+}
+
 STATIC int
 xfs_file_fsync(
        struct file             *file,
@@ -137,6 +166,7 @@ xfs_file_fsync(
        struct xfs_trans        *tp;
        int                     error = 0;
        int                     log_flushed = 0;
+       xfs_lsn_t               lsn = 0;
 
        trace_xfs_file_fsync(ip);
 
@@ -149,10 +179,6 @@ xfs_file_fsync(
 
        xfs_iflags_clear(ip, XFS_ITRUNCATED);
 
-       xfs_ilock(ip, XFS_IOLOCK_SHARED);
-       xfs_ioend_wait(ip);
-       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-
        if (mp->m_flags & XFS_MOUNT_BARRIER) {
                /*
                 * If we have an RT and/or log subvolume we need to make sure
@@ -216,11 +242,11 @@ xfs_file_fsync(
                 * transaction.  So we play it safe and fire off the
                 * transaction anyway.
                 */
-               xfs_trans_ijoin(tp, ip);
+               xfs_trans_ijoin(tp, ip, 0);
                xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-               xfs_trans_set_sync(tp);
-               error = _xfs_trans_commit(tp, 0, &log_flushed);
+               error = xfs_trans_commit(tp, 0);
 
+               lsn = ip->i_itemp->ili_last_lsn;
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
        } else {
                /*
@@ -231,14 +257,14 @@ xfs_file_fsync(
                 * disk yet, the inode will be still be pinned.  If it is,
                 * force the log.
                 */
-               if (xfs_ipincount(ip)) {
-                       error = _xfs_log_force_lsn(mp,
-                                       ip->i_itemp->ili_last_lsn,
-                                       XFS_LOG_SYNC, &log_flushed);
-               }
+               if (xfs_ipincount(ip))
+                       lsn = ip->i_itemp->ili_last_lsn;
                xfs_iunlock(ip, XFS_ILOCK_SHARED);
        }
 
+       if (!error && lsn)
+               error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed);
+
        /*
         * If we only have a single device, and the log force about was
         * a no-op we might have to flush the data device cache here.
@@ -317,7 +343,19 @@ xfs_file_aio_read(
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       if (unlikely(ioflags & IO_ISDIRECT)) {
+       /*
+        * Locking is a bit tricky here. If we take an exclusive lock
+        * for direct IO, we effectively serialise all new concurrent
+        * read IO to this file and block it behind IO that is currently in
+        * progress because IO in progress holds the IO lock shared. We only
+        * need to hold the lock exclusive to blow away the page cache, so
+        * only take lock exclusively if the page cache needs invalidation.
+        * This allows the normal direct IO case of no page cache pages to
+        * proceeed concurrently without serialisation.
+        */
+       xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
+       if ((ioflags & IO_ISDIRECT) && inode->i_mapping->nrpages) {
+               xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
                xfs_rw_ilock(ip, XFS_IOLOCK_EXCL);
 
                if (inode->i_mapping->nrpages) {
@@ -330,8 +368,7 @@ xfs_file_aio_read(
                        }
                }
                xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
-       } else
-               xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
+       }
 
        trace_xfs_file_read(ip, size, iocb->ki_pos, ioflags);
 
@@ -407,11 +444,13 @@ xfs_aio_write_isize_update(
  */
 STATIC void
 xfs_aio_write_newsize_update(
-       struct xfs_inode        *ip)
+       struct xfs_inode        *ip,
+       xfs_fsize_t             new_size)
 {
-       if (ip->i_new_size) {
+       if (new_size == ip->i_new_size) {
                xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
-               ip->i_new_size = 0;
+               if (new_size == ip->i_new_size)
+                       ip->i_new_size = 0;
                if (ip->i_d.di_size > ip->i_size)
                        ip->i_d.di_size = ip->i_size;
                xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
@@ -462,7 +501,7 @@ xfs_file_splice_write(
        ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
 
        xfs_aio_write_isize_update(inode, ppos, ret);
-       xfs_aio_write_newsize_update(ip);
+       xfs_aio_write_newsize_update(ip, new_size);
        xfs_iunlock(ip, XFS_IOLOCK_EXCL);
        return ret;
 }
@@ -500,11 +539,9 @@ xfs_zero_last_block(
 
        last_fsb = XFS_B_TO_FSBT(mp, isize);
        nimaps = 1;
-       error = xfs_bmapi(NULL, ip, last_fsb, 1, 0, NULL, 0, &imap,
-                         &nimaps, NULL);
-       if (error) {
+       error = xfs_bmapi_read(ip, last_fsb, 1, &imap, &nimaps, 0);
+       if (error)
                return error;
-       }
        ASSERT(nimaps > 0);
        /*
         * If the block underlying isize is just a hole, then there
@@ -595,8 +632,8 @@ xfs_zero_eof(
        while (start_zero_fsb <= end_zero_fsb) {
                nimaps = 1;
                zero_count_fsb = end_zero_fsb - start_zero_fsb + 1;
-               error = xfs_bmapi(NULL, ip, start_zero_fsb, zero_count_fsb,
-                                 0, NULL, 0, &imap, &nimaps, NULL);
+               error = xfs_bmapi_read(ip, start_zero_fsb, zero_count_fsb,
+                                         &imap, &nimaps, 0);
                if (error) {
                        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
                        return error;
@@ -659,6 +696,7 @@ xfs_file_aio_write_checks(
        struct file             *file,
        loff_t                  *pos,
        size_t                  *count,
+       xfs_fsize_t             *new_sizep,
        int                     *iolock)
 {
        struct inode            *inode = file->f_mapping->host;
@@ -666,6 +704,9 @@ xfs_file_aio_write_checks(
        xfs_fsize_t             new_size;
        int                     error = 0;
 
+       xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
+       *new_sizep = 0;
+restart:
        error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode));
        if (error) {
                xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
@@ -673,20 +714,41 @@ xfs_file_aio_write_checks(
                return error;
        }
 
-       new_size = *pos + *count;
-       if (new_size > ip->i_size)
-               ip->i_new_size = new_size;
-
        if (likely(!(file->f_mode & FMODE_NOCMTIME)))
                file_update_time(file);
 
        /*
         * If the offset is beyond the size of the file, we need to zero any
         * blocks that fall between the existing EOF and the start of this
-        * write.
+        * write. There is no need to issue zeroing if another in-flght IO ends
+        * at or before this one If zeronig is needed and we are currently
+        * holding the iolock shared, we need to update it to exclusive which
+        * involves dropping all locks and relocking to maintain correct locking
+        * order. If we do this, restart the function to ensure all checks and
+        * values are still valid.
         */
-       if (*pos > ip->i_size)
+       if ((ip->i_new_size && *pos > ip->i_new_size) ||
+           (!ip->i_new_size && *pos > ip->i_size)) {
+               if (*iolock == XFS_IOLOCK_SHARED) {
+                       xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
+                       *iolock = XFS_IOLOCK_EXCL;
+                       xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
+                       goto restart;
+               }
                error = -xfs_zero_eof(ip, *pos, ip->i_size);
+       }
+
+       /*
+        * If this IO extends beyond EOF, we may need to update ip->i_new_size.
+        * We have already zeroed space beyond EOF (if necessary).  Only update
+        * ip->i_new_size if this IO ends beyond any other in-flight writes.
+        */
+       new_size = *pos + *count;
+       if (new_size > ip->i_size) {
+               if (new_size > ip->i_new_size)
+                       ip->i_new_size = new_size;
+               *new_sizep = new_size;
+       }
 
        xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
        if (error)
@@ -721,7 +783,7 @@ xfs_file_aio_write_checks(
  * the dio layer.  To avoid the problem with aio, we also need to wait for
  * outstanding IOs to complete so that unwritten extent conversion is completed
  * before we try to map the overlapping block. This is currently implemented by
- * hitting it with a big hammer (i.e. xfs_ioend_wait()).
+ * hitting it with a big hammer (i.e. inode_dio_wait()).
  *
  * Returns with locks held indicated by @iolock and errors indicated by
  * negative return values.
@@ -733,6 +795,7 @@ xfs_file_dio_aio_write(
        unsigned long           nr_segs,
        loff_t                  pos,
        size_t                  ocount,
+       xfs_fsize_t             *new_size,
        int                     *iolock)
 {
        struct file             *file = iocb->ki_filp;
@@ -753,18 +816,35 @@ xfs_file_dio_aio_write(
        if ((pos & mp->m_blockmask) || ((pos + count) & mp->m_blockmask))
                unaligned_io = 1;
 
-       if (unaligned_io || mapping->nrpages || pos > ip->i_size)
+       /*
+        * We don't need to take an exclusive lock unless there page cache needs
+        * to be invalidated or unaligned IO is being executed. We don't need to
+        * consider the EOF extension case here because
+        * xfs_file_aio_write_checks() will relock the inode as necessary for
+        * EOF zeroing cases and fill out the new inode size as appropriate.
+        */
+       if (unaligned_io || mapping->nrpages)
                *iolock = XFS_IOLOCK_EXCL;
        else
                *iolock = XFS_IOLOCK_SHARED;
-       xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
+       xfs_rw_ilock(ip, *iolock);
 
-       ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
+       /*
+        * Recheck if there are cached pages that need invalidate after we got
+        * the iolock to protect against other threads adding new pages while
+        * we were waiting for the iolock.
+        */
+       if (mapping->nrpages && *iolock == XFS_IOLOCK_SHARED) {
+               xfs_rw_iunlock(ip, *iolock);
+               *iolock = XFS_IOLOCK_EXCL;
+               xfs_rw_ilock(ip, *iolock);
+       }
+
+       ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock);
        if (ret)
                return ret;
 
        if (mapping->nrpages) {
-               WARN_ON(*iolock != XFS_IOLOCK_EXCL);
                ret = -xfs_flushinval_pages(ip, (pos & PAGE_CACHE_MASK), -1,
                                                        FI_REMAPF_LOCKED);
                if (ret)
@@ -776,7 +856,7 @@ xfs_file_dio_aio_write(
         * otherwise demote the lock if we had to flush cached pages
         */
        if (unaligned_io)
-               xfs_ioend_wait(ip);
+               inode_dio_wait(inode);
        else if (*iolock == XFS_IOLOCK_EXCL) {
                xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
                *iolock = XFS_IOLOCK_SHARED;
@@ -798,6 +878,7 @@ xfs_file_buffered_aio_write(
        unsigned long           nr_segs,
        loff_t                  pos,
        size_t                  ocount,
+       xfs_fsize_t             *new_size,
        int                     *iolock)
 {
        struct file             *file = iocb->ki_filp;
@@ -809,9 +890,9 @@ xfs_file_buffered_aio_write(
        size_t                  count = ocount;
 
        *iolock = XFS_IOLOCK_EXCL;
-       xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
+       xfs_rw_ilock(ip, *iolock);
 
-       ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
+       ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock);
        if (ret)
                return ret;
 
@@ -851,6 +932,7 @@ xfs_file_aio_write(
        ssize_t                 ret;
        int                     iolock;
        size_t                  ocount = 0;
+       xfs_fsize_t             new_size = 0;
 
        XFS_STATS_INC(xs_write_calls);
 
@@ -870,10 +952,10 @@ xfs_file_aio_write(
 
        if (unlikely(file->f_flags & O_DIRECT))
                ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos,
-                                               ocount, &iolock);
+                                               ocount, &new_size, &iolock);
        else
                ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos,
-                                               ocount, &iolock);
+                                               ocount, &new_size, &iolock);
 
        xfs_aio_write_isize_update(inode, &iocb->ki_pos, ret);
 
@@ -894,7 +976,7 @@ xfs_file_aio_write(
        }
 
 out_unlock:
-       xfs_aio_write_newsize_update(ip);
+       xfs_aio_write_newsize_update(ip, new_size);
        xfs_rw_iunlock(ip, iolock);
        return ret;
 }
@@ -1087,7 +1169,7 @@ const struct file_operations xfs_dir_file_operations = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = xfs_file_compat_ioctl,
 #endif
-       .fsync          = xfs_file_fsync,
+       .fsync          = xfs_dir_fsync,
 };
 
 static const struct vm_operations_struct xfs_file_vm_ops = {
index 3ff3d9e..5170306 100644 (file)
@@ -682,7 +682,7 @@ xfs_filestream_new_ag(
        ip = ap->ip;
        mp = ip->i_mount;
        cache = mp->m_filestream;
-       minlen = ap->alen;
+       minlen = ap->length;
        *agp = NULLAGNUMBER;
 
        /*
@@ -761,7 +761,7 @@ xfs_filestream_new_ag(
         */
        ag = (ag == NULLAGNUMBER) ? 0 : (ag + 1) % mp->m_sb.sb_agcount;
        flags = (ap->userdata ? XFS_PICK_USERDATA : 0) |
-               (ap->low ? XFS_PICK_LOWSPACE : 0);
+               (ap->flist->xbf_low ? XFS_PICK_LOWSPACE : 0);
 
        err = _xfs_filestream_pick_ag(mp, ag, agp, flags, minlen);
        if (err || *agp == NULLAGNUMBER)
index 9153d2c..1c6fdeb 100644 (file)
@@ -194,6 +194,10 @@ xfs_growfs_data_private(
                bp = xfs_buf_get(mp->m_ddev_targp,
                                 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
                                 XFS_FSS_TO_BB(mp, 1), XBF_LOCK | XBF_MAPPED);
+               if (!bp) {
+                       error = ENOMEM;
+                       goto error0;
+               }
                agf = XFS_BUF_TO_AGF(bp);
                memset(agf, 0, mp->m_sb.sb_sectsize);
                agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
@@ -216,16 +220,21 @@ xfs_growfs_data_private(
                tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp);
                agf->agf_freeblks = cpu_to_be32(tmpsize);
                agf->agf_longest = cpu_to_be32(tmpsize);
-               error = xfs_bwrite(mp, bp);
-               if (error) {
+               error = xfs_bwrite(bp);
+               xfs_buf_relse(bp);
+               if (error)
                        goto error0;
-               }
+
                /*
                 * AG inode header block
                 */
                bp = xfs_buf_get(mp->m_ddev_targp,
                                 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
                                 XFS_FSS_TO_BB(mp, 1), XBF_LOCK | XBF_MAPPED);
+               if (!bp) {
+                       error = ENOMEM;
+                       goto error0;
+               }
                agi = XFS_BUF_TO_AGI(bp);
                memset(agi, 0, mp->m_sb.sb_sectsize);
                agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
@@ -240,10 +249,11 @@ xfs_growfs_data_private(
                agi->agi_dirino = cpu_to_be32(NULLAGINO);
                for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
                        agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
-               error = xfs_bwrite(mp, bp);
-               if (error) {
+               error = xfs_bwrite(bp);
+               xfs_buf_relse(bp);
+               if (error)
                        goto error0;
-               }
+
                /*
                 * BNO btree root block
                 */
@@ -251,6 +261,10 @@ xfs_growfs_data_private(
                                 XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)),
                                 BTOBB(mp->m_sb.sb_blocksize),
                                 XBF_LOCK | XBF_MAPPED);
+               if (!bp) {
+                       error = ENOMEM;
+                       goto error0;
+               }
                block = XFS_BUF_TO_BLOCK(bp);
                memset(block, 0, mp->m_sb.sb_blocksize);
                block->bb_magic = cpu_to_be32(XFS_ABTB_MAGIC);
@@ -262,10 +276,11 @@ xfs_growfs_data_private(
                arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
                arec->ar_blockcount = cpu_to_be32(
                        agsize - be32_to_cpu(arec->ar_startblock));
-               error = xfs_bwrite(mp, bp);
-               if (error) {
+               error = xfs_bwrite(bp);
+               xfs_buf_relse(bp);
+               if (error)
                        goto error0;
-               }
+
                /*
                 * CNT btree root block
                 */
@@ -273,6 +288,10 @@ xfs_growfs_data_private(
                                 XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)),
                                 BTOBB(mp->m_sb.sb_blocksize),
                                 XBF_LOCK | XBF_MAPPED);
+               if (!bp) {
+                       error = ENOMEM;
+                       goto error0;
+               }
                block = XFS_BUF_TO_BLOCK(bp);
                memset(block, 0, mp->m_sb.sb_blocksize);
                block->bb_magic = cpu_to_be32(XFS_ABTC_MAGIC);
@@ -285,10 +304,11 @@ xfs_growfs_data_private(
                arec->ar_blockcount = cpu_to_be32(
                        agsize - be32_to_cpu(arec->ar_startblock));
                nfree += be32_to_cpu(arec->ar_blockcount);
-               error = xfs_bwrite(mp, bp);
-               if (error) {
+               error = xfs_bwrite(bp);
+               xfs_buf_relse(bp);
+               if (error)
                        goto error0;
-               }
+
                /*
                 * INO btree root block
                 */
@@ -296,6 +316,10 @@ xfs_growfs_data_private(
                                 XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)),
                                 BTOBB(mp->m_sb.sb_blocksize),
                                 XBF_LOCK | XBF_MAPPED);
+               if (!bp) {
+                       error = ENOMEM;
+                       goto error0;
+               }
                block = XFS_BUF_TO_BLOCK(bp);
                memset(block, 0, mp->m_sb.sb_blocksize);
                block->bb_magic = cpu_to_be32(XFS_IBT_MAGIC);
@@ -303,10 +327,10 @@ xfs_growfs_data_private(
                block->bb_numrecs = 0;
                block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
                block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
-               error = xfs_bwrite(mp, bp);
-               if (error) {
+               error = xfs_bwrite(bp);
+               xfs_buf_relse(bp);
+               if (error)
                        goto error0;
-               }
        }
        xfs_trans_agblocks_delta(tp, nfree);
        /*
@@ -396,9 +420,9 @@ xfs_growfs_data_private(
                 * just issue a warning and continue.  The real work is
                 * already done and committed.
                 */
-               if (!(error = xfs_bwrite(mp, bp))) {
-                       continue;
-               } else {
+               error = xfs_bwrite(bp);
+               xfs_buf_relse(bp);
+               if (error) {
                        xfs_warn(mp,
                "write error %d updating secondary superblock for ag %d",
                                error, agno);
index 9f24ec2..169380e 100644 (file)
@@ -150,7 +150,7 @@ xfs_check_agi_freecount(
 /*
  * Initialise a new set of inodes.
  */
-STATIC void
+STATIC int
 xfs_ialloc_inode_init(
        struct xfs_mount        *mp,
        struct xfs_trans        *tp,
@@ -202,8 +202,8 @@ xfs_ialloc_inode_init(
                fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
                                         mp->m_bsize * blks_per_cluster,
                                         XBF_LOCK);
-               ASSERT(!xfs_buf_geterror(fbuf));
-
+               if (!fbuf)
+                       return ENOMEM;
                /*
                 * Initialize all inodes in this buffer and then log them.
                 *
@@ -225,6 +225,7 @@ xfs_ialloc_inode_init(
                }
                xfs_trans_inode_alloc_buf(tp, fbuf);
        }
+       return 0;
 }
 
 /*
@@ -369,9 +370,11 @@ xfs_ialloc_ag_alloc(
         * rather than a linear progression to prevent the next generation
         * number from being easily guessable.
         */
-       xfs_ialloc_inode_init(args.mp, tp, agno, args.agbno, args.len,
-                             random32());
+       error = xfs_ialloc_inode_init(args.mp, tp, agno, args.agbno,
+                       args.len, random32());
 
+       if (error)
+               return error;
        /*
         * Convert the results.
         */
@@ -1502,7 +1505,7 @@ xfs_read_agi(
                return XFS_ERROR(EFSCORRUPTED);
        }
 
-       XFS_BUF_SET_VTYPE_REF(*bpp, B_FS_AGI, XFS_AGI_REF);
+       xfs_buf_set_ref(*bpp, XFS_AGI_REF);
 
        xfs_check_agi_unlinked(agi);
        return 0;
index 7759812..0fa98b1 100644 (file)
@@ -75,7 +75,6 @@ xfs_inode_alloc(
                return NULL;
        }
 
-       ASSERT(atomic_read(&ip->i_iocount) == 0);
        ASSERT(atomic_read(&ip->i_pincount) == 0);
        ASSERT(!spin_is_locked(&ip->i_flags_lock));
        ASSERT(completion_done(&ip->i_flush));
@@ -150,7 +149,6 @@ xfs_inode_free(
        }
 
        /* asserts to verify all state is correct here */
-       ASSERT(atomic_read(&ip->i_iocount) == 0);
        ASSERT(atomic_read(&ip->i_pincount) == 0);
        ASSERT(!spin_is_locked(&ip->i_flags_lock));
        ASSERT(completion_done(&ip->i_flush));
index 0239a7c..c0237c6 100644 (file)
@@ -190,12 +190,6 @@ xfs_imap_to_bp(
        }
 
        xfs_inobp_check(mp, bp);
-
-       /*
-        * Mark the buffer as an inode buffer now that it looks good
-        */
-       XFS_BUF_SET_VTYPE(bp, B_FS_INO);
-
        *bpp = bp;
        return 0;
 }
@@ -1152,7 +1146,7 @@ xfs_ialloc(
        /*
         * Log the new values stuffed into the inode.
         */
-       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
        xfs_trans_log_inode(tp, ip, flags);
 
        /* now that we have an i_mode we can setup inode ops and unlock */
@@ -1187,6 +1181,7 @@ xfs_isize_check(
        xfs_fileoff_t           map_first;
        int                     nimaps;
        xfs_bmbt_irec_t         imaps[2];
+       int                     error;
 
        if (!S_ISREG(ip->i_d.di_mode))
                return;
@@ -1203,13 +1198,12 @@ xfs_isize_check(
         * The filesystem could be shutting down, so bmapi may return
         * an error.
         */
-       if (xfs_bmapi(NULL, ip, map_first,
+       error = xfs_bmapi_read(ip, map_first,
                         (XFS_B_TO_FSB(mp,
-                                      (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) -
-                         map_first),
-                        XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps,
-                        NULL))
-           return;
+                              (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - map_first),
+                        imaps, &nimaps, XFS_BMAPI_ENTIRE);
+       if (error)
+               return;
        ASSERT(nimaps == 1);
        ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK);
 }
@@ -1297,7 +1291,7 @@ xfs_itruncate_extents(
                 */
                error = xfs_bmap_finish(&tp, &free_list, &committed);
                if (committed)
-                       xfs_trans_ijoin(tp, ip);
+                       xfs_trans_ijoin(tp, ip, 0);
                if (error)
                        goto out_bmap_cancel;
 
@@ -1313,7 +1307,7 @@ xfs_itruncate_extents(
                error = xfs_trans_commit(tp, 0);
                tp = ntp;
 
-               xfs_trans_ijoin(tp, ip);
+               xfs_trans_ijoin(tp, ip, 0);
 
                if (error)
                        goto out;
@@ -1644,7 +1638,7 @@ xfs_iunlink_remove(
  * inodes that are in memory - they all must be marked stale and attached to
  * the cluster buffer.
  */
-STATIC void
+STATIC int
 xfs_ifree_cluster(
        xfs_inode_t     *free_ip,
        xfs_trans_t     *tp,
@@ -1690,6 +1684,8 @@ xfs_ifree_cluster(
                                        mp->m_bsize * blks_per_cluster,
                                        XBF_LOCK);
 
+               if (!bp)
+                       return ENOMEM;
                /*
                 * Walk the inodes already attached to the buffer and mark them
                 * stale. These will all have the flush locks held, so an
@@ -1799,6 +1795,7 @@ retry:
        }
 
        xfs_perag_put(pag);
+       return 0;
 }
 
 /*
@@ -1878,10 +1875,10 @@ xfs_ifree(
        dip->di_mode = 0;
 
        if (delete) {
-               xfs_ifree_cluster(ip, tp, first_ino);
+               error = xfs_ifree_cluster(ip, tp, first_ino);
        }
 
-       return 0;
+       return error;
 }
 
 /*
@@ -2472,11 +2469,11 @@ cluster_corrupt_out:
                 */
                if (bp->b_iodone) {
                        XFS_BUF_UNDONE(bp);
-                       XFS_BUF_STALE(bp);
+                       xfs_buf_stale(bp);
                        xfs_buf_ioerror(bp, EIO);
                        xfs_buf_ioend(bp, 0);
                } else {
-                       XFS_BUF_STALE(bp);
+                       xfs_buf_stale(bp);
                        xfs_buf_relse(bp);
                }
        }
@@ -2597,9 +2594,11 @@ xfs_iflush(
                goto cluster_corrupt_out;
 
        if (flags & SYNC_WAIT)
-               error = xfs_bwrite(mp, bp);
+               error = xfs_bwrite(bp);
        else
-               xfs_bdwrite(mp, bp);
+               xfs_buf_delwri_queue(bp);
+
+       xfs_buf_relse(bp);
        return error;
 
 corrupt_out:
index 2380a4b..760140d 100644 (file)
@@ -257,7 +257,6 @@ typedef struct xfs_inode {
 
        xfs_fsize_t             i_size;         /* in-memory size */
        xfs_fsize_t             i_new_size;     /* size when write completes */
-       atomic_t                i_iocount;      /* outstanding I/O count */
 
        /* VFS inode */
        struct inode            i_vnode;        /* embedded VFS inode */
index 836ad80..b7cf21b 100644 (file)
@@ -658,10 +658,8 @@ xfs_inode_item_unlock(
 
        lock_flags = iip->ili_lock_flags;
        iip->ili_lock_flags = 0;
-       if (lock_flags) {
+       if (lock_flags)
                xfs_iunlock(ip, lock_flags);
-               IRELE(ip);
-       }
 }
 
 /*
index f7ce7de..d99a905 100644 (file)
@@ -1069,7 +1069,7 @@ xfs_ioctl_setattr(
                }
        }
 
-       xfs_trans_ijoin(tp, ip);
+       xfs_trans_ijoin(tp, ip, 0);
 
        /*
         * Change file ownership.  Must be the owner or privileged.
index 091d82b..9afa282 100644 (file)
@@ -208,22 +208,20 @@ xfs_iomap_write_direct(
        if (error)
                goto error1;
 
-       xfs_trans_ijoin(tp, ip);
+       xfs_trans_ijoin(tp, ip, 0);
 
-       bmapi_flag = XFS_BMAPI_WRITE;
+       bmapi_flag = 0;
        if (offset < ip->i_size || extsz)
                bmapi_flag |= XFS_BMAPI_PREALLOC;
 
        /*
-        * Issue the xfs_bmapi() call to allocate the blocks.
-        *
         * From this point onwards we overwrite the imap pointer that the
         * caller gave to us.
         */
        xfs_bmap_init(&free_list, &firstfsb);
        nimaps = 1;
-       error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, bmapi_flag,
-               &firstfsb, 0, imap, &nimaps, &free_list);
+       error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, bmapi_flag,
+                               &firstfsb, 0, imap, &nimaps, &free_list);
        if (error)
                goto error0;
 
@@ -300,8 +298,8 @@ xfs_iomap_eof_want_preallocate(
        while (count_fsb > 0) {
                imaps = nimaps;
                firstblock = NULLFSBLOCK;
-               error = xfs_bmapi(NULL, ip, start_fsb, count_fsb, 0,
-                                 &firstblock, 0, imap, &imaps, NULL);
+               error = xfs_bmapi_read(ip, start_fsb, count_fsb, imap, &imaps,
+                                      0);
                if (error)
                        return error;
                for (n = 0; n < imaps; n++) {
@@ -381,7 +379,6 @@ xfs_iomap_write_delay(
        xfs_fileoff_t   last_fsb;
        xfs_off_t       aligned_offset;
        xfs_fileoff_t   ioalign;
-       xfs_fsblock_t   firstblock;
        xfs_extlen_t    extsz;
        int             nimaps;
        xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS];
@@ -425,12 +422,8 @@ retry:
        }
 
        nimaps = XFS_WRITE_IMAPS;
-       firstblock = NULLFSBLOCK;
-       error = xfs_bmapi(NULL, ip, offset_fsb,
-                         (xfs_filblks_t)(last_fsb - offset_fsb),
-                         XFS_BMAPI_DELAY | XFS_BMAPI_WRITE |
-                         XFS_BMAPI_ENTIRE, &firstblock, 1, imap,
-                         &nimaps, NULL);
+       error = xfs_bmapi_delay(ip, offset_fsb, last_fsb - offset_fsb,
+                               imap, &nimaps, XFS_BMAPI_ENTIRE);
        switch (error) {
        case 0:
        case ENOSPC:
@@ -535,7 +528,7 @@ xfs_iomap_write_allocate(
                                return XFS_ERROR(error);
                        }
                        xfs_ilock(ip, XFS_ILOCK_EXCL);
-                       xfs_trans_ijoin(tp, ip);
+                       xfs_trans_ijoin(tp, ip, 0);
 
                        xfs_bmap_init(&free_list, &first_block);
 
@@ -587,14 +580,12 @@ xfs_iomap_write_allocate(
                        }
 
                        /*
-                        * Go get the actual blocks.
-                        *
                         * From this point onwards we overwrite the imap
                         * pointer that the caller gave to us.
                         */
-                       error = xfs_bmapi(tp, ip, map_start_fsb, count_fsb,
-                                       XFS_BMAPI_WRITE, &first_block, 1,
-                                       imap, &nimaps, &free_list);
+                       error = xfs_bmapi_write(tp, ip, map_start_fsb,
+                                               count_fsb, 0, &first_block, 1,
+                                               imap, &nimaps, &free_list);
                        if (error)
                                goto trans_cancel;
 
@@ -701,15 +692,15 @@ xfs_iomap_write_unwritten(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip);
+               xfs_trans_ijoin(tp, ip, 0);
 
                /*
                 * Modify the unwritten extent state of the buffer.
                 */
                xfs_bmap_init(&free_list, &firstfsb);
                nimaps = 1;
-               error = xfs_bmapi(tp, ip, offset_fsb, count_fsb,
-                                 XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb,
+               error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
+                                 XFS_BMAPI_CONVERT, &firstfsb,
                                  1, &imap, &nimaps, &free_list);
                if (error)
                        goto error_on_bmapi_transaction;
index 673704f..556bbe7 100644 (file)
@@ -465,7 +465,7 @@ xfs_vn_getattr(
        trace_xfs_getattr(ip);
 
        if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
+               return -XFS_ERROR(EIO);
 
        stat->size = XFS_ISIZE(ip);
        stat->dev = inode->i_sb->s_dev;
@@ -611,7 +611,7 @@ xfs_setattr_nonsize(
                }
        }
 
-       xfs_trans_ijoin(tp, ip);
+       xfs_trans_ijoin(tp, ip, 0);
 
        /*
         * Change file ownership.  Must be the owner or privileged.
@@ -833,16 +833,16 @@ xfs_setattr_size(
         * care about here.
         */
        if (ip->i_size != ip->i_d.di_size && iattr->ia_size > ip->i_d.di_size) {
-               error = xfs_flush_pages(ip, ip->i_d.di_size, iattr->ia_size,
-                                       XBF_ASYNC, FI_NONE);
+               error = xfs_flush_pages(ip, ip->i_d.di_size, iattr->ia_size, 0,
+                                       FI_NONE);
                if (error)
                        goto out_unlock;
        }
 
        /*
-        * Wait for all I/O to complete.
+        * Wait for all direct I/O to complete.
         */
-       xfs_ioend_wait(ip);
+       inode_dio_wait(inode);
 
        error = -block_truncate_page(inode->i_mapping, iattr->ia_size,
                                     xfs_get_blocks);
@@ -863,7 +863,7 @@ xfs_setattr_size(
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
 
-       xfs_trans_ijoin(tp, ip);
+       xfs_trans_ijoin(tp, ip, 0);
 
        /*
         * Only change the c/mtime if we are changing the size or we are
index 3a8d4f6..2758a62 100644 (file)
@@ -880,8 +880,8 @@ xlog_iodone(xfs_buf_t *bp)
         */
        if (XFS_TEST_ERROR((xfs_buf_geterror(bp)), l->l_mp,
                        XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) {
-               xfs_ioerror_alert("xlog_iodone", l->l_mp, bp, XFS_BUF_ADDR(bp));
-               XFS_BUF_STALE(bp);
+               xfs_buf_ioerror_alert(bp, __func__);
+               xfs_buf_stale(bp);
                xfs_force_shutdown(l->l_mp, SHUTDOWN_LOG_IO_ERROR);
                /*
                 * This flag will be propagated to the trans-committed
@@ -1047,7 +1047,7 @@ xlog_alloc_log(xfs_mount_t        *mp,
        xlog_get_iclog_buffer_size(mp, log);
 
        error = ENOMEM;
-       bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp);
+       bp = xfs_buf_alloc(mp->m_logdev_targp, 0, log->l_iclog_size, 0);
        if (!bp)
                goto out_free_log;
        bp->b_iodone = xlog_iodone;
@@ -1247,7 +1247,7 @@ xlog_bdstrat(
 
        if (iclog->ic_state & XLOG_STATE_IOERROR) {
                xfs_buf_ioerror(bp, EIO);
-               XFS_BUF_STALE(bp);
+               xfs_buf_stale(bp);
                xfs_buf_ioend(bp, 0);
                /*
                 * It would seem logical to return EIO here, but we rely on
@@ -1387,9 +1387,9 @@ xlog_sync(xlog_t          *log,
         */
        XFS_BUF_WRITE(bp);
 
-       if ((error = xlog_bdstrat(bp))) {
-               xfs_ioerror_alert("xlog_sync", log->l_mp, bp,
-                                 XFS_BUF_ADDR(bp));
+       error = xlog_bdstrat(bp);
+       if (error) {
+               xfs_buf_ioerror_alert(bp, "xlog_sync");
                return error;
        }
        if (split) {
@@ -1423,9 +1423,9 @@ xlog_sync(xlog_t          *log,
                /* account for internal log which doesn't start at block #0 */
                XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart);
                XFS_BUF_WRITE(bp);
-               if ((error = xlog_bdstrat(bp))) {
-                       xfs_ioerror_alert("xlog_sync (split)", log->l_mp,
-                                         bp, XFS_BUF_ADDR(bp));
+               error = xlog_bdstrat(bp);
+               if (error) {
+                       xfs_buf_ioerror_alert(bp, "xlog_sync (split)");
                        return error;
                }
        }
index a199dbc..541a508 100644 (file)
@@ -183,8 +183,7 @@ xlog_bread_noalign(
        xfsbdstrat(log->l_mp, bp);
        error = xfs_buf_iowait(bp);
        if (error)
-               xfs_ioerror_alert("xlog_bread", log->l_mp,
-                                 bp, XFS_BUF_ADDR(bp));
+               xfs_buf_ioerror_alert(bp, __func__);
        return error;
 }
 
@@ -268,9 +267,10 @@ xlog_bwrite(
        xfs_buf_lock(bp);
        XFS_BUF_SET_COUNT(bp, BBTOB(nbblks));
 
-       if ((error = xfs_bwrite(log->l_mp, bp)))
-               xfs_ioerror_alert("xlog_bwrite", log->l_mp,
-                                 bp, XFS_BUF_ADDR(bp));
+       error = xfs_bwrite(bp);
+       if (error)
+               xfs_buf_ioerror_alert(bp, __func__);
+       xfs_buf_relse(bp);
        return error;
 }
 
@@ -361,9 +361,7 @@ xlog_recover_iodone(
                 * We're not going to bother about retrying
                 * this during recovery. One strike!
                 */
-               xfs_ioerror_alert("xlog_recover_iodone",
-                                       bp->b_target->bt_mount, bp,
-                                       XFS_BUF_ADDR(bp));
+               xfs_buf_ioerror_alert(bp, __func__);
                xfs_force_shutdown(bp->b_target->bt_mount,
                                        SHUTDOWN_META_IO_ERROR);
        }
@@ -2135,8 +2133,7 @@ xlog_recover_buffer_pass2(
                return XFS_ERROR(ENOMEM);
        error = bp->b_error;
        if (error) {
-               xfs_ioerror_alert("xlog_recover_do..(read#1)", mp,
-                                 bp, buf_f->blf_blkno);
+               xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#1)");
                xfs_buf_relse(bp);
                return error;
        }
@@ -2171,15 +2168,16 @@ xlog_recover_buffer_pass2(
            be16_to_cpu(*((__be16 *)xfs_buf_offset(bp, 0))) &&
            (XFS_BUF_COUNT(bp) != MAX(log->l_mp->m_sb.sb_blocksize,
                        (__uint32_t)XFS_INODE_CLUSTER_SIZE(log->l_mp)))) {
-               XFS_BUF_STALE(bp);
-               error = xfs_bwrite(mp, bp);
+               xfs_buf_stale(bp);
+               error = xfs_bwrite(bp);
        } else {
                ASSERT(bp->b_target->bt_mount == mp);
                bp->b_iodone = xlog_recover_iodone;
-               xfs_bdwrite(mp, bp);
+               xfs_buf_delwri_queue(bp);
        }
 
-       return (error);
+       xfs_buf_relse(bp);
+       return error;
 }
 
 STATIC int
@@ -2230,8 +2228,7 @@ xlog_recover_inode_pass2(
        }
        error = bp->b_error;
        if (error) {
-               xfs_ioerror_alert("xlog_recover_do..(read#2)", mp,
-                                 bp, in_f->ilf_blkno);
+               xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#2)");
                xfs_buf_relse(bp);
                goto error;
        }
@@ -2439,7 +2436,8 @@ xlog_recover_inode_pass2(
 write_inode_buffer:
        ASSERT(bp->b_target->bt_mount == mp);
        bp->b_iodone = xlog_recover_iodone;
-       xfs_bdwrite(mp, bp);
+       xfs_buf_delwri_queue(bp);
+       xfs_buf_relse(bp);
 error:
        if (need_free)
                kmem_free(in_f);
@@ -2537,8 +2535,7 @@ xlog_recover_dquot_pass2(
                             XFS_FSB_TO_BB(mp, dq_f->qlf_len),
                             0, &bp);
        if (error) {
-               xfs_ioerror_alert("xlog_recover_do..(read#3)", mp,
-                                 bp, dq_f->qlf_blkno);
+               xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#3)");
                return error;
        }
        ASSERT(bp);
@@ -2561,7 +2558,8 @@ xlog_recover_dquot_pass2(
        ASSERT(dq_f->qlf_size == 2);
        ASSERT(bp->b_target->bt_mount == mp);
        bp->b_iodone = xlog_recover_iodone;
-       xfs_bdwrite(mp, bp);
+       xfs_buf_delwri_queue(bp);
+       xfs_buf_relse(bp);
 
        return (0);
 }
@@ -3656,7 +3654,7 @@ xlog_do_recover(
                return error;
        }
 
-       XFS_bflush(log->l_mp->m_ddev_targp);
+       xfs_flush_buftarg(log->l_mp->m_ddev_targp, 1);
 
        /*
         * If IO errors happened during recovery, bail out.
@@ -3689,8 +3687,7 @@ xlog_do_recover(
        xfsbdstrat(log->l_mp, bp);
        error = xfs_buf_iowait(bp);
        if (error) {
-               xfs_ioerror_alert("xlog_do_recover",
-                                 log->l_mp, bp, XFS_BUF_ADDR(bp));
+               xfs_buf_ioerror_alert(bp, __func__);
                ASSERT(0);
                xfs_buf_relse(bp);
                return error;
index 0081657..d06afbc 100644 (file)
@@ -44,9 +44,6 @@
 #include "xfs_trace.h"
 
 
-STATIC void    xfs_unmountfs_wait(xfs_mount_t *);
-
-
 #ifdef HAVE_PERCPU_SB
 STATIC void    xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t,
                                                int);
@@ -1484,7 +1481,7 @@ xfs_unmountfs(
         * state as much as possible.
         */
        xfs_reclaim_inodes(mp, 0);
-       XFS_bflush(mp->m_ddev_targp);
+       xfs_flush_buftarg(mp->m_ddev_targp, 1);
        xfs_reclaim_inodes(mp, SYNC_WAIT);
 
        xfs_qm_unmount(mp);
@@ -1496,11 +1493,6 @@ xfs_unmountfs(
         */
        xfs_log_force(mp, XFS_LOG_SYNC);
 
-       xfs_binval(mp->m_ddev_targp);
-       if (mp->m_rtdev_targp) {
-               xfs_binval(mp->m_rtdev_targp);
-       }
-
        /*
         * Unreserve any blocks we have so that when we unmount we don't account
         * the reserved free space as used. This is really only necessary for
@@ -1526,7 +1518,16 @@ xfs_unmountfs(
                xfs_warn(mp, "Unable to update superblock counters. "
                                "Freespace may not be correct on next mount.");
        xfs_unmountfs_writesb(mp);
-       xfs_unmountfs_wait(mp);                 /* wait for async bufs */
+
+       /*
+        * Make sure all buffers have been flushed and completed before
+        * unmounting the log.
+        */
+       error = xfs_flush_buftarg(mp->m_ddev_targp, 1);
+       if (error)
+               xfs_warn(mp, "%d busy buffers during unmount.", error);
+       xfs_wait_buftarg(mp->m_ddev_targp);
+
        xfs_log_unmount_write(mp);
        xfs_log_unmount(mp);
        xfs_uuid_unmount(mp);
@@ -1537,16 +1538,6 @@ xfs_unmountfs(
        xfs_free_perag(mp);
 }
 
-STATIC void
-xfs_unmountfs_wait(xfs_mount_t *mp)
-{
-       if (mp->m_logdev_targp != mp->m_ddev_targp)
-               xfs_wait_buftarg(mp->m_logdev_targp);
-       if (mp->m_rtdev_targp)
-               xfs_wait_buftarg(mp->m_rtdev_targp);
-       xfs_wait_buftarg(mp->m_ddev_targp);
-}
-
 int
 xfs_fs_writable(xfs_mount_t *mp)
 {
@@ -1612,15 +1603,14 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
 
                XFS_BUF_UNDONE(sbp);
                XFS_BUF_UNREAD(sbp);
-               XFS_BUF_UNDELAYWRITE(sbp);
+               xfs_buf_delwri_dequeue(sbp);
                XFS_BUF_WRITE(sbp);
                XFS_BUF_UNASYNC(sbp);
                ASSERT(sbp->b_target == mp->m_ddev_targp);
                xfsbdstrat(mp, sbp);
                error = xfs_buf_iowait(sbp);
                if (error)
-                       xfs_ioerror_alert("xfs_unmountfs_writesb",
-                                         mp, sbp, XFS_BUF_ADDR(sbp));
+                       xfs_buf_ioerror_alert(sbp, __func__);
                xfs_buf_relse(sbp);
        }
        return error;
index 9a0aa76..5cff443 100644 (file)
@@ -1296,7 +1296,8 @@ xfs_qm_dqiter_bufs(
                        break;
 
                xfs_qm_reset_dqcounts(mp, bp, firstid, type);
-               xfs_bdwrite(mp, bp);
+               xfs_buf_delwri_queue(bp);
+               xfs_buf_relse(bp);
                /*
                 * goto the next block.
                 */
@@ -1346,11 +1347,8 @@ xfs_qm_dqiterate(
                 * the inode is never added to the transaction.
                 */
                xfs_ilock(qip, XFS_ILOCK_SHARED);
-               error = xfs_bmapi(NULL, qip, lblkno,
-                                 maxlblkcnt - lblkno,
-                                 XFS_BMAPI_METADATA,
-                                 NULL,
-                                 0, map, &nmaps, NULL);
+               error = xfs_bmapi_read(qip, lblkno, maxlblkcnt - lblkno,
+                                      map, &nmaps, 0);
                xfs_iunlock(qip, XFS_ILOCK_SHARED);
                if (error)
                        break;
@@ -1683,7 +1681,7 @@ xfs_qm_quotacheck(
         * quotacheck'd stamp on the superblock. So, here we do a synchronous
         * flush.
         */
-       XFS_bflush(mp->m_ddev_targp);
+       xfs_flush_buftarg(mp->m_ddev_targp, 1);
 
        /*
         * If one type of quotas is off, then it will lose its
index 609246f..5cc3dde 100644 (file)
@@ -261,7 +261,7 @@ xfs_qm_scall_trunc_qfile(
        }
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip);
+       xfs_trans_ijoin(tp, ip, 0);
 
        error = xfs_itruncate_data(&tp, ip, 0);
        if (error) {
index df78c29..866de27 100644 (file)
@@ -170,12 +170,12 @@ xfs_rename(
         * we can rely on either trans_commit or trans_cancel to unlock
         * them.
         */
-       xfs_trans_ijoin_ref(tp, src_dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
        if (new_parent)
-               xfs_trans_ijoin_ref(tp, target_dp, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin_ref(tp, src_ip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
        if (target_ip)
-               xfs_trans_ijoin_ref(tp, target_ip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
 
        /*
         * If we are using project inheritance, we only allow renames
index 35561a5..87323f1 100644 (file)
@@ -112,7 +112,7 @@ xfs_growfs_rt_alloc(
                 * Lock the inode.
                 */
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
                xfs_bmap_init(&flist, &firstblock);
                /*
@@ -120,9 +120,9 @@ xfs_growfs_rt_alloc(
                 */
                nmap = 1;
                cancelflags |= XFS_TRANS_ABORT;
-               error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks,
-                       XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock,
-                       resblks, &map, &nmap, &flist);
+               error = xfs_bmapi_write(tp, ip, oblocks, nblocks - oblocks,
+                                       XFS_BMAPI_METADATA, &firstblock,
+                                       resblks, &map, &nmap, &flist);
                if (!error && nmap < 1)
                        error = XFS_ERROR(ENOSPC);
                if (error)
@@ -155,7 +155,7 @@ xfs_growfs_rt_alloc(
                         * Lock the bitmap inode.
                         */
                        xfs_ilock(ip, XFS_ILOCK_EXCL);
-                       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
+                       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
                        /*
                         * Get a buffer for the block.
                         */
@@ -856,33 +856,23 @@ xfs_rtbuf_get(
        xfs_buf_t       **bpp)          /* output: buffer for the block */
 {
        xfs_buf_t       *bp;            /* block buffer, result */
-       xfs_daddr_t     d;              /* disk addr of block */
-       int             error;          /* error value */
-       xfs_fsblock_t   fsb;            /* fs block number for block */
        xfs_inode_t     *ip;            /* bitmap or summary inode */
+       xfs_bmbt_irec_t map;
+       int             nmap;
+       int             error;          /* error value */
 
        ip = issum ? mp->m_rsumip : mp->m_rbmip;
-       /*
-        * Map from the file offset (block) and inode number to the
-        * file system block.
-        */
-       error = xfs_bmapi_single(tp, ip, XFS_DATA_FORK, &fsb, block);
-       if (error) {
+
+       error = xfs_bmapi_read(ip, block, 1, &map, &nmap, XFS_DATA_FORK);
+       if (error)
                return error;
-       }
-       ASSERT(fsb != NULLFSBLOCK);
-       /*
-        * Convert to disk address for buffer cache.
-        */
-       d = XFS_FSB_TO_DADDR(mp, fsb);
-       /*
-        * Read the buffer.
-        */
-       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
+
+       ASSERT(map.br_startblock != NULLFSBLOCK);
+       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
+                                  XFS_FSB_TO_DADDR(mp, map.br_startblock),
                                   mp->m_bsize, 0, &bp);
-       if (error) {
+       if (error)
                return error;
-       }
        ASSERT(!xfs_buf_geterror(bp));
        *bpp = bp;
        return 0;
@@ -1970,7 +1960,7 @@ xfs_growfs_rt(
                 * Lock out other callers by grabbing the bitmap inode lock.
                 */
                xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin_ref(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
                /*
                 * Update the bitmap inode's size.
                 */
@@ -1982,7 +1972,7 @@ xfs_growfs_rt(
                 * Get the summary inode into the transaction.
                 */
                xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin_ref(tp, mp->m_rsumip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, mp->m_rsumip, XFS_ILOCK_EXCL);
                /*
                 * Update the summary inode's size.
                 */
@@ -2153,7 +2143,7 @@ xfs_rtfree_extent(
         * Synchronize by locking the bitmap inode.
         */
        xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin_ref(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
 
 #if defined(__KERNEL__) && defined(DEBUG)
        /*
index c96a8a0..597d044 100644 (file)
@@ -92,24 +92,6 @@ xfs_do_force_shutdown(
 }
 
 /*
- * Prints out an ALERT message about I/O error.
- */
-void
-xfs_ioerror_alert(
-       char                    *func,
-       struct xfs_mount        *mp,
-       xfs_buf_t               *bp,
-       xfs_daddr_t             blkno)
-{
-       xfs_alert(mp,
-                "I/O error occurred: meta-data dev %s block 0x%llx"
-                "       (\"%s\") error %d buf count %zd",
-               xfs_buf_target_name(bp->b_target),
-               (__uint64_t)blkno, func,
-               bp->b_error, XFS_BUF_COUNT(bp));
-}
-
-/*
  * This isn't an absolute requirement, but it is
  * just a good idea to call xfs_read_buf instead of
  * directly doing a read_buf call. For one, we shouldn't
@@ -143,14 +125,13 @@ xfs_read_buf(
        } else {
                *bpp = NULL;
                if (error) {
-                       xfs_ioerror_alert("xfs_read_buf", mp, bp, XFS_BUF_ADDR(bp));
+                       xfs_buf_ioerror_alert(bp, __func__);
                } else {
                        error = XFS_ERROR(EIO);
                }
                if (bp) {
                        XFS_BUF_UNDONE(bp);
-                       XFS_BUF_UNDELAYWRITE(bp);
-                       XFS_BUF_STALE(bp);
+                       xfs_buf_stale(bp);
                        /*
                         * brelse clears B_ERROR and b_error
                         */
index 11c41ec..bbdb9ad 100644 (file)
@@ -42,8 +42,6 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
 extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp,
                        xfs_daddr_t blkno, int len, uint flags,
                        struct xfs_buf **bpp);
-extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp,
-                               xfs_buf_t *bp, xfs_daddr_t blkno);
 extern xfs_extlen_t xfs_get_extsz_hint(struct xfs_inode *ip);
 
 #endif /* __XFS_RW_H__ */
index 5cf06b8..3eca58f 100644 (file)
@@ -796,8 +796,6 @@ xfs_fs_destroy_inode(
        if (is_bad_inode(inode))
                goto out_reclaim;
 
-       xfs_ioend_wait(ip);
-
        ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
 
        /*
@@ -837,7 +835,6 @@ xfs_fs_inode_init_once(
        inode_init_once(VFS_I(ip));
 
        /* xfs inode */
-       atomic_set(&ip->i_iocount, 0);
        atomic_set(&ip->i_pincount, 0);
        spin_lock_init(&ip->i_flags_lock);
        init_waitqueue_head(&ip->i_ipin_wait);
@@ -887,7 +884,7 @@ xfs_log_inode(
        }
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        return xfs_trans_commit(tp, 0);
 }
@@ -914,9 +911,8 @@ xfs_fs_write_inode(
                 * of forcing it all the way to stable storage using a
                 * synchronous transaction we let the log force inside the
                 * ->sync_fs call do that for thus, which reduces the number
-                * of synchronous log foces dramatically.
+                * of synchronous log forces dramatically.
                 */
-               xfs_ioend_wait(ip);
                error = xfs_log_inode(ip);
                if (error)
                        goto out;
@@ -1019,7 +1015,7 @@ xfs_fs_put_super(
         */
        xfs_filestream_unmount(mp);
 
-       XFS_bflush(mp->m_ddev_targp);
+       xfs_flush_buftarg(mp->m_ddev_targp, 1);
 
        xfs_unmountfs(mp);
        xfs_freesb(mp);
@@ -1443,7 +1439,7 @@ xfs_fs_fill_super(
         */
        xfs_filestream_unmount(mp);
 
-       XFS_bflush(mp->m_ddev_targp);
+       xfs_flush_buftarg(mp->m_ddev_targp, 1);
 
        xfs_unmountfs(mp);
        goto out_free_sb;
@@ -1670,7 +1666,6 @@ init_xfs_fs(void)
        printk(KERN_INFO XFS_VERSION_STRING " with "
                         XFS_BUILD_OPTIONS " enabled\n");
 
-       xfs_ioend_init();
        xfs_dir_startup();
 
        error = xfs_init_zones();
index 4604f90..aa3dc1a 100644 (file)
@@ -227,21 +227,17 @@ xfs_sync_inode_data(
        int                     error = 0;
 
        if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
-               goto out_wait;
+               return 0;
 
        if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) {
                if (flags & SYNC_TRYLOCK)
-                       goto out_wait;
+                       return 0;
                xfs_ilock(ip, XFS_IOLOCK_SHARED);
        }
 
        error = xfs_flush_pages(ip, 0, -1, (flags & SYNC_WAIT) ?
                                0 : XBF_ASYNC, FI_NONE);
        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-
- out_wait:
-       if (flags & SYNC_WAIT)
-               xfs_ioend_wait(ip);
        return error;
 }
 
@@ -322,6 +318,7 @@ xfs_sync_fsdata(
        struct xfs_mount        *mp)
 {
        struct xfs_buf          *bp;
+       int                     error;
 
        /*
         * If the buffer is pinned then push on the log so we won't get stuck
@@ -334,8 +331,9 @@ xfs_sync_fsdata(
        bp = xfs_getsb(mp, 0);
        if (xfs_buf_ispinned(bp))
                xfs_log_force(mp, 0);
-
-       return xfs_bwrite(mp, bp);
+       error = xfs_bwrite(bp);
+       xfs_buf_relse(bp);
+       return error;
 }
 
 /*
@@ -379,7 +377,7 @@ xfs_quiesce_data(
 
        /* flush data-only devices */
        if (mp->m_rtdev_targp)
-               XFS_bflush(mp->m_rtdev_targp);
+               xfs_flush_buftarg(mp->m_rtdev_targp, 1);
 
        return error ? error : error2;
 }
index 690fc7a..b78f2c6 100644 (file)
@@ -320,7 +320,6 @@ DEFINE_BUF_EVENT(xfs_buf_rele);
 DEFINE_BUF_EVENT(xfs_buf_iodone);
 DEFINE_BUF_EVENT(xfs_buf_iorequest);
 DEFINE_BUF_EVENT(xfs_buf_bawrite);
-DEFINE_BUF_EVENT(xfs_buf_bdwrite);
 DEFINE_BUF_EVENT(xfs_buf_lock);
 DEFINE_BUF_EVENT(xfs_buf_lock_done);
 DEFINE_BUF_EVENT(xfs_buf_trylock);
@@ -577,6 +576,7 @@ DEFINE_INODE_EVENT(xfs_vm_bmap);
 DEFINE_INODE_EVENT(xfs_file_ioctl);
 DEFINE_INODE_EVENT(xfs_file_compat_ioctl);
 DEFINE_INODE_EVENT(xfs_ioctl_setattr);
+DEFINE_INODE_EVENT(xfs_dir_fsync);
 DEFINE_INODE_EVENT(xfs_file_fsync);
 DEFINE_INODE_EVENT(xfs_destroy_inode);
 DEFINE_INODE_EVENT(xfs_write_inode);
index efc147f..1f35b2f 100644 (file)
@@ -1790,9 +1790,7 @@ xfs_trans_commit_cil(
 }
 
 /*
- * xfs_trans_commit
- *
- * Commit the given transaction to the log a/synchronously.
+ * Commit the given transaction to the log.
  *
  * XFS disk error handling mechanism is not based on a typical
  * transaction abort mechanism. Logically after the filesystem
@@ -1804,10 +1802,9 @@ xfs_trans_commit_cil(
  * Do not reference the transaction structure after this call.
  */
 int
-_xfs_trans_commit(
+xfs_trans_commit(
        struct xfs_trans        *tp,
-       uint                    flags,
-       int                     *log_flushed)
+       uint                    flags)
 {
        struct xfs_mount        *mp = tp->t_mountp;
        xfs_lsn_t               commit_lsn = -1;
@@ -1866,7 +1863,7 @@ _xfs_trans_commit(
        if (sync) {
                if (!error) {
                        error = _xfs_log_force_lsn(mp, commit_lsn,
-                                     XFS_LOG_SYNC, log_flushed);
+                                     XFS_LOG_SYNC, NULL);
                }
                XFS_STATS_INC(xs_trans_sync);
        } else {
@@ -2021,6 +2018,6 @@ xfs_trans_roll(
        if (error)
                return error;
 
-       xfs_trans_ijoin(trans, dp);
+       xfs_trans_ijoin(trans, dp, 0);
        return 0;
 }
index 53597f4..603f3eb 100644 (file)
@@ -470,8 +470,7 @@ void                xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
 void           xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
-void           xfs_trans_ijoin_ref(struct xfs_trans *, struct xfs_inode *, uint);
-void           xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *);
+void           xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
 void           xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
 void           xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
 struct xfs_efi_log_item        *xfs_trans_get_efi(xfs_trans_t *, uint);
@@ -487,10 +486,7 @@ void               xfs_trans_log_efd_extent(xfs_trans_t *,
                                         struct xfs_efd_log_item *,
                                         xfs_fsblock_t,
                                         xfs_extlen_t);
-int            _xfs_trans_commit(xfs_trans_t *,
-                                 uint flags,
-                                 int *);
-#define xfs_trans_commit(tp, flags)    _xfs_trans_commit(tp, flags, NULL)
+int            xfs_trans_commit(xfs_trans_t *, uint flags);
 void           xfs_trans_cancel(xfs_trans_t *, int);
 int            xfs_trans_ail_init(struct xfs_mount *);
 void           xfs_trans_ail_destroy(struct xfs_mount *);
index 3a1e7ca..512ff64 100644 (file)
@@ -364,12 +364,24 @@ xfsaild_push(
        xfs_lsn_t               lsn;
        xfs_lsn_t               target;
        long                    tout = 10;
-       int                     flush_log = 0;
        int                     stuck = 0;
        int                     count = 0;
        int                     push_xfsbufd = 0;
 
+       /*
+        * If last time we ran we encountered pinned items, force the log first
+        * and wait for it before pushing again.
+        */
        spin_lock(&ailp->xa_lock);
+       if (ailp->xa_last_pushed_lsn == 0 && ailp->xa_log_flush &&
+           !list_empty(&ailp->xa_ail)) {
+               ailp->xa_log_flush = 0;
+               spin_unlock(&ailp->xa_lock);
+               XFS_STATS_INC(xs_push_ail_flush);
+               xfs_log_force(mp, XFS_LOG_SYNC);
+               spin_lock(&ailp->xa_lock);
+       }
+
        target = ailp->xa_target;
        lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn);
        if (!lip || XFS_FORCED_SHUTDOWN(mp)) {
@@ -432,7 +444,7 @@ xfsaild_push(
                case XFS_ITEM_PINNED:
                        XFS_STATS_INC(xs_push_ail_pinned);
                        stuck++;
-                       flush_log = 1;
+                       ailp->xa_log_flush++;
                        break;
 
                case XFS_ITEM_LOCKED:
@@ -476,16 +488,6 @@ xfsaild_push(
        xfs_trans_ail_cursor_done(ailp, &cur);
        spin_unlock(&ailp->xa_lock);
 
-       if (flush_log) {
-               /*
-                * If something we need to push out was pinned, then
-                * push out the log so it will become unpinned and
-                * move forward in the AIL.
-                */
-               XFS_STATS_INC(xs_push_ail_flush);
-               xfs_log_force(mp, 0);
-       }
-
        if (push_xfsbufd) {
                /* we've got delayed write buffers to flush */
                wake_up_process(mp->m_ddev_targp->bt_task);
@@ -496,6 +498,7 @@ out_done:
        if (!count) {
                /* We're past our target or empty, so idle */
                ailp->xa_last_pushed_lsn = 0;
+               ailp->xa_log_flush = 0;
 
                tout = 50;
        } else if (XFS_LSN_CMP(lsn, target) >= 0) {
@@ -514,9 +517,13 @@ out_done:
                 * were stuck.
                 *
                 * Backoff a bit more to allow some I/O to complete before
-                * continuing from where we were.
+                * restarting from the start of the AIL. This prevents us
+                * from spinning on the same items, and if they are pinned will
+                * all the restart to issue a log force to unpin the stuck
+                * items.
                 */
                tout = 20;
+               ailp->xa_last_pushed_lsn = 0;
        }
 
        return tout;
index 137e2b9..475a4de 100644 (file)
@@ -160,8 +160,10 @@ xfs_trans_get_buf(xfs_trans_t      *tp,
        bp = xfs_trans_buf_item_match(tp, target_dev, blkno, len);
        if (bp != NULL) {
                ASSERT(xfs_buf_islocked(bp));
-               if (XFS_FORCED_SHUTDOWN(tp->t_mountp))
-                       XFS_BUF_SUPER_STALE(bp);
+               if (XFS_FORCED_SHUTDOWN(tp->t_mountp)) {
+                       xfs_buf_stale(bp);
+                       XFS_BUF_DONE(bp);
+               }
 
                /*
                 * If the buffer is stale then it was binval'ed
@@ -294,8 +296,7 @@ xfs_trans_read_buf(
 
                if (bp->b_error) {
                        error = bp->b_error;
-                       xfs_ioerror_alert("xfs_trans_read_buf", mp,
-                                         bp, blkno);
+                       xfs_buf_ioerror_alert(bp, __func__);
                        xfs_buf_relse(bp);
                        return error;
                }
@@ -337,8 +338,7 @@ xfs_trans_read_buf(
                        xfsbdstrat(tp->t_mountp, bp);
                        error = xfs_buf_iowait(bp);
                        if (error) {
-                               xfs_ioerror_alert("xfs_trans_read_buf", mp,
-                                                 bp, blkno);
+                               xfs_buf_ioerror_alert(bp, __func__);
                                xfs_buf_relse(bp);
                                /*
                                 * We can gracefully recover from most read
@@ -387,9 +387,9 @@ xfs_trans_read_buf(
        }
        if (bp->b_error) {
                error = bp->b_error;
-               XFS_BUF_SUPER_STALE(bp);
-               xfs_ioerror_alert("xfs_trans_read_buf", mp,
-                                 bp, blkno);
+               xfs_buf_stale(bp);
+               XFS_BUF_DONE(bp);
+               xfs_buf_ioerror_alert(bp, __func__);
                if (tp->t_flags & XFS_TRANS_DIRTY)
                        xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR);
                xfs_buf_relse(bp);
@@ -643,13 +643,14 @@ xfs_trans_log_buf(xfs_trans_t     *tp,
         * inside the b_bdstrat callback so that this won't get written to
         * disk.
         */
-       XFS_BUF_DELAYWRITE(bp);
        XFS_BUF_DONE(bp);
 
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        bp->b_iodone = xfs_buf_iodone_callbacks;
        bip->bli_item.li_cb = xfs_buf_iodone;
 
+       xfs_buf_delwri_queue(bp);
+
        trace_xfs_trans_log_buf(bip);
 
        /*
@@ -738,8 +739,7 @@ xfs_trans_binval(
         * We set the stale bit in the buffer as well since we're getting
         * rid of it.
         */
-       XFS_BUF_UNDELAYWRITE(bp);
-       XFS_BUF_STALE(bp);
+       xfs_buf_stale(bp);
        bip->bli_flags |= XFS_BLI_STALE;
        bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY);
        bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF;
index c8dea2f..32f0288 100644 (file)
@@ -47,11 +47,13 @@ xfs_trans_inode_broot_debug(
  * Add a locked inode to the transaction.
  *
  * The inode must be locked, and it cannot be associated with any transaction.
+ * If lock_flags is non-zero the inode will be unlocked on transaction commit.
  */
 void
 xfs_trans_ijoin(
        struct xfs_trans        *tp,
-       struct xfs_inode        *ip)
+       struct xfs_inode        *ip,
+       uint                    lock_flags)
 {
        xfs_inode_log_item_t    *iip;
 
@@ -59,7 +61,9 @@ xfs_trans_ijoin(
        if (ip->i_itemp == NULL)
                xfs_inode_item_init(ip, ip->i_mount);
        iip = ip->i_itemp;
+
        ASSERT(iip->ili_lock_flags == 0);
+       iip->ili_lock_flags = lock_flags;
 
        /*
         * Get a log_item_desc to point at the new item.
@@ -70,25 +74,6 @@ xfs_trans_ijoin(
 }
 
 /*
- * Add a locked inode to the transaction.
- *
- *
- * Grabs a reference to the inode which will be dropped when the transaction
- * is committed.  The inode will also be unlocked at that point.  The inode
- * must be locked, and it cannot be associated with any transaction.
- */
-void
-xfs_trans_ijoin_ref(
-       struct xfs_trans        *tp,
-       struct xfs_inode        *ip,
-       uint                    lock_flags)
-{
-       xfs_trans_ijoin(tp, ip);
-       IHOLD(ip);
-       ip->i_itemp->ili_lock_flags = lock_flags;
-}
-
-/*
  * Transactional inode timestamp update. Requires the inode to be locked and
  * joined to the transaction supplied. Relies on the transaction subsystem to
  * track dirty state and update/writeback the inode accordingly.
index 22750b5..44820b9 100644 (file)
@@ -70,6 +70,7 @@ struct xfs_ail {
        struct list_head        xa_cursors;
        spinlock_t              xa_lock;
        xfs_lsn_t               xa_last_pushed_lsn;
+       int                     xa_log_flush;
 };
 
 /*
index 51fc429..4ecf2a5 100644 (file)
@@ -72,8 +72,8 @@ xfs_readlink_bmap(
        xfs_buf_t       *bp;
        int             error = 0;
 
-       error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0,
-                       mval, &nmaps, NULL);
+       error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, pathlen), mval, &nmaps,
+                              0);
        if (error)
                goto out;
 
@@ -87,8 +87,7 @@ xfs_readlink_bmap(
                        return XFS_ERROR(ENOMEM);
                error = bp->b_error;
                if (error) {
-                       xfs_ioerror_alert("xfs_readlink",
-                                 ip->i_mount, bp, XFS_BUF_ADDR(bp));
+                       xfs_buf_ioerror_alert(bp, __func__);
                        xfs_buf_relse(bp);
                        goto out;
                }
@@ -178,8 +177,7 @@ xfs_free_eofblocks(
 
        nimaps = 1;
        xfs_ilock(ip, XFS_ILOCK_SHARED);
-       error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0,
-                         NULL, 0, &imap, &nimaps, NULL);
+       error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0);
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
        if (!error && (nimaps != 0) &&
@@ -220,7 +218,7 @@ xfs_free_eofblocks(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip);
+               xfs_trans_ijoin(tp, ip, 0);
 
                error = xfs_itruncate_data(&tp, ip, ip->i_size);
                if (error) {
@@ -289,7 +287,7 @@ xfs_inactive_symlink_rmt(
        xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
        size = (int)ip->i_d.di_size;
        ip->i_d.di_size = 0;
-       xfs_trans_ijoin(tp, ip);
+       xfs_trans_ijoin(tp, ip, 0);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        /*
         * Find the block(s) so we can inval and unmap them.
@@ -297,9 +295,9 @@ xfs_inactive_symlink_rmt(
        done = 0;
        xfs_bmap_init(&free_list, &first_block);
        nmaps = ARRAY_SIZE(mval);
-       if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size),
-                       XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps,
-                       &free_list)))
+       error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, size),
+                               mval, &nmaps, 0);
+       if (error)
                goto error0;
        /*
         * Invalidate the block(s).
@@ -308,6 +306,10 @@ xfs_inactive_symlink_rmt(
                bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
                        XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
                        XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0);
+               if (!bp) {
+                       error = ENOMEM;
+                       goto error1;
+               }
                xfs_trans_binval(tp, bp);
        }
        /*
@@ -333,7 +335,7 @@ xfs_inactive_symlink_rmt(
         * Mark it dirty so it will be logged and moved forward in the log as
         * part of every commit.
         */
-       xfs_trans_ijoin(tp, ip);
+       xfs_trans_ijoin(tp, ip, 0);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        /*
         * Get a new, empty transaction to return to our caller.
@@ -466,7 +468,7 @@ xfs_inactive_attrs(
                goto error_cancel;
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip);
+       xfs_trans_ijoin(tp, ip, 0);
        xfs_idestroy_fork(ip, XFS_ATTR_FORK);
 
        ASSERT(ip->i_d.di_anextents == 0);
@@ -647,8 +649,6 @@ xfs_inactive(
        if (truncate) {
                xfs_ilock(ip, XFS_IOLOCK_EXCL);
 
-               xfs_ioend_wait(ip);
-
                error = xfs_trans_reserve(tp, 0,
                                          XFS_ITRUNCATE_LOG_RES(mp),
                                          0, XFS_TRANS_PERM_LOG_RES,
@@ -662,7 +662,7 @@ xfs_inactive(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip);
+               xfs_trans_ijoin(tp, ip, 0);
 
                error = xfs_itruncate_data(&tp, ip, 0);
                if (error) {
@@ -686,7 +686,7 @@ xfs_inactive(
                        return VN_INACTIVE_CACHE;
                }
 
-               xfs_trans_ijoin(tp, ip);
+               xfs_trans_ijoin(tp, ip, 0);
        } else {
                error = xfs_trans_reserve(tp, 0,
                                          XFS_IFREE_LOG_RES(mp),
@@ -699,7 +699,7 @@ xfs_inactive(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-               xfs_trans_ijoin(tp, ip);
+               xfs_trans_ijoin(tp, ip, 0);
        }
 
        /*
@@ -939,7 +939,7 @@ xfs_create(
         * the transaction cancel unlocking dp so don't do it explicitly in the
         * error path.
         */
-       xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
        unlock_dp_on_error = B_FALSE;
 
        error = xfs_dir_createname(tp, dp, name, ip->i_ino,
@@ -1260,8 +1260,8 @@ xfs_remove(
 
        xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);
 
-       xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
        /*
         * If we're removing a directory perform some additional validation.
@@ -1406,8 +1406,8 @@ xfs_link(
 
        xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
 
-       xfs_trans_ijoin_ref(tp, sip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin_ref(tp, tdp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
 
        /*
         * If the source has too many links, we can't make any more to it.
@@ -1601,7 +1601,7 @@ xfs_symlink(
         * transaction cancel unlocking dp so don't do it explicitly in the
         * error path.
         */
-       xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
        unlock_dp_on_error = B_FALSE;
 
        /*
@@ -1632,10 +1632,9 @@ xfs_symlink(
                first_fsb = 0;
                nmaps = SYMLINK_MAPS;
 
-               error = xfs_bmapi(tp, ip, first_fsb, fs_blocks,
-                                 XFS_BMAPI_WRITE | XFS_BMAPI_METADATA,
-                                 &first_block, resblks, mval, &nmaps,
-                                 &free_list);
+               error = xfs_bmapi_write(tp, ip, first_fsb, fs_blocks,
+                                 XFS_BMAPI_METADATA, &first_block, resblks,
+                                 mval, &nmaps, &free_list);
                if (error)
                        goto error2;
 
@@ -1650,7 +1649,10 @@ xfs_symlink(
                        byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
                        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
                                               BTOBB(byte_cnt), 0);
-                       ASSERT(!xfs_buf_geterror(bp));
+                       if (!bp) {
+                               error = ENOMEM;
+                               goto error2;
+                       }
                        if (pathlen < byte_cnt) {
                                byte_cnt = pathlen;
                        }
@@ -1732,7 +1734,7 @@ xfs_set_dmattrs(
                return error;
        }
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
        ip->i_d.di_dmevmask = evmask;
        ip->i_d.di_dmstate  = state;
@@ -1778,7 +1780,6 @@ xfs_alloc_file_space(
        xfs_fileoff_t           startoffset_fsb;
        xfs_fsblock_t           firstfsb;
        int                     nimaps;
-       int                     bmapi_flag;
        int                     quota_flag;
        int                     rt;
        xfs_trans_t             *tp;
@@ -1806,7 +1807,6 @@ xfs_alloc_file_space(
        count = len;
        imapp = &imaps[0];
        nimaps = 1;
-       bmapi_flag = XFS_BMAPI_WRITE | alloc_type;
        startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
        allocatesize_fsb = XFS_B_TO_FSB(mp, count);
 
@@ -1877,16 +1877,12 @@ xfs_alloc_file_space(
                if (error)
                        goto error1;
 
-               xfs_trans_ijoin(tp, ip);
+               xfs_trans_ijoin(tp, ip, 0);
 
-               /*
-                * Issue the xfs_bmapi() call to allocate the blocks
-                */
                xfs_bmap_init(&free_list, &firstfsb);
-               error = xfs_bmapi(tp, ip, startoffset_fsb,
-                                 allocatesize_fsb, bmapi_flag,
-                                 &firstfsb, 0, imapp, &nimaps,
-                                 &free_list);
+               error = xfs_bmapi_write(tp, ip, startoffset_fsb,
+                                       allocatesize_fsb, alloc_type, &firstfsb,
+                                       0, imapp, &nimaps, &free_list);
                if (error) {
                        goto error0;
                }
@@ -1976,8 +1972,7 @@ xfs_zero_remaining_bytes(
        for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
                offset_fsb = XFS_B_TO_FSBT(mp, offset);
                nimap = 1;
-               error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0,
-                       NULL, 0, &imap, &nimap, NULL);
+               error = xfs_bmapi_read(ip, offset_fsb, 1, &imap, &nimap, 0);
                if (error || nimap < 1)
                        break;
                ASSERT(imap.br_blockcount >= 1);
@@ -1997,8 +1992,8 @@ xfs_zero_remaining_bytes(
                xfsbdstrat(mp, bp);
                error = xfs_buf_iowait(bp);
                if (error) {
-                       xfs_ioerror_alert("xfs_zero_remaining_bytes(read)",
-                                         mp, bp, XFS_BUF_ADDR(bp));
+                       xfs_buf_ioerror_alert(bp,
+                                       "xfs_zero_remaining_bytes(read)");
                        break;
                }
                memset(bp->b_addr +
@@ -2010,8 +2005,8 @@ xfs_zero_remaining_bytes(
                xfsbdstrat(mp, bp);
                error = xfs_buf_iowait(bp);
                if (error) {
-                       xfs_ioerror_alert("xfs_zero_remaining_bytes(write)",
-                                         mp, bp, XFS_BUF_ADDR(bp));
+                       xfs_buf_ioerror_alert(bp,
+                                       "xfs_zero_remaining_bytes(write)");
                        break;
                }
        }
@@ -2076,7 +2071,7 @@ xfs_free_file_space(
        if (need_iolock) {
                xfs_ilock(ip, XFS_IOLOCK_EXCL);
                /* wait for the completion of any pending DIOs */
-               xfs_ioend_wait(ip);
+               inode_dio_wait(VFS_I(ip));
        }
 
        rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
@@ -2096,8 +2091,8 @@ xfs_free_file_space(
         */
        if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
                nimap = 1;
-               error = xfs_bmapi(NULL, ip, startoffset_fsb,
-                       1, 0, NULL, 0, &imap, &nimap, NULL);
+               error = xfs_bmapi_read(ip, startoffset_fsb, 1,
+                                       &imap, &nimap, 0);
                if (error)
                        goto out_unlock_iolock;
                ASSERT(nimap == 0 || nimap == 1);
@@ -2111,8 +2106,8 @@ xfs_free_file_space(
                                startoffset_fsb += mp->m_sb.sb_rextsize - mod;
                }
                nimap = 1;
-               error = xfs_bmapi(NULL, ip, endoffset_fsb - 1,
-                       1, 0, NULL, 0, &imap, &nimap, NULL);
+               error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1,
+                                       &imap, &nimap, 0);
                if (error)
                        goto out_unlock_iolock;
                ASSERT(nimap == 0 || nimap == 1);
@@ -2180,7 +2175,7 @@ xfs_free_file_space(
                if (error)
                        goto error1;
 
-               xfs_trans_ijoin(tp, ip);
+               xfs_trans_ijoin(tp, ip, 0);
 
                /*
                 * issue the bunmapi() call to free the blocks
@@ -2353,8 +2348,7 @@ xfs_change_file_space(
        }
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-       xfs_trans_ijoin(tp, ip);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
        if ((attr_flags & XFS_ATTR_DMI) == 0) {
                ip->i_d.di_mode &= ~S_ISUID;
@@ -2379,10 +2373,5 @@ xfs_change_file_space(
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        if (attr_flags & XFS_ATTR_SYNC)
                xfs_trans_set_sync(tp);
-
-       error = xfs_trans_commit(tp, 0);
-
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
-       return error;
+       return xfs_trans_commit(tp, 0);
 }