]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: sync trace, hold complete node longer 20191/head
authorYehuda Sadeh <yehuda@redhat.com>
Tue, 30 Jan 2018 23:46:00 +0000 (15:46 -0800)
committerYehuda Sadeh <yehuda@redhat.com>
Wed, 31 Jan 2018 00:52:07 +0000 (16:52 -0800)
Fixes: http://tracker.ceph.com/issues/22833
Inserting an entry to the complete_nodes list in
RGWSyncTraceManager::finish_node() can trigger an eviction of another
entry, which in turn will call finish_node() recursively. Avoid the
destruction of that entry under the lockby holding a reference to it
a little longer.

Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
src/rgw/rgw_sync_trace.cc

index 2cd2338c6d30ba08c60ae6456e3dc00c709252c4..edfbd916c5dfe2856dea577e02506c0edce88e96 100644 (file)
@@ -257,18 +257,30 @@ bool RGWSyncTraceManager::call(std::string command, cmdmap_t& cmdmap, std::strin
 
 void RGWSyncTraceManager::finish_node(RGWSyncTraceNode *node)
 {
-  shunique_lock wl(lock, ceph::acquire_unique);
-  if (!node) {
-    return;
-  }
-  auto iter = nodes.find(node->handle);
-  if (iter == nodes.end()) {
-    /* not found, already finished */
-    return;
-  }
+  RGWSyncTraceNodeRef old_node;
 
-  complete_nodes.push_back(iter->second);
-  nodes.erase(iter);
+  {
+    shunique_lock wl(lock, ceph::acquire_unique);
+    if (!node) {
+      return;
+    }
+    auto iter = nodes.find(node->handle);
+    if (iter == nodes.end()) {
+      /* not found, already finished */
+      return;
+    }
+
+    if (complete_nodes.full()) {
+      /* take a reference to the entry that is going to be evicted,
+       * can't let it get evicted under lock held, otherwise
+       * it's a deadlock as it will call finish_node()
+       */
+      old_node = complete_nodes.front();
+    }
+
+    complete_nodes.push_back(iter->second);
+    nodes.erase(iter);
+  }
 };
 
 #endif