]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: honor scatter_wanted while freezing
authorSage Weil <sage@newdream.net>
Wed, 27 Jul 2011 21:38:38 +0000 (14:38 -0700)
committerSage Weil <sage@newdream.net>
Thu, 28 Jul 2011 16:49:22 +0000 (09:49 -0700)
- mds A authpins item on mds B
- mds B starts to freeze tree containing item
- mds A tries wrlock_start on A, sends REQSCATTER to B
- mds B lock is unstable, sets scatter_wanted
- mds B lock stabilizes, calls try_eval, defers because freezing.
-> deadlock

In general, we want to avoid the eval while freezing to prevent starvation.
However, in this case with the multi-mds locking, we need to honor
the scatter_wanted even so.

Insert this check in try_eval().  This will catch it on the first try_eval
call after the lock stabilizes.  The ambiguous auth will never catch us
while freezing, and the master holds an auth_pin to prevent a freeze, so
we will never defer the eval; no need to do the same logic in the other
eval method (eval(MDSCacheObject*, ...)) used for retry.

Signed-off-by: Sage Weil <sage@newdream.net>
src/mds/Locker.cc

index 48d64bba7f0badcc8f828f152f4a5af96f6f9b72..022a7714ff6aa070c4e07fbc37ceb04da880ce7d 100644 (file)
@@ -842,8 +842,37 @@ void Locker::try_eval(SimpleLock *lock, bool *pneed_issue)
     return;
   }
 
-  if (!p->can_auth_pin()) {
-    dout(7) << "try_eval " << *lock << " can't auth_pin, waiting on " << *p << dendl;
+  if (p->is_frozen()) {
+    dout(7) << "try_eval " << *lock << " frozen, waiting on " << *p << dendl;
+    p->add_waiter(MDSCacheObject::WAIT_UNFREEZE, new C_Locker_Eval(this, p, lock->get_type()));
+    return;
+  }
+
+  /*
+   * We could have a situation like:
+   *
+   * - mds A authpins item on mds B
+   * - mds B starts to freeze tree containing item
+   * - mds A tries wrlock_start on A, sends REQSCATTER to B
+   * - mds B lock is unstable, sets scatter_wanted
+   * - mds B lock stabilizes, calls try_eval.
+   *
+   * We can defer while freezing without causing a deadlock.  Honor
+   * scatter_wanted flag here.  This will never get deferred by the
+   * checks above due to the auth_pin held by the master.
+   */
+  if (lock->is_scatterlock()) {
+    ScatterLock *slock = (ScatterLock *)lock;
+    if (slock->get_scatter_wanted() &&
+       slock->get_state() != LOCK_MIX) {
+      scatter_mix(slock, pneed_issue);
+      if (!lock->is_stable())
+       return;
+    }
+  }
+
+  if (p->is_freezing()) {
+    dout(7) << "try_eval " << *lock << " frozen, waiting on " << *p << dendl;
     p->add_waiter(MDSCacheObject::WAIT_UNFREEZE, new C_Locker_Eval(this, p, lock->get_type()));
     return;
   }