DLM: fix conversion deadlock when DLM_LKF_NODLCKWT flag is set
authortsutomu.owa@toshiba.co.jp <tsutomu.owa@toshiba.co.jp>
Fri, 15 Sep 2017 19:17:23 +0000 (14:17 -0500)
committerDavid Teigland <teigland@redhat.com>
Mon, 25 Sep 2017 17:45:21 +0000 (12:45 -0500)
When the DLM_LKF_NODLCKWT flag was set, even if conversion deadlock
was detected, the caller of can_be_granted() was unknown.
We change the behavior of can_be_granted() and change it to detect
conversion deadlock regardless of whether the DLM_LKF_NODLCKWT flag
is set or not. And depending on whether the DLM_LKF_NODLCKWT flag
is set or not, we change the behavior at the caller of can_be_granted().

This fix has no effect except when using DLM_LKF_NODLCKWT flag.
Currently, ocfs2 uses the DLM_LKF_NODLCKWT flag and does not expect a
cancel operation from conversion deadlock when calling dlm_lock().
ocfs2 is implemented to perform a cancel operation by requesting
BASTs (callback).

Signed-off-by: Tadashi Miyauchi <miyauchi@toshiba-tops.co.jp>
Signed-off-by: Tsutomu Owa <tsutomu.owa@toshiba.co.jp>
Signed-off-by: David Teigland <teigland@redhat.com>
fs/dlm/lock.c

index d4aaddec1b16207c6ae394075b31110b8cead77d..f145a2a9d6cb55ae8794150023653831d2c393c0 100644 (file)
@@ -2465,14 +2465,12 @@ static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
                if (lkb->lkb_exflags & DLM_LKF_CONVDEADLK) {
                        lkb->lkb_grmode = DLM_LOCK_NL;
                        lkb->lkb_sbflags |= DLM_SBF_DEMOTED;
-               } else if (!(lkb->lkb_exflags & DLM_LKF_NODLCKWT)) {
-                       if (err)
-                               *err = -EDEADLK;
-                       else {
-                               log_print("can_be_granted deadlock %x now %d",
-                                         lkb->lkb_id, now);
-                               dlm_dump_rsb(r);
-                       }
+               } else if (err) {
+                       *err = -EDEADLK;
+               } else {
+                       log_print("can_be_granted deadlock %x now %d",
+                                 lkb->lkb_id, now);
+                       dlm_dump_rsb(r);
                }
                goto out;
        }
@@ -2501,13 +2499,6 @@ static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
        return rv;
 }
 
-/* FIXME: I don't think that can_be_granted() can/will demote or find deadlock
-   for locks pending on the convert list.  Once verified (watch for these
-   log_prints), we should be able to just call _can_be_granted() and not
-   bother with the demote/deadlk cases here (and there's no easy way to deal
-   with a deadlk here, we'd have to generate something like grant_lock with
-   the deadlk error.) */
-
 /* Returns the highest requested mode of all blocked conversions; sets
    cw if there's a blocked conversion to DLM_LOCK_CW. */
 
@@ -2545,9 +2536,22 @@ static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw,
                }
 
                if (deadlk) {
-                       log_print("WARN: pending deadlock %x node %d %s",
-                                 lkb->lkb_id, lkb->lkb_nodeid, r->res_name);
-                       dlm_dump_rsb(r);
+                       /*
+                        * If DLM_LKB_NODLKWT flag is set and conversion
+                        * deadlock is detected, we request blocking AST and
+                        * down (or cancel) conversion.
+                        */
+                       if (lkb->lkb_exflags & DLM_LKF_NODLCKWT) {
+                               if (lkb->lkb_highbast < lkb->lkb_rqmode) {
+                                       queue_bast(r, lkb, lkb->lkb_rqmode);
+                                       lkb->lkb_highbast = lkb->lkb_rqmode;
+                               }
+                       } else {
+                               log_print("WARN: pending deadlock %x node %d %s",
+                                         lkb->lkb_id, lkb->lkb_nodeid,
+                                         r->res_name);
+                               dlm_dump_rsb(r);
+                       }
                        continue;
                }
 
@@ -3123,7 +3127,7 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
           deadlock, so we leave it on the granted queue and return EDEADLK in
           the ast for the convert. */
 
-       if (deadlk) {
+       if (deadlk && !(lkb->lkb_exflags & DLM_LKF_NODLCKWT)) {
                /* it's left on the granted queue */
                revert_lock(r, lkb);
                queue_cast(r, lkb, -EDEADLK);