gfs2: use workqueue instead of slow-work
authorTejun Heo <tj@kernel.org>
Tue, 20 Jul 2010 20:09:02 +0000 (22:09 +0200)
committerTejun Heo <tj@kernel.org>
Fri, 23 Jul 2010 11:14:25 +0000 (13:14 +0200)
Workqueue can now handle high concurrency.  Convert gfs to use
workqueue instead of slow-work.

* Steven pointed out that recovery path might be run from allocation
  path and thus requires forward progress guarantee without memory
  allocation.  Create and use gfs_recovery_wq with rescuer.  Please
  note that forward progress wasn't guaranteed with slow-work.

* Updated to use non-reentrant workqueue.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Steven Whitehouse <swhiteho@redhat.com>
fs/gfs2/Kconfig
fs/gfs2/incore.h
fs/gfs2/main.c
fs/gfs2/ops_fstype.c
fs/gfs2/recovery.c
fs/gfs2/recovery.h
fs/gfs2/sys.c

index a47b4310711201889a2e0ff84b4f004fdf3e1850..cc9665522148a730b010953596cc24edefc00ed6 100644 (file)
@@ -7,7 +7,6 @@ config GFS2_FS
        select IP_SCTP if DLM_SCTP
        select FS_POSIX_ACL
        select CRC32
-       select SLOW_WORK
        select QUOTACTL
        help
          A cluster filesystem.
index b5d7363b22da08cdbcaab0c3f5188022c5f7bffe..dd8f2e63d15ac7a8c50afc44a8b11d0554c7c863 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/fs.h>
 #include <linux/workqueue.h>
-#include <linux/slow-work.h>
 #include <linux/dlm.h>
 #include <linux/buffer_head.h>
 
@@ -383,7 +382,7 @@ struct gfs2_journal_extent {
 struct gfs2_jdesc {
        struct list_head jd_list;
        struct list_head extent_list;
-       struct slow_work jd_work;
+       struct work_struct jd_work;
        struct inode *jd_inode;
        unsigned long jd_flags;
 #define JDF_RECOVERY 1
index fb2a5f93b7c3bf088f1a1c10556fd99cf56da4e5..b1e9630eb46a8d0338fef57ffa15caf23ab1cf0f 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/init.h>
 #include <linux/gfs2_ondisk.h>
 #include <asm/atomic.h>
-#include <linux/slow-work.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -24,6 +23,7 @@
 #include "util.h"
 #include "glock.h"
 #include "quota.h"
+#include "recovery.h"
 
 static struct shrinker qd_shrinker = {
        .shrink = gfs2_shrink_qd_memory,
@@ -138,9 +138,11 @@ static int __init init_gfs2_fs(void)
        if (error)
                goto fail_unregister;
 
-       error = slow_work_register_user(THIS_MODULE);
-       if (error)
-               goto fail_slow;
+       error = -ENOMEM;
+       gfs_recovery_wq = alloc_workqueue("gfs_recovery",
+                                         WQ_NON_REENTRANT | WQ_RESCUER, 0);
+       if (!gfs_recovery_wq)
+               goto fail_wq;
 
        gfs2_register_debugfs();
 
@@ -148,7 +150,7 @@ static int __init init_gfs2_fs(void)
 
        return 0;
 
-fail_slow:
+fail_wq:
        unregister_filesystem(&gfs2meta_fs_type);
 fail_unregister:
        unregister_filesystem(&gfs2_fs_type);
@@ -190,7 +192,7 @@ static void __exit exit_gfs2_fs(void)
        gfs2_unregister_debugfs();
        unregister_filesystem(&gfs2_fs_type);
        unregister_filesystem(&gfs2meta_fs_type);
-       slow_work_unregister_user(THIS_MODULE);
+       destroy_workqueue(gfs_recovery_wq);
 
        kmem_cache_destroy(gfs2_quotad_cachep);
        kmem_cache_destroy(gfs2_rgrpd_cachep);
index 3593b3a7290e874b1d3d6a2238a2a83567685b04..9a08e1bd6fbddf74daf4f0ac0b8b326f10485f65 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/slow-work.h>
 #include <linux/quotaops.h>
 
 #include "gfs2.h"
@@ -673,7 +672,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
                        break;
 
                INIT_LIST_HEAD(&jd->extent_list);
-               slow_work_init(&jd->jd_work, &gfs2_recover_ops);
+               INIT_WORK(&jd->jd_work, gfs2_recover_func);
                jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1);
                if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
                        if (!jd->jd_inode)
@@ -782,7 +781,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
        if (sdp->sd_lockstruct.ls_first) {
                unsigned int x;
                for (x = 0; x < sdp->sd_journals; x++) {
-                       error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x));
+                       error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x),
+                                                    true);
                        if (error) {
                                fs_err(sdp, "error recovering journal %u: %d\n",
                                       x, error);
@@ -792,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
 
                gfs2_others_may_mount(sdp);
        } else if (!sdp->sd_args.ar_spectator) {
-               error = gfs2_recover_journal(sdp->sd_jdesc);
+               error = gfs2_recover_journal(sdp->sd_jdesc, true);
                if (error) {
                        fs_err(sdp, "error recovering my journal: %d\n", error);
                        goto fail_jinode_gh;
index 4b9bece3d4372e323135156bd029d94877da5949..f7f89a94a5a4598a4b532016a0c16846a62cef2b 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/slow-work.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -28,6 +27,8 @@
 #include "util.h"
 #include "dir.h"
 
+struct workqueue_struct *gfs_recovery_wq;
+
 int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
                           struct buffer_head **bh)
 {
@@ -443,23 +444,7 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
         kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
 }
 
-static int gfs2_recover_get_ref(struct slow_work *work)
-{
-       struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
-       if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags))
-               return -EBUSY;
-       return 0;
-}
-
-static void gfs2_recover_put_ref(struct slow_work *work)
-{
-       struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
-       clear_bit(JDF_RECOVERY, &jd->jd_flags);
-       smp_mb__after_clear_bit();
-       wake_up_bit(&jd->jd_flags, JDF_RECOVERY);
-}
-
-static void gfs2_recover_work(struct slow_work *work)
+void gfs2_recover_func(struct work_struct *work)
 {
        struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
        struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
@@ -578,7 +563,7 @@ static void gfs2_recover_work(struct slow_work *work)
                gfs2_glock_dq_uninit(&j_gh);
 
        fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
-       return;
+       goto done;
 
 fail_gunlock_tr:
        gfs2_glock_dq_uninit(&t_gh);
@@ -590,32 +575,35 @@ fail_gunlock_j:
        }
 
        fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
-
 fail:
        gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
+done:
+       clear_bit(JDF_RECOVERY, &jd->jd_flags);
+       smp_mb__after_clear_bit();
+       wake_up_bit(&jd->jd_flags, JDF_RECOVERY);
 }
 
-struct slow_work_ops gfs2_recover_ops = {
-       .owner   = THIS_MODULE,
-       .get_ref = gfs2_recover_get_ref,
-       .put_ref = gfs2_recover_put_ref,
-       .execute = gfs2_recover_work,
-};
-
-
 static int gfs2_recovery_wait(void *word)
 {
        schedule();
        return 0;
 }
 
-int gfs2_recover_journal(struct gfs2_jdesc *jd)
+int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait)
 {
        int rv;
-       rv = slow_work_enqueue(&jd->jd_work);
-       if (rv)
-               return rv;
-       wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE);
+
+       if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags))
+               return -EBUSY;
+
+       /* we have JDF_RECOVERY, queue should always succeed */
+       rv = queue_work(gfs_recovery_wq, &jd->jd_work);
+       BUG_ON(!rv);
+
+       if (wait)
+               wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait,
+                           TASK_UNINTERRUPTIBLE);
+
        return 0;
 }
 
index 1616ac22569a940726c6123ef349ca8e157633d0..2226136c7647372c2e2a80fc20ebf439a8809dcf 100644 (file)
@@ -12,6 +12,8 @@
 
 #include "incore.h"
 
+extern struct workqueue_struct *gfs_recovery_wq;
+
 static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk)
 {
        if (++*blk == sdp->sd_jdesc->jd_blocks)
@@ -27,8 +29,8 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp);
 
 extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
                    struct gfs2_log_header_host *head);
-extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd);
-extern struct slow_work_ops gfs2_recover_ops;
+extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait);
+extern void gfs2_recover_func(struct work_struct *work);
 
 #endif /* __RECOVERY_DOT_H__ */
 
index 37f5393e68e6e34c96820ebb682fc2b9942e9004..6b60316ae3276df1c0998ba4f2372ddf42a992d6 100644 (file)
@@ -25,6 +25,7 @@
 #include "quota.h"
 #include "util.h"
 #include "glops.h"
+#include "recovery.h"
 
 struct gfs2_attr {
        struct attribute attr;
@@ -352,7 +353,7 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
        list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
                if (jd->jd_jid != jid)
                        continue;
-               rv = slow_work_enqueue(&jd->jd_work);
+               rv = gfs2_recover_journal(jd, false);
                break;
        }
 out: