diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2009-05-19 05:01:18 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2009-05-19 05:01:18 -0400 |
commit | fe64d517df0970a68417184a12fcd4ba0589cc28 (patch) | |
tree | d977f214fdf6ba96254cfbf6683e8583ecebe504 /fs/gfs2 | |
parent | 9582d41135c0d362f04ed6bf3dc8d693a7eafee2 (diff) |
GFS2: Umount recovery race fix
This patch fixes a race condition where we can receive recovery
requests part way through processing a umount. This was causing
problems since the recovery thread had already gone away.
Looking in more detail at the recovery code, it was really trying
to implement a slight variation on a work queue, and that happens to
align nicely with the recently introduced slow-work subsystem. As a
result I've updated the code to use slow-work, rather than its own home
grown variety of work queue.
When using the wait_on_bit() function, I noticed that the wait function
that was supplied as an argument was appearing in the WCHAN field, so
I've updated the function names in order to produce more meaningful
output.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/Kconfig | 1 | ||||
-rw-r--r-- | fs/gfs2/glock.c | 21 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 14 | ||||
-rw-r--r-- | fs/gfs2/main.c | 8 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 20 | ||||
-rw-r--r-- | fs/gfs2/ops_super.c | 25 | ||||
-rw-r--r-- | fs/gfs2/recovery.c | 102 | ||||
-rw-r--r-- | fs/gfs2/recovery.h | 2 | ||||
-rw-r--r-- | fs/gfs2/sys.c | 53 |
9 files changed, 122 insertions, 124 deletions
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index 3a981b7f64c..cad957cdb1e 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig | |||
@@ -7,6 +7,7 @@ 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 | ||
10 | help | 11 | help |
11 | A cluster filesystem. | 12 | A cluster filesystem. |
12 | 13 | ||
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index ff498109048..2bf62bcc518 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -796,22 +796,37 @@ void gfs2_holder_uninit(struct gfs2_holder *gh) | |||
796 | gh->gh_ip = 0; | 796 | gh->gh_ip = 0; |
797 | } | 797 | } |
798 | 798 | ||
799 | static int just_schedule(void *word) | 799 | /** |
800 | * gfs2_glock_holder_wait | ||
801 | * @word: unused | ||
802 | * | ||
803 | * This function and gfs2_glock_demote_wait both show up in the WCHAN | ||
804 | * field. Thus I've separated these otherwise identical functions in | ||
805 | * order to be more informative to the user. | ||
806 | */ | ||
807 | |||
808 | static int gfs2_glock_holder_wait(void *word) | ||
800 | { | 809 | { |
801 | schedule(); | 810 | schedule(); |
802 | return 0; | 811 | return 0; |
803 | } | 812 | } |
804 | 813 | ||
814 | static int gfs2_glock_demote_wait(void *word) | ||
815 | { | ||
816 | schedule(); | ||
817 | return 0; | ||
818 | } | ||
819 | |||
805 | static void wait_on_holder(struct gfs2_holder *gh) | 820 | static void wait_on_holder(struct gfs2_holder *gh) |
806 | { | 821 | { |
807 | might_sleep(); | 822 | might_sleep(); |
808 | wait_on_bit(&gh->gh_iflags, HIF_WAIT, just_schedule, TASK_UNINTERRUPTIBLE); | 823 | wait_on_bit(&gh->gh_iflags, HIF_WAIT, gfs2_glock_holder_wait, TASK_UNINTERRUPTIBLE); |
809 | } | 824 | } |
810 | 825 | ||
811 | static void wait_on_demote(struct gfs2_glock *gl) | 826 | static void wait_on_demote(struct gfs2_glock *gl) |
812 | { | 827 | { |
813 | might_sleep(); | 828 | might_sleep(); |
814 | wait_on_bit(&gl->gl_flags, GLF_DEMOTE, just_schedule, TASK_UNINTERRUPTIBLE); | 829 | wait_on_bit(&gl->gl_flags, GLF_DEMOTE, gfs2_glock_demote_wait, TASK_UNINTERRUPTIBLE); |
815 | } | 830 | } |
816 | 831 | ||
817 | /** | 832 | /** |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 65f438e9537..0060e9564bb 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -12,6 +12,7 @@ | |||
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> | ||
15 | #include <linux/dlm.h> | 16 | #include <linux/dlm.h> |
16 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
17 | 18 | ||
@@ -376,11 +377,11 @@ struct gfs2_journal_extent { | |||
376 | struct gfs2_jdesc { | 377 | struct gfs2_jdesc { |
377 | struct list_head jd_list; | 378 | struct list_head jd_list; |
378 | struct list_head extent_list; | 379 | struct list_head extent_list; |
379 | 380 | struct slow_work jd_work; | |
380 | struct inode *jd_inode; | 381 | struct inode *jd_inode; |
382 | unsigned long jd_flags; | ||
383 | #define JDF_RECOVERY 1 | ||
381 | unsigned int jd_jid; | 384 | unsigned int jd_jid; |
382 | int jd_dirty; | ||
383 | |||
384 | unsigned int jd_blocks; | 385 | unsigned int jd_blocks; |
385 | }; | 386 | }; |
386 | 387 | ||
@@ -390,9 +391,6 @@ struct gfs2_statfs_change_host { | |||
390 | s64 sc_dinodes; | 391 | s64 sc_dinodes; |
391 | }; | 392 | }; |
392 | 393 | ||
393 | #define GFS2_GLOCKD_DEFAULT 1 | ||
394 | #define GFS2_GLOCKD_MAX 16 | ||
395 | |||
396 | #define GFS2_QUOTA_DEFAULT GFS2_QUOTA_OFF | 394 | #define GFS2_QUOTA_DEFAULT GFS2_QUOTA_OFF |
397 | #define GFS2_QUOTA_OFF 0 | 395 | #define GFS2_QUOTA_OFF 0 |
398 | #define GFS2_QUOTA_ACCOUNT 1 | 396 | #define GFS2_QUOTA_ACCOUNT 1 |
@@ -427,7 +425,6 @@ struct gfs2_tune { | |||
427 | unsigned int gt_incore_log_blocks; | 425 | unsigned int gt_incore_log_blocks; |
428 | unsigned int gt_log_flush_secs; | 426 | unsigned int gt_log_flush_secs; |
429 | 427 | ||
430 | unsigned int gt_recoverd_secs; | ||
431 | unsigned int gt_logd_secs; | 428 | unsigned int gt_logd_secs; |
432 | 429 | ||
433 | unsigned int gt_quota_simul_sync; /* Max quotavals to sync at once */ | 430 | unsigned int gt_quota_simul_sync; /* Max quotavals to sync at once */ |
@@ -448,6 +445,7 @@ enum { | |||
448 | SDF_JOURNAL_LIVE = 1, | 445 | SDF_JOURNAL_LIVE = 1, |
449 | SDF_SHUTDOWN = 2, | 446 | SDF_SHUTDOWN = 2, |
450 | SDF_NOBARRIERS = 3, | 447 | SDF_NOBARRIERS = 3, |
448 | SDF_NORECOVERY = 4, | ||
451 | }; | 449 | }; |
452 | 450 | ||
453 | #define GFS2_FSNAME_LEN 256 | 451 | #define GFS2_FSNAME_LEN 256 |
@@ -494,7 +492,6 @@ struct lm_lockstruct { | |||
494 | unsigned long ls_flags; | 492 | unsigned long ls_flags; |
495 | dlm_lockspace_t *ls_dlm; | 493 | dlm_lockspace_t *ls_dlm; |
496 | 494 | ||
497 | int ls_recover_jid; | ||
498 | int ls_recover_jid_done; | 495 | int ls_recover_jid_done; |
499 | int ls_recover_jid_status; | 496 | int ls_recover_jid_status; |
500 | }; | 497 | }; |
@@ -583,7 +580,6 @@ struct gfs2_sbd { | |||
583 | 580 | ||
584 | /* Daemon stuff */ | 581 | /* Daemon stuff */ |
585 | 582 | ||
586 | struct task_struct *sd_recoverd_process; | ||
587 | struct task_struct *sd_logd_process; | 583 | struct task_struct *sd_logd_process; |
588 | struct task_struct *sd_quotad_process; | 584 | struct task_struct *sd_quotad_process; |
589 | 585 | ||
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index a6892ed0840..eacd78a5d08 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c | |||
@@ -15,6 +15,7 @@ | |||
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> | ||
18 | 19 | ||
19 | #include "gfs2.h" | 20 | #include "gfs2.h" |
20 | #include "incore.h" | 21 | #include "incore.h" |
@@ -113,12 +114,18 @@ static int __init init_gfs2_fs(void) | |||
113 | if (error) | 114 | if (error) |
114 | goto fail_unregister; | 115 | goto fail_unregister; |
115 | 116 | ||
117 | error = slow_work_register_user(); | ||
118 | if (error) | ||
119 | goto fail_slow; | ||
120 | |||
116 | gfs2_register_debugfs(); | 121 | gfs2_register_debugfs(); |
117 | 122 | ||
118 | printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__); | 123 | printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__); |
119 | 124 | ||
120 | return 0; | 125 | return 0; |
121 | 126 | ||
127 | fail_slow: | ||
128 | unregister_filesystem(&gfs2meta_fs_type); | ||
122 | fail_unregister: | 129 | fail_unregister: |
123 | unregister_filesystem(&gfs2_fs_type); | 130 | unregister_filesystem(&gfs2_fs_type); |
124 | fail: | 131 | fail: |
@@ -156,6 +163,7 @@ static void __exit exit_gfs2_fs(void) | |||
156 | gfs2_unregister_debugfs(); | 163 | gfs2_unregister_debugfs(); |
157 | unregister_filesystem(&gfs2_fs_type); | 164 | unregister_filesystem(&gfs2_fs_type); |
158 | unregister_filesystem(&gfs2meta_fs_type); | 165 | unregister_filesystem(&gfs2meta_fs_type); |
166 | slow_work_unregister_user(); | ||
159 | 167 | ||
160 | kmem_cache_destroy(gfs2_quotad_cachep); | 168 | kmem_cache_destroy(gfs2_quotad_cachep); |
161 | kmem_cache_destroy(gfs2_rgrpd_cachep); | 169 | kmem_cache_destroy(gfs2_rgrpd_cachep); |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 7981fbc9fc3..2cd1164c88d 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -17,6 +17,7 @@ | |||
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> | ||
20 | 21 | ||
21 | #include "gfs2.h" | 22 | #include "gfs2.h" |
22 | #include "incore.h" | 23 | #include "incore.h" |
@@ -55,7 +56,6 @@ static void gfs2_tune_init(struct gfs2_tune *gt) | |||
55 | spin_lock_init(>->gt_spin); | 56 | spin_lock_init(>->gt_spin); |
56 | 57 | ||
57 | gt->gt_incore_log_blocks = 1024; | 58 | gt->gt_incore_log_blocks = 1024; |
58 | gt->gt_recoverd_secs = 60; | ||
59 | gt->gt_logd_secs = 1; | 59 | gt->gt_logd_secs = 1; |
60 | gt->gt_quota_simul_sync = 64; | 60 | gt->gt_quota_simul_sync = 64; |
61 | gt->gt_quota_warn_period = 10; | 61 | gt->gt_quota_warn_period = 10; |
@@ -675,6 +675,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) | |||
675 | break; | 675 | break; |
676 | 676 | ||
677 | INIT_LIST_HEAD(&jd->extent_list); | 677 | INIT_LIST_HEAD(&jd->extent_list); |
678 | slow_work_init(&jd->jd_work, &gfs2_recover_ops); | ||
678 | jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1); | 679 | jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1); |
679 | if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { | 680 | if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { |
680 | if (!jd->jd_inode) | 681 | if (!jd->jd_inode) |
@@ -700,14 +701,13 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) | |||
700 | { | 701 | { |
701 | struct inode *master = sdp->sd_master_dir->d_inode; | 702 | struct inode *master = sdp->sd_master_dir->d_inode; |
702 | struct gfs2_holder ji_gh; | 703 | struct gfs2_holder ji_gh; |
703 | struct task_struct *p; | ||
704 | struct gfs2_inode *ip; | 704 | struct gfs2_inode *ip; |
705 | int jindex = 1; | 705 | int jindex = 1; |
706 | int error = 0; | 706 | int error = 0; |
707 | 707 | ||
708 | if (undo) { | 708 | if (undo) { |
709 | jindex = 0; | 709 | jindex = 0; |
710 | goto fail_recoverd; | 710 | goto fail_jinode_gh; |
711 | } | 711 | } |
712 | 712 | ||
713 | sdp->sd_jindex = gfs2_lookup_simple(master, "jindex"); | 713 | sdp->sd_jindex = gfs2_lookup_simple(master, "jindex"); |
@@ -800,18 +800,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) | |||
800 | gfs2_glock_dq_uninit(&ji_gh); | 800 | gfs2_glock_dq_uninit(&ji_gh); |
801 | jindex = 0; | 801 | jindex = 0; |
802 | 802 | ||
803 | p = kthread_run(gfs2_recoverd, sdp, "gfs2_recoverd"); | ||
804 | error = IS_ERR(p); | ||
805 | if (error) { | ||
806 | fs_err(sdp, "can't start recoverd thread: %d\n", error); | ||
807 | goto fail_jinode_gh; | ||
808 | } | ||
809 | sdp->sd_recoverd_process = p; | ||
810 | |||
811 | return 0; | 803 | return 0; |
812 | 804 | ||
813 | fail_recoverd: | ||
814 | kthread_stop(sdp->sd_recoverd_process); | ||
815 | fail_jinode_gh: | 805 | fail_jinode_gh: |
816 | if (!sdp->sd_args.ar_spectator) | 806 | if (!sdp->sd_args.ar_spectator) |
817 | gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); | 807 | gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); |
@@ -1172,8 +1162,10 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
1172 | goto fail; | 1162 | goto fail; |
1173 | } | 1163 | } |
1174 | 1164 | ||
1175 | if (sdp->sd_args.ar_spectator) | 1165 | if (sdp->sd_args.ar_spectator) { |
1176 | sb->s_flags |= MS_RDONLY; | 1166 | sb->s_flags |= MS_RDONLY; |
1167 | set_bit(SDF_NORECOVERY, &sdp->sd_flags); | ||
1168 | } | ||
1177 | if (sdp->sd_args.ar_posix_acl) | 1169 | if (sdp->sd_args.ar_posix_acl) |
1178 | sb->s_flags |= MS_POSIXACL; | 1170 | sb->s_flags |= MS_POSIXACL; |
1179 | 1171 | ||
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 0677a837856..a3c2272e7ca 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c | |||
@@ -121,6 +121,12 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) | |||
121 | return error; | 121 | return error; |
122 | } | 122 | } |
123 | 123 | ||
124 | static int gfs2_umount_recovery_wait(void *word) | ||
125 | { | ||
126 | schedule(); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
124 | /** | 130 | /** |
125 | * gfs2_put_super - Unmount the filesystem | 131 | * gfs2_put_super - Unmount the filesystem |
126 | * @sb: The VFS superblock | 132 | * @sb: The VFS superblock |
@@ -131,6 +137,7 @@ static void gfs2_put_super(struct super_block *sb) | |||
131 | { | 137 | { |
132 | struct gfs2_sbd *sdp = sb->s_fs_info; | 138 | struct gfs2_sbd *sdp = sb->s_fs_info; |
133 | int error; | 139 | int error; |
140 | struct gfs2_jdesc *jd; | ||
134 | 141 | ||
135 | /* Unfreeze the filesystem, if we need to */ | 142 | /* Unfreeze the filesystem, if we need to */ |
136 | 143 | ||
@@ -139,9 +146,25 @@ static void gfs2_put_super(struct super_block *sb) | |||
139 | gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); | 146 | gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); |
140 | mutex_unlock(&sdp->sd_freeze_lock); | 147 | mutex_unlock(&sdp->sd_freeze_lock); |
141 | 148 | ||
149 | /* No more recovery requests */ | ||
150 | set_bit(SDF_NORECOVERY, &sdp->sd_flags); | ||
151 | smp_mb(); | ||
152 | |||
153 | /* Wait on outstanding recovery */ | ||
154 | restart: | ||
155 | spin_lock(&sdp->sd_jindex_spin); | ||
156 | list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { | ||
157 | if (!test_bit(JDF_RECOVERY, &jd->jd_flags)) | ||
158 | continue; | ||
159 | spin_unlock(&sdp->sd_jindex_spin); | ||
160 | wait_on_bit(&jd->jd_flags, JDF_RECOVERY, | ||
161 | gfs2_umount_recovery_wait, TASK_UNINTERRUPTIBLE); | ||
162 | goto restart; | ||
163 | } | ||
164 | spin_unlock(&sdp->sd_jindex_spin); | ||
165 | |||
142 | kthread_stop(sdp->sd_quotad_process); | 166 | kthread_stop(sdp->sd_quotad_process); |
143 | kthread_stop(sdp->sd_logd_process); | 167 | kthread_stop(sdp->sd_logd_process); |
144 | kthread_stop(sdp->sd_recoverd_process); | ||
145 | 168 | ||
146 | if (!(sb->s_flags & MS_RDONLY)) { | 169 | if (!(sb->s_flags & MS_RDONLY)) { |
147 | error = gfs2_make_fs_ro(sdp); | 170 | error = gfs2_make_fs_ro(sdp); |
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 247e8f7d6b3..59d2695509d 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c | |||
@@ -13,8 +13,7 @@ | |||
13 | #include <linux/buffer_head.h> | 13 | #include <linux/buffer_head.h> |
14 | #include <linux/gfs2_ondisk.h> | 14 | #include <linux/gfs2_ondisk.h> |
15 | #include <linux/crc32.h> | 15 | #include <linux/crc32.h> |
16 | #include <linux/kthread.h> | 16 | #include <linux/slow-work.h> |
17 | #include <linux/freezer.h> | ||
18 | 17 | ||
19 | #include "gfs2.h" | 18 | #include "gfs2.h" |
20 | #include "incore.h" | 19 | #include "incore.h" |
@@ -441,18 +440,25 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, | |||
441 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); | 440 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); |
442 | } | 441 | } |
443 | 442 | ||
444 | /** | 443 | static int gfs2_recover_get_ref(struct slow_work *work) |
445 | * gfs2_recover_journal - recover a given journal | 444 | { |
446 | * @jd: the struct gfs2_jdesc describing the journal | 445 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); |
447 | * | 446 | if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags)) |
448 | * Acquire the journal's lock, check to see if the journal is clean, and | 447 | return -EBUSY; |
449 | * do recovery if necessary. | 448 | return 0; |
450 | * | 449 | } |
451 | * Returns: errno | ||
452 | */ | ||
453 | 450 | ||
454 | int gfs2_recover_journal(struct gfs2_jdesc *jd) | 451 | static void gfs2_recover_put_ref(struct slow_work *work) |
452 | { | ||
453 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); | ||
454 | clear_bit(JDF_RECOVERY, &jd->jd_flags); | ||
455 | smp_mb__after_clear_bit(); | ||
456 | wake_up_bit(&jd->jd_flags, JDF_RECOVERY); | ||
457 | } | ||
458 | |||
459 | static void gfs2_recover_work(struct slow_work *work) | ||
455 | { | 460 | { |
461 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); | ||
456 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); | 462 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); |
457 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); | 463 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
458 | struct gfs2_log_header_host head; | 464 | struct gfs2_log_header_host head; |
@@ -569,7 +575,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) | |||
569 | gfs2_glock_dq_uninit(&j_gh); | 575 | gfs2_glock_dq_uninit(&j_gh); |
570 | 576 | ||
571 | fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); | 577 | fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); |
572 | return 0; | 578 | return; |
573 | 579 | ||
574 | fail_gunlock_tr: | 580 | fail_gunlock_tr: |
575 | gfs2_glock_dq_uninit(&t_gh); | 581 | gfs2_glock_dq_uninit(&t_gh); |
@@ -584,70 +590,28 @@ fail_gunlock_j: | |||
584 | 590 | ||
585 | fail: | 591 | fail: |
586 | gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); | 592 | gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); |
587 | return error; | ||
588 | } | 593 | } |
589 | 594 | ||
590 | static struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp) | 595 | struct slow_work_ops gfs2_recover_ops = { |
591 | { | 596 | .get_ref = gfs2_recover_get_ref, |
592 | struct gfs2_jdesc *jd; | 597 | .put_ref = gfs2_recover_put_ref, |
593 | int found = 0; | 598 | .execute = gfs2_recover_work, |
594 | 599 | }; | |
595 | spin_lock(&sdp->sd_jindex_spin); | ||
596 | 600 | ||
597 | list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { | ||
598 | if (jd->jd_dirty) { | ||
599 | jd->jd_dirty = 0; | ||
600 | found = 1; | ||
601 | break; | ||
602 | } | ||
603 | } | ||
604 | spin_unlock(&sdp->sd_jindex_spin); | ||
605 | |||
606 | if (!found) | ||
607 | jd = NULL; | ||
608 | 601 | ||
609 | return jd; | 602 | static int gfs2_recovery_wait(void *word) |
610 | } | ||
611 | |||
612 | /** | ||
613 | * gfs2_check_journals - Recover any dirty journals | ||
614 | * @sdp: the filesystem | ||
615 | * | ||
616 | */ | ||
617 | |||
618 | static void gfs2_check_journals(struct gfs2_sbd *sdp) | ||
619 | { | 603 | { |
620 | struct gfs2_jdesc *jd; | 604 | schedule(); |
621 | 605 | return 0; | |
622 | for (;;) { | ||
623 | jd = gfs2_jdesc_find_dirty(sdp); | ||
624 | if (!jd) | ||
625 | break; | ||
626 | |||
627 | if (jd != sdp->sd_jdesc) | ||
628 | gfs2_recover_journal(jd); | ||
629 | } | ||
630 | } | 606 | } |
631 | 607 | ||
632 | /** | 608 | int gfs2_recover_journal(struct gfs2_jdesc *jd) |
633 | * gfs2_recoverd - Recover dead machine's journals | ||
634 | * @sdp: Pointer to GFS2 superblock | ||
635 | * | ||
636 | */ | ||
637 | |||
638 | int gfs2_recoverd(void *data) | ||
639 | { | 609 | { |
640 | struct gfs2_sbd *sdp = data; | 610 | int rv; |
641 | unsigned long t; | 611 | rv = slow_work_enqueue(&jd->jd_work); |
642 | 612 | if (rv) | |
643 | while (!kthread_should_stop()) { | 613 | return rv; |
644 | gfs2_check_journals(sdp); | 614 | wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE); |
645 | t = gfs2_tune_get(sdp, gt_recoverd_secs) * HZ; | ||
646 | if (freezing(current)) | ||
647 | refrigerator(); | ||
648 | schedule_timeout_interruptible(t); | ||
649 | } | ||
650 | |||
651 | return 0; | 615 | return 0; |
652 | } | 616 | } |
653 | 617 | ||
diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index a8218ea15b5..1616ac22569 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h | |||
@@ -28,7 +28,7 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp); | |||
28 | extern int gfs2_find_jhead(struct gfs2_jdesc *jd, | 28 | extern int gfs2_find_jhead(struct gfs2_jdesc *jd, |
29 | struct gfs2_log_header_host *head); | 29 | struct gfs2_log_header_host *head); |
30 | extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd); | 30 | extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd); |
31 | extern int gfs2_recoverd(void *data); | 31 | extern struct slow_work_ops gfs2_recover_ops; |
32 | 32 | ||
33 | #endif /* __RECOVERY_DOT_H__ */ | 33 | #endif /* __RECOVERY_DOT_H__ */ |
34 | 34 | ||
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 894bf773ec9..9f6d48b75fd 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c | |||
@@ -356,34 +356,33 @@ static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf) | |||
356 | return sprintf(buf, "%d\n", ls->ls_first_done); | 356 | return sprintf(buf, "%d\n", ls->ls_first_done); |
357 | } | 357 | } |
358 | 358 | ||
359 | static ssize_t recover_show(struct gfs2_sbd *sdp, char *buf) | 359 | static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) |
360 | { | ||
361 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; | ||
362 | return sprintf(buf, "%d\n", ls->ls_recover_jid); | ||
363 | } | ||
364 | |||
365 | static void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid) | ||
366 | { | 360 | { |
361 | unsigned jid; | ||
367 | struct gfs2_jdesc *jd; | 362 | struct gfs2_jdesc *jd; |
363 | int rv; | ||
364 | |||
365 | rv = sscanf(buf, "%u", &jid); | ||
366 | if (rv != 1) | ||
367 | return -EINVAL; | ||
368 | 368 | ||
369 | rv = -ESHUTDOWN; | ||
369 | spin_lock(&sdp->sd_jindex_spin); | 370 | spin_lock(&sdp->sd_jindex_spin); |
371 | if (test_bit(SDF_NORECOVERY, &sdp->sd_flags)) | ||
372 | goto out; | ||
373 | rv = -EBUSY; | ||
374 | if (sdp->sd_jdesc->jd_jid == jid) | ||
375 | goto out; | ||
376 | rv = -ENOENT; | ||
370 | list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { | 377 | list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { |
371 | if (jd->jd_jid != jid) | 378 | if (jd->jd_jid != jid) |
372 | continue; | 379 | continue; |
373 | jd->jd_dirty = 1; | 380 | rv = slow_work_enqueue(&jd->jd_work); |
374 | break; | 381 | break; |
375 | } | 382 | } |
383 | out: | ||
376 | spin_unlock(&sdp->sd_jindex_spin); | 384 | spin_unlock(&sdp->sd_jindex_spin); |
377 | } | 385 | return rv ? rv : len; |
378 | |||
379 | static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) | ||
380 | { | ||
381 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; | ||
382 | ls->ls_recover_jid = simple_strtol(buf, NULL, 0); | ||
383 | gfs2_jdesc_make_dirty(sdp, ls->ls_recover_jid); | ||
384 | if (sdp->sd_recoverd_process) | ||
385 | wake_up_process(sdp->sd_recoverd_process); | ||
386 | return len; | ||
387 | } | 386 | } |
388 | 387 | ||
389 | static ssize_t recover_done_show(struct gfs2_sbd *sdp, char *buf) | 388 | static ssize_t recover_done_show(struct gfs2_sbd *sdp, char *buf) |
@@ -401,15 +400,15 @@ static ssize_t recover_status_show(struct gfs2_sbd *sdp, char *buf) | |||
401 | #define GDLM_ATTR(_name,_mode,_show,_store) \ | 400 | #define GDLM_ATTR(_name,_mode,_show,_store) \ |
402 | static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) | 401 | static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) |
403 | 402 | ||
404 | GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); | 403 | GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); |
405 | GDLM_ATTR(block, 0644, block_show, block_store); | 404 | GDLM_ATTR(block, 0644, block_show, block_store); |
406 | GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); | 405 | GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); |
407 | GDLM_ATTR(id, 0444, lkid_show, NULL); | 406 | GDLM_ATTR(id, 0444, lkid_show, NULL); |
408 | GDLM_ATTR(first, 0444, lkfirst_show, NULL); | 407 | GDLM_ATTR(first, 0444, lkfirst_show, NULL); |
409 | GDLM_ATTR(first_done, 0444, first_done_show, NULL); | 408 | GDLM_ATTR(first_done, 0444, first_done_show, NULL); |
410 | GDLM_ATTR(recover, 0644, recover_show, recover_store); | 409 | GDLM_ATTR(recover, 0200, NULL, recover_store); |
411 | GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); | 410 | GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); |
412 | GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); | 411 | GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); |
413 | 412 | ||
414 | static struct attribute *lock_module_attrs[] = { | 413 | static struct attribute *lock_module_attrs[] = { |
415 | &gdlm_attr_proto_name.attr, | 414 | &gdlm_attr_proto_name.attr, |