Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 86934198eefa ("gfs2: Clear
flags when withdraw prevents xmote").

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>

+48 -37
+48 -37
fs/gfs2/glock.c
··· 458 458 459 459 static void do_promote(struct gfs2_glock *gl) 460 460 { 461 + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; 461 462 struct gfs2_holder *gh, *current_gh; 463 + 464 + if (gfs2_withdrawn(sdp)) { 465 + do_error(gl, LM_OUT_ERROR); 466 + return; 467 + } 462 468 463 469 current_gh = find_first_holder(gl); 464 470 list_for_each_entry(gh, &gl->gl_holders, gh_list) { ··· 571 565 state_change(gl, state); 572 566 } 573 567 574 - 575 568 /* Demote to UN request arrived during demote to SH or DF */ 576 569 if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags) && 577 570 gl->gl_state != LM_ST_UNLOCKED && ··· 659 654 struct lm_lockstruct *ls = &sdp->sd_lockstruct; 660 655 int ret; 661 656 662 - if (target != LM_ST_UNLOCKED && gfs2_withdrawn(sdp)) 663 - goto skip_inval; 657 + /* 658 + * When a filesystem is withdrawing, the remaining cluster nodes will 659 + * take care of recovering the withdrawing node's journal. We only 660 + * need to make sure that once we trigger remote recovery, we won't 661 + * write to the shared block device anymore. This means that here, 662 + * 663 + * - no new writes to the filesystem must be triggered (->go_sync()). 664 + * 665 + * - any cached data should be discarded by calling ->go_inval(), dirty 666 + * or not and journaled or unjournaled. 667 + * 668 + * - no more dlm locking operations should be issued (->lm_lock()). 669 + */ 664 670 665 671 GLOCK_BUG_ON(gl, gl->gl_state == target); 666 672 GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target); 673 + 667 674 if (!glops->go_inval || !glops->go_sync) 668 675 goto skip_inval; 669 676 670 677 spin_unlock(&gl->gl_lockref.lock); 671 - ret = glops->go_sync(gl); 672 - /* If we had a problem syncing (due to io errors or whatever, 673 - * we should not invalidate the metadata or tell dlm to 674 - * release the glock to other nodes. 675 - */ 676 - if (ret) { 677 - if (cmpxchg(&sdp->sd_log_error, 0, ret)) { 678 - fs_err(sdp, "Error %d syncing glock\n", ret); 679 - gfs2_dump_glock(NULL, gl, true); 680 - gfs2_withdraw(sdp); 678 + if (!gfs2_withdrawn(sdp)) { 679 + ret = glops->go_sync(gl); 680 + if (ret) { 681 + if (cmpxchg(&sdp->sd_log_error, 0, ret)) { 682 + fs_err(sdp, "Error %d syncing glock\n", ret); 683 + gfs2_dump_glock(NULL, gl, true); 684 + gfs2_withdraw(sdp); 685 + } 681 686 } 682 - spin_lock(&gl->gl_lockref.lock); 683 - goto skip_inval; 684 687 } 685 688 686 689 if (target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED) ··· 696 683 spin_lock(&gl->gl_lockref.lock); 697 684 698 685 skip_inval: 699 - if (gfs2_withdrawn(sdp) && target != LM_ST_UNLOCKED) { 700 - request_demote(gl, LM_ST_UNLOCKED, 0, false); 701 - /* 702 - * Ordinarily, we would call dlm and its callback would call 703 - * finish_xmote, which would call state_change() to the new state. 704 - * Since we withdrew, we won't call dlm, so call state_change 705 - * manually, but to the UNLOCKED state we desire. 706 - */ 707 - state_change(gl, LM_ST_UNLOCKED); 708 - /* 709 - * We skip telling dlm to do the locking, so we won't get a 710 - * reply that would otherwise clear GLF_LOCK. So we clear it here. 711 - */ 712 - if (!test_bit(GLF_CANCELING, &gl->gl_flags)) 713 - clear_bit(GLF_LOCK, &gl->gl_flags); 714 - clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags); 715 - gl->gl_lockref.count++; 716 - gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD); 717 - return; 686 + if (gfs2_withdrawn(sdp)) { 687 + if (target != LM_ST_UNLOCKED) 688 + target = LM_OUT_ERROR; 689 + goto out; 718 690 } 719 691 720 692 if (ls->ls_ops->lm_lock) { ··· 715 717 } 716 718 clear_bit(GLF_PENDING_REPLY, &gl->gl_flags); 717 719 718 - if (ret == -ENODEV && gl->gl_target == LM_ST_UNLOCKED && 719 - target == LM_ST_UNLOCKED) { 720 + if (ret == -ENODEV) { 720 721 /* 721 722 * The lockspace has been released and the lock has 722 723 * been unlocked implicitly. 723 724 */ 725 + if (target != LM_ST_UNLOCKED) { 726 + target = LM_OUT_ERROR; 727 + goto out; 728 + } 724 729 } else { 725 730 fs_err(sdp, "lm_lock ret %d\n", ret); 726 731 GLOCK_BUG_ON(gl, !gfs2_withdrawn(sdp)); ··· 731 730 } 732 731 } 733 732 733 + out: 734 734 /* Complete the operation now. */ 735 735 finish_xmote(gl, target); 736 736 gl->gl_lockref.count++; ··· 2083 2081 static void withdraw_glock(struct gfs2_glock *gl) 2084 2082 { 2085 2083 spin_lock(&gl->gl_lockref.lock); 2086 - if (!__lockref_is_dead(&gl->gl_lockref)) 2084 + if (!__lockref_is_dead(&gl->gl_lockref)) { 2085 + /* 2086 + * We don't want to write back any more dirty data. Unlock the 2087 + * remaining inode and resource group glocks; this will cause 2088 + * their ->go_inval() hooks to toss out all the remaining 2089 + * cached data, dirty or not. 2090 + */ 2091 + if (gl->gl_ops->go_inval && gl->gl_state != LM_ST_UNLOCKED) 2092 + request_demote(gl, LM_ST_UNLOCKED, 0, false); 2087 2093 do_error(gl, LM_OUT_ERROR); /* remove pending waiters */ 2094 + } 2088 2095 spin_unlock(&gl->gl_lockref.lock); 2089 2096 } 2090 2097