From 6844a52ebbc45a046b4a94909b48bc4fc0c305c7 Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Wed, 12 Dec 2018 15:42:49 +0000 Subject: [PATCH] librbd: disable image mirroring when moving to trash And enable when restoring if mirror pool mode set. Fixes: https://tracker.ceph.com/issues/37596 Signed-off-by: Mykola Golub --- src/librbd/api/Trash.cc | 101 +++++++++++++++++++++++++++++- src/test/librbd/test_mirroring.cc | 51 +++++++++++++++ 2 files changed, 151 insertions(+), 1 deletion(-) diff --git a/src/librbd/api/Trash.cc b/src/librbd/api/Trash.cc index c8c40a1eefe..319be136b58 100644 --- a/src/librbd/api/Trash.cc +++ b/src/librbd/api/Trash.cc @@ -15,6 +15,8 @@ #include "librbd/TrashWatcher.h" #include "librbd/Utils.h" #include "librbd/api/Image.h" +#include "librbd/mirror/DisableRequest.h" +#include "librbd/mirror/EnableRequest.h" #include "librbd/trash/MoveRequest.h" #define dout_subsys ceph_subsys_rbd @@ -24,6 +26,93 @@ namespace librbd { namespace api { +namespace { + +template +int disable_mirroring(I *ictx) { + if (!ictx->test_features(RBD_FEATURE_JOURNALING)) { + return 0; + } + + cls::rbd::MirrorImage mirror_image; + int r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id, &mirror_image); + if (r == -ENOENT) { + ldout(ictx->cct, 10) << "mirroring is not enabled for this image" << dendl; + return 0; + } + + if (r < 0) { + lderr(ictx->cct) << "failed to retrieve mirror image: " << cpp_strerror(r) + << dendl; + return r; + } + + ldout(ictx->cct, 10) << dendl; + + C_SaferCond ctx; + auto req = mirror::DisableRequest::create(ictx, false, true, &ctx); + req->send(); + r = ctx.wait(); + if (r < 0) { + lderr(ictx->cct) << "failed to disable mirroring: " << cpp_strerror(r) + << dendl; + return r; + } + + return 0; +} + +template +int enable_mirroring(IoCtx &io_ctx, const std::string &image_id) { + auto cct = reinterpret_cast(io_ctx.cct()); + + uint64_t features; + uint64_t incompatible_features; + int r = cls_client::get_features(&io_ctx, util::header_name(image_id), true, + &features, &incompatible_features); + if (r < 0) { + lderr(cct) << "failed to retrieve features: " << cpp_strerror(r) << dendl; + return r; + } + + if ((features & RBD_FEATURE_JOURNALING) == 0) { + return 0; + } + + cls::rbd::MirrorMode mirror_mode; + r = cls_client::mirror_mode_get(&io_ctx, &mirror_mode); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to retrieve mirror mode: " << cpp_strerror(r) + << dendl; + return r; + } + + if (mirror_mode != cls::rbd::MIRROR_MODE_POOL) { + ldout(cct, 10) << "not pool mirroring mode" << dendl; + return 0; + } + + ldout(cct, 10) << dendl; + + ThreadPool *thread_pool; + ContextWQ *op_work_queue; + ImageCtx::get_thread_pool_instance(cct, &thread_pool, &op_work_queue); + C_SaferCond ctx; + auto req = mirror::EnableRequest::create(io_ctx, image_id, "", + op_work_queue, &ctx); + req->send(); + r = ctx.wait(); + if (r < 0) { + lderr(cct) << "failed to enable mirroring: " << cpp_strerror(r) + << dendl; + return r; + } + + return 0; +} + +} // anonymous namespace + template int Trash::move(librados::IoCtx &io_ctx, rbd_trash_image_source_t source, const std::string &image_name, uint64_t delay) { @@ -75,6 +164,11 @@ int Trash::move(librados::IoCtx &io_ctx, rbd_trash_image_source_t source, return -EINVAL; } + r = disable_mirroring(ictx); + if (r < 0) { + return r; + } + utime_t delete_time{ceph_clock_now()}; utime_t deferment_end_time{delete_time}; deferment_end_time += delay; @@ -324,7 +418,7 @@ int Trash::restore(librados::IoCtx &io_ctx, const std::string &image_id, } } - ldout(cct, 2) << "adding rbd image from v2 directory..." << dendl; + ldout(cct, 2) << "adding rbd image to v2 directory..." << dendl; r = cls_client::dir_add_image(&io_ctx, RBD_DIRECTORY, image_name, image_id); if (r < 0 && r != -EEXIST) { @@ -333,6 +427,11 @@ int Trash::restore(librados::IoCtx &io_ctx, const std::string &image_id, return r; } + r = enable_mirroring(io_ctx, image_id); + if (r < 0) { + // not fatal -- ignore + } + ldout(cct, 2) << "removing image from trash..." << dendl; r = cls_client::trash_remove(&io_ctx, image_id); if (r < 0 && r != -ENOENT) { diff --git a/src/test/librbd/test_mirroring.cc b/src/test/librbd/test_mirroring.cc index 245f81943cb..4b2211e24da 100644 --- a/src/test/librbd/test_mirroring.cc +++ b/src/test/librbd/test_mirroring.cc @@ -276,6 +276,45 @@ public: ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); } + void check_trash_move_restore(rbd_mirror_mode_t mirror_mode, + bool enable_mirroring) { + + ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, mirror_mode)); + + int order = 20; + uint64_t features = RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_JOURNALING; + ASSERT_EQ(0, m_rbd.create2(m_ioctx, image_name.c_str(), 4096, features, + &order)); + librbd::Image image; + ASSERT_EQ(0, m_rbd.open(m_ioctx, image, image_name.c_str())); + + if (enable_mirroring) { + ASSERT_EQ(0, image.mirror_image_enable()); + } + + std::string image_id; + ASSERT_EQ(0, image.get_id(&image_id)); + + ASSERT_EQ(0, m_rbd.trash_move(m_ioctx, image_name.c_str(), 100)); + + librbd::mirror_image_info_t mirror_image; + ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image))); + ASSERT_EQ(mirror_image.state, RBD_MIRROR_IMAGE_DISABLED); + + ASSERT_EQ(0, m_rbd.trash_restore(m_ioctx, image_id.c_str(), "")); + + ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image))); + if (mirror_mode == RBD_MIRROR_MODE_POOL) { + ASSERT_EQ(mirror_image.state, RBD_MIRROR_IMAGE_ENABLED); + } else { + ASSERT_EQ(mirror_image.state, RBD_MIRROR_IMAGE_DISABLED); + } + + image.close(); + ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str())); + ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); + } + void setup_mirror_peer(librados::IoCtx &io_ctx, librbd::Image &image) { ASSERT_EQ(0, image.snap_create("sync-point-snap")); @@ -632,6 +671,18 @@ TEST_F(TestMirroring, RemoveImage_With_MirrorImageDemoted) { true, true); } +TEST_F(TestMirroring, TrashMoveRestore_PoolMode) { + check_trash_move_restore(RBD_MIRROR_MODE_POOL, false); +} + +TEST_F(TestMirroring, TrashMoveRestore_ImageMode_MirroringDisabled) { + check_trash_move_restore(RBD_MIRROR_MODE_IMAGE, false); +} + +TEST_F(TestMirroring, TrashMoveRestore_ImageMode_MirroringEnabled) { + check_trash_move_restore(RBD_MIRROR_MODE_IMAGE, true); +} + TEST_F(TestMirroring, MirrorStatusList) { std::vector features_vec(5, RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_JOURNALING); -- 2.39.5