From: Jason Dillaman Date: Mon, 19 Jan 2015 15:28:56 +0000 (-0500) Subject: librbd: gracefully handle deleted/renamed pools X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=refs%2Fpull%2F3439%2Fhead;p=ceph.git librbd: gracefully handle deleted/renamed pools 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, #10122 Backport: giant, firefly Signed-off-by: Jason Dillaman (cherry picked from commit 436923c68b77c900b7774fbef918c0d6e1614a36) --- diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 627c11344dd..d7a428d4f02 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -425,7 +425,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; } @@ -640,32 +643,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 pools; - rados.pool_list(pools); - std::set children; - for (std::list::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 pools; + rados.pool_list(pools); + for (std::list::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 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,