2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

gfs2: sanitize the gdlm_ast -> finish_xmote interface

When gdlm_ast() is called with a non-zero status code, this means that
the requested operation did not succeed and the current lock state
didn't change.  Turn that into a non-zero LM_OUT_* status code (with ret
& ~LM_OUT_ST_MASK != 0) instead of pretending that dlm returned the
current lock state.

That way, we can easily change finish_xmote() to only update
gl->gl_state when the state has actually changed.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Andrew Price <anprice@redhat.com>
This commit is contained in:
Andreas Gruenbacher 2025-06-25 14:41:58 +02:00
parent 75bb2ddea9
commit 6e417b3eb8
3 changed files with 34 additions and 14 deletions

View File

@ -590,20 +590,25 @@ static void gfs2_demote_wake(struct gfs2_glock *gl)
static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
{
const struct gfs2_glock_operations *glops = gl->gl_ops;
struct gfs2_holder *gh;
unsigned state = ret & LM_OUT_ST_MASK;
trace_gfs2_glock_state_change(gl, state);
state_change(gl, state);
gh = find_first_waiter(gl);
if (!(ret & ~LM_OUT_ST_MASK)) {
unsigned state = ret & LM_OUT_ST_MASK;
trace_gfs2_glock_state_change(gl, state);
state_change(gl, state);
}
/* Demote to UN request arrived during demote to SH or DF */
if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags) &&
state != LM_ST_UNLOCKED && gl->gl_demote_state == LM_ST_UNLOCKED)
gl->gl_state != LM_ST_UNLOCKED &&
gl->gl_demote_state == LM_ST_UNLOCKED)
gl->gl_target = LM_ST_UNLOCKED;
/* Check for state != intended state */
if (unlikely(state != gl->gl_target)) {
if (unlikely(gl->gl_state != gl->gl_target)) {
struct gfs2_holder *gh = find_first_waiter(gl);
if (gh && (ret & LM_OUT_CANCELED))
gfs2_holder_wake(gh);
if (gh && !test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)) {
@ -629,7 +634,7 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
goto out;
}
}
switch(state) {
switch(gl->gl_state) {
/* Unlocked due to conversion deadlock, try again */
case LM_ST_UNLOCKED:
do_xmote(gl, gh, gl->gl_target);
@ -640,8 +645,10 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
do_xmote(gl, gh, LM_ST_UNLOCKED);
break;
default: /* Everything else */
fs_err(gl->gl_name.ln_sbd, "wanted %u got %u\n",
gl->gl_target, state);
fs_err(gl->gl_name.ln_sbd,
"glock %u:%llu requested=%u ret=%u\n",
gl->gl_name.ln_type, gl->gl_name.ln_number,
gl->gl_req, ret);
GLOCK_BUG_ON(gl, 1);
}
return;
@ -650,7 +657,7 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
/* Fast path - we got what we asked for */
if (test_and_clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags))
gfs2_demote_wake(gl);
if (state != LM_ST_UNLOCKED) {
if (gl->gl_state != LM_ST_UNLOCKED) {
if (glops->go_xmote_bh) {
int rv;

View File

@ -92,12 +92,22 @@ enum {
* LM_OUT_ST_MASK
* Masks the lower two bits of lock state in the returned value.
*
* LM_OUT_TRY_AGAIN
* The trylock request failed.
*
* LM_OUT_DEADLOCK
* The lock request failed because it would deadlock.
*
* LM_OUT_CANCELED
* The lock request was canceled.
*
* LM_OUT_ERROR
* The lock request timed out or failed.
*/
#define LM_OUT_ST_MASK 0x00000003
#define LM_OUT_TRY_AGAIN 0x00000020
#define LM_OUT_DEADLOCK 0x00000010
#define LM_OUT_CANCELED 0x00000008
#define LM_OUT_ERROR 0x00000004

View File

@ -119,7 +119,7 @@ static inline void gfs2_update_request_times(struct gfs2_glock *gl)
static void gdlm_ast(void *arg)
{
struct gfs2_glock *gl = arg;
unsigned ret = gl->gl_state;
unsigned ret;
/* If the glock is dead, we only react to a dlm_unlock() reply. */
if (__lockref_is_dead(&gl->gl_lockref) &&
@ -139,13 +139,16 @@ static void gdlm_ast(void *arg)
gfs2_glock_free(gl);
return;
case -DLM_ECANCEL: /* Cancel while getting lock */
ret |= LM_OUT_CANCELED;
ret = LM_OUT_CANCELED;
goto out;
case -EAGAIN: /* Try lock fails */
ret = LM_OUT_TRY_AGAIN;
goto out;
case -EDEADLK: /* Deadlock detected */
ret = LM_OUT_DEADLOCK;
goto out;
case -ETIMEDOUT: /* Canceled due to timeout */
ret |= LM_OUT_ERROR;
ret = LM_OUT_ERROR;
goto out;
case 0: /* Success */
break;