Skip to content

Commit 0e10da6

Browse files
author
Andreas Gruenbacher
committed
gfs2: Clean up properly during a withdraw
During a withdraw, we don't want to write out any more data than we have to, so in do_xmote(), skip the ->go_sync() glock operation. We still want to keep calling ->go_inval() to discard any cached data or metadata, whether clean or dirty. We do still allow glocks to transition into state LM_ST_UNLOCKED. This has the desired side effect of calling ->go_inval() and invalidating the glock caches. Function gfs2_withdraw_glocks() is already used for dequeuing any left-over waiters. We still want that to happen, but additionally, we want all glocks to be unlocked. Finally, we change function do_promote() to refuse any further promotions. This commit cleans up the leftovers of commit 8693419 ("gfs2: Clear flags when withdraw prevents xmote"). Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
1 parent 473678c commit 0e10da6

1 file changed

Lines changed: 48 additions & 37 deletions

File tree

fs/gfs2/glock.c

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,14 @@ int gfs2_instantiate(struct gfs2_holder *gh)
458458

459459
static void do_promote(struct gfs2_glock *gl)
460460
{
461+
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
461462
struct gfs2_holder *gh, *current_gh;
462463

464+
if (gfs2_withdrawn(sdp)) {
465+
do_error(gl, LM_OUT_ERROR);
466+
return;
467+
}
468+
463469
current_gh = find_first_holder(gl);
464470
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
465471
if (test_bit(HIF_HOLDER, &gh->gh_iflags))
@@ -565,7 +571,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
565571
state_change(gl, state);
566572
}
567573

568-
569574
/* Demote to UN request arrived during demote to SH or DF */
570575
if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags) &&
571576
gl->gl_state != LM_ST_UNLOCKED &&
@@ -654,54 +659,47 @@ __acquires(&gl->gl_lockref.lock)
654659
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
655660
int ret;
656661

657-
if (target != LM_ST_UNLOCKED && gfs2_withdrawn(sdp))
658-
goto skip_inval;
662+
/*
663+
* When a filesystem is withdrawing, the remaining cluster nodes will
664+
* take care of recovering the withdrawing node's journal. We only
665+
* need to make sure that once we trigger remote recovery, we won't
666+
* write to the shared block device anymore. This means that here,
667+
*
668+
* - no new writes to the filesystem must be triggered (->go_sync()).
669+
*
670+
* - any cached data should be discarded by calling ->go_inval(), dirty
671+
* or not and journaled or unjournaled.
672+
*
673+
* - no more dlm locking operations should be issued (->lm_lock()).
674+
*/
659675

660676
GLOCK_BUG_ON(gl, gl->gl_state == target);
661677
GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target);
678+
662679
if (!glops->go_inval || !glops->go_sync)
663680
goto skip_inval;
664681

665682
spin_unlock(&gl->gl_lockref.lock);
666-
ret = glops->go_sync(gl);
667-
/* If we had a problem syncing (due to io errors or whatever,
668-
* we should not invalidate the metadata or tell dlm to
669-
* release the glock to other nodes.
670-
*/
671-
if (ret) {
672-
if (cmpxchg(&sdp->sd_log_error, 0, ret)) {
673-
fs_err(sdp, "Error %d syncing glock\n", ret);
674-
gfs2_dump_glock(NULL, gl, true);
675-
gfs2_withdraw(sdp);
683+
if (!gfs2_withdrawn(sdp)) {
684+
ret = glops->go_sync(gl);
685+
if (ret) {
686+
if (cmpxchg(&sdp->sd_log_error, 0, ret)) {
687+
fs_err(sdp, "Error %d syncing glock\n", ret);
688+
gfs2_dump_glock(NULL, gl, true);
689+
gfs2_withdraw(sdp);
690+
}
676691
}
677-
spin_lock(&gl->gl_lockref.lock);
678-
goto skip_inval;
679692
}
680693

681694
if (target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED)
682695
glops->go_inval(gl, target == LM_ST_DEFERRED ? 0 : DIO_METADATA);
683696
spin_lock(&gl->gl_lockref.lock);
684697

685698
skip_inval:
686-
if (gfs2_withdrawn(sdp) && target != LM_ST_UNLOCKED) {
687-
request_demote(gl, LM_ST_UNLOCKED, 0, false);
688-
/*
689-
* Ordinarily, we would call dlm and its callback would call
690-
* finish_xmote, which would call state_change() to the new state.
691-
* Since we withdrew, we won't call dlm, so call state_change
692-
* manually, but to the UNLOCKED state we desire.
693-
*/
694-
state_change(gl, LM_ST_UNLOCKED);
695-
/*
696-
* We skip telling dlm to do the locking, so we won't get a
697-
* reply that would otherwise clear GLF_LOCK. So we clear it here.
698-
*/
699-
if (!test_bit(GLF_CANCELING, &gl->gl_flags))
700-
clear_bit(GLF_LOCK, &gl->gl_flags);
701-
clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
702-
gl->gl_lockref.count++;
703-
gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD);
704-
return;
699+
if (gfs2_withdrawn(sdp)) {
700+
if (target != LM_ST_UNLOCKED)
701+
target = LM_OUT_ERROR;
702+
goto out;
705703
}
706704

707705
if (ls->ls_ops->lm_lock) {
@@ -717,19 +715,23 @@ __acquires(&gl->gl_lockref.lock)
717715
}
718716
clear_bit(GLF_PENDING_REPLY, &gl->gl_flags);
719717

720-
if (ret == -ENODEV && gl->gl_target == LM_ST_UNLOCKED &&
721-
target == LM_ST_UNLOCKED) {
718+
if (ret == -ENODEV) {
722719
/*
723720
* The lockspace has been released and the lock has
724721
* been unlocked implicitly.
725722
*/
723+
if (target != LM_ST_UNLOCKED) {
724+
target = LM_OUT_ERROR;
725+
goto out;
726+
}
726727
} else {
727728
fs_err(sdp, "lm_lock ret %d\n", ret);
728729
GLOCK_BUG_ON(gl, !gfs2_withdrawn(sdp));
729730
return;
730731
}
731732
}
732733

734+
out:
733735
/* Complete the operation now. */
734736
finish_xmote(gl, target);
735737
gl->gl_lockref.count++;
@@ -2081,8 +2083,17 @@ static void dump_glock_func(struct gfs2_glock *gl)
20812083
static void withdraw_glock(struct gfs2_glock *gl)
20822084
{
20832085
spin_lock(&gl->gl_lockref.lock);
2084-
if (!__lockref_is_dead(&gl->gl_lockref))
2086+
if (!__lockref_is_dead(&gl->gl_lockref)) {
2087+
/*
2088+
* We don't want to write back any more dirty data. Unlock the
2089+
* remaining inode and resource group glocks; this will cause
2090+
* their ->go_inval() hooks to toss out all the remaining
2091+
* cached data, dirty or not.
2092+
*/
2093+
if (gl->gl_ops->go_inval && gl->gl_state != LM_ST_UNLOCKED)
2094+
request_demote(gl, LM_ST_UNLOCKED, 0, false);
20852095
do_error(gl, LM_OUT_ERROR); /* remove pending waiters */
2096+
}
20862097
spin_unlock(&gl->gl_lockref.lock);
20872098
}
20882099

0 commit comments

Comments
 (0)