diff options
Diffstat (limited to 'fs/gfs2/util.c')
| -rw-r--r-- | fs/gfs2/util.c | 59 | 
1 files changed, 50 insertions, 9 deletions
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index a374397f4273..8d3c670c990f 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -91,12 +91,39 @@ out_unlock:  	return error;  } +/** + * gfs2_freeze_lock - hold the freeze glock + * @sdp: the superblock + * @freeze_gh: pointer to the requested holder + * @caller_flags: any additional flags needed by the caller + */ +int gfs2_freeze_lock(struct gfs2_sbd *sdp, struct gfs2_holder *freeze_gh, +		     int caller_flags) +{ +	int flags = LM_FLAG_NOEXP | GL_EXACT | caller_flags; +	int error; + +	error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, flags, +				   freeze_gh); +	if (error && error != GLR_TRYFAILED) +		fs_err(sdp, "can't lock the freeze lock: %d\n", error); +	return error; +} + +void gfs2_freeze_unlock(struct gfs2_holder *freeze_gh) +{ +	if (gfs2_holder_initialized(freeze_gh)) +		gfs2_glock_dq_uninit(freeze_gh); +} +  static void signal_our_withdraw(struct gfs2_sbd *sdp)  { -	struct gfs2_glock *gl = sdp->sd_live_gh.gh_gl; +	struct gfs2_glock *live_gl = sdp->sd_live_gh.gh_gl;  	struct inode *inode = sdp->sd_jdesc->jd_inode;  	struct gfs2_inode *ip = GFS2_I(inode); +	struct gfs2_glock *i_gl = ip->i_gl;  	u64 no_formal_ino = ip->i_no_formal_ino; +	int log_write_allowed = test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);  	int ret = 0;  	int tries; @@ -117,8 +144,21 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)  	 * therefore we need to clear SDF_JOURNAL_LIVE manually.  	 */  	clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); -	if (!sb_rdonly(sdp->sd_vfs)) -		ret = gfs2_make_fs_ro(sdp); +	if (!sb_rdonly(sdp->sd_vfs)) { +		struct gfs2_holder freeze_gh; + +		gfs2_holder_mark_uninitialized(&freeze_gh); +		if (sdp->sd_freeze_gl && +		    !gfs2_glock_is_locked_by_me(sdp->sd_freeze_gl)) { +			ret = gfs2_freeze_lock(sdp, &freeze_gh, +				       log_write_allowed ? 0 : LM_FLAG_TRY); +			if (ret == GLR_TRYFAILED) +				ret = 0; +		} +		if (!ret) +			ret = gfs2_make_fs_ro(sdp); +		gfs2_freeze_unlock(&freeze_gh); +	}  	if (sdp->sd_lockstruct.ls_ops->lm_lock == NULL) { /* lock_nolock */  		if (!ret) @@ -141,7 +181,8 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)  		atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);  		thaw_super(sdp->sd_vfs);  	} else { -		wait_on_bit(&gl->gl_flags, GLF_DEMOTE, TASK_UNINTERRUPTIBLE); +		wait_on_bit(&i_gl->gl_flags, GLF_DEMOTE, +			    TASK_UNINTERRUPTIBLE);  	}  	/* @@ -161,15 +202,15 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)  	 * on other nodes to be successful, otherwise we remain the owner of  	 * the glock as far as dlm is concerned.  	 */ -	if (gl->gl_ops->go_free) { -		set_bit(GLF_FREEING, &gl->gl_flags); -		wait_on_bit(&gl->gl_flags, GLF_FREEING, TASK_UNINTERRUPTIBLE); +	if (i_gl->gl_ops->go_free) { +		set_bit(GLF_FREEING, &i_gl->gl_flags); +		wait_on_bit(&i_gl->gl_flags, GLF_FREEING, TASK_UNINTERRUPTIBLE);  	}  	/*  	 * Dequeue the "live" glock, but keep a reference so it's never freed.  	 */ -	gfs2_glock_hold(gl); +	gfs2_glock_hold(live_gl);  	gfs2_glock_dq_wait(&sdp->sd_live_gh);  	/*  	 * We enqueue the "live" glock in EX so that all other nodes @@ -208,7 +249,7 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)  		gfs2_glock_nq(&sdp->sd_live_gh);  	} -	gfs2_glock_queue_put(gl); /* drop the extra reference we acquired */ +	gfs2_glock_queue_put(live_gl); /* drop extra reference we acquired */  	clear_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags);  	/*  | 
