aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/ops_super.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2009-05-19 10:01:18 +0100
committerSteven Whitehouse <swhiteho@redhat.com>2009-05-19 10:01:18 +0100
commitfe64d517df0970a68417184a12fcd4ba0589cc28 (patch)
treed977f214fdf6ba96254cfbf6683e8583ecebe504 /fs/gfs2/ops_super.c
parent9582d41135c0d362f04ed6bf3dc8d693a7eafee2 (diff)
downloadlinux-fe64d517df0970a68417184a12fcd4ba0589cc28.tar.gz
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/ops_super.c')
-rw-r--r--fs/gfs2/ops_super.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index 0677a837856006..a3c2272e7cade1 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)
return error;
}
+static int gfs2_umount_recovery_wait(void *word)
+{
+ schedule();
+ return 0;
+}
+
/**
* gfs2_put_super - Unmount the filesystem
* @sb: The VFS superblock
@@ -131,6 +137,7 @@ static void gfs2_put_super(struct super_block *sb)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
int error;
+ struct gfs2_jdesc *jd;
/* Unfreeze the filesystem, if we need to */
@@ -139,9 +146,25 @@ static void gfs2_put_super(struct super_block *sb)
gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
mutex_unlock(&sdp->sd_freeze_lock);
+ /* No more recovery requests */
+ set_bit(SDF_NORECOVERY, &sdp->sd_flags);
+ smp_mb();
+
+ /* Wait on outstanding recovery */
+restart:
+ spin_lock(&sdp->sd_jindex_spin);
+ list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+ if (!test_bit(JDF_RECOVERY, &jd->jd_flags))
+ continue;
+ spin_unlock(&sdp->sd_jindex_spin);
+ wait_on_bit(&jd->jd_flags, JDF_RECOVERY,
+ gfs2_umount_recovery_wait, TASK_UNINTERRUPTIBLE);
+ goto restart;
+ }
+ spin_unlock(&sdp->sd_jindex_spin);
+
kthread_stop(sdp->sd_quotad_process);
kthread_stop(sdp->sd_logd_process);
- kthread_stop(sdp->sd_recoverd_process);
if (!(sb->s_flags & MS_RDONLY)) {
error = gfs2_make_fs_ro(sdp);