diff options
Diffstat (limited to 'fs/gfs2/util.c')
| -rw-r--r-- | fs/gfs2/util.c | 34 | 
1 files changed, 21 insertions, 13 deletions
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index dac22b1c1a2e..da29fafb6272 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -9,6 +9,7 @@  #include <linux/spinlock.h>  #include <linux/completion.h>  #include <linux/buffer_head.h> +#include <linux/kthread.h>  #include <linux/crc32.h>  #include <linux/gfs2_ondisk.h>  #include <linux/delay.h> @@ -150,7 +151,14 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)  	if (!sb_rdonly(sdp->sd_vfs)) {  		bool locked = mutex_trylock(&sdp->sd_freeze_mutex); -		gfs2_make_fs_ro(sdp); +		wake_up(&sdp->sd_logd_waitq); +		wake_up(&sdp->sd_quota_wait); + +		wait_event_timeout(sdp->sd_log_waitq, +				   gfs2_log_is_empty(sdp), +				   HZ * 5); + +		sdp->sd_vfs->s_flags |= SB_RDONLY;  		if (locked)  			mutex_unlock(&sdp->sd_freeze_mutex); @@ -315,19 +323,19 @@ int gfs2_withdraw(struct gfs2_sbd *sdp)  	struct lm_lockstruct *ls = &sdp->sd_lockstruct;  	const struct lm_lockops *lm = ls->ls_ops; -	if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW && -	    test_and_set_bit(SDF_WITHDRAWN, &sdp->sd_flags)) { -		if (!test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags)) -			return -1; - -		wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_IN_PROG, -			    TASK_UNINTERRUPTIBLE); -		return -1; -	} - -	set_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags); -  	if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) { +		unsigned long old = READ_ONCE(sdp->sd_flags), new; + +		do { +			if (old & BIT(SDF_WITHDRAWN)) { +				wait_on_bit(&sdp->sd_flags, +					    SDF_WITHDRAW_IN_PROG, +					    TASK_UNINTERRUPTIBLE); +				return -1; +			} +			new = old | BIT(SDF_WITHDRAWN) | BIT(SDF_WITHDRAW_IN_PROG); +		} while (unlikely(!try_cmpxchg(&sdp->sd_flags, &old, new))); +  		fs_err(sdp, "about to withdraw this file system\n");  		BUG_ON(sdp->sd_args.ar_debug);  |