staging/lustre/ldlm: Fix flock deadlock detection race
authorAndriy Skulysh <Andriy_Skulysh@xyratex.com>
Mon, 22 Jul 2013 16:06:52 +0000 (00:06 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 23 Jul 2013 20:39:13 +0000 (13:39 -0700)
Deadlock isn't detected if 2 threads are trying to
grant 2 locks which deadlock on each other.
They call ldlm_flock_deadlock() simultaneously
and deadlock ins't detected.

The soulition is to add lock to blocking list before
calling ldlm_flock_deadlock()

Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-1602
Lustre-change: http://review.whamcloud.com/3277
Signed-off-by: Andriy Skulysh <Andriy_Skulysh@xyratex.com>
Reviewed-by: Vitaly Fertman <vitaly_fertman@xyratex.com>
Reviewed-by: Bruce Korb <bruce_korb@xyratex.com>
Reviewed-by: Keith Mannthey <keith.mannthey@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
Signed-off-by: Peng Tao <tao.peng@emc.com>
Signed-off-by: Andreas Dilger <andreas.dilger@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/lustre/lustre/ldlm/ldlm_flock.c

index aca1073d18b525da1363c8df9feb3725fd008ba0..39973cb110a3ba39351789ea03031b07a94b619a 100644 (file)
@@ -198,6 +198,7 @@ ldlm_flock_deadlock(struct ldlm_lock *req, struct ldlm_lock *bl_lock)
                if (lock == NULL)
                        break;
 
+               LASSERT(req != lock);
                flock = &lock->l_policy_data.l_flock;
                LASSERT(flock->owner == bl_owner);
                bl_owner = flock->blocking_owner;
@@ -329,18 +330,21 @@ reprocess:
                                RETURN(LDLM_ITER_STOP);
                        }
 
-                       if (ldlm_flock_deadlock(req, lock)) {
-                               ldlm_flock_destroy(req, mode, *flags);
-                               *err = -EDEADLK;
-                               RETURN(LDLM_ITER_STOP);
-                       }
-
+                       /* add lock to blocking list before deadlock
+                        * check to prevent race */
                        rc = ldlm_flock_blocking_link(req, lock);
                        if (rc) {
                                ldlm_flock_destroy(req, mode, *flags);
                                *err = rc;
                                RETURN(LDLM_ITER_STOP);
                        }
+                       if (ldlm_flock_deadlock(req, lock)) {
+                               ldlm_flock_blocking_unlink(req);
+                               ldlm_flock_destroy(req, mode, *flags);
+                               *err = -EDEADLK;
+                               RETURN(LDLM_ITER_STOP);
+                       }
+
                        ldlm_resource_add_lock(res, &res->lr_waiting, req);
                        *flags |= LDLM_FL_BLOCK_GRANTED;
                        RETURN(LDLM_ITER_STOP);