Skip to content

Commit e3da6be

Browse files
author
Andreas Gruenbacher
committed
gfs2: Fix withdraw race
Function gfs2_withdraw() tries to synchronize concurrent callers by atomically setting the SDF_WITHDRAWN flag in the first caller, setting the SDF_WITHDRAW_IN_PROG flag to indicate that a withdraw is in progress, performing the actual withdraw, and clearing the SDF_WITHDRAW_IN_PROG flag when done. All other callers wait for the SDF_WITHDRAW_IN_PROG flag to be cleared before returning. This leaves a small window in which callers can find the SDF_WITHDRAWN flag set before the SDF_WITHDRAW_IN_PROG flag has been set, causing them to return prematurely, before the withdraw has been completed. Fix that by setting the SDF_WITHDRAWN and SDF_WITHDRAW_IN_PROG flags atomically. Signed-off-by: Andreas Gruenbacher <[email protected]>
1 parent fe0690f commit e3da6be

File tree

1 file changed

+12
-12
lines changed

1 file changed

+12
-12
lines changed

fs/gfs2/util.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -323,19 +323,19 @@ int gfs2_withdraw(struct gfs2_sbd *sdp)
323323
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
324324
const struct lm_lockops *lm = ls->ls_ops;
325325

326-
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW &&
327-
test_and_set_bit(SDF_WITHDRAWN, &sdp->sd_flags)) {
328-
if (!test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags))
329-
return -1;
330-
331-
wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_IN_PROG,
332-
TASK_UNINTERRUPTIBLE);
333-
return -1;
334-
}
335-
336-
set_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags);
337-
338326
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) {
327+
unsigned long old = READ_ONCE(sdp->sd_flags), new;
328+
329+
do {
330+
if (old & BIT(SDF_WITHDRAWN)) {
331+
wait_on_bit(&sdp->sd_flags,
332+
SDF_WITHDRAW_IN_PROG,
333+
TASK_UNINTERRUPTIBLE);
334+
return -1;
335+
}
336+
new = old | BIT(SDF_WITHDRAWN) | BIT(SDF_WITHDRAW_IN_PROG);
337+
} while (unlikely(!try_cmpxchg(&sdp->sd_flags, &old, new)));
338+
339339
fs_err(sdp, "about to withdraw this file system\n");
340340
BUG_ON(sdp->sd_args.ar_debug);
341341

0 commit comments

Comments
 (0)