aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,