mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
gfs2: Fix additional unlikely request cancelation race
In gfs2_glock_dq(), we must drop the glock spin lock before calling ->lm_cancel, but this means that in the meantime, the operation we are trying to cancel could complete. If the operation completes unsuccessfully, another holder can end up at the head of the queue and another ->lm_lock operation can get started. In this case, we would end up canceling that second operation by accident. To prevent that, introduce a new GLF_CANCELING flag. Set that flag in gfs2_glock_dq() when trying to cancel an operation. When seeing that flag, finish_xmote() will then keep the GLF_LOCK flag set to prevent other glock operations from taking place. gfs2_glock_dq() then completes the cancelation attempt by clearing GLF_LOCK and GLF_CANCELING. In addition, add a missing GLF_DEMOTE_IN_PROGRESS check in gfs2_glock_dq() to make sure that we won't accidentally cancel a demote request. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
parent
a431d49243
commit
6cb3b1c2df
3 changed files with 14 additions and 3 deletions
|
@ -665,7 +665,8 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
|
|||
do_promote(gl);
|
||||
}
|
||||
out:
|
||||
clear_bit(GLF_LOCK, &gl->gl_flags);
|
||||
if (!test_bit(GLF_CANCELING, &gl->gl_flags))
|
||||
clear_bit(GLF_LOCK, &gl->gl_flags);
|
||||
}
|
||||
|
||||
static bool is_system_glock(struct gfs2_glock *gl)
|
||||
|
@ -1671,11 +1672,17 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
|
|||
}
|
||||
|
||||
if (list_is_first(&gh->gh_list, &gl->gl_holders) &&
|
||||
!test_bit(HIF_HOLDER, &gh->gh_iflags)) {
|
||||
!test_bit(HIF_HOLDER, &gh->gh_iflags) &&
|
||||
test_bit(GLF_LOCK, &gl->gl_flags) &&
|
||||
!test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags) &&
|
||||
!test_bit(GLF_CANCELING, &gl->gl_flags)) {
|
||||
set_bit(GLF_CANCELING, &gl->gl_flags);
|
||||
spin_unlock(&gl->gl_lockref.lock);
|
||||
gl->gl_name.ln_sbd->sd_lockstruct.ls_ops->lm_cancel(gl);
|
||||
wait_on_bit(&gh->gh_iflags, HIF_WAIT, TASK_UNINTERRUPTIBLE);
|
||||
spin_lock(&gl->gl_lockref.lock);
|
||||
clear_bit(GLF_CANCELING, &gl->gl_flags);
|
||||
clear_bit(GLF_LOCK, &gl->gl_flags);
|
||||
if (!gfs2_holder_queued(gh))
|
||||
goto out;
|
||||
}
|
||||
|
@ -2352,6 +2359,8 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
|
|||
*p++ = 'E';
|
||||
if (test_bit(GLF_DEFER_DELETE, gflags))
|
||||
*p++ = 's';
|
||||
if (test_bit(GLF_CANCELING, gflags))
|
||||
*p++ = 'C';
|
||||
*p = 0;
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -332,6 +332,7 @@ enum {
|
|||
GLF_VERIFY_DELETE = 18, /* iopen glocks only */
|
||||
GLF_PENDING_REPLY = 19,
|
||||
GLF_DEFER_DELETE = 20, /* iopen glocks only */
|
||||
GLF_CANCELING = 21,
|
||||
};
|
||||
|
||||
struct gfs2_glock {
|
||||
|
|
|
@ -65,7 +65,8 @@
|
|||
{(1UL << GLF_INSTANTIATE_IN_PROG), "N" }, \
|
||||
{(1UL << GLF_TRY_TO_EVICT), "e" }, \
|
||||
{(1UL << GLF_VERIFY_DELETE), "E" }, \
|
||||
{(1UL << GLF_DEFER_DELETE), "s" })
|
||||
{(1UL << GLF_DEFER_DELETE), "s" }, \
|
||||
{(1UL << GLF_CANCELING), "C" })
|
||||
|
||||
#ifndef NUMPTY
|
||||
#define NUMPTY
|
||||
|
|
Loading…
Add table
Reference in a new issue