xfs
[Top] [All Lists]

[PATCH 3/3] xfs: wait on IO completion inside an IO context

To: xfs@xxxxxxxxxxx
Subject: [PATCH 3/3] xfs: wait on IO completion inside an IO context
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Fri, 23 Jul 2010 20:41:18 +1000
In-reply-to: <1279881678-1660-1-git-send-email-david@xxxxxxxxxxxxx>
References: <1279881678-1660-1-git-send-email-david@xxxxxxxxxxxxx>
From: Dave Chinner <dchinner@xxxxxxxxxx>

To wait while IOs drain from the inode while inside an ioend context, we have
to wait until the inode io count drops to 1 - the reference we hold - rather
than zero. Add functionality to the ioend wait subsystem to do this.

Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
---
 fs/xfs/linux-2.6/xfs_aops.c |   50 +++++++++++++++++++++++++++++++++++++++++-
 fs/xfs/xfs_inode.h          |   13 ++++++-----
 2 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 5682490..ec499f2 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -64,6 +64,9 @@ xfs_ioend_init(void)
                init_waitqueue_head(&xfs_ioend_wq[i]);
 }
 
+/*
+ * wait for all IO to drain from the inode
+ */
 void
 xfs_ioend_wait(
        xfs_inode_t     *ip)
@@ -73,12 +76,55 @@ xfs_ioend_wait(
        wait_event(*wq, (atomic_read(&ip->i_iocount) == 0));
 }
 
+/*
+ * If we have an active ioend in the caller context (e.g.
+ * xfs_get_blocks_direct) we need to wait for the count to drop to one before
+ * we are woken.
+ *
+ * For this to work in the context of concurrent callers (concurrent direct 
IO),
+ * this function must be called with the iolock held exclusively to prevent
+ * other IOs blocking here and preventing the count from ever dropping to 1.
+ */
+STATIC void
+xfs_ioend_wait_excl(
+       xfs_inode_t     *ip)
+{
+       wait_queue_head_t *wq = to_ioend_wq(ip);
+
+       ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
+       xfs_iflags_set(ip, XFS_IIOEND_WAIT_EXCL);
+       wait_event(*wq, (atomic_read(&ip->i_iocount) == 1));
+       xfs_iflags_clear(ip, XFS_IIOEND_WAIT_EXCL);
+}
+
 STATIC void
 xfs_ioend_wake(
        xfs_inode_t     *ip)
 {
-       if (atomic_dec_and_test(&ip->i_iocount))
+       if (atomic_dec_and_test(&ip->i_iocount)) {
+               wake_up(to_ioend_wq(ip));
+               return;
+       }
+
+       /*
+        * do an unlocked check for an exclusive wait before trying to get
+        * spinlocks to avoid hurting the normal path too much. We can do this
+        * check unlocked because if the flag is not set here and this is the
+        * last IO remaining (i.e. iocount == 1 after the above decrement),
+        * then any code that enters xfs_ioend_wait_excl() will now see that
+        * i_iocount == 1 and return immediately. Hence we don't need to issue
+        * a wakeup in this case, and it keeps the common case overhead as low
+        * as possible.
+        */
+       smp_rmb();
+       if (!__xfs_iflags_test(ip, XFS_IIOEND_WAIT_EXCL))
+               return;
+
+       spin_lock(&ip->i_flags_lock);
+       if (atomic_read(&ip->i_iocount) == 1 &&
+           __xfs_iflags_test(ip, XFS_IIOEND_WAIT_EXCL))
                wake_up(to_ioend_wq(ip));
+       spin_unlock(&ip->i_flags_lock);
 }
 
 void
@@ -1334,7 +1380,7 @@ remap:
            (flags & GET_BLOCKS_UNALIGNED) && !iolock_changed) {
                xfs_iunlock(XFS_I(inode), XFS_IOLOCK_SHARED);
                xfs_ilock(XFS_I(inode), XFS_IOLOCK_EXCL);
-               xfs_ioend_wait(XFS_I(inode));
+               xfs_ioend_wait_excl(XFS_I(inode));
                iolock_changed = 1;
                goto remap;
        }
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 0898c54..40b5203 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -357,12 +357,13 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)
 /*
  * In-core inode flags.
  */
-#define XFS_IRECLAIM    0x0001  /* we have started reclaiming this inode    */
-#define XFS_ISTALE     0x0002  /* inode has been staled */
-#define XFS_IRECLAIMABLE 0x0004 /* inode can be reclaimed */
-#define XFS_INEW       0x0008  /* inode has just been allocated */
-#define XFS_IFILESTREAM        0x0010  /* inode is in a filestream directory */
-#define XFS_ITRUNCATED 0x0020  /* truncated down so flush-on-close */
+#define XFS_IRECLAIM           0x0001  /* have started reclaiming this inode */
+#define XFS_ISTALE             0x0002  /* inode has been staled */
+#define XFS_IRECLAIMABLE       0x0004  /* inode can be reclaimed */
+#define XFS_INEW               0x0008  /* inode has just been allocated */
+#define XFS_IFILESTREAM                0x0010  /* inode is in a filestream 
directory */
+#define XFS_ITRUNCATED         0x0020  /* truncated down so flush-on-close */
+#define XFS_IIOEND_WAIT_EXCL   0x0040  /* io completion waiter in io context */
 
 /*
  * Flags for inode locking.
-- 
1.7.1

<Prev in Thread] Current Thread [Next in Thread>