From 541b6a12be30131ee133f669d35052e5f20b1f37 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Wed, 20 Feb 2019 22:05:51 -0500 Subject: [PATCH] librbd: split image pre-removal logic to separate state machine Signed-off-by: Jason Dillaman --- src/librbd/CMakeLists.txt | 1 + src/librbd/image/PreRemoveRequest.cc | 305 +++++++++++++ src/librbd/image/PreRemoveRequest.h | 100 +++++ src/librbd/image/RemoveRequest.cc | 257 +---------- src/librbd/image/RemoveRequest.h | 83 ++-- src/test/librbd/CMakeLists.txt | 1 + .../image/test_mock_PreRemoveRequest.cc | 400 ++++++++++++++++++ .../librbd/image/test_mock_RemoveRequest.cc | 307 ++------------ 8 files changed, 870 insertions(+), 584 deletions(-) create mode 100644 src/librbd/image/PreRemoveRequest.cc create mode 100644 src/librbd/image/PreRemoveRequest.h create mode 100644 src/test/librbd/image/test_mock_PreRemoveRequest.cc diff --git a/src/librbd/CMakeLists.txt b/src/librbd/CMakeLists.txt index e7da59cf267..a3440a1b24e 100644 --- a/src/librbd/CMakeLists.txt +++ b/src/librbd/CMakeLists.txt @@ -59,6 +59,7 @@ set(librbd_internal_srcs image/DetachParentRequest.cc image/ListWatchersRequest.cc image/OpenRequest.cc + image/PreRemoveRequest.cc image/RefreshParentRequest.cc image/RefreshRequest.cc image/RemoveRequest.cc diff --git a/src/librbd/image/PreRemoveRequest.cc b/src/librbd/image/PreRemoveRequest.cc new file mode 100644 index 00000000000..0ed6cf946ad --- /dev/null +++ b/src/librbd/image/PreRemoveRequest.cc @@ -0,0 +1,305 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "librbd/image/PreRemoveRequest.h" +#include "common/dout.h" +#include "common/errno.h" +#include "cls/rbd/cls_rbd_types.h" +#include "librbd/ExclusiveLock.h" +#include "librbd/Utils.h" +#include "librbd/image/ListWatchersRequest.h" +#include "librbd/journal/DisabledPolicy.h" +#include "librbd/operation/SnapshotRemoveRequest.h" + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::image::PreRemoveRequest: " << this \ + << " " << __func__ << ": " + +namespace librbd { +namespace image { + +namespace { + +bool auto_delete_snapshot(const SnapInfo& snap_info) { + auto snap_namespace_type = cls::rbd::get_snap_namespace_type( + snap_info.snap_namespace); + switch (snap_namespace_type) { + case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH: + return true; + default: + return false; + } +} + +} // anonymous namespace + +using util::create_context_callback; +using util::create_rados_callback; + +template +void PreRemoveRequest::send() { + auto cct = m_image_ctx->cct; + if (m_image_ctx->operations_disabled) { + lderr(cct) << "image operations disabled due to unsupported op features" + << dendl; + finish(-EROFS); + return; + } + + acquire_exclusive_lock(); +} + +template +void PreRemoveRequest::acquire_exclusive_lock() { + RWLock::RLocker owner_lock(m_image_ctx->owner_lock); + if (m_image_ctx->exclusive_lock == nullptr) { + validate_image_removal(); + return; + } + + auto cct = m_image_ctx->cct; + ldout(cct, 5) << dendl; + + // do not attempt to open the journal when removing the image in case + // it's corrupt + if (m_image_ctx->test_features(RBD_FEATURE_JOURNALING)) { + RWLock::WLocker snap_locker(m_image_ctx->snap_lock); + m_image_ctx->set_journal_policy(new journal::DisabledPolicy()); + } + + if (m_force) { + auto ctx = create_context_callback< + PreRemoveRequest, + &PreRemoveRequest::handle_exclusive_lock_force>(this); + + m_exclusive_lock = m_image_ctx->exclusive_lock; + m_exclusive_lock->shut_down(ctx); + } else { + auto ctx = create_context_callback< + PreRemoveRequest, &PreRemoveRequest::handle_exclusive_lock>(this); + + m_image_ctx->exclusive_lock->try_acquire_lock(ctx); + } +} + +template +void PreRemoveRequest::handle_exclusive_lock(int r) { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << "r=" << r << dendl; + + if (r < 0 || !m_image_ctx->exclusive_lock->is_lock_owner()) { + lderr(cct) << "cannot obtain exclusive lock - not removing" << dendl; + finish(-EBUSY); + return; + } + + validate_image_removal(); +} + +template +void PreRemoveRequest::handle_exclusive_lock_force(int r) { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << "r=" << r << dendl; + + delete m_exclusive_lock; + m_exclusive_lock = nullptr; + + if (r < 0) { + lderr(cct) << "error shutting down exclusive lock: " << cpp_strerror(r) + << dendl; + finish(r); + return; + } + + ceph_assert(m_image_ctx->exclusive_lock == nullptr); + validate_image_removal(); +} + +template +void PreRemoveRequest::validate_image_removal() { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << dendl; + + if (!m_image_ctx->ignore_migrating && + m_image_ctx->test_features(RBD_FEATURE_MIGRATING)) { + lderr(cct) << "image in migration state - not removing" << dendl; + finish(-EBUSY); + return; + } + + check_image_snaps(); +} + +template +void PreRemoveRequest::check_image_snaps() { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << dendl; + + m_image_ctx->snap_lock.get_read(); + for (auto& snap_info : m_image_ctx->snap_info) { + if (auto_delete_snapshot(snap_info.second)) { + m_snap_infos.insert(snap_info); + } else { + m_image_ctx->snap_lock.put_read(); + + lderr(cct) << "image has snapshots - not removing" << dendl; + finish(-ENOTEMPTY); + return; + } + } + m_image_ctx->snap_lock.put_read(); + + list_image_watchers(); +} + +template +void PreRemoveRequest::list_image_watchers() { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << dendl; + + int flags = LIST_WATCHERS_FILTER_OUT_MY_INSTANCE | + LIST_WATCHERS_FILTER_OUT_MIRROR_INSTANCES; + auto ctx = create_context_callback< + PreRemoveRequest, + &PreRemoveRequest::handle_list_image_watchers>(this); + auto req = ListWatchersRequest::create(*m_image_ctx, flags, &m_watchers, + ctx); + req->send(); +} + +template +void PreRemoveRequest::handle_list_image_watchers(int r) { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << "r=" << r << dendl; + + if (r < 0) { + lderr(cct) << "error listing image watchers: " << cpp_strerror(r) << dendl; + finish(r); + return; + } + + check_image_watchers(); +} + +template +void PreRemoveRequest::check_image_watchers() { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << dendl; + + if (!m_watchers.empty()) { + lderr(cct) << "image has watchers - not removing" << dendl; + finish(-EBUSY); + return; + } + + check_group(); +} + +template +void PreRemoveRequest::check_group() { + if (m_image_ctx->old_format) { + finish(0); + return; + } + + auto cct = m_image_ctx->cct; + ldout(cct, 5) << dendl; + + librados::ObjectReadOperation op; + librbd::cls_client::image_group_get_start(&op); + + auto rados_completion = create_rados_callback< + PreRemoveRequest, &PreRemoveRequest::handle_check_group>(this); + m_out_bl.clear(); + int r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, + rados_completion, &op, &m_out_bl); + ceph_assert(r == 0); + rados_completion->release(); +} + +template +void PreRemoveRequest::handle_check_group(int r) { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << "r=" << r << dendl; + + cls::rbd::GroupSpec s; + if (r == 0) { + auto it = m_out_bl.cbegin(); + r = librbd::cls_client::image_group_get_finish(&it, &s); + } + if (r < 0 && r != -EOPNOTSUPP) { + lderr(cct) << "error fetching group for image: " << cpp_strerror(r) + << dendl; + finish(r); + return; + } + + if (s.is_valid()) { + lderr(cct) << "image is in a group - not removing" << dendl; + finish(-EMLINK); + return; + } + + remove_snapshot(); +} + +template +void PreRemoveRequest::remove_snapshot() { + if (m_snap_infos.empty()) { + finish(0); + return; + } + + auto cct = m_image_ctx->cct; + auto snap_id = m_snap_infos.begin()->first; + auto& snap_info = m_snap_infos.begin()->second; + ldout(cct, 20) << "snap_id=" << snap_id << ", " + << "snap_name=" << snap_info.name << dendl; + + RWLock::RLocker owner_lock(m_image_ctx->owner_lock); + auto ctx = create_context_callback< + PreRemoveRequest, &PreRemoveRequest::handle_remove_snapshot>(this); + auto req = librbd::operation::SnapshotRemoveRequest::create( + *m_image_ctx, snap_info.snap_namespace, snap_info.name, + snap_id, ctx); + req->send(); + +} + +template +void PreRemoveRequest::handle_remove_snapshot(int r) { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << "r=" << r << dendl; + + if (r < 0 && r != -ENOENT) { + auto snap_id = m_snap_infos.begin()->first; + lderr(cct) << "failed to auto-prune snapshot " << snap_id << ": " + << cpp_strerror(r) << dendl; + + if (r == -EBUSY) { + r = -ENOTEMPTY; + } + finish(r); + return; + } + + ceph_assert(!m_snap_infos.empty()); + m_snap_infos.erase(m_snap_infos.begin()); + + remove_snapshot(); +} + +template +void PreRemoveRequest::finish(int r) { + auto cct = m_image_ctx->cct; + ldout(cct, 5) << "r=" << r << dendl; + + m_on_finish->complete(r); + delete this; +} + +} // namespace image +} // namespace librbd + +template class librbd::image::PreRemoveRequest; diff --git a/src/librbd/image/PreRemoveRequest.h b/src/librbd/image/PreRemoveRequest.h new file mode 100644 index 00000000000..99981491b65 --- /dev/null +++ b/src/librbd/image/PreRemoveRequest.h @@ -0,0 +1,100 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_IMAGE_PRE_REMOVE_REQUEST_H +#define CEPH_LIBRBD_IMAGE_PRE_REMOVE_REQUEST_H + +#include "include/rados/librados.hpp" +#include "include/buffer.h" +#include "librbd/ImageCtx.h" +#include +#include + +class Context; + +namespace librbd { +namespace image { + +template +class PreRemoveRequest { +public: + + static PreRemoveRequest *create(ImageCtxT *image_ctx, bool force, + Context *on_finish) { + return new PreRemoveRequest(image_ctx, force, on_finish); + } + + PreRemoveRequest(ImageCtxT *image_ctx, bool force, Context *on_finish) + : m_image_ctx(image_ctx), m_force(force), m_on_finish(on_finish) { + } + + void send(); + +private: + /** + * @verbatim + * + * + * | + * v + * CHECK EXCLUSIVE LOCK + * | + * v (skip if not needed) + * ACQUIRE EXCLUSIVE LOCK + * | + * v + * CHECK IMAGE WATCHERS + * | + * v + * CHECK GROUP + * | + * | /------\ + * | | | + * v v | + * REMOVE SNAPS ----/ + * | + * v + * + * + * @endverbatim + */ + + ImageCtxT* m_image_ctx; + bool m_force; + Context* m_on_finish; + + decltype(m_image_ctx->exclusive_lock) m_exclusive_lock = nullptr; + + bufferlist m_out_bl; + std::list m_watchers; + + std::map m_snap_infos; + + void acquire_exclusive_lock(); + void handle_exclusive_lock(int r); + void handle_exclusive_lock_force(int r); + + void validate_image_removal(); + void check_image_snaps(); + + void list_image_watchers(); + void handle_list_image_watchers(int r); + + void check_image_watchers(); + + void check_group(); + void handle_check_group(int r); + + void remove_snapshot(); + void handle_remove_snapshot(int r); + + void finish(int r); + +}; + +} // namespace image +} // namespace librbd + +extern template class librbd::image::PreRemoveRequest; + +#endif // CEPH_LIBRBD_IMAGE_PRE_REMOVE_REQUEST_H diff --git a/src/librbd/image/RemoveRequest.cc b/src/librbd/image/RemoveRequest.cc index dad354bfd79..88af466615a 100644 --- a/src/librbd/image/RemoveRequest.cc +++ b/src/librbd/image/RemoveRequest.cc @@ -8,14 +8,11 @@ #include "librbd/ImageState.h" #include "librbd/Journal.h" #include "librbd/ObjectMap.h" -#include "librbd/ExclusiveLock.h" #include "librbd/MirroringWatcher.h" #include "librbd/image/DetachChildRequest.h" -#include "librbd/image/ListWatchersRequest.h" -#include "librbd/journal/DisabledPolicy.h" +#include "librbd/image/PreRemoveRequest.h" #include "librbd/journal/RemoveRequest.h" #include "librbd/mirror/DisableRequest.h" -#include "librbd/operation/SnapshotRemoveRequest.h" #include "librbd/operation/TrimRequest.h" #define dout_subsys ceph_subsys_rbd @@ -26,21 +23,6 @@ namespace librbd { namespace image { -namespace { - -bool auto_delete_snapshot(const SnapInfo& snap_info) { - auto snap_namespace_type = cls::rbd::get_snap_namespace_type( - snap_info.snap_namespace); - switch (snap_namespace_type) { - case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH: - return true; - default: - return false; - } -} - -} // anonymous namespace - using librados::IoCtx; using util::create_context_callback; using util::create_async_context_callback; @@ -82,7 +64,7 @@ void RemoveRequest::send() { template void RemoveRequest::open_image() { if (m_image_ctx != nullptr) { - check_exclusive_lock(); + pre_remove_image(); return; } @@ -122,246 +104,29 @@ void RemoveRequest::handle_open_image(int r) { m_old_format = m_image_ctx->old_format; m_unknown_format = false; - check_exclusive_lock(); -} - -template -void RemoveRequest::check_exclusive_lock() { - if (m_image_ctx->operations_disabled) { - lderr(m_cct) << "image operations disabled due to unsupported op features" - << dendl; - send_close_image(-EROFS); - return; - } - - ldout(m_cct, 20) << dendl; - - if (m_image_ctx->exclusive_lock == nullptr) { - validate_image_removal(); - } else { - acquire_exclusive_lock(); - } -} - -template -void RemoveRequest::acquire_exclusive_lock() { - ldout(m_cct, 20) << dendl; - - // do not attempt to open the journal when removing the image in case - // it's corrupt - if (m_image_ctx->test_features(RBD_FEATURE_JOURNALING)) { - RWLock::WLocker snap_locker(m_image_ctx->snap_lock); - m_image_ctx->set_journal_policy(new journal::DisabledPolicy()); - } - - using klass = RemoveRequest; - if (m_force) { - Context *ctx = create_context_callback< - klass, &klass::handle_exclusive_lock_force>(this); - m_exclusive_lock = m_image_ctx->exclusive_lock; - m_exclusive_lock->shut_down(ctx); - } else { - Context *ctx = create_context_callback< - klass, &klass::handle_exclusive_lock>(this); - RWLock::WLocker owner_lock(m_image_ctx->owner_lock); - m_image_ctx->exclusive_lock->try_acquire_lock(ctx); - } -} - -template -void RemoveRequest::handle_exclusive_lock_force(int r) { - ldout(m_cct, 20) << "r=" << r << dendl; - - delete m_exclusive_lock; - m_exclusive_lock = nullptr; - - if (r < 0) { - lderr(m_cct) << "error shutting down exclusive lock: " - << cpp_strerror(r) << dendl; - send_close_image(r); - return; - } - - ceph_assert(m_image_ctx->exclusive_lock == nullptr); - validate_image_removal(); + pre_remove_image(); } template -void RemoveRequest::handle_exclusive_lock(int r) { - ldout(m_cct, 20) << "r=" << r << dendl; - - if (r < 0 || !m_image_ctx->exclusive_lock->is_lock_owner()) { - lderr(m_cct) << "cannot obtain exclusive lock - not removing" << dendl; - send_close_image(-EBUSY); - return; - } - - validate_image_removal(); -} - -template -void RemoveRequest::validate_image_removal() { - ldout(m_cct, 20) << dendl; - - if (!m_image_ctx->ignore_migrating && - m_image_ctx->test_features(RBD_FEATURE_MIGRATING)) { - lderr(m_cct) << "image in migration state - not removing" << dendl; - send_close_image(-EBUSY); - return; - } +void RemoveRequest::pre_remove_image() { + ldout(m_cct, 5) << dendl; - check_image_snaps(); -} - -template -void RemoveRequest::check_image_snaps() { - ldout(m_cct, 20) << dendl; - - m_image_ctx->snap_lock.get_read(); - for (auto& snap_info : m_image_ctx->snap_info) { - if (auto_delete_snapshot(snap_info.second)) { - m_snap_infos.insert(snap_info); - } else { - m_image_ctx->snap_lock.put_read(); - - lderr(m_cct) << "image has snapshots - not removing" << dendl; - send_close_image(-ENOTEMPTY); - return; - } - } - m_image_ctx->snap_lock.put_read(); - - list_image_watchers(); -} - -template -void RemoveRequest::list_image_watchers() { - ldout(m_cct, 20) << dendl; - - int flags = LIST_WATCHERS_FILTER_OUT_MY_INSTANCE | - LIST_WATCHERS_FILTER_OUT_MIRROR_INSTANCES; - using klass = RemoveRequest; - Context *ctx = create_context_callback< - klass, &klass::handle_list_image_watchers>(this); - - auto req = ListWatchersRequest::create(*m_image_ctx, flags, &m_watchers, - ctx); - req->send(); -} - -template -void RemoveRequest::handle_list_image_watchers(int r) { - ldout(m_cct, 20) << "r=" << r << dendl; - - if (r < 0) { - lderr(m_cct) << "error listing image watchers: " << cpp_strerror(r) - << dendl; - send_close_image(r); - return; - } - - check_image_watchers(); -} - -template -void RemoveRequest::check_image_watchers() { - if (!m_watchers.empty()) { - lderr(m_cct) << "image has watchers - not removing" << dendl; - send_close_image(-EBUSY); - return; - } - - check_group(); -} - -template -void RemoveRequest::check_group() { - if (m_old_format) { - trim_image(); - return; - } - - ldout(m_cct, 20) << dendl; - - librados::ObjectReadOperation op; - librbd::cls_client::image_group_get_start(&op); - - using klass = RemoveRequest; - librados::AioCompletion *rados_completion = create_rados_callback< - klass, &klass::handle_check_group>(this); - m_out_bl.clear(); - int r = m_image_ctx->md_ctx.aio_operate(m_header_oid, rados_completion, &op, - &m_out_bl); - ceph_assert(r == 0); - rados_completion->release(); -} - -template -void RemoveRequest::handle_check_group(int r) { - ldout(m_cct, 20) << "r=" << r << dendl; - - cls::rbd::GroupSpec s; - if (r == 0) { - auto it = m_out_bl.cbegin(); - r = librbd::cls_client::image_group_get_finish(&it, &s); - } - if (r < 0 && r != -EOPNOTSUPP) { - lderr(m_cct) << "error fetching group for image: " - << cpp_strerror(r) << dendl; - send_close_image(r); - return; - } - - if (s.is_valid()) { - lderr(m_cct) << "image is in a group - not removing" << dendl; - send_close_image(-EMLINK); - return; - } - - remove_snapshot(); -} - -template -void RemoveRequest::remove_snapshot() { - if (m_snap_infos.empty()) { - trim_image(); - return; - } - - auto snap_id = m_snap_infos.begin()->first; - auto& snap_info = m_snap_infos.begin()->second; - ldout(m_cct, 20) << "snap_id=" << snap_id << ", " - << "snap_name=" << snap_info.name << dendl; - - RWLock::RLocker owner_lock(m_image_ctx->owner_lock); auto ctx = create_context_callback< - RemoveRequest, &RemoveRequest::handle_remove_snapshot>(this); - auto req = librbd::operation::SnapshotRemoveRequest::create( - *m_image_ctx, snap_info.snap_namespace, snap_info.name, - snap_id, ctx); + RemoveRequest, &RemoveRequest::handle_pre_remove_image>(this); + auto req = PreRemoveRequest::create(m_image_ctx, m_force, ctx); req->send(); } template -void RemoveRequest::handle_remove_snapshot(int r) { - ldout(m_cct, 20) << "r=" << r << dendl; - - if (r < 0 && r != -ENOENT) { - auto snap_id = m_snap_infos.begin()->first; - lderr(m_cct) << "failed to auto-prune snapshot " << snap_id << ": " - << cpp_strerror(r) << dendl; +void RemoveRequest::handle_pre_remove_image(int r) { + ldout(m_cct, 5) << "r=" << r << dendl; - if (r == -EBUSY) { - r = -ENOTEMPTY; - } + if (r < 0) { send_close_image(r); return; } - ceph_assert(!m_snap_infos.empty()); - m_snap_infos.erase(m_snap_infos.begin()); - - remove_snapshot(); + trim_image(); } template diff --git a/src/librbd/image/RemoveRequest.h b/src/librbd/image/RemoveRequest.h index 75288d9ae14..40a571e5aab 100644 --- a/src/librbd/image/RemoveRequest.h +++ b/src/librbd/image/RemoveRequest.h @@ -60,53 +60,41 @@ private: * (skip if already opened) OPEN IMAGE------------------\ * | | * v | - * error CHECK EXCLUSIVE LOCK---\ | - * /-------<-------\ | | | - * | | | (acquired)| - * | | v | | - * | | ACQUIRE EXCLUSIVE LOCK | | - * | | / | | | - * | |------<-------/ | | | - * | | v | | - * | | VALIDATE IMAGE REMOVAL<-/ | - * | | / | v - * | \------<--------/ | /------\ | - * | v v | | - * | REMOVE SNAPS ----/ | - * | | | - * | v | - * | TRIM IMAGE | - * | | | - * v v | - * | DETACH CHILD | - * | | | - * | v v - * \--------->------------------>CLOSE IMAGE | + * PRE REMOVE IMAGE * * * | + * | * | + * v * | + * TRIM IMAGE * * * * * | + * | * | + * v * | + * DETACH CHILD * | + * | * | + * v * v + * CLOSE IMAGE < * * * * | * | | - * error v | + * error v | * /------<--------\ REMOVE HEADER<--------------/ - * | | / | - * | |-------<-------/ | + * | | / | + * | |-------<-------/ | * | | v * | | REMOVE JOURNAL - * | | / | - * | |-------<-------/ | + * | | / | + * | |-------<-------/ | * | | v - * v ^ REMOVE OBJECTMAP - * | | / | - * | |-------<-------/ | + * v ^ REMOVE OBJECTMAP + * | | / | + * | |-------<-------/ | * | | v - * | | REMOVE MIRROR IMAGE - * | | / | - * | |-------<-------/ | + * | | REMOVE MIRROR IMAGE + * | | / | + * | |-------<-------/ | * | | v * | | REMOVE ID OBJECT - * | | / | - * | |-------<-------/ | + * | | / | + * | |-------<-------/ | * | | v * | | REMOVE IMAGE - * | | / | - * | \-------<-------/ | + * | | / | + * | \-------<-------/ | * | v * \------------------>------------ * @@ -159,25 +147,8 @@ private: void mirror_image_remove(); void handle_mirror_image_remove(int r); - void check_exclusive_lock(); - - void acquire_exclusive_lock(); - void handle_exclusive_lock(int r); - void handle_exclusive_lock_force(int r); - - void validate_image_removal(); - void check_image_snaps(); - - void list_image_watchers(); - void handle_list_image_watchers(int r); - - void check_image_watchers(); - - void check_group(); - void handle_check_group(int r); - - void remove_snapshot(); - void handle_remove_snapshot(int r); + void pre_remove_image(); + void handle_pre_remove_image(int r); void trim_image(); void handle_trim_image(int r); diff --git a/src/test/librbd/CMakeLists.txt b/src/test/librbd/CMakeLists.txt index 3295afe8d7a..945e22800a4 100644 --- a/src/test/librbd/CMakeLists.txt +++ b/src/test/librbd/CMakeLists.txt @@ -65,6 +65,7 @@ set(unittest_librbd_srcs image/test_mock_DetachChildRequest.cc image/test_mock_DetachParentRequest.cc image/test_mock_ListWatchersRequest.cc + image/test_mock_PreRemoveRequest.cc image/test_mock_RefreshRequest.cc image/test_mock_RemoveRequest.cc io/test_mock_ImageRequest.cc diff --git a/src/test/librbd/image/test_mock_PreRemoveRequest.cc b/src/test/librbd/image/test_mock_PreRemoveRequest.cc new file mode 100644 index 00000000000..131b1d80127 --- /dev/null +++ b/src/test/librbd/image/test_mock_PreRemoveRequest.cc @@ -0,0 +1,400 @@ +// -*- mode:c++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "test/librbd/test_mock_fixture.h" +#include "test/librbd/test_support.h" +#include "test/librbd/mock/MockImageCtx.h" +#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" +#include "test/librados_test_stub/MockTestMemRadosClient.h" +#include "librbd/ImageState.h" +#include "librbd/Operations.h" +#include "librbd/image/ListWatchersRequest.h" +#include "librbd/image/PreRemoveRequest.h" +#include "librbd/image/RefreshParentRequest.h" +#include "librbd/operation/SnapshotRemoveRequest.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace librbd { +namespace { + +struct MockTestImageCtx : public MockImageCtx { + MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) { + } +}; + +} // anonymous namespace + +namespace operation { + +template <> +class SnapshotRemoveRequest { +public: + static SnapshotRemoveRequest *s_instance; + static SnapshotRemoveRequest *create(MockTestImageCtx &image_ctx, + cls::rbd::SnapshotNamespace sn, + std::string name, + uint64_t id, Context *on_finish) { + ceph_assert(s_instance != nullptr); + s_instance->on_finish = on_finish; + return s_instance; + } + + Context *on_finish = nullptr; + + SnapshotRemoveRequest() { + s_instance = this; + } + + MOCK_METHOD0(send, void()); +}; + +SnapshotRemoveRequest *SnapshotRemoveRequest::s_instance; + +} // namespace operation + +namespace image { + +template<> +class ListWatchersRequest { +public: + static ListWatchersRequest *s_instance; + Context *on_finish = nullptr; + + static ListWatchersRequest *create(MockTestImageCtx &image_ctx, int flags, + std::list *watchers, + Context *on_finish) { + ceph_assert(s_instance != nullptr); + s_instance->on_finish = on_finish; + return s_instance; + } + + ListWatchersRequest() { + s_instance = this; + } + + MOCK_METHOD0(send, void()); +}; + +ListWatchersRequest *ListWatchersRequest::s_instance; + +} // namespace image +} // namespace librbd + +// template definitions +#include "librbd/image/PreRemoveRequest.cc" + +ACTION_P(TestFeatures, image_ctx) { + return ((image_ctx->features & arg0) != 0); +} + +ACTION_P(ShutDownExclusiveLock, image_ctx) { + // shutting down exclusive lock will close object map and journal + image_ctx->exclusive_lock = nullptr; + image_ctx->object_map = nullptr; + image_ctx->journal = nullptr; +} + +namespace librbd { +namespace image { + +using ::testing::_; +using ::testing::DoAll; +using ::testing::DoDefault; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::StrEq; + +class TestMockImagePreRemoveRequest : public TestMockFixture { +public: + typedef PreRemoveRequest MockPreRemoveRequest; + typedef ListWatchersRequest MockListWatchersRequest; + typedef librbd::operation::SnapshotRemoveRequest MockSnapshotRemoveRequest; + + void SetUp() override { + TestMockFixture::SetUp(); + + ASSERT_EQ(0, open_image(m_image_name, &m_test_imctx)); + m_mock_imctx = new MockTestImageCtx(*m_test_imctx); + } + + void TearDown() override { + delete m_mock_imctx; + TestMockFixture::TearDown(); + } + + void expect_test_features(MockTestImageCtx &mock_image_ctx) { + EXPECT_CALL(mock_image_ctx, test_features(_)) + .WillRepeatedly(TestFeatures(&mock_image_ctx)); + } + + void expect_set_journal_policy(MockTestImageCtx &mock_image_ctx) { + if (m_test_imctx->test_features(RBD_FEATURE_JOURNALING)) { + EXPECT_CALL(mock_image_ctx, set_journal_policy(_)) + .WillOnce(Invoke([](journal::Policy* policy) { + ASSERT_TRUE(policy->journal_disabled()); + delete policy; + })); + } + } + + void expect_try_acquire_exclusive_lock(MockTestImageCtx &mock_image_ctx, + MockExclusiveLock &mock_exclusive_lock, + int r) { + if (m_mock_imctx->exclusive_lock != nullptr) { + EXPECT_CALL(mock_exclusive_lock, try_acquire_lock(_)) + .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); + } + } + + void expect_shut_down_exclusive_lock(MockTestImageCtx &mock_image_ctx, + MockExclusiveLock &mock_exclusive_lock, + int r) { + if (m_mock_imctx->exclusive_lock != nullptr) { + EXPECT_CALL(mock_exclusive_lock, shut_down(_)) + .WillOnce(DoAll(ShutDownExclusiveLock(&mock_image_ctx), + CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue))); + } + } + + void expect_is_exclusive_lock_owner(MockTestImageCtx &mock_image_ctx, + MockExclusiveLock &mock_exclusive_lock, + bool is_owner) { + if (m_mock_imctx->exclusive_lock != nullptr) { + EXPECT_CALL(mock_exclusive_lock, is_lock_owner()).WillOnce(Return(is_owner)); + } + } + + void expect_list_image_watchers( + MockTestImageCtx &mock_image_ctx, + MockListWatchersRequest &mock_list_watchers_request, int r) { + EXPECT_CALL(mock_list_watchers_request, send()) + .WillOnce(FinishRequest(&mock_list_watchers_request, r, &mock_image_ctx)); + } + + void expect_get_group(MockTestImageCtx &mock_image_ctx, int r) { + if (mock_image_ctx.old_format) { + return; + } + + auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), + exec(mock_image_ctx.header_oid, _, StrEq("rbd"), + StrEq("image_group_get"), _, _, _)); + if (r < 0) { + expect.WillOnce(Return(r)); + } else { + expect.WillOnce(DoDefault()); + } + } + + void expect_remove_snap(MockTestImageCtx &mock_image_ctx, + MockSnapshotRemoveRequest& mock_snap_remove_request, + int r) { + EXPECT_CALL(mock_snap_remove_request, send()) + .WillOnce(FinishRequest(&mock_snap_remove_request, r, &mock_image_ctx)); + } + + librbd::ImageCtx *m_test_imctx = nullptr; + MockTestImageCtx *m_mock_imctx = nullptr; +}; + +TEST_F(TestMockImagePreRemoveRequest, Success) { + MockExclusiveLock *mock_exclusive_lock = new MockExclusiveLock(); + if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { + m_mock_imctx->exclusive_lock = mock_exclusive_lock; + } + + expect_op_work_queue(*m_mock_imctx); + expect_test_features(*m_mock_imctx); + + InSequence seq; + expect_set_journal_policy(*m_mock_imctx); + expect_shut_down_exclusive_lock(*m_mock_imctx, *mock_exclusive_lock, 0); + + MockListWatchersRequest mock_list_watchers_request; + expect_list_image_watchers(*m_mock_imctx, mock_list_watchers_request, 0); + + expect_get_group(*m_mock_imctx, 0); + + C_SaferCond ctx; + auto req = MockPreRemoveRequest::create(m_mock_imctx, true, &ctx); + req->send(); + + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockImagePreRemoveRequest, OperationsDisabled) { + REQUIRE_FORMAT_V2(); + + m_mock_imctx->operations_disabled = true; + + C_SaferCond ctx; + auto req = MockPreRemoveRequest::create(m_mock_imctx, false, &ctx); + req->send(); + + ASSERT_EQ(-EROFS, ctx.wait()); +} + +TEST_F(TestMockImagePreRemoveRequest, ExclusiveLockShutDownFailed) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + MockExclusiveLock *mock_exclusive_lock = new MockExclusiveLock(); + if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { + m_mock_imctx->exclusive_lock = mock_exclusive_lock; + } + + expect_op_work_queue(*m_mock_imctx); + expect_test_features(*m_mock_imctx); + + InSequence seq; + expect_set_journal_policy(*m_mock_imctx); + expect_shut_down_exclusive_lock(*m_mock_imctx, *mock_exclusive_lock, -EINVAL); + + C_SaferCond ctx; + auto req = MockPreRemoveRequest::create(m_mock_imctx, true, &ctx); + req->send(); + + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockImagePreRemoveRequest, ExclusiveLockTryAcquireFailed) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + MockExclusiveLock mock_exclusive_lock; + if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { + m_mock_imctx->exclusive_lock = &mock_exclusive_lock; + } + + expect_op_work_queue(*m_mock_imctx); + expect_test_features(*m_mock_imctx); + + InSequence seq; + expect_set_journal_policy(*m_mock_imctx); + expect_try_acquire_exclusive_lock(*m_mock_imctx, mock_exclusive_lock, + -EINVAL); + + C_SaferCond ctx; + auto req = MockPreRemoveRequest::create(m_mock_imctx, false, &ctx); + req->send(); + + ASSERT_EQ(-EBUSY, ctx.wait()); +} + +TEST_F(TestMockImagePreRemoveRequest, Migration) { + m_mock_imctx->features |= RBD_FEATURE_MIGRATING; + + expect_test_features(*m_mock_imctx); + + C_SaferCond ctx; + auto req = MockPreRemoveRequest::create(m_mock_imctx, false, &ctx); + req->send(); + + ASSERT_EQ(-EBUSY, ctx.wait()); +} + +TEST_F(TestMockImagePreRemoveRequest, Snapshots) { + m_mock_imctx->snap_info = { + {123, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}}}; + + expect_test_features(*m_mock_imctx); + + C_SaferCond ctx; + auto req = MockPreRemoveRequest::create(m_mock_imctx, false, &ctx); + req->send(); + + ASSERT_EQ(-ENOTEMPTY, ctx.wait()); +} + +TEST_F(TestMockImagePreRemoveRequest, Watchers) { + MockExclusiveLock mock_exclusive_lock; + if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { + m_mock_imctx->exclusive_lock = &mock_exclusive_lock; + } + + expect_op_work_queue(*m_mock_imctx); + expect_test_features(*m_mock_imctx); + + InSequence seq; + expect_set_journal_policy(*m_mock_imctx); + expect_try_acquire_exclusive_lock(*m_mock_imctx, mock_exclusive_lock, 0); + expect_is_exclusive_lock_owner(*m_mock_imctx, mock_exclusive_lock, true); + + MockListWatchersRequest mock_list_watchers_request; + expect_list_image_watchers(*m_mock_imctx, mock_list_watchers_request, + -EINVAL); + + C_SaferCond ctx; + auto req = MockPreRemoveRequest::create(m_mock_imctx, false, &ctx); + req->send(); + + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockImagePreRemoveRequest, GroupError) { + REQUIRE_FORMAT_V2(); + + MockExclusiveLock mock_exclusive_lock; + if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { + m_mock_imctx->exclusive_lock = &mock_exclusive_lock; + } + + expect_op_work_queue(*m_mock_imctx); + expect_test_features(*m_mock_imctx); + + InSequence seq; + expect_set_journal_policy(*m_mock_imctx); + expect_try_acquire_exclusive_lock(*m_mock_imctx, mock_exclusive_lock, 0); + expect_is_exclusive_lock_owner(*m_mock_imctx, mock_exclusive_lock, true); + + MockListWatchersRequest mock_list_watchers_request; + expect_list_image_watchers(*m_mock_imctx, mock_list_watchers_request, 0); + + expect_get_group(*m_mock_imctx, -EINVAL); + + C_SaferCond ctx; + auto req = MockPreRemoveRequest::create(m_mock_imctx, false, &ctx); + req->send(); + + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockImagePreRemoveRequest, AutoDeleteSnapshots) { + REQUIRE_FORMAT_V2(); + + MockExclusiveLock mock_exclusive_lock; + if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { + m_mock_imctx->exclusive_lock = &mock_exclusive_lock; + } + + expect_op_work_queue(*m_mock_imctx); + expect_test_features(*m_mock_imctx); + + m_mock_imctx->snap_info = { + {123, {"snap1", {cls::rbd::TrashSnapshotNamespace{}}, {}, {}, {}, {}, {}}}}; + + InSequence seq; + expect_set_journal_policy(*m_mock_imctx); + expect_try_acquire_exclusive_lock(*m_mock_imctx, mock_exclusive_lock, 0); + expect_is_exclusive_lock_owner(*m_mock_imctx, mock_exclusive_lock, true); + + MockListWatchersRequest mock_list_watchers_request; + expect_list_image_watchers(*m_mock_imctx, mock_list_watchers_request, 0); + + expect_get_group(*m_mock_imctx, 0); + + MockSnapshotRemoveRequest mock_snap_remove_request; + expect_remove_snap(*m_mock_imctx, mock_snap_remove_request, 0); + + C_SaferCond ctx; + auto req = MockPreRemoveRequest::create(m_mock_imctx, false, &ctx); + req->send(); + + ASSERT_EQ(0, ctx.wait()); +} + +} // namespace image +} // namespace librbd diff --git a/src/test/librbd/image/test_mock_RemoveRequest.cc b/src/test/librbd/image/test_mock_RemoveRequest.cc index c9ea3796530..05f4a546fe3 100644 --- a/src/test/librbd/image/test_mock_RemoveRequest.cc +++ b/src/test/librbd/image/test_mock_RemoveRequest.cc @@ -9,15 +9,12 @@ #include "test/librados_test_stub/MockTestMemRadosClient.h" #include "librbd/ImageState.h" #include "librbd/internal.h" -#include "librbd/Operations.h" #include "librbd/image/TypeTraits.h" #include "librbd/image/DetachChildRequest.h" -#include "librbd/image/ListWatchersRequest.h" +#include "librbd/image/PreRemoveRequest.h" #include "librbd/image/RemoveRequest.h" -#include "librbd/image/RefreshParentRequest.h" #include "librbd/journal/RemoveRequest.h" #include "librbd/mirror/DisableRequest.h" -#include "librbd/operation/SnapshotRemoveRequest.h" #include "librbd/operation/TrimRequest.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -46,6 +43,7 @@ struct MockTestImageCtx : public MockImageCtx { MockTestImageCtx* MockTestImageCtx::s_instance = nullptr; } // anonymous namespace + namespace image { template <> @@ -75,18 +73,12 @@ public: DetachChildRequest *DetachChildRequest::s_instance; -} // namespace image - -namespace operation { - template <> -class SnapshotRemoveRequest { +class PreRemoveRequest { public: - static SnapshotRemoveRequest *s_instance; - static SnapshotRemoveRequest *create(MockTestImageCtx &image_ctx, - cls::rbd::SnapshotNamespace sn, - std::string name, - uint64_t id, Context *on_finish) { + static PreRemoveRequest *s_instance; + static PreRemoveRequest *create(MockTestImageCtx* image_ctx, bool force, + Context* on_finish) { ceph_assert(s_instance != nullptr); s_instance->on_finish = on_finish; return s_instance; @@ -94,14 +86,18 @@ public: Context *on_finish = nullptr; - SnapshotRemoveRequest() { + PreRemoveRequest() { s_instance = this; } MOCK_METHOD0(send, void()); }; -SnapshotRemoveRequest *SnapshotRemoveRequest::s_instance; +PreRemoveRequest *PreRemoveRequest::s_instance = nullptr; + +} // namespace image + +namespace operation { template <> class TrimRequest { @@ -183,49 +179,11 @@ public: DisableRequest *DisableRequest::s_instance; } // namespace mirror - -namespace image { - -template<> -class ListWatchersRequest { -public: - static ListWatchersRequest *s_instance; - Context *on_finish = nullptr; - - static ListWatchersRequest *create(MockTestImageCtx &image_ctx, int flags, - std::list *watchers, - Context *on_finish) { - ceph_assert(s_instance != nullptr); - s_instance->on_finish = on_finish; - return s_instance; - } - - ListWatchersRequest() { - s_instance = this; - } - - MOCK_METHOD0(send, void()); -}; - -ListWatchersRequest *ListWatchersRequest::s_instance; - -} // namespace image } // namespace librbd // template definitions #include "librbd/image/RemoveRequest.cc" -ACTION_P(TestFeatures, image_ctx) { - return ((image_ctx->features & arg0) != 0); -} - -ACTION_P(ShutDownExclusiveLock, image_ctx) { - // shutting down exclusive lock will close object map and journal - image_ctx->exclusive_lock = nullptr; - image_ctx->object_map = nullptr; - image_ctx->journal = nullptr; -} - namespace librbd { namespace image { @@ -244,9 +202,8 @@ public: typedef ::librbd::image::TypeTraits TypeTraits; typedef typename TypeTraits::ContextWQ ContextWQ; typedef RemoveRequest MockRemoveRequest; + typedef PreRemoveRequest MockPreRemoveRequest; typedef DetachChildRequest MockDetachChildRequest; - typedef ListWatchersRequest MockListWatchersRequest; - typedef librbd::operation::SnapshotRemoveRequest MockSnapshotRemoveRequest; typedef librbd::operation::TrimRequest MockTrimRequest; typedef librbd::journal::RemoveRequest MockJournalRemoveRequest; typedef librbd::mirror::DisableRequest MockMirrorDisableRequest; @@ -254,7 +211,6 @@ public: librbd::ImageCtx *m_test_imctx = NULL; MockTestImageCtx *m_mock_imctx = NULL; - void SetUp() override { TestMockFixture::SetUp(); @@ -293,29 +249,10 @@ public: })); } - void expect_list_image_watchers( - MockTestImageCtx &mock_image_ctx, - MockListWatchersRequest &mock_list_watchers_request, int r) { - EXPECT_CALL(mock_list_watchers_request, send()) - .WillOnce(FinishRequest(&mock_list_watchers_request, r, &mock_image_ctx)); - } - - void expect_get_group(MockTestImageCtx &mock_image_ctx, int r) { - auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), - exec(mock_image_ctx.header_oid, _, StrEq("rbd"), - StrEq("image_group_get"), _, _, _)); - if (r < 0) { - expect.WillOnce(Return(r)); - } else { - expect.WillOnce(DoDefault()); - } - } - - void expect_remove_snap(MockTestImageCtx &mock_image_ctx, - MockSnapshotRemoveRequest& mock_snap_remove_request, - int r) { - EXPECT_CALL(mock_snap_remove_request, send()) - .WillOnce(FinishRequest(&mock_snap_remove_request, r, &mock_image_ctx)); + void expect_pre_remove_image(MockTestImageCtx &mock_image_ctx, + MockPreRemoveRequest& mock_request, int r) { + EXPECT_CALL(mock_request, send()) + .WillOnce(FinishRequest(&mock_request, r, &mock_image_ctx)); } void expect_trim(MockTestImageCtx &mock_image_ctx, @@ -355,32 +292,6 @@ public: EXPECT_CALL(mock_request, send()) .WillOnce(FinishRequest(&mock_request, r, &mock_image_ctx)); } - - void expect_test_features(MockTestImageCtx &mock_image_ctx) { - EXPECT_CALL(mock_image_ctx, test_features(_)) - .WillRepeatedly(TestFeatures(&mock_image_ctx)); - } - - void expect_set_journal_policy(MockTestImageCtx &mock_image_ctx) { - if (m_test_imctx->test_features(RBD_FEATURE_JOURNALING)) { - EXPECT_CALL(mock_image_ctx, set_journal_policy(_)) - .WillOnce(Invoke([](journal::Policy* policy) { - ASSERT_TRUE(policy->journal_disabled()); - delete policy; - })); - } - } - - void expect_shut_down_exclusive_lock(MockTestImageCtx &mock_image_ctx, - MockExclusiveLock &mock_exclusive_lock, - int r) { - if (m_mock_imctx->exclusive_lock != nullptr) { - EXPECT_CALL(mock_exclusive_lock, shut_down(_)) - .WillOnce(DoAll(ShutDownExclusiveLock(&mock_image_ctx), - CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue))); - } - } - }; TEST_F(TestMockImageRemoveRequest, SuccessV1) { @@ -389,10 +300,9 @@ TEST_F(TestMockImageRemoveRequest, SuccessV1) { InSequence seq; expect_state_open(*m_mock_imctx, 0); - expect_test_features(*m_mock_imctx); - MockListWatchersRequest mock_list_watchers_request; - expect_list_image_watchers(*m_mock_imctx, mock_list_watchers_request, 0); + MockPreRemoveRequest mock_pre_remove_request; + expect_pre_remove_image(*m_mock_imctx, mock_pre_remove_request, 0); MockTrimRequest mock_trim_request; expect_trim(*m_mock_imctx, mock_trim_request, 0); @@ -432,11 +342,6 @@ TEST_F(TestMockImageRemoveRequest, OpenFailV1) { TEST_F(TestMockImageRemoveRequest, SuccessV2CloneV1) { REQUIRE_FEATURE(RBD_FEATURE_LAYERING); - MockExclusiveLock *mock_exclusive_lock = new MockExclusiveLock(); - if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { - m_mock_imctx->exclusive_lock = mock_exclusive_lock; - } - expect_op_work_queue(*m_mock_imctx); m_mock_imctx->parent_md.spec.pool_id = m_ioctx.get_id(); @@ -445,20 +350,9 @@ TEST_F(TestMockImageRemoveRequest, SuccessV2CloneV1) { InSequence seq; expect_state_open(*m_mock_imctx, 0); - expect_test_features(*m_mock_imctx); - - if (m_mock_imctx->exclusive_lock != nullptr) { - expect_test_features(*m_mock_imctx); - } - expect_set_journal_policy(*m_mock_imctx); - expect_shut_down_exclusive_lock(*m_mock_imctx, *mock_exclusive_lock, 0); - - expect_test_features(*m_mock_imctx); - - MockListWatchersRequest mock_list_watchers_request; - expect_list_image_watchers(*m_mock_imctx, mock_list_watchers_request, 0); - expect_get_group(*m_mock_imctx, 0); + MockPreRemoveRequest mock_pre_remove_request; + expect_pre_remove_image(*m_mock_imctx, mock_pre_remove_request, 0); MockTrimRequest mock_trim_request; expect_trim(*m_mock_imctx, mock_trim_request, 0); @@ -490,11 +384,6 @@ TEST_F(TestMockImageRemoveRequest, SuccessV2CloneV1) { TEST_F(TestMockImageRemoveRequest, SuccessV2CloneV2) { REQUIRE_FEATURE(RBD_FEATURE_LAYERING); - MockExclusiveLock *mock_exclusive_lock = new MockExclusiveLock(); - if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { - m_mock_imctx->exclusive_lock = mock_exclusive_lock; - } - expect_op_work_queue(*m_mock_imctx); m_mock_imctx->parent_md.spec.pool_id = m_ioctx.get_id(); @@ -503,20 +392,9 @@ TEST_F(TestMockImageRemoveRequest, SuccessV2CloneV2) { InSequence seq; expect_state_open(*m_mock_imctx, 0); - expect_test_features(*m_mock_imctx); - if (m_mock_imctx->exclusive_lock != nullptr) { - expect_test_features(*m_mock_imctx); - } - expect_set_journal_policy(*m_mock_imctx); - expect_shut_down_exclusive_lock(*m_mock_imctx, *mock_exclusive_lock, 0); - - expect_test_features(*m_mock_imctx); - - MockListWatchersRequest mock_list_watchers_request; - expect_list_image_watchers(*m_mock_imctx, mock_list_watchers_request, 0); - - expect_get_group(*m_mock_imctx, 0); + MockPreRemoveRequest mock_pre_remove_request; + expect_pre_remove_image(*m_mock_imctx, mock_pre_remove_request, 0); MockTrimRequest mock_trim_request; expect_trim(*m_mock_imctx, mock_trim_request, 0); @@ -548,11 +426,6 @@ TEST_F(TestMockImageRemoveRequest, SuccessV2CloneV2) { TEST_F(TestMockImageRemoveRequest, NotExistsV2) { REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); - MockExclusiveLock *mock_exclusive_lock = new MockExclusiveLock(); - if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { - m_mock_imctx->exclusive_lock = mock_exclusive_lock; - } - expect_op_work_queue(*m_mock_imctx); m_mock_imctx->parent_md.spec.pool_id = m_ioctx.get_id(); @@ -561,18 +434,9 @@ TEST_F(TestMockImageRemoveRequest, NotExistsV2) { InSequence seq; expect_state_open(*m_mock_imctx, 0); - expect_test_features(*m_mock_imctx); - - expect_test_features(*m_mock_imctx); - expect_set_journal_policy(*m_mock_imctx); - expect_shut_down_exclusive_lock(*m_mock_imctx, *mock_exclusive_lock, 0); - - expect_test_features(*m_mock_imctx); - MockListWatchersRequest mock_list_watchers_request; - expect_list_image_watchers(*m_mock_imctx, mock_list_watchers_request, 0); - - expect_get_group(*m_mock_imctx, 0); + MockPreRemoveRequest mock_pre_remove_request; + expect_pre_remove_image(*m_mock_imctx, mock_pre_remove_request, 0); MockTrimRequest mock_trim_request; expect_trim(*m_mock_imctx, mock_trim_request, 0); @@ -600,126 +464,5 @@ TEST_F(TestMockImageRemoveRequest, NotExistsV2) { ASSERT_EQ(-ENOENT, ctx.wait()); } -TEST_F(TestMockImageRemoveRequest, OperationsDisabled) { - MockExclusiveLock mock_exclusive_lock; - if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { - m_mock_imctx->exclusive_lock = &mock_exclusive_lock; - } - - m_mock_imctx->operations_disabled = true; - - InSequence seq; - expect_state_open(*m_mock_imctx, 0); - expect_test_features(*m_mock_imctx); - expect_state_close(*m_mock_imctx); - - C_SaferCond ctx; - librbd::NoOpProgressContext no_op; - ContextWQ op_work_queue; - MockRemoveRequest *req = MockRemoveRequest::create( - m_ioctx, m_image_name, "", true, false, no_op, &op_work_queue, &ctx); - req->send(); - - ASSERT_EQ(-EROFS, ctx.wait()); -} - -TEST_F(TestMockImageRemoveRequest, Migration) { - m_mock_imctx->features |= RBD_FEATURE_MIGRATING; - - InSequence seq; - expect_state_open(*m_mock_imctx, 0); - expect_test_features(*m_mock_imctx); - expect_state_close(*m_mock_imctx); - - C_SaferCond ctx; - librbd::NoOpProgressContext no_op; - ContextWQ op_work_queue; - MockRemoveRequest *req = MockRemoveRequest::create( - m_ioctx, m_image_name, "", true, false, no_op, &op_work_queue, &ctx); - req->send(); - - ASSERT_EQ(-EBUSY, ctx.wait()); -} - -TEST_F(TestMockImageRemoveRequest, Snapshots) { - m_mock_imctx->snap_info = { - {123, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}}}; - - InSequence seq; - expect_state_open(*m_mock_imctx, 0); - expect_test_features(*m_mock_imctx); - expect_state_close(*m_mock_imctx); - - C_SaferCond ctx; - librbd::NoOpProgressContext no_op; - ContextWQ op_work_queue; - MockRemoveRequest *req = MockRemoveRequest::create( - m_ioctx, m_image_name, "", true, false, no_op, &op_work_queue, &ctx); - req->send(); - - ASSERT_EQ(-ENOTEMPTY, ctx.wait()); -} - -TEST_F(TestMockImageRemoveRequest, AutoDeleteSnapshots) { - REQUIRE_FORMAT_V2(); - - MockExclusiveLock *mock_exclusive_lock = new MockExclusiveLock(); - if (m_test_imctx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { - m_mock_imctx->exclusive_lock = mock_exclusive_lock; - } - - expect_op_work_queue(*m_mock_imctx); - - m_mock_imctx->snap_info = { - {123, {"snap1", {cls::rbd::TrashSnapshotNamespace{}}, {}, {}, {}, {}, {}}}}; - - InSequence seq; - expect_state_open(*m_mock_imctx, 0); - expect_test_features(*m_mock_imctx); - - if (m_mock_imctx->exclusive_lock != nullptr) { - expect_test_features(*m_mock_imctx); - } - expect_set_journal_policy(*m_mock_imctx); - expect_shut_down_exclusive_lock(*m_mock_imctx, *mock_exclusive_lock, 0); - - expect_test_features(*m_mock_imctx); - - MockListWatchersRequest mock_list_watchers_request; - expect_list_image_watchers(*m_mock_imctx, mock_list_watchers_request, 0); - - expect_get_group(*m_mock_imctx, 0); - - MockSnapshotRemoveRequest mock_snap_remove_request; - expect_remove_snap(*m_mock_imctx, mock_snap_remove_request, 0); - - MockTrimRequest mock_trim_request; - expect_trim(*m_mock_imctx, mock_trim_request, 0); - - MockDetachChildRequest mock_detach_child_request; - expect_detach_child(*m_mock_imctx, mock_detach_child_request, 0); - - MockMirrorDisableRequest mock_mirror_disable_request; - expect_mirror_disable(*m_mock_imctx, mock_mirror_disable_request, 0); - - expect_state_close(*m_mock_imctx); - - MockJournalRemoveRequest mock_journal_remove_request; - expect_journal_remove(*m_mock_imctx, mock_journal_remove_request, 0); - - expect_remove_mirror_image(m_ioctx, 0); - expect_dir_remove_image(m_ioctx, 0); - - C_SaferCond ctx; - librbd::NoOpProgressContext no_op; - ContextWQ op_work_queue; - MockRemoveRequest *req = MockRemoveRequest::create( - m_ioctx, m_image_name, "", true, false, no_op, &op_work_queue, &ctx); - req->send(); - - ASSERT_EQ(0, ctx.wait()); - -} - } // namespace image } // namespace librbd -- 2.39.5