Commit 6ecd7c2d authored by Tejun Heo's avatar Tejun Heo

gfs2: use workqueue instead of slow-work

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: default avatarTejun Heo <tj@kernel.org>
Acked-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 991ea75c
...@@ -7,7 +7,6 @@ config GFS2_FS ...@@ -7,7 +7,6 @@ config GFS2_FS
select IP_SCTP if DLM_SCTP select IP_SCTP if DLM_SCTP
select FS_POSIX_ACL select FS_POSIX_ACL
select CRC32 select CRC32
select SLOW_WORK
select QUOTACTL select QUOTACTL
help help
A cluster filesystem. A cluster filesystem.
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/slow-work.h>
#include <linux/dlm.h> #include <linux/dlm.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
...@@ -383,7 +382,7 @@ struct gfs2_journal_extent { ...@@ -383,7 +382,7 @@ struct gfs2_journal_extent {
struct gfs2_jdesc { struct gfs2_jdesc {
struct list_head jd_list; struct list_head jd_list;
struct list_head extent_list; struct list_head extent_list;
struct slow_work jd_work; struct work_struct jd_work;
struct inode *jd_inode; struct inode *jd_inode;
unsigned long jd_flags; unsigned long jd_flags;
#define JDF_RECOVERY 1 #define JDF_RECOVERY 1
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <linux/slow-work.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
...@@ -24,6 +23,7 @@ ...@@ -24,6 +23,7 @@
#include "util.h" #include "util.h"
#include "glock.h" #include "glock.h"
#include "quota.h" #include "quota.h"
#include "recovery.h"
static struct shrinker qd_shrinker = { static struct shrinker qd_shrinker = {
.shrink = gfs2_shrink_qd_memory, .shrink = gfs2_shrink_qd_memory,
...@@ -138,9 +138,11 @@ static int __init init_gfs2_fs(void) ...@@ -138,9 +138,11 @@ static int __init init_gfs2_fs(void)
if (error) if (error)
goto fail_unregister; goto fail_unregister;
error = slow_work_register_user(THIS_MODULE); error = -ENOMEM;
if (error) gfs_recovery_wq = alloc_workqueue("gfs_recovery",
goto fail_slow; WQ_NON_REENTRANT | WQ_RESCUER, 0);
if (!gfs_recovery_wq)
goto fail_wq;
gfs2_register_debugfs(); gfs2_register_debugfs();
...@@ -148,7 +150,7 @@ static int __init init_gfs2_fs(void) ...@@ -148,7 +150,7 @@ static int __init init_gfs2_fs(void)
return 0; return 0;
fail_slow: fail_wq:
unregister_filesystem(&gfs2meta_fs_type); unregister_filesystem(&gfs2meta_fs_type);
fail_unregister: fail_unregister:
unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2_fs_type);
...@@ -190,7 +192,7 @@ static void __exit exit_gfs2_fs(void) ...@@ -190,7 +192,7 @@ static void __exit exit_gfs2_fs(void)
gfs2_unregister_debugfs(); gfs2_unregister_debugfs();
unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2_fs_type);
unregister_filesystem(&gfs2meta_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_quotad_cachep);
kmem_cache_destroy(gfs2_rgrpd_cachep); kmem_cache_destroy(gfs2_rgrpd_cachep);
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/slow-work.h>
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include "gfs2.h" #include "gfs2.h"
...@@ -673,7 +672,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) ...@@ -673,7 +672,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
break; break;
INIT_LIST_HEAD(&jd->extent_list); 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); jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1);
if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
if (!jd->jd_inode) if (!jd->jd_inode)
...@@ -782,7 +781,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ...@@ -782,7 +781,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
if (sdp->sd_lockstruct.ls_first) { if (sdp->sd_lockstruct.ls_first) {
unsigned int x; unsigned int x;
for (x = 0; x < sdp->sd_journals; 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) { if (error) {
fs_err(sdp, "error recovering journal %u: %d\n", fs_err(sdp, "error recovering journal %u: %d\n",
x, error); x, error);
...@@ -792,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ...@@ -792,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
gfs2_others_may_mount(sdp); gfs2_others_may_mount(sdp);
} else if (!sdp->sd_args.ar_spectator) { } else if (!sdp->sd_args.ar_spectator) {
error = gfs2_recover_journal(sdp->sd_jdesc); error = gfs2_recover_journal(sdp->sd_jdesc, true);
if (error) { if (error) {
fs_err(sdp, "error recovering my journal: %d\n", error); fs_err(sdp, "error recovering my journal: %d\n", error);
goto fail_jinode_gh; goto fail_jinode_gh;
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/slow-work.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
...@@ -28,6 +27,8 @@ ...@@ -28,6 +27,8 @@
#include "util.h" #include "util.h"
#include "dir.h" #include "dir.h"
struct workqueue_struct *gfs_recovery_wq;
int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
struct buffer_head **bh) struct buffer_head **bh)
{ {
...@@ -443,23 +444,7 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, ...@@ -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); kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
} }
static int gfs2_recover_get_ref(struct slow_work *work) void gfs2_recover_func(struct work_struct *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)
{ {
struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
struct gfs2_inode *ip = GFS2_I(jd->jd_inode); struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
...@@ -578,7 +563,7 @@ static void gfs2_recover_work(struct slow_work *work) ...@@ -578,7 +563,7 @@ static void gfs2_recover_work(struct slow_work *work)
gfs2_glock_dq_uninit(&j_gh); gfs2_glock_dq_uninit(&j_gh);
fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
return; goto done;
fail_gunlock_tr: fail_gunlock_tr:
gfs2_glock_dq_uninit(&t_gh); gfs2_glock_dq_uninit(&t_gh);
...@@ -590,32 +575,35 @@ static void gfs2_recover_work(struct slow_work *work) ...@@ -590,32 +575,35 @@ static void gfs2_recover_work(struct slow_work *work)
} }
fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done"); fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
fail: fail:
gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); 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) static int gfs2_recovery_wait(void *word)
{ {
schedule(); schedule();
return 0; return 0;
} }
int gfs2_recover_journal(struct gfs2_jdesc *jd) int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait)
{ {
int rv; int rv;
rv = slow_work_enqueue(&jd->jd_work);
if (rv) if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags))
return rv; return -EBUSY;
wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE);
/* 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; return 0;
} }
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "incore.h" #include "incore.h"
extern struct workqueue_struct *gfs_recovery_wq;
static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk)
{ {
if (++*blk == sdp->sd_jdesc->jd_blocks) if (++*blk == sdp->sd_jdesc->jd_blocks)
...@@ -27,8 +29,8 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp); ...@@ -27,8 +29,8 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp);
extern int gfs2_find_jhead(struct gfs2_jdesc *jd, extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
struct gfs2_log_header_host *head); struct gfs2_log_header_host *head);
extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd); extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait);
extern struct slow_work_ops gfs2_recover_ops; extern void gfs2_recover_func(struct work_struct *work);
#endif /* __RECOVERY_DOT_H__ */ #endif /* __RECOVERY_DOT_H__ */
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "quota.h" #include "quota.h"
#include "util.h" #include "util.h"
#include "glops.h" #include "glops.h"
#include "recovery.h"
struct gfs2_attr { struct gfs2_attr {
struct attribute attr; struct attribute attr;
...@@ -352,7 +353,7 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) ...@@ -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) { list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
if (jd->jd_jid != jid) if (jd->jd_jid != jid)
continue; continue;
rv = slow_work_enqueue(&jd->jd_work); rv = gfs2_recover_journal(jd, false);
break; break;
} }
out: out:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment