aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2009-05-19 05:01:18 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2009-05-19 05:01:18 -0400
commitfe64d517df0970a68417184a12fcd4ba0589cc28 (patch)
treed977f214fdf6ba96254cfbf6683e8583ecebe504
parent9582d41135c0d362f04ed6bf3dc8d693a7eafee2 (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>
-rw-r--r--fs/gfs2/Kconfig1
-rw-r--r--fs/gfs2/glock.c21
-rw-r--r--fs/gfs2/incore.h14
-rw-r--r--fs/gfs2/main.c8
-rw-r--r--fs/gfs2/ops_fstype.c20
-rw-r--r--fs/gfs2/ops_super.c25
-rw-r--r--fs/gfs2/recovery.c102
-rw-r--r--fs/gfs2/recovery.h2
-rw-r--r--fs/gfs2/sys.c53
9 files changed, 122 insertions, 124 deletions
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
index 3a981b7f64ca..cad957cdb1e5 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 ff4981090489..2bf62bcc5181 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
799static 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
808static int gfs2_glock_holder_wait(void *word)
800{ 809{
801 schedule(); 810 schedule();
802 return 0; 811 return 0;
803} 812}
804 813
814static int gfs2_glock_demote_wait(void *word)
815{
816 schedule();
817 return 0;
818}
819
805static void wait_on_holder(struct gfs2_holder *gh) 820static 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
811static void wait_on_demote(struct gfs2_glock *gl) 826static 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 65f438e9537a..0060e9564bb9 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 {
376struct gfs2_jdesc { 377struct 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 a6892ed0840a..eacd78a5d082 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
127fail_slow:
128 unregister_filesystem(&gfs2meta_fs_type);
122fail_unregister: 129fail_unregister:
123 unregister_filesystem(&gfs2_fs_type); 130 unregister_filesystem(&gfs2_fs_type);
124fail: 131fail:
@@ -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 7981fbc9fc3b..2cd1164c88d7 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->gt_spin); 56 spin_lock_init(&gt->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
813fail_recoverd:
814 kthread_stop(sdp->sd_recoverd_process);
815fail_jinode_gh: 805fail_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 0677a8378560..a3c2272e7cad 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
124static 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 */
154restart:
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 247e8f7d6b3d..59d2695509d3 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/** 443static 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
454int gfs2_recover_journal(struct gfs2_jdesc *jd) 451static 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
459static 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
574fail_gunlock_tr: 580fail_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
585fail: 591fail:
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
590static struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp) 595struct 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; 602static int gfs2_recovery_wait(void *word)
610}
611
612/**
613 * gfs2_check_journals - Recover any dirty journals
614 * @sdp: the filesystem
615 *
616 */
617
618static 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/** 608int gfs2_recover_journal(struct gfs2_jdesc *jd)
633 * gfs2_recoverd - Recover dead machine's journals
634 * @sdp: Pointer to GFS2 superblock
635 *
636 */
637
638int 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 a8218ea15b57..1616ac22569a 100644
--- a/fs/gfs2/recovery.h
+++ b/fs/gfs2/recovery.h
@@ -28,7 +28,7 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp);
28extern int gfs2_find_jhead(struct gfs2_jdesc *jd, 28extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
29 struct gfs2_log_header_host *head); 29 struct gfs2_log_header_host *head);
30extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd); 30extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd);
31extern int gfs2_recoverd(void *data); 31extern 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 894bf773ec93..9f6d48b75fd2 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
359static ssize_t recover_show(struct gfs2_sbd *sdp, char *buf) 359static 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
365static 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 }
383out:
376 spin_unlock(&sdp->sd_jindex_spin); 384 spin_unlock(&sdp->sd_jindex_spin);
377} 385 return rv ? rv : len;
378
379static 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
389static ssize_t recover_done_show(struct gfs2_sbd *sdp, char *buf) 388static 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) \
402static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) 401static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
403 402
404GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); 403GDLM_ATTR(proto_name, 0444, proto_name_show, NULL);
405GDLM_ATTR(block, 0644, block_show, block_store); 404GDLM_ATTR(block, 0644, block_show, block_store);
406GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); 405GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store);
407GDLM_ATTR(id, 0444, lkid_show, NULL); 406GDLM_ATTR(id, 0444, lkid_show, NULL);
408GDLM_ATTR(first, 0444, lkfirst_show, NULL); 407GDLM_ATTR(first, 0444, lkfirst_show, NULL);
409GDLM_ATTR(first_done, 0444, first_done_show, NULL); 408GDLM_ATTR(first_done, 0444, first_done_show, NULL);
410GDLM_ATTR(recover, 0644, recover_show, recover_store); 409GDLM_ATTR(recover, 0200, NULL, recover_store);
411GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); 410GDLM_ATTR(recover_done, 0444, recover_done_show, NULL);
412GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); 411GDLM_ATTR(recover_status, 0444, recover_status_show, NULL);
413 412
414static struct attribute *lock_module_attrs[] = { 413static struct attribute *lock_module_attrs[] = {
415 &gdlm_attr_proto_name.attr, 414 &gdlm_attr_proto_name.attr,