[XFS] Delay I/O completion for unwritten extents after conversion
authorChristoph Hellwig <hch@sgi.com>
Sun, 4 Sep 2005 22:23:35 +0000 (08:23 +1000)
committerNathan Scott <nathans@sgi.com>
Sun, 4 Sep 2005 22:23:35 +0000 (08:23 +1000)
SGI-PV: 936584
SGI-Modid: xfs-linux:xfs-kern:196886a

Signed-off-by: Christoph Hellwig <hch@sgi.com>
Signed-off-by: Nathan Scott <nathans@sgi.com>
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_aops.h

index 2add9a8a8df75487803b4f78f8754960e4343a0b..ea615e2f476d6d1c4f449d52ad492421f26c1d4b 100644 (file)
@@ -136,10 +136,21 @@ xfs_end_bio_unwritten(
        vnode_t                 *vp = ioend->io_vnode;
        xfs_off_t               offset = ioend->io_offset;
        size_t                  size = ioend->io_size;
+       struct buffer_head      *bh, *next;
        int                     error;
 
        if (ioend->io_uptodate)
                VOP_BMAP(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL, error);
+
+       /* ioend->io_buffer_head is only non-NULL for buffered I/O */
+       for (bh = ioend->io_buffer_head; bh; bh = next) {
+               next = bh->b_private;
+
+               bh->b_end_io = NULL;
+               clear_buffer_unwritten(bh);
+               end_buffer_async_write(bh, ioend->io_uptodate);
+       }
+
        xfs_destroy_ioend(ioend);
 }
 
@@ -165,6 +176,7 @@ xfs_alloc_ioend(
        atomic_set(&ioend->io_remaining, 1);
        ioend->io_uptodate = 1; /* cleared if any I/O fails */
        ioend->io_vnode = LINVFS_GET_VP(inode);
+       ioend->io_buffer_head = NULL;
        atomic_inc(&ioend->io_vnode->v_iocount);
        ioend->io_offset = 0;
        ioend->io_size = 0;
@@ -180,15 +192,26 @@ linvfs_unwritten_done(
        int                     uptodate)
 {
        xfs_ioend_t             *ioend = bh->b_private;
+       static spinlock_t       unwritten_done_lock = SPIN_LOCK_UNLOCKED;
+       unsigned long           flags;
 
        ASSERT(buffer_unwritten(bh));
        bh->b_end_io = NULL;
-       clear_buffer_unwritten(bh);
+
        if (!uptodate)
                ioend->io_uptodate = 0;
 
+       /*
+        * Deep magic here.  We reuse b_private in the buffer_heads to build
+        * a chain for completing the I/O from user context after we've issued
+        * a transaction to convert the unwritten extent.
+        */
+       spin_lock_irqsave(&unwritten_done_lock, flags);
+       bh->b_private = ioend->io_buffer_head;
+       ioend->io_buffer_head = bh;
+       spin_unlock_irqrestore(&unwritten_done_lock, flags);
+
        xfs_finish_ioend(ioend);
-       end_buffer_async_write(bh, uptodate);
 }
 
 STATIC int
index ee46307a7321158aee8b27ce26481dd5b74de43f..2fa62974a04d924929e09a9626d674f7f346cbed 100644 (file)
@@ -41,6 +41,7 @@ typedef struct xfs_ioend {
        unsigned int            io_uptodate;    /* I/O status register */
        atomic_t                io_remaining;   /* hold count */
        struct vnode            *io_vnode;      /* file being written to */
+       struct buffer_head      *io_buffer_head;/* buffer linked list head */
        size_t                  io_size;        /* size of the extent */
        xfs_off_t               io_offset;      /* offset in the file */
        struct work_struct      io_work;        /* xfsdatad work queue */