xfs
[Top] [All Lists]

[PATCH 1/5] xfs: use per-filesystem I/O completion workqueues

To: xfs@xxxxxxxxxxx
Subject: [PATCH 1/5] xfs: use per-filesystem I/O completion workqueues
From: Christoph Hellwig <hch@xxxxxxxxxxxxx>
Date: Tue, 07 Feb 2012 13:10:38 -0500
References: <20120207181037.745771452@xxxxxxxxxxxxxxxxxxxxxx>
User-agent: quilt/0.48-1
The new concurrency managed workqueues are cheap enough that we can create
per-filesystem instead of global workqueues.  This allows us to remove the
trylock or defer scheme on the ilock, which is not helpful once we have
outstanding log reservations until finishing a size update.

Signed-off-by: Christoph Hellwig <hch@xxxxxx>

---
 fs/xfs/xfs_aops.c  |   39 ++++++++++-----------------------------
 fs/xfs/xfs_aops.h  |    2 --
 fs/xfs/xfs_buf.c   |   17 -----------------
 fs/xfs/xfs_mount.h |    3 +++
 fs/xfs/xfs_super.c |   43 ++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 55 insertions(+), 49 deletions(-)

Index: xfs/fs/xfs/xfs_aops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_aops.c  2012-01-30 11:54:44.000000000 +0100
+++ xfs/fs/xfs/xfs_aops.c       2012-01-30 11:56:50.096005059 +0100
@@ -126,21 +126,15 @@ static inline bool xfs_ioend_is_append(s
 
 /*
  * Update on-disk file size now that data has been written to disk.
- *
- * This function does not block as blocking on the inode lock in IO completion
- * can lead to IO completion order dependency deadlocks.. If it can't get the
- * inode ilock it will return EAGAIN. Callers must handle this.
  */
-STATIC int
+STATIC void
 xfs_setfilesize(
-       xfs_ioend_t             *ioend)
+       struct xfs_ioend        *ioend)
 {
-       xfs_inode_t             *ip = XFS_I(ioend->io_inode);
+       struct xfs_inode        *ip = XFS_I(ioend->io_inode);
        xfs_fsize_t             isize;
 
-       if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL))
-               return EAGAIN;
-
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
        isize = xfs_ioend_new_eof(ioend);
        if (isize) {
                trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
@@ -149,7 +143,6 @@ xfs_setfilesize(
        }
 
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       return 0;
 }
 
 /*
@@ -163,10 +156,12 @@ xfs_finish_ioend(
        struct xfs_ioend        *ioend)
 {
        if (atomic_dec_and_test(&ioend->io_remaining)) {
+               struct xfs_mount        *mp = XFS_I(ioend->io_inode)->i_mount;
+
                if (ioend->io_type == IO_UNWRITTEN)
-                       queue_work(xfsconvertd_workqueue, &ioend->io_work);
+                       queue_work(mp->m_unwritten_workqueue, &ioend->io_work);
                else if (xfs_ioend_is_append(ioend))
-                       queue_work(xfsdatad_workqueue, &ioend->io_work);
+                       queue_work(mp->m_data_workqueue, &ioend->io_work);
                else
                        xfs_destroy_ioend(ioend);
        }
@@ -207,23 +202,9 @@ xfs_end_io(
         * We might have to update the on-disk file size after extending
         * writes.
         */
-       error = xfs_setfilesize(ioend);
-       ASSERT(!error || error == EAGAIN);
-
+       xfs_setfilesize(ioend);
 done:
-       /*
-        * If we didn't complete processing of the ioend, requeue it to the
-        * tail of the workqueue for another attempt later. Otherwise destroy
-        * it.
-        */
-       if (error == EAGAIN) {
-               atomic_inc(&ioend->io_remaining);
-               xfs_finish_ioend(ioend);
-               /* ensure we don't spin on blocked ioends */
-               delay(1);
-       } else {
-               xfs_destroy_ioend(ioend);
-       }
+       xfs_destroy_ioend(ioend);
 }
 
 /*
Index: xfs/fs/xfs/xfs_aops.h
===================================================================
--- xfs.orig/fs/xfs/xfs_aops.h  2012-01-04 16:09:18.886530605 +0100
+++ xfs/fs/xfs/xfs_aops.h       2012-01-30 11:56:50.096005059 +0100
@@ -18,8 +18,6 @@
 #ifndef __XFS_AOPS_H__
 #define __XFS_AOPS_H__
 
-extern struct workqueue_struct *xfsdatad_workqueue;
-extern struct workqueue_struct *xfsconvertd_workqueue;
 extern mempool_t *xfs_ioend_pool;
 
 /*
Index: xfs/fs/xfs/xfs_buf.c
===================================================================
--- xfs.orig/fs/xfs/xfs_buf.c   2012-01-24 20:57:27.075957561 +0100
+++ xfs/fs/xfs/xfs_buf.c        2012-01-30 11:56:50.096005059 +0100
@@ -45,8 +45,6 @@ static kmem_zone_t *xfs_buf_zone;
 STATIC int xfsbufd(void *);
 
 static struct workqueue_struct *xfslogd_workqueue;
-struct workqueue_struct *xfsdatad_workqueue;
-struct workqueue_struct *xfsconvertd_workqueue;
 
 #ifdef XFS_BUF_LOCK_TRACKING
 # define XB_SET_OWNER(bp)      ((bp)->b_last_holder = current->pid)
@@ -1793,21 +1791,8 @@ xfs_buf_init(void)
        if (!xfslogd_workqueue)
                goto out_free_buf_zone;
 
-       xfsdatad_workqueue = alloc_workqueue("xfsdatad", WQ_MEM_RECLAIM, 1);
-       if (!xfsdatad_workqueue)
-               goto out_destroy_xfslogd_workqueue;
-
-       xfsconvertd_workqueue = alloc_workqueue("xfsconvertd",
-                                               WQ_MEM_RECLAIM, 1);
-       if (!xfsconvertd_workqueue)
-               goto out_destroy_xfsdatad_workqueue;
-
        return 0;
 
- out_destroy_xfsdatad_workqueue:
-       destroy_workqueue(xfsdatad_workqueue);
- out_destroy_xfslogd_workqueue:
-       destroy_workqueue(xfslogd_workqueue);
  out_free_buf_zone:
        kmem_zone_destroy(xfs_buf_zone);
  out:
@@ -1817,8 +1802,6 @@ xfs_buf_init(void)
 void
 xfs_buf_terminate(void)
 {
-       destroy_workqueue(xfsconvertd_workqueue);
-       destroy_workqueue(xfsdatad_workqueue);
        destroy_workqueue(xfslogd_workqueue);
        kmem_zone_destroy(xfs_buf_zone);
 }
Index: xfs/fs/xfs/xfs_super.c
===================================================================
--- xfs.orig/fs/xfs/xfs_super.c 2012-01-24 20:57:27.000000000 +0100
+++ xfs/fs/xfs/xfs_super.c      2012-01-30 11:56:50.099338392 +0100
@@ -760,6 +760,40 @@ xfs_setup_devices(
        return 0;
 }
 
+STATIC int
+xfs_init_mount_workqueues(
+       struct xfs_mount        *mp)
+{
+#define XFS_WQ_NAME_LEN                512
+       char                    name[XFS_WQ_NAME_LEN];
+
+       snprintf(name, XFS_WQ_NAME_LEN, "xfs-data/%s", mp->m_fsname);
+       mp->m_data_workqueue = alloc_workqueue(name, WQ_MEM_RECLAIM, 1);
+       if (!mp->m_data_workqueue)
+               goto out;
+
+       snprintf(name, XFS_WQ_NAME_LEN, "xfs-conv/%s", mp->m_fsname);
+       mp->m_unwritten_workqueue = alloc_workqueue(name, WQ_MEM_RECLAIM, 1);
+       if (!mp->m_unwritten_workqueue)
+               goto out_destroy_data_iodone_queue;
+
+       return 0;
+
+out_destroy_data_iodone_queue:
+       destroy_workqueue(mp->m_data_workqueue);
+out:
+       return -ENOMEM;
+#undef XFS_WQ_NAME_LEN
+}
+
+STATIC void
+xfs_destroy_mount_workqueues(
+       struct xfs_mount        *mp)
+{
+       destroy_workqueue(mp->m_data_workqueue);
+       destroy_workqueue(mp->m_unwritten_workqueue);
+}
+
 /* Catch misguided souls that try to use this interface on XFS */
 STATIC struct inode *
 xfs_fs_alloc_inode(
@@ -983,6 +1017,7 @@ xfs_fs_put_super(
        xfs_unmountfs(mp);
        xfs_freesb(mp);
        xfs_icsb_destroy_counters(mp);
+       xfs_destroy_mount_workqueues(mp);
        xfs_close_devices(mp);
        xfs_free_fsname(mp);
        kfree(mp);
@@ -1309,10 +1344,14 @@ xfs_fs_fill_super(
        if (error)
                goto out_free_fsname;
 
-       error = xfs_icsb_init_counters(mp);
+       error = xfs_init_mount_workqueues(mp);
        if (error)
                goto out_close_devices;
 
+       error = xfs_icsb_init_counters(mp);
+       if (error)
+               goto out_destroy_workqueues;
+
        error = xfs_readsb(mp, flags);
        if (error)
                goto out_destroy_counters;
@@ -1375,6 +1414,8 @@ xfs_fs_fill_super(
        xfs_freesb(mp);
  out_destroy_counters:
        xfs_icsb_destroy_counters(mp);
+out_destroy_workqueues:
+       xfs_destroy_mount_workqueues(mp);
  out_close_devices:
        xfs_close_devices(mp);
  out_free_fsname:
Index: xfs/fs/xfs/xfs_mount.h
===================================================================
--- xfs.orig/fs/xfs/xfs_mount.h 2012-01-06 16:07:32.405601416 +0100
+++ xfs/fs/xfs/xfs_mount.h      2012-01-30 11:56:50.099338392 +0100
@@ -211,6 +211,9 @@ typedef struct xfs_mount {
        struct shrinker         m_inode_shrink; /* inode reclaim shrinker */
        int64_t                 m_low_space[XFS_LOWSP_MAX];
                                                /* low free space thresholds */
+
+       struct workqueue_struct *m_data_workqueue;
+       struct workqueue_struct *m_unwritten_workqueue;
 } xfs_mount_t;
 
 /*

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