From 53929ba1751fad9c9cd8545c4cd6985982d2eb5f Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Thu, 11 Dec 2014 17:00:46 -0500 Subject: [PATCH] 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 Backport: giant, firefly Signed-off-by: Jason Dillaman --- src/librbd/internal.cc | 104 +++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 39 deletions(-) diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index d84361721c0..d8031a7c183 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -413,33 +413,42 @@ namespace librbd { // search all pools for children depending on this snapshot Rados rados(ictx->md_ctx); - std::list pools; - rados.pool_list(pools); + std::list > pools; + rados.pool_list2(pools); - for (std::list::const_iterator it = pools.begin(); - it != pools.end(); ++it) { - int64_t pool_id = rados.pool_lookup(it->c_str()); + for (std::list >::const_iterator it = + pools.begin(); it != pools.end(); ++it) { int64_t base_tier; - int r = rados.pool_get_base_tier(pool_id, &base_tier); - if (r < 0) { + int r = rados.pool_get_base_tier(it->first, &base_tier); + if (r == -ENOENT) { + ldout(cct, 1) << "pool " << it->second << " no longer exists" << dendl; + continue; + } else if (r < 0) { + lderr(cct) << "Error retrieving base tier for pool " << it->second + << dendl; return r; } - if (base_tier != pool_id) { + if (it->first != base_tier) { // pool is a cache; skip it continue; } + IoCtx ioctx; - r = rados.ioctx_create(it->c_str(), ioctx); - if (r < 0) { - lderr(cct) << "Error accessing child image pool " << *it << dendl; + r = rados.ioctx_create2(it->first, ioctx); + if (r == -ENOENT) { + ldout(cct, 1) << "pool " << it->second << " no longer exists" << dendl; + continue; + } else if (r < 0) { + lderr(cct) << "Error accessing child image pool " << it->second + << dendl; return r; } set image_ids; - r = cls_client::get_children(&ioctx, RBD_CHILDREN, - parent_spec, image_ids); + r = cls_client::get_children(&ioctx, RBD_CHILDREN, parent_spec, + image_ids); if (r < 0 && r != -ENOENT) { - lderr(cct) << "Error reading list of children from pool " << *it + lderr(cct) << "Error reading list of children from pool " << it->second << dendl; return r; } @@ -451,10 +460,10 @@ namespace librbd { *id_it, &name); if (r < 0) { lderr(cct) << "Error looking up name for image id " << *id_it - << " in pool " << *it << dendl; + << " in pool " << it->second << dendl; return r; } - names.insert(make_pair(*it, name)); + names.insert(make_pair(it->second, name)); } } @@ -648,42 +657,59 @@ 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) { - int64_t pool_id = rados.pool_lookup(it->c_str()); + rados.wait_for_latest_osdmap(); + + // protect against pools being renamed/deleted + std::list > pools; + rados.pool_list2(pools); + + for (std::list >::const_iterator it = + pools.begin(); it != pools.end(); ++it) { int64_t base_tier; - r = rados.pool_get_base_tier(pool_id, &base_tier); - if (r < 0) { - return r; - } - if (base_tier != pool_id) { + int r = rados.pool_get_base_tier(it->first, &base_tier); + if (r == -ENOENT) { + ldout(ictx->cct, 1) << "pool " << it->second << " no longer exists" + << dendl; + continue; + } else if (r < 0) { + lderr(ictx->cct) << "snap_unprotect: error retrieving base tier for " + << "pool " << it->second << dendl; + goto reprotect_and_return_err; + } + if (it->first != base_tier) { // pool is a cache; skip it continue; } + 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 = rados.ioctx_create2(it->first, pool_ioctx); + if (r == -ENOENT) { + ldout(ictx->cct, 1) << "pool " << it->second << " no longer exists" + << dendl; + continue; + } else if (r < 0) { + lderr(ictx->cct) << "snap_unprotect: can't create ioctx for pool " + << it->second << 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; + lderr(ictx->cct) << "can't get children for pool " << it->second + << 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; + lderr(ictx->cct) << "snap_unprotect: can't unprotect; at least " + << children.size() << " child(ren) in pool " << it->second << dendl; + r = -EBUSY; + goto reprotect_and_return_err; } - pool_ioctx.close(); // last one out will self-destruct } + // didn't find any child in any pool, go ahead with unprotect r = cls_client::set_protection_status(&ictx->md_ctx, ictx->header_oid, -- 2.47.3