aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/sys.c
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 /fs/gfs2/sys.c
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>
Diffstat (limited to 'fs/gfs2/sys.c')
-rw-r--r--fs/gfs2/sys.c53
1 files changed, 26 insertions, 27 deletions
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,