]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: gracefully handle deleted/renamed pools 3403/head
authorJason Dillaman <dillaman@redhat.com>
Mon, 19 Jan 2015 15:28:56 +0000 (10:28 -0500)
committerJason Dillaman <dillaman@redhat.com>
Mon, 19 Jan 2015 15:28:56 +0000 (10:28 -0500)
snap_unprotect and list_children both attempt to scan all
pools. If a pool is deleted or renamed during the scan,
the methods would previously return -ENOENT. Both methods
have been modified to more gracefully handle this condition.

Fixes: #10270
Backport: giant, firefly
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/internal.cc

index 9f1c943a91487acb5b04a855e7e93528254082a1..b767d43516f75ff7a584bdef59d288033f0b2f9c 100644 (file)
@@ -420,7 +420,10 @@ namespace librbd {
         it != pools.end(); ++it) {
       IoCtx ioctx;
       r = rados.ioctx_create(it->c_str(), ioctx);
-      if (r < 0) {
+      if (r == -ENOENT) {
+        ldout(cct, 1) << "pool " << *it << " no longer exists" << dendl;
+        continue;
+      } else if (r < 0) {
         lderr(cct) << "Error accessing child image pool " << *it << dendl;
         return r;
       }
@@ -638,32 +641,46 @@ namespace librbd {
     parent_spec pspec(ictx->md_ctx.get_id(), ictx->id, snap_id);
     // search all pools for children depending on this snapshot
     Rados rados(ictx->md_ctx);
-    std::list<std::string> pools;
-    rados.pool_list(pools);
-    std::set<std::string> children;
-    for (std::list<std::string>::const_iterator it = pools.begin(); it != pools.end(); ++it) {
-      IoCtx pool_ioctx;
-      r = rados.ioctx_create(it->c_str(), pool_ioctx);
-      if (r < 0) {
-       lderr(ictx->cct) << "snap_unprotect: can't create ioctx for pool "
-                        << *it << dendl;
-       goto reprotect_and_return_err;
-      }
-      r = cls_client::get_children(&pool_ioctx, RBD_CHILDREN, pspec, children);
-      // key should not exist for this parent if there is no entry
-      if (((r < 0) && (r != -ENOENT))) {
-       lderr(ictx->cct) << "can't get children for pool " << *it << dendl;
-       goto reprotect_and_return_err;
-      }
-      // if we found a child, can't unprotect
-      if (r == 0) {
-       lderr(ictx->cct) << "snap_unprotect: can't unprotect; at least " 
-         << children.size() << " child(ren) in pool " << it->c_str() << dendl;
-       r = -EBUSY;
-       goto reprotect_and_return_err;
+
+    // protect against pools being renamed/deleted
+    bool retry_pool_check;
+    do {
+      retry_pool_check = false;
+
+      std::list<std::string> pools;
+      rados.pool_list(pools);
+      for (std::list<std::string>::const_iterator it = pools.begin(); it != pools.end(); ++it) {
+       IoCtx pool_ioctx;
+       r = rados.ioctx_create(it->c_str(), pool_ioctx);
+        if (r == -ENOENT) {
+          ldout(ictx->cct, 1) << "pool " << *it << " no longer exists" << dendl;
+          retry_pool_check = true;
+          break;
+        } else if (r < 0) {
+          lderr(ictx->cct) << "snap_unprotect: can't create ioctx for pool "
+                          << *it << dendl;
+          goto reprotect_and_return_err;
+        }
+
+       std::set<std::string> children;
+       r = cls_client::get_children(&pool_ioctx, RBD_CHILDREN, pspec, children);
+       // key should not exist for this parent if there is no entry
+       if (((r < 0) && (r != -ENOENT))) {
+         lderr(ictx->cct) << "can't get children for pool " << *it << dendl;
+         goto reprotect_and_return_err;
+       }
+       // if we found a child, can't unprotect
+       if (r == 0) {
+         lderr(ictx->cct) << "snap_unprotect: can't unprotect; at least "
+                          << children.size() << " child(ren) in pool "
+                          << it->c_str() << dendl;
+         r = -EBUSY;
+         goto reprotect_and_return_err;
+       }
+       pool_ioctx.close();     // last one out will self-destruct
       }
-      pool_ioctx.close();      // last one out will self-destruct
-    }
+    } while(retry_pool_check);
+
     // didn't find any child in any pool, go ahead with unprotect
     r = cls_client::set_protection_status(&ictx->md_ctx,
                                          ictx->header_oid,