diff options
author | Bob Peterson <rpeterso@redhat.com> | 2022-08-18 13:32:37 -0500 |
---|---|---|
committer | Andreas Gruenbacher <agruenba@redhat.com> | 2022-08-25 17:11:14 +0200 |
commit | 053640a73838400dca23087d66a9c0db579adafb (patch) | |
tree | 42169cec2192266f57afe4c1228a3d3c96f471d2 /fs/gfs2 | |
parent | 04133b607a78f2fd3daadbe5519513942b0f3a05 (diff) |
gfs2: Dequeue waiters when withdrawn
When a withdraw occurs, ordinary (not system) glocks may not be granted
anymore. Later, when the file system is unmounted, gfs2_gl_hash_clear()
tries to clear out all the glocks, but these un-grantable pending
waiters prevent some glocks from being freed. So the unmount hangs, at
least for its ten-minute timeout period.
This patch takes measures to remove any pending waiters from
the glocks that will never be granted. This allows the unmount to
proceed in a reasonable period of time.
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 | 14 | ||||
-rw-r--r-- | fs/gfs2/glock.h | 1 | ||||
-rw-r--r-- | fs/gfs2/util.c | 5 |
3 files changed, 20 insertions, 0 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 57dcfd05b362..858616afcae6 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -2196,6 +2196,20 @@ static void dump_glock_func(struct gfs2_glock *gl) dump_glock(NULL, gl, true); } +static void withdraw_dq(struct gfs2_glock *gl) +{ + spin_lock(&gl->gl_lockref.lock); + if (!__lockref_is_dead(&gl->gl_lockref) && + glock_blocked_by_withdraw(gl)) + do_error(gl, LM_OUT_ERROR); /* remove pending waiters */ + spin_unlock(&gl->gl_lockref.lock); +} + +void gfs2_gl_dq_holders(struct gfs2_sbd *sdp) +{ + glock_hash_walk(withdraw_dq, sdp); +} + /** * gfs2_gl_hash_clear - Empty out the glock hash table * @sdp: the filesystem diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 5aed8b500cf5..0199a3dcb114 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -274,6 +274,7 @@ extern void gfs2_cancel_delete_work(struct gfs2_glock *gl); extern bool gfs2_delete_work_queued(const struct gfs2_glock *gl); extern void gfs2_flush_delete_work(struct gfs2_sbd *sdp); extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); +extern void gfs2_gl_dq_holders(struct gfs2_sbd *sdp); extern void gfs2_glock_thaw(struct gfs2_sbd *sdp); extern void gfs2_glock_add_to_lru(struct gfs2_glock *gl); extern void gfs2_glock_free(struct gfs2_glock *gl); diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 95c79a3ec161..88185a341504 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -164,6 +164,11 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp) } if (!ret) gfs2_make_fs_ro(sdp); + /* + * Dequeue any pending non-system glock holders that can no + * longer be granted because the file system is withdrawn. + */ + gfs2_gl_dq_holders(sdp); gfs2_freeze_unlock(&freeze_gh); } |