diff options
-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 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 | ||
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 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 { | |||
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 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 | ||
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 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_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 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 | ||
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 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 | /** | 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 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); | |||
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 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 | ||
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, |