diff options
author | Tejun Heo <tj@kernel.org> | 2010-07-20 16:09:02 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2010-07-23 07:14:25 -0400 |
commit | 6ecd7c2dd9f5dd4f6e8f65c8027159f9c73b0e4c (patch) | |
tree | ba12b0b9ba00e21ff73eee82714be448c5a7c6e9 /fs/gfs2 | |
parent | 991ea75cb1df7188d209274b3d51c105b4f18ffe (diff) |
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: Tejun Heo <tj@kernel.org>
Acked-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/Kconfig | 1 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 3 | ||||
-rw-r--r-- | fs/gfs2/main.c | 14 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 8 | ||||
-rw-r--r-- | fs/gfs2/recovery.c | 54 | ||||
-rw-r--r-- | fs/gfs2/recovery.h | 6 | ||||
-rw-r--r-- | fs/gfs2/sys.c | 3 |
7 files changed, 40 insertions, 49 deletions
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index a47b43107112..cc9665522148 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig | |||
@@ -7,7 +7,6 @@ config GFS2_FS | |||
7 | select IP_SCTP if DLM_SCTP | 7 | select IP_SCTP if DLM_SCTP |
8 | select FS_POSIX_ACL | 8 | select FS_POSIX_ACL |
9 | select CRC32 | 9 | select CRC32 |
10 | select SLOW_WORK | ||
11 | select QUOTACTL | 10 | select QUOTACTL |
12 | help | 11 | help |
13 | A cluster filesystem. | 12 | A cluster filesystem. |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index b5d7363b22da..dd8f2e63d15a 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -12,7 +12,6 @@ | |||
12 | 12 | ||
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/workqueue.h> | 14 | #include <linux/workqueue.h> |
15 | #include <linux/slow-work.h> | ||
16 | #include <linux/dlm.h> | 15 | #include <linux/dlm.h> |
17 | #include <linux/buffer_head.h> | 16 | #include <linux/buffer_head.h> |
18 | 17 | ||
@@ -383,7 +382,7 @@ struct gfs2_journal_extent { | |||
383 | struct gfs2_jdesc { | 382 | struct gfs2_jdesc { |
384 | struct list_head jd_list; | 383 | struct list_head jd_list; |
385 | struct list_head extent_list; | 384 | struct list_head extent_list; |
386 | struct slow_work jd_work; | 385 | struct work_struct jd_work; |
387 | struct inode *jd_inode; | 386 | struct inode *jd_inode; |
388 | unsigned long jd_flags; | 387 | unsigned long jd_flags; |
389 | #define JDF_RECOVERY 1 | 388 | #define JDF_RECOVERY 1 |
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index fb2a5f93b7c3..b1e9630eb46a 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/gfs2_ondisk.h> | 16 | #include <linux/gfs2_ondisk.h> |
17 | #include <asm/atomic.h> | 17 | #include <asm/atomic.h> |
18 | #include <linux/slow-work.h> | ||
19 | 18 | ||
20 | #include "gfs2.h" | 19 | #include "gfs2.h" |
21 | #include "incore.h" | 20 | #include "incore.h" |
@@ -24,6 +23,7 @@ | |||
24 | #include "util.h" | 23 | #include "util.h" |
25 | #include "glock.h" | 24 | #include "glock.h" |
26 | #include "quota.h" | 25 | #include "quota.h" |
26 | #include "recovery.h" | ||
27 | 27 | ||
28 | static struct shrinker qd_shrinker = { | 28 | static struct shrinker qd_shrinker = { |
29 | .shrink = gfs2_shrink_qd_memory, | 29 | .shrink = gfs2_shrink_qd_memory, |
@@ -138,9 +138,11 @@ static int __init init_gfs2_fs(void) | |||
138 | if (error) | 138 | if (error) |
139 | goto fail_unregister; | 139 | goto fail_unregister; |
140 | 140 | ||
141 | error = slow_work_register_user(THIS_MODULE); | 141 | error = -ENOMEM; |
142 | if (error) | 142 | gfs_recovery_wq = alloc_workqueue("gfs_recovery", |
143 | goto fail_slow; | 143 | WQ_NON_REENTRANT | WQ_RESCUER, 0); |
144 | if (!gfs_recovery_wq) | ||
145 | goto fail_wq; | ||
144 | 146 | ||
145 | gfs2_register_debugfs(); | 147 | gfs2_register_debugfs(); |
146 | 148 | ||
@@ -148,7 +150,7 @@ static int __init init_gfs2_fs(void) | |||
148 | 150 | ||
149 | return 0; | 151 | return 0; |
150 | 152 | ||
151 | fail_slow: | 153 | fail_wq: |
152 | unregister_filesystem(&gfs2meta_fs_type); | 154 | unregister_filesystem(&gfs2meta_fs_type); |
153 | fail_unregister: | 155 | fail_unregister: |
154 | unregister_filesystem(&gfs2_fs_type); | 156 | unregister_filesystem(&gfs2_fs_type); |
@@ -190,7 +192,7 @@ static void __exit exit_gfs2_fs(void) | |||
190 | gfs2_unregister_debugfs(); | 192 | gfs2_unregister_debugfs(); |
191 | unregister_filesystem(&gfs2_fs_type); | 193 | unregister_filesystem(&gfs2_fs_type); |
192 | unregister_filesystem(&gfs2meta_fs_type); | 194 | unregister_filesystem(&gfs2meta_fs_type); |
193 | slow_work_unregister_user(THIS_MODULE); | 195 | destroy_workqueue(gfs_recovery_wq); |
194 | 196 | ||
195 | kmem_cache_destroy(gfs2_quotad_cachep); | 197 | kmem_cache_destroy(gfs2_quotad_cachep); |
196 | kmem_cache_destroy(gfs2_rgrpd_cachep); | 198 | kmem_cache_destroy(gfs2_rgrpd_cachep); |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 3593b3a7290e..9a08e1bd6fbd 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/namei.h> | 17 | #include <linux/namei.h> |
18 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
19 | #include <linux/gfs2_ondisk.h> | 19 | #include <linux/gfs2_ondisk.h> |
20 | #include <linux/slow-work.h> | ||
21 | #include <linux/quotaops.h> | 20 | #include <linux/quotaops.h> |
22 | 21 | ||
23 | #include "gfs2.h" | 22 | #include "gfs2.h" |
@@ -673,7 +672,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) | |||
673 | break; | 672 | break; |
674 | 673 | ||
675 | INIT_LIST_HEAD(&jd->extent_list); | 674 | INIT_LIST_HEAD(&jd->extent_list); |
676 | slow_work_init(&jd->jd_work, &gfs2_recover_ops); | 675 | INIT_WORK(&jd->jd_work, gfs2_recover_func); |
677 | jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1); | 676 | jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1); |
678 | if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { | 677 | if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { |
679 | if (!jd->jd_inode) | 678 | if (!jd->jd_inode) |
@@ -782,7 +781,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) | |||
782 | if (sdp->sd_lockstruct.ls_first) { | 781 | if (sdp->sd_lockstruct.ls_first) { |
783 | unsigned int x; | 782 | unsigned int x; |
784 | for (x = 0; x < sdp->sd_journals; x++) { | 783 | for (x = 0; x < sdp->sd_journals; x++) { |
785 | error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x)); | 784 | error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x), |
785 | true); | ||
786 | if (error) { | 786 | if (error) { |
787 | fs_err(sdp, "error recovering journal %u: %d\n", | 787 | fs_err(sdp, "error recovering journal %u: %d\n", |
788 | x, error); | 788 | x, error); |
@@ -792,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) | |||
792 | 792 | ||
793 | gfs2_others_may_mount(sdp); | 793 | gfs2_others_may_mount(sdp); |
794 | } else if (!sdp->sd_args.ar_spectator) { | 794 | } else if (!sdp->sd_args.ar_spectator) { |
795 | error = gfs2_recover_journal(sdp->sd_jdesc); | 795 | error = gfs2_recover_journal(sdp->sd_jdesc, true); |
796 | if (error) { | 796 | if (error) { |
797 | fs_err(sdp, "error recovering my journal: %d\n", error); | 797 | fs_err(sdp, "error recovering my journal: %d\n", error); |
798 | goto fail_jinode_gh; | 798 | goto fail_jinode_gh; |
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 4b9bece3d437..f7f89a94a5a4 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/buffer_head.h> | 14 | #include <linux/buffer_head.h> |
15 | #include <linux/gfs2_ondisk.h> | 15 | #include <linux/gfs2_ondisk.h> |
16 | #include <linux/crc32.h> | 16 | #include <linux/crc32.h> |
17 | #include <linux/slow-work.h> | ||
18 | 17 | ||
19 | #include "gfs2.h" | 18 | #include "gfs2.h" |
20 | #include "incore.h" | 19 | #include "incore.h" |
@@ -28,6 +27,8 @@ | |||
28 | #include "util.h" | 27 | #include "util.h" |
29 | #include "dir.h" | 28 | #include "dir.h" |
30 | 29 | ||
30 | struct workqueue_struct *gfs_recovery_wq; | ||
31 | |||
31 | int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, | 32 | int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, |
32 | struct buffer_head **bh) | 33 | struct buffer_head **bh) |
33 | { | 34 | { |
@@ -443,23 +444,7 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, | |||
443 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); | 444 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); |
444 | } | 445 | } |
445 | 446 | ||
446 | static int gfs2_recover_get_ref(struct slow_work *work) | 447 | void gfs2_recover_func(struct work_struct *work) |
447 | { | ||
448 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); | ||
449 | if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags)) | ||
450 | return -EBUSY; | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static void gfs2_recover_put_ref(struct slow_work *work) | ||
455 | { | ||
456 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); | ||
457 | clear_bit(JDF_RECOVERY, &jd->jd_flags); | ||
458 | smp_mb__after_clear_bit(); | ||
459 | wake_up_bit(&jd->jd_flags, JDF_RECOVERY); | ||
460 | } | ||
461 | |||
462 | static void gfs2_recover_work(struct slow_work *work) | ||
463 | { | 448 | { |
464 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); | 449 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); |
465 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); | 450 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); |
@@ -578,7 +563,7 @@ static void gfs2_recover_work(struct slow_work *work) | |||
578 | gfs2_glock_dq_uninit(&j_gh); | 563 | gfs2_glock_dq_uninit(&j_gh); |
579 | 564 | ||
580 | fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); | 565 | fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); |
581 | return; | 566 | goto done; |
582 | 567 | ||
583 | fail_gunlock_tr: | 568 | fail_gunlock_tr: |
584 | gfs2_glock_dq_uninit(&t_gh); | 569 | gfs2_glock_dq_uninit(&t_gh); |
@@ -590,32 +575,35 @@ fail_gunlock_j: | |||
590 | } | 575 | } |
591 | 576 | ||
592 | fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done"); | 577 | fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done"); |
593 | |||
594 | fail: | 578 | fail: |
595 | gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); | 579 | gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); |
580 | done: | ||
581 | clear_bit(JDF_RECOVERY, &jd->jd_flags); | ||
582 | smp_mb__after_clear_bit(); | ||
583 | wake_up_bit(&jd->jd_flags, JDF_RECOVERY); | ||
596 | } | 584 | } |
597 | 585 | ||
598 | struct slow_work_ops gfs2_recover_ops = { | ||
599 | .owner = THIS_MODULE, | ||
600 | .get_ref = gfs2_recover_get_ref, | ||
601 | .put_ref = gfs2_recover_put_ref, | ||
602 | .execute = gfs2_recover_work, | ||
603 | }; | ||
604 | |||
605 | |||
606 | static int gfs2_recovery_wait(void *word) | 586 | static int gfs2_recovery_wait(void *word) |
607 | { | 587 | { |
608 | schedule(); | 588 | schedule(); |
609 | return 0; | 589 | return 0; |
610 | } | 590 | } |
611 | 591 | ||
612 | int gfs2_recover_journal(struct gfs2_jdesc *jd) | 592 | int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait) |
613 | { | 593 | { |
614 | int rv; | 594 | int rv; |
615 | rv = slow_work_enqueue(&jd->jd_work); | 595 | |
616 | if (rv) | 596 | if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags)) |
617 | return rv; | 597 | return -EBUSY; |
618 | wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE); | 598 | |
599 | /* we have JDF_RECOVERY, queue should always succeed */ | ||
600 | rv = queue_work(gfs_recovery_wq, &jd->jd_work); | ||
601 | BUG_ON(!rv); | ||
602 | |||
603 | if (wait) | ||
604 | wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, | ||
605 | TASK_UNINTERRUPTIBLE); | ||
606 | |||
619 | return 0; | 607 | return 0; |
620 | } | 608 | } |
621 | 609 | ||
diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index 1616ac22569a..2226136c7647 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h | |||
@@ -12,6 +12,8 @@ | |||
12 | 12 | ||
13 | #include "incore.h" | 13 | #include "incore.h" |
14 | 14 | ||
15 | extern struct workqueue_struct *gfs_recovery_wq; | ||
16 | |||
15 | static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) | 17 | static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) |
16 | { | 18 | { |
17 | if (++*blk == sdp->sd_jdesc->jd_blocks) | 19 | if (++*blk == sdp->sd_jdesc->jd_blocks) |
@@ -27,8 +29,8 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp); | |||
27 | 29 | ||
28 | extern int gfs2_find_jhead(struct gfs2_jdesc *jd, | 30 | extern int gfs2_find_jhead(struct gfs2_jdesc *jd, |
29 | struct gfs2_log_header_host *head); | 31 | struct gfs2_log_header_host *head); |
30 | extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd); | 32 | extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait); |
31 | extern struct slow_work_ops gfs2_recover_ops; | 33 | extern void gfs2_recover_func(struct work_struct *work); |
32 | 34 | ||
33 | #endif /* __RECOVERY_DOT_H__ */ | 35 | #endif /* __RECOVERY_DOT_H__ */ |
34 | 36 | ||
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 37f5393e68e6..6b60316ae327 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "quota.h" | 25 | #include "quota.h" |
26 | #include "util.h" | 26 | #include "util.h" |
27 | #include "glops.h" | 27 | #include "glops.h" |
28 | #include "recovery.h" | ||
28 | 29 | ||
29 | struct gfs2_attr { | 30 | struct gfs2_attr { |
30 | struct attribute attr; | 31 | struct attribute attr; |
@@ -352,7 +353,7 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) | |||
352 | list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { | 353 | list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { |
353 | if (jd->jd_jid != jid) | 354 | if (jd->jd_jid != jid) |
354 | continue; | 355 | continue; |
355 | rv = slow_work_enqueue(&jd->jd_work); | 356 | rv = gfs2_recover_journal(jd, false); |
356 | break; | 357 | break; |
357 | } | 358 | } |
358 | out: | 359 | out: |