From: Dongsheng Yang Date: Mon, 6 Feb 2017 11:55:43 +0000 (+0800) Subject: librbd: asynchronous image removal state machine X-Git-Tag: v12.0.1~282^2~10 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=10a012f1dee91b781d85be5b5121b473e5e257ef;p=ceph.git librbd: asynchronous image removal state machine Signed-off-by: Dongsheng Yang Signed-off-by: Venky Shankar --- diff --git a/src/librbd/CMakeLists.txt b/src/librbd/CMakeLists.txt index cfd0951aefc6..ccbe4090ad28 100644 --- a/src/librbd/CMakeLists.txt +++ b/src/librbd/CMakeLists.txt @@ -35,6 +35,7 @@ set(librbd_internal_srcs image/OpenRequest.cc image/RefreshParentRequest.cc image/RefreshRequest.cc + image/RemoveRequest.cc image/SetFlagsRequest.cc image/SetSnapRequest.cc image_watcher/NotifyLockOwner.cc diff --git a/src/librbd/image/RemoveRequest.cc b/src/librbd/image/RemoveRequest.cc new file mode 100644 index 000000000000..98c0fef7cf6c --- /dev/null +++ b/src/librbd/image/RemoveRequest.cc @@ -0,0 +1,770 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "common/dout.h" +#include "common/errno.h" +#include "librbd/internal.h" +#include "librbd/ImageState.h" +#include "librbd/Journal.h" +#include "librbd/ObjectMap.h" +#include "librbd/ExclusiveLock.h" +#include "librbd/MirroringWatcher.h" +#include "librbd/journal/RemoveRequest.h" +#include "librbd/image/RemoveRequest.h" +#include "librbd/operation/TrimRequest.h" +#include "librbd/mirror/DisableRequest.h" + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::image::RemoveRequest: " << this << " " \ + << __func__ << " " + +namespace librbd { +namespace image { + +using librados::IoCtx; +using util::create_context_callback; +using util::create_async_context_callback; +using util::create_rados_ack_callback; + +static const std::string IMAGE_CLIENT_ID(""); + +template +RemoveRequest::RemoveRequest(IoCtx &ioctx, const std::string &image_name, const std::string &image_id, + bool force, ProgressContext &prog_ctx, ContextWQ *op_work_queue, + Context *on_finish) : + m_ioctx(ioctx), m_image_name(image_name), m_image_id(image_id), m_force(force), + m_prog_ctx(prog_ctx), m_op_work_queue(op_work_queue), m_on_finish(on_finish) { + m_cct = reinterpret_cast(m_ioctx.cct()); + + m_image_ctx = new I((m_image_id.empty() ? m_image_name : std::string()), + m_image_id, nullptr, m_ioctx, false); +} + +template +void RemoveRequest::send() { + ldout(m_cct, 20) << dendl; + + open_image(); +} + +template +void RemoveRequest::open_image() { + ldout(m_cct, 20) << dendl; + + using klass = RemoveRequest; + Context *ctx = create_context_callback(this); + + m_image_ctx->state->open(true, ctx); +} + +template +Context *RemoveRequest::handle_open_image(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result < 0) { + if (*result != -ENOENT) { + lderr(m_cct) << "error opening image: " << cpp_strerror(*result) << dendl; + } + m_ret_val = *result; + switch_thread_context(); + return nullptr; + } + + m_image_id = m_image_ctx->id; + m_image_name = m_image_ctx->name; + m_header_oid = m_image_ctx->header_oid; + m_old_format = m_image_ctx->old_format; + m_unknown_format = false; + + check_exclusive_lock(); + return nullptr; +} + +template +void RemoveRequest::check_exclusive_lock() { + 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; + + using klass = RemoveRequest; + if (m_force) { + Context *ctx = create_context_callback(this); + m_image_ctx->exclusive_lock->shut_down(ctx); + } else { + Context *ctx = create_context_callback(this); + RWLock::WLocker owner_lock(m_image_ctx->owner_lock); + m_image_ctx->exclusive_lock->try_acquire_lock(ctx); + } +} + +template +Context *RemoveRequest::handle_exclusive_lock_force(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result < 0) { + lderr(m_cct) << "error shutting down exclusive lock" << cpp_strerror(*result) + << dendl; + send_close_image(*result); + return nullptr; + } + + assert(m_image_ctx->exclusive_lock == nullptr); + validate_image_removal(); + return nullptr; +} + +template +Context *RemoveRequest::handle_exclusive_lock(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if ((*result < 0) || !m_image_ctx->exclusive_lock->is_lock_owner()) { + lderr(m_cct) << "cannot obtain exclusive lock - not removing" << dendl; + send_close_image(-EBUSY); + return nullptr; + } + + validate_image_removal(); + return nullptr; +} + +template +void RemoveRequest::validate_image_removal() { + ldout(m_cct, 20) << dendl; + + check_image_snaps(); +} + +template +void RemoveRequest::check_image_snaps() { + ldout(m_cct, 20) << dendl; + + if (m_image_ctx->snaps.size()) { + lderr(m_cct) << "image has snapshots - not removing" << dendl; + send_close_image(-ENOTEMPTY); + return; + } + + check_image_watchers(); +} + +template +void RemoveRequest::check_image_watchers() { + ldout(m_cct, 20) << dendl; + + librados::ObjectReadOperation op; + op.list_watchers(&m_watchers, &m_ret_val); + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + + int r = m_image_ctx->md_ctx.aio_operate(m_header_oid, + rados_completion, &op, &m_out_bl); + assert(r == 0); + rados_completion->release(); +} + +template +void RemoveRequest::filter_out_mirror_watchers() { + if (m_watchers.empty()) { + return; + } + + if ((m_image_ctx->features & RBD_FEATURE_JOURNALING) == 0) { + return; + } + + cls::rbd::MirrorImage mirror_image; + int r = cls_client::mirror_image_get(&m_image_ctx->md_ctx, m_image_ctx->id, &mirror_image); + if (r < 0) { + if (r != -ENOENT) { + lderr(m_cct) << "failed to retrieve mirroring state: " + << cpp_strerror(r) << dendl; + } + return; + } + + if (mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) { + return; + } + + std::list mirror_watchers; + r = m_image_ctx->md_ctx.list_watchers(RBD_MIRRORING, &mirror_watchers); + if (r < 0) { + if (r != -ENOENT) { + lderr(m_cct) << "error listing mirroring watchers: " + << cpp_strerror(r) << dendl; + } + return; + } + for (auto &watcher : mirror_watchers) { + m_watchers.remove_if([watcher] (obj_watch_t &w) { + return (strncmp(w.addr, watcher.addr, sizeof(w.addr)) == 0); + }); + } +} + +template +Context *RemoveRequest::handle_check_image_watchers(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result < 0) { + lderr(m_cct) << "error listing image watchers: " << cpp_strerror(*result) << dendl; + send_close_image(*result); + return nullptr; + } + // If an image is being bootstrapped by rbd-mirror, it implies + // that the rbd-mirror daemon currently has the image open. + // Permit removal if this is the case. + filter_out_mirror_watchers(); + + if (m_watchers.size() > 1) { + lderr(m_cct) << "image has watchers - not removing" << dendl; + send_close_image(-EBUSY); + return nullptr; + } + + check_image_consistency_group(); + return nullptr; +} + +template +void RemoveRequest::check_image_consistency_group() { + ldout(m_cct, 20) << dendl; + + librados::ObjectReadOperation op; + librbd::cls_client::image_get_group_start(&op); + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + m_out_bl.clear(); + int r = m_image_ctx->md_ctx.aio_operate(m_header_oid, + rados_completion, &op, &m_out_bl); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_check_image_consistency_group(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result < 0) { + lderr(m_cct) << "error fetching consistency group for image" << cpp_strerror(*result) + << dendl; + send_close_image(*result); + return nullptr; + } + + cls::rbd::GroupSpec s; + bufferlist::iterator it = m_out_bl.begin(); + *result = librbd::cls_client::image_get_group_finish(&it, &s); + if (*result < 0) { + send_close_image(*result); + return nullptr; + } + if (s.is_valid()) { + lderr(m_cct) << "image is in a consistency group - not removing" << dendl; + send_close_image(-EMLINK); + return nullptr; + } + + trim_image(); + + return nullptr; +} + +template +void RemoveRequest::trim_image() { + ldout(m_cct, 20) << dendl; + + using klass = RemoveRequest; + Context *ctx = create_async_context_callback( + *m_image_ctx, create_context_callback(this)); + + RWLock::RLocker owner_lock(m_image_ctx->owner_lock); + librbd::operation::TrimRequest *req = librbd::operation::TrimRequest::create( + *m_image_ctx, ctx, m_image_ctx->size, 0, m_prog_ctx); + req->send(); +} + +template +Context *RemoveRequest::handle_trim_image(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result < 0) { + lderr(m_cct) << "warning: failed to remove some object(s): " << cpp_strerror(*result) + << dendl; + } + + if (m_old_format) { + send_close_image(*result); + return nullptr; + } + + remove_child(); + return nullptr; +} + +template +void RemoveRequest::remove_child() { + ldout(m_cct, 20) << dendl; + + m_image_ctx->parent_lock.get_read(); + parent_info parent_info = m_image_ctx->parent_md; + m_image_ctx->parent_lock.put_read(); + + librados::ObjectWriteOperation op; + librbd::cls_client::remove_child(&op, parent_info.spec, m_image_id); + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + int r = m_image_ctx->md_ctx.aio_operate(RBD_CHILDREN, rados_completion, &op); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_remove_child(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result == -ENOENT) { + *result = 0; + } else if (*result < 0) { + lderr(m_cct) << "error removing child from children list" << cpp_strerror(*result) + << dendl; + send_close_image(*result); + return nullptr; + } + + + send_disable_mirror(); + return nullptr; +} + +template +void RemoveRequest::send_disable_mirror() { + ldout(m_cct, 20) << dendl; + + using klass = RemoveRequest; + Context *ctx = create_context_callback(this); + + mirror::DisableRequest *req = + mirror::DisableRequest::create(m_image_ctx, m_force, !m_force, ctx); + req->send(); +} + +template +Context *RemoveRequest::handle_disable_mirror(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + + if (*result == -EOPNOTSUPP) { + *result = 0; + } else if (*result < 0) { + lderr(m_cct) << "error disabling image mirroring: " << cpp_strerror(*result) + << dendl; + } + + send_close_image(*result); + return nullptr; +} + +template +void RemoveRequest::send_close_image(int r) { + ldout(m_cct, 20) << dendl; + + m_ret_val = r; + using klass = RemoveRequest; + Context *ctx = create_context_callback(this); + + m_image_ctx->state->close(ctx); +} + +template +Context *RemoveRequest::handle_send_close_image(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result < 0) { + lderr(m_cct) << "error encountered while closing image: " << cpp_strerror(*result) + << dendl; + } + + if (m_ret_val < 0) { + switch_thread_context(); + } else { + remove_header(); + } + return nullptr; +} + +template +void RemoveRequest::remove_header() { + ldout(m_cct, 20) << dendl; + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + int r = m_ioctx.aio_remove(m_header_oid, rados_completion); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_remove_header(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if ((*result < 0) && (*result != -ENOENT)) { + lderr(m_cct) << "error removing header: " << cpp_strerror(*result) << dendl; + m_ret_val = *result; + } + + switch_thread_context(); + return nullptr; +} + +template +void RemoveRequest::switch_thread_context() { + ldout(m_cct, 20) << dendl; + + using klass = RemoveRequest; + + Context *ctx = create_context_callback(this); + m_op_work_queue->queue(ctx, 0); +} + +template +void RemoveRequest::handle_switch_thread_context(int r) { + ldout(m_cct, 20) << ": r=" << r << dendl; + + delete m_image_ctx; + m_image_ctx = nullptr; + + if (m_ret_val < 0 && m_ret_val != -ENOENT) { + m_on_finish->complete(m_ret_val); + return; + } + + remove_image(); + return; +} + +template +void RemoveRequest::remove_header_v2() { + ldout(m_cct, 20) << dendl; + + if (m_header_oid.empty()) { + m_header_oid = util::header_name(m_image_id); + } + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + int r = m_ioctx.aio_remove(m_header_oid, rados_completion); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_remove_header_v2(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if ((*result < 0) && (*result != -ENOENT)) { + lderr(m_cct) << "error removing header: " << cpp_strerror(*result) << dendl; + return m_on_finish; + } + + send_journal_remove(); + return nullptr; +} + +template +void RemoveRequest::send_journal_remove() { + ldout(m_cct, 20) << dendl; + + using klass = RemoveRequest; + Context *ctx = create_context_callback(this); + + journal::RemoveRequest *req = journal::RemoveRequest::create( + m_ioctx, m_image_id, IMAGE_CLIENT_ID, m_op_work_queue, ctx); + req->send(); +} + +template +Context *RemoveRequest::handle_journal_remove(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result < 0 && *result != -ENOENT) { + lderr(m_cct) << "failed to remove image journal: " << cpp_strerror(*result) + << dendl; + return m_on_finish; + } else { + *result = 0; + } + + send_object_map_remove(); + return nullptr; +} + +template +void RemoveRequest::send_object_map_remove() { + ldout(m_cct, 20) << dendl; + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + + int r = ObjectMap<>::aio_remove(m_ioctx, + m_image_id, + rados_completion); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_object_map_remove(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result < 0 && *result != -ENOENT) { + lderr(m_cct) << "failed to remove image journal: " << cpp_strerror(*result) + << dendl; + return m_on_finish; + } else { + *result = 0; + } + + mirror_image_remove(); + return nullptr; +} + +template +void RemoveRequest::mirror_image_remove() { + ldout(m_cct, 20) << dendl; + + librados::ObjectWriteOperation op; + cls_client::mirror_image_remove(&op, m_image_id); + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + int r = m_ioctx.aio_operate(RBD_MIRRORING, rados_completion, &op); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_mirror_image_remove(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if (*result < 0 && *result != -ENOENT && *result != -EOPNOTSUPP) { + lderr(m_cct) << "failed to remove mirror image state: " << cpp_strerror(*result) + << dendl; + return m_on_finish; + } else { + *result = 0; + } + + remove_id_object(); + return nullptr; +} + +template +void RemoveRequest::remove_image() { + ldout(m_cct, 20) << dendl; + + if (m_old_format || m_unknown_format) { + remove_v1_image(); + } else { + remove_v2_image(); + } +} + +template +void RemoveRequest::remove_v1_image() { + ldout(m_cct, 20) << dendl; + + Context *ctx = new FunctionContext([this] (int r) { + r = tmap_rm(m_ioctx, m_image_name); + handle_remove_v1_image(r); + }); + + m_op_work_queue->queue(ctx, 0); +} + +template +void RemoveRequest::handle_remove_v1_image(int r) { + ldout(m_cct, 20) << ": r=" << r << dendl; + + m_old_format = (r == 0); + if ((r == 0) || ((r < 0) && !m_unknown_format)) { + if ((r < 0) && (r != -ENOENT)) { + lderr(m_cct) << "error removing image from v1 directory: " + << cpp_strerror(r) << dendl; + } + + m_on_finish->complete(r); + return; + } + + if (!m_old_format) { + remove_v2_image(); + } +} + +template +void RemoveRequest::remove_v2_image() { + ldout(m_cct, 20) << dendl; + + if (m_image_id.empty()) { + dir_get_image_id(); + return; + } else if (m_image_name.empty()) { + dir_get_image_name(); + return; + } + + remove_header_v2(); + return; +} + +template +void RemoveRequest::dir_get_image_id() { + ldout(m_cct, 20) << dendl; + + librados::ObjectReadOperation op; + librbd::cls_client::dir_get_id_start(&op, m_image_name); + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + m_out_bl.clear(); + int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_dir_get_image_id(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if ((*result < 0) && (*result != -ENOENT)) { + lderr(m_cct) << "error fetching image id: " << cpp_strerror(*result) << dendl; + return m_on_finish; + } + + if (!*result) { + bufferlist::iterator iter = m_out_bl.begin(); + *result = librbd::cls_client::dir_get_id_finish(&iter, &m_image_id); + if (*result < 0) { + return m_on_finish; + } + } + + remove_header_v2(); + return nullptr; +} + +template +void RemoveRequest::dir_get_image_name() { + ldout(m_cct, 20) << dendl; + + librados::ObjectReadOperation op; + librbd::cls_client::dir_get_name_start(&op, m_image_id); + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + m_out_bl.clear(); + int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_dir_get_image_name(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if ((*result < 0) && (*result != -ENOENT)) { + lderr(m_cct) << "error fetching image name: " << cpp_strerror(*result) << dendl; + return m_on_finish; + } + + if (!*result) { + bufferlist::iterator iter = m_out_bl.begin(); + *result = librbd::cls_client::dir_get_name_finish(&iter, &m_image_name); + if (*result < 0) { + return m_on_finish; + } + } + + remove_header_v2(); + return nullptr; +} + +template +void RemoveRequest::remove_id_object() { + ldout(m_cct, 20) << dendl; + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + int r = m_ioctx.aio_remove(util::id_obj_name(m_image_name), rados_completion); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_remove_id_object(int *result) { + ldout(m_cct, 20) << ": r=" << *result << dendl; + + if ((*result < 0) && (*result != -ENOENT)) { + lderr(m_cct) << "error removing id object: " << cpp_strerror(*result) << dendl; + return m_on_finish; + } + + dir_remove_image(); + return nullptr; +} + +template +void RemoveRequest::dir_remove_image() { + ldout(m_cct, 20) << dendl; + + librados::ObjectWriteOperation op; + librbd::cls_client::dir_remove_image(&op, m_image_name, m_image_id); + + using klass = RemoveRequest; + librados::AioCompletion *rados_completion = + create_rados_ack_callback(this); + int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op); + assert(r == 0); + rados_completion->release(); +} + +template +Context *RemoveRequest::handle_dir_remove_image(int *result) { + ldout(m_cct, 20) << ":r =" << *result << dendl; + + if ((*result < 0) && (*result != -ENOENT)) { + lderr(m_cct) << "error removing image from v2 directory: " + << cpp_strerror(*result) << dendl; + } + + return m_on_finish; +} + +} // namespace image +} // namespace librbd + +template class librbd::image::RemoveRequest; diff --git a/src/librbd/image/RemoveRequest.h b/src/librbd/image/RemoveRequest.h new file mode 100644 index 000000000000..10ae7bf27563 --- /dev/null +++ b/src/librbd/image/RemoveRequest.h @@ -0,0 +1,184 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_IMAGE_REMOVE_REQUEST_H +#define CEPH_LIBRBD_IMAGE_REMOVE_REQUEST_H + +#include "librbd/image/TypeTraits.h" + +class Context; +class ContextWQ; +class SafeTimer; + +namespace librbd { + +class ImageCtx; +class ProgressContext; + +namespace image { + +template +class RemoveRequest { +private: + // mock unit testing support + typedef ::librbd::image::TypeTraits TypeTraits; + typedef typename TypeTraits::ContextWQ ContextWQ; +public: + static RemoveRequest *create(librados::IoCtx &ioctx, const std::string &image_name, const std::string &image_id, + bool force, ProgressContext &prog_ctx, ContextWQ *op_work_queue, + Context *on_finish) { + return new RemoveRequest(ioctx, image_name, image_id, force, prog_ctx, op_work_queue, on_finish); + } + + void send(); + +private: + /** + * @verbatim + * + * + * | + * v + * OPEN IMAGE------------------- + * | | + * v | + * error CHECK EXCLUSIVE LOCK---- | + * _______<_______ | | | + * | | v (aquired) | + * | | AQUIRE EXCLUSIVE LOCK | | + * | | / | | | + * | |------<-------/ v | | + * | | VALIDATE IMAGE REMOVAL<- | + * | | / | v + * | |------<--------/ v | + * | TRIM IMAGE | + * | | | + * v v | + * | REMOVE CHILD | + * | | | + * | v v + * |--------->------------------>CLOSE IMAGE | + * | | + * error v | + * |------<--------| SWITCH THREAD CONTEXT<----------- + * | | / | + * | |-------<-------/ v + * | | REMOVE HEADER + * | | / | + * | |-------<-------/ v + * | | REMOVE JOURNAL + * | | / | + * | |-------<-------/ v + * v ^ REMOVE OBJECTMAP + * | | / | + * | |-------<-------/ v + * | | REMOVE MIRROR IMAGE + * | | / | + * | |-------<-------/ v + * | | REMOVE ID OBJECT + * | | / | + * | |-------<-------/ v + * | | REMOVE IMAGE + * | | / | + * | |-------<-------/ v + * ------------------->------------ + * + * @endverbatim + */ + + RemoveRequest(librados::IoCtx &ioctx, const std::string &image_name, const std::string &image_id, + bool force, ProgressContext &prog_ctx, ContextWQ *op_work_queue, Context *on_finish); + + librados::IoCtx &m_ioctx; + std::string m_image_name; + std::string m_image_id; + bool m_force; + ProgressContext &m_prog_ctx; + ContextWQ *m_op_work_queue; + Context *m_on_finish; + + CephContext *m_cct; + std::string m_header_oid; + bool m_old_format = false; + bool m_unknown_format = true; + ImageCtxT *m_image_ctx; + + int m_ret_val = 0; + bufferlist m_out_bl; + std::list m_watchers; + + void open_image(); + Context *handle_open_image(int *result); + + void send_journal_remove(); + Context* handle_journal_remove(int *result); + + void send_object_map_remove(); + Context* handle_object_map_remove(int *result); + + void mirror_image_remove(); + Context* handle_mirror_image_remove(int *result); + + void check_exclusive_lock(); + + void acquire_exclusive_lock(); + Context *handle_exclusive_lock(int *result); + Context *handle_exclusive_lock_force(int *result); + + void validate_image_removal(); + void check_image_snaps(); + + void filter_out_mirror_watchers(); + void check_image_watchers(); + Context *handle_check_image_watchers(int *result); + + void check_image_consistency_group(); + Context *handle_check_image_consistency_group(int *result); + + void trim_image(); + Context *handle_trim_image(int *result); + + void remove_child(); + Context *handle_remove_child(int *result); + + void send_disable_mirror(); + Context *handle_disable_mirror(int *result); + + void send_close_image(int r); + Context *handle_send_close_image(int *result); + + void switch_thread_context(); + void handle_switch_thread_context(int r); + + void remove_header(); + Context *handle_remove_header(int *result); + + void remove_header_v2(); + Context *handle_remove_header_v2(int *result); + + void remove_image(); + + void remove_v1_image(); + void handle_remove_v1_image(int r); + + void remove_v2_image(); + + void dir_get_image_id(); + Context *handle_dir_get_image_id(int *result); + + void dir_get_image_name(); + Context *handle_dir_get_image_name(int *result); + + void remove_id_object(); + Context *handle_remove_id_object(int *result); + + void dir_remove_image(); + Context *handle_dir_remove_image(int *result); +}; + +} // namespace image +} // namespace librbd + +extern template class librbd::image::RemoveRequest; + +#endif // CEPH_LIBRBD_IMAGE_REMOVE_REQUEST_H