]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
gfs2: sanitize the gdlm_ast -> finish_xmote interface
authorAndreas Gruenbacher <agruenba@redhat.com>
Wed, 25 Jun 2025 12:41:58 +0000 (14:41 +0200)
committerAndreas Gruenbacher <agruenba@redhat.com>
Tue, 15 Jul 2025 02:20:40 +0000 (04:20 +0200)
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>
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/lock_dlm.c

index ea96113edbe31bb5a31b413f4bcc6fe0ac9ad2cd..a3a5edc28a51c9f5576c66695d40de55fedf17a9 100644 (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;
 
index c171f745650fd3118ddecbea42fcb660005083f3..9339a3bff6eeb1db620a4f828826ab886647ac37 100644 (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
 
index 7cb9d216d8bb9075ad91d3293db229116c415aed..cee5d199d2d87086afbb61e4727f9422501365db 100644 (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;