diff options
author | Bob Peterson <rpeterso@redhat.com> | 2022-06-11 00:53:32 +0200 |
---|---|---|
committer | Andreas Gruenbacher <agruenba@redhat.com> | 2022-06-29 17:00:55 +0200 |
commit | 0befb8511e6a91716980c40c552acc5eec963cbd (patch) | |
tree | 9c469656279521973ba71c5ac90788513dc5c77b /fs/gfs2 | |
parent | 8f0028fc60a42a1305040676ce22e5f5488efee5 (diff) | |
download | linux-0befb8511e6a91716980c40c552acc5eec963cbd.tar.gz |
gfs2: do_promote glock holder stealing fix
In do_promote(), when the glock had no strong holders, we were
accidentally calling demote_incompat_holders() with new_gh == NULL, so
no weak holders were considered incompatible. Instead, the new holder
should have been passed in.
For doing that, the HIF_HOLDER flag needs to be set in new_gh to prevent
may_grant() from complaining. This means that the new holder will now
be recognized as a current holder, so skip over it explicitly in
demote_incompat_holders() to prevent it from being dequeued.
To further clarify things, we can now rename new_gh to current_gh in
demote_incompat_holders(); after all, the HIF_HOLDER flag is already set,
which means the new holder is already a current holder.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/glock.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 27b519099579..2138460a7369 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -405,10 +405,13 @@ static void do_error(struct gfs2_glock *gl, const int ret) /** * demote_incompat_holders - demote incompatible demoteable holders * @gl: the glock we want to promote - * @new_gh: the new holder to be promoted + * @current_gh: the newly promoted holder + * + * We're passing the newly promoted holder in @current_gh, but actually, any of + * the strong holders would do. */ static void demote_incompat_holders(struct gfs2_glock *gl, - struct gfs2_holder *new_gh) + struct gfs2_holder *current_gh) { struct gfs2_holder *gh, *tmp; @@ -424,8 +427,10 @@ static void demote_incompat_holders(struct gfs2_glock *gl, */ if (!test_bit(HIF_HOLDER, &gh->gh_iflags)) return; + if (gh == current_gh) + continue; if (test_bit(HIF_MAY_DEMOTE, &gh->gh_iflags) && - !may_grant(gl, new_gh, gh)) { + !may_grant(gl, current_gh, gh)) { /* * We should not recurse into do_promote because * __gfs2_glock_dq only calls handle_callback, @@ -547,14 +552,14 @@ static int do_promote(struct gfs2_glock *gl) do_error(gl, 0); break; } + set_bit(HIF_HOLDER, &gh->gh_iflags); + trace_gfs2_promote(gh); + gfs2_holder_wake(gh); if (!incompat_holders_demoted) { + current_gh = gh; demote_incompat_holders(gl, current_gh); incompat_holders_demoted = true; - current_gh = gh; } - set_bit(HIF_HOLDER, &gh->gh_iflags); - trace_gfs2_promote(gh); - gfs2_holder_wake(gh); } return 0; } |