From: zhuangzeqiang Date: Sat, 25 Jun 2016 02:21:25 +0000 (+0800) Subject: rbd: restrict mirror enable/disable actions on parents/clones X-Git-Tag: v11.0.0~14^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=11dee0bbf0a85f2c197192d0560bd486bc2ad6fc;p=ceph.git rbd: restrict mirror enable/disable actions on parents/clones Fixes: http://tracker.ceph.com/issues/16056 Signed-off-by: zhuangzeqiang zhuang.zeqiang@h3c.com --- diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 49dea3cc9c48..ba35a4142726 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -877,17 +877,53 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force, CephContext *cct = ictx->cct; ldout(cct, 20) << "children list " << ictx->name << dendl; + RWLock::RLocker l(ictx->snap_lock); + parent_spec parent_spec(ictx->md_ctx.get_id(), ictx->id, ictx->snap_id); + map< pair, set > image_info; + + int r = list_children_info(ictx, parent_spec,image_info); + if (r < 0) { + return r; + } + + Rados rados(ictx->md_ctx); + for ( auto &info : image_info){ + IoCtx ioctx; + r = rados.ioctx_create2(info.first.first, ioctx); + if (r < 0) { + lderr(cct) << "Error accessing child image pool " << info.first.second + << dendl; + return r; + } + + for (auto &id_it : info.second) { + string name; + r = cls_client::dir_get_name(&ioctx, RBD_DIRECTORY, id_it, &name); + if (r < 0) { + lderr(cct) << "Error looking up name for image id " << id_it + << " in pool " << info.first.second << dendl; + return r; + } + names.insert(make_pair(info.first.second, name)); + } + } + + return 0; + } + + int list_children_info(ImageCtx *ictx, librbd::parent_spec parent_spec, + map< pair, set >& image_info) + { + CephContext *cct = ictx->cct; int r = ictx->state->refresh_if_required(); if (r < 0) return r; // no children for non-layered or old format image - if (!ictx->test_features(RBD_FEATURE_LAYERING)) + if (!ictx->test_features(RBD_FEATURE_LAYERING, ictx->snap_lock)) return 0; - parent_spec parent_spec(ictx->md_ctx.get_id(), ictx->id, ictx->snap_id); - names.clear(); - + image_info.clear(); // search all pools for children depending on this snapshot Rados rados(ictx->md_ctx); std::list > pools; @@ -933,19 +969,7 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force, << dendl; return r; } - - for (set::const_iterator id_it = image_ids.begin(); - id_it != image_ids.end(); ++id_it) { - string name; - r = cls_client::dir_get_name(&ioctx, RBD_DIRECTORY, - *id_it, &name); - if (r < 0) { - lderr(cct) << "Error looking up name for image id " << *id_it - << " in pool " << it->second << dendl; - return r; - } - names.insert(make_pair(it->second, name)); - } + image_info.insert(make_pair(make_pair(it->first, it->second), image_ids)); } return 0; @@ -2813,6 +2837,20 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force, return -EINVAL; } + // is mirroring not enabled for the parent? + { + RWLock::RLocker l(ictx->parent_lock); + ImageCtx *parent = ictx->parent; + if(parent) { + cls::rbd::MirrorImage mirror_image_internal; + r = cls_client::mirror_image_get(&(parent->md_ctx), parent->id, &mirror_image_internal); + if (r == -ENOENT) { + lderr(cct) << "mirroring is not enabled for the parent" << dendl; + return -EINVAL; + } + } + } + r = mirror_image_enable_internal(ictx); if (r < 0) { return r; @@ -2838,6 +2876,77 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force, return -EINVAL; } + // is mirroring enabled for the child? + cls::rbd::MirrorImage mirror_image_internal; + r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id, &mirror_image_internal); + if (r == -ENOENT) { + // mirroring is not enabled for this image + ldout(cct, 20) << "ignoring disable command: mirroring is not enabled for this image" + << dendl; + return 0; + } else if (r == -EOPNOTSUPP) { + ldout(cct, 5) << "mirroring not supported by OSD" << dendl; + return r; + } else if (r < 0) { + lderr(cct) << "failed to retrieve mirror image metadata: " << cpp_strerror(r) << dendl; + return r; + } + mirror_image_internal.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING; + r = cls_client::mirror_image_set(&ictx->md_ctx, ictx->id, mirror_image_internal); + if (r < 0) { + lderr(cct) << "cannot disable mirroring: " << cpp_strerror(r) << dendl; + return r; + } else { + bool rollback = false; + BOOST_SCOPE_EXIT_ALL(ictx, rollback) { + if (rollback) { + CephContext *cct = ictx->cct; + cls::rbd::MirrorImage mirror_image_internal; + mirror_image_internal.state = cls::rbd::MIRROR_IMAGE_STATE_ENABLED; + int r = cls_client::mirror_image_set(&ictx->md_ctx, ictx->id, mirror_image_internal); + if (r < 0) { + lderr(cct) << "failed to re-enable image mirroring: " << cpp_strerror(r) + << dendl; + } + } + }; + + RWLock::RLocker l(ictx->snap_lock); + map snap_info = ictx->snap_info; + for (auto &info : snap_info) { + librbd::parent_spec parent_spec(ictx->md_ctx.get_id(), ictx->id, info.first); + map< pair, set > image_info; + + r = list_children_info(ictx, parent_spec, image_info); + if (r < 0) { + rollback = true; + return r; + } + if (image_info.empty()) + continue; + + Rados rados(ictx->md_ctx); + for (auto &info: image_info) { + IoCtx ioctx; + r = rados.ioctx_create2(info.first.first, ioctx); + if (r < 0) { + rollback = true; + lderr(cct) << "Error accessing child image pool " << info.first.second << dendl; + return r; + } + for (auto &id_it : info.second) { + cls::rbd::MirrorImage mirror_image_internal; + r = cls_client::mirror_image_get(&ioctx, id_it, &mirror_image_internal); + if (r != -ENOENT) { + rollback = true; + lderr(cct) << "mirroring is enabled on one or more children " << dendl; + return -EBUSY; + } + } + } + } + } + r = mirror_image_disable_internal(ictx, force); if (r < 0) { return r; diff --git a/src/librbd/internal.h b/src/librbd/internal.h index 3fd068691fe0..f119f39a4904 100644 --- a/src/librbd/internal.h +++ b/src/librbd/internal.h @@ -95,6 +95,8 @@ namespace librbd { int list(librados::IoCtx& io_ctx, std::vector& names); int list_children(ImageCtx *ictx, std::set > & names); + int list_children_info(ImageCtx *ictx, librbd::parent_spec parent_spec, + std::map, std::set >& image_info); int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size, int *order); int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size,