aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Peterson <rpeterso@redhat.com>2023-07-26 12:01:08 -0500
committerAndreas Gruenbacher <agruenba@redhat.com>2023-09-05 15:58:16 +0200
commit66fa9912ec973796de4ce9b430d0811d401c17bb (patch)
tree577a2d7ef6c537a6fd410dceb633c30433cd59da
parent0b93bac2271e11beb980fca037a34a9819c7dc37 (diff)
downloadlinux-66fa9912ec973796de4ce9b430d0811d401c17bb.tar.gz
gfs2: conversion deadlock do_promote bypass
Consider the following case: 1. A glock is held in shared mode. 2. A process requests the glock in exclusive mode (rename). 3. Before the lock is granted, more processes (read / ls) request the glock in shared mode again. 4. gfs2 sends a request to dlm for the lock in exclusive mode because that holder is at the head of the queue. 5. Somehow the dlm request gets canceled, so dlm sends us back a response with state == LM_ST_SHARED and LM_OUT_CANCELED. So at that point, the glock is still held in shared mode. 6. finish_xmote gets called to process the response from dlm. It detects that the glock is not in the requested mode and no demote is in progress, so it moves the canceled holder to the tail of the queue and finds the new holder at the head of the queue. That holder is requesting the glock in shared mode. 7. finish_xmote calls do_xmote to transition the glock into shared mode, but the glock is already in shared mode and so do_xmote complains about that with: GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target); Instead, in finish_xmote, after moving the canceled holder to the tail of the queue, check if any new holders can be granted. Only call do_xmote to repeat the dlm request if the holder at the head of the queue is requesting the glock in a mode that is incompatible with the mode the glock is currently held in. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
-rw-r--r--fs/gfs2/glock.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 72346f3306e45c..675bfec7770678 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -594,6 +594,8 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
list_move_tail(&gh->gh_list, &gl->gl_holders);
gh = find_first_waiter(gl);
gl->gl_target = gh->gh_state;
+ if (do_promote(gl))
+ goto out;
goto retry;
}
/* Some error or failed "try lock" - report it */