[PATCH 3/3] xfs: wait on IO completion inside an IO context
Dave Chinner
david at fromorbit.com
Fri Jul 23 05:41:18 CDT 2010
From: Dave Chinner <dchinner at redhat.com>
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 at redhat.com>
---
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
More information about the xfs
mailing list