// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
+#include "librbd/image/RemoveRequest.h"
#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/DisabledPolicy.h"
+#include "librbd/image/DetachChildRequest.h"
+#include "librbd/image/PreRemoveRequest.h"
#include "librbd/journal/RemoveRequest.h"
-#include "librbd/image/RemoveRequest.h"
-#include "librbd/operation/TrimRequest.h"
#include "librbd/mirror/DisableRequest.h"
+#include "librbd/operation/TrimRequest.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
m_prog_ctx(prog_ctx), m_op_work_queue(op_work_queue),
m_on_finish(on_finish) {
m_cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
+}
- m_image_ctx = I::create((m_image_id.empty() ? m_image_name : std::string()),
- m_image_id, nullptr, m_ioctx, false);
+template<typename I>
+RemoveRequest<I>::RemoveRequest(IoCtx &ioctx, I *image_ctx, bool force,
+ bool from_trash_remove,
+ ProgressContext &prog_ctx,
+ ContextWQ *op_work_queue, Context *on_finish)
+ : m_ioctx(ioctx), m_image_name(image_ctx->name), m_image_id(image_ctx->id),
+ m_image_ctx(image_ctx), m_force(force),
+ m_from_trash_remove(from_trash_remove), m_prog_ctx(prog_ctx),
+ m_op_work_queue(op_work_queue), m_on_finish(on_finish),
+ m_cct(image_ctx->cct), m_header_oid(image_ctx->header_oid),
+ m_old_format(image_ctx->old_format), m_unknown_format(false) {
}
template<typename I>
template<typename I>
void RemoveRequest<I>::open_image() {
+ if (m_image_ctx != nullptr) {
+ pre_remove_image();
+ return;
+ }
+
+ m_image_ctx = I::create(m_image_id.empty() ? m_image_name : "", m_image_id,
+ nullptr, m_ioctx, false);
+
ldout(m_cct, 20) << dendl;
using klass = RemoveRequest<I>;
Context *ctx = create_context_callback<klass, &klass::handle_open_image>(
this);
- m_image_ctx->state->open(true, ctx);
+ m_image_ctx->state->open(OPEN_FLAG_SKIP_OPEN_PARENT, ctx);
}
template<typename I>
m_old_format = m_image_ctx->old_format;
m_unknown_format = false;
- check_exclusive_lock();
-}
-
-template<typename I>
-void RemoveRequest<I>::check_exclusive_lock() {
- ldout(m_cct, 20) << dendl;
-
- if (m_image_ctx->exclusive_lock == nullptr) {
- validate_image_removal();
- } else {
- acquire_exclusive_lock();
- }
+ pre_remove_image();
}
template<typename I>
-void RemoveRequest<I>::acquire_exclusive_lock() {
- ldout(m_cct, 20) << dendl;
+void RemoveRequest<I>::pre_remove_image() {
+ ldout(m_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());
- }
-
- using klass = RemoveRequest<I>;
- 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<typename I>
-void RemoveRequest<I>::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;
- }
-
- assert(m_image_ctx->exclusive_lock == nullptr);
- validate_image_removal();
-}
-
-template<typename I>
-void RemoveRequest<I>::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<typename I>
-void RemoveRequest<I>::validate_image_removal() {
- ldout(m_cct, 20) << dendl;
-
- check_image_snaps();
-}
-
-template<typename I>
-void RemoveRequest<I>::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;
- }
-
- list_image_watchers();
-}
-
-template<typename I>
-void RemoveRequest<I>::list_image_watchers() {
- ldout(m_cct, 20) << dendl;
-
- librados::ObjectReadOperation op;
- op.list_watchers(&m_watchers, &m_ret_val);
-
- using klass = RemoveRequest<I>;
- librados::AioCompletion *rados_completion =
- create_rados_callback<klass, &klass::handle_list_image_watchers>(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();
+ auto ctx = create_context_callback<
+ RemoveRequest<I>, &RemoveRequest<I>::handle_pre_remove_image>(this);
+ auto req = PreRemoveRequest<I>::create(m_image_ctx, m_force, ctx);
+ req->send();
}
template<typename I>
-void RemoveRequest<I>::handle_list_image_watchers(int r) {
- ldout(m_cct, 20) << "r=" << r << dendl;
+void RemoveRequest<I>::handle_pre_remove_image(int r) {
+ ldout(m_cct, 5) << "r=" << r << dendl;
- if (r == 0 && m_ret_val < 0) {
- r = m_ret_val;
- }
if (r < 0) {
- lderr(m_cct) << "error listing image watchers: " << cpp_strerror(r)
- << dendl;
- send_close_image(r);
- return;
- }
-
- get_mirror_image();
-}
-
-template<typename I>
-void RemoveRequest<I>::get_mirror_image() {
- ldout(m_cct, 20) << dendl;
- if ((m_watchers.empty()) ||
- ((m_image_ctx->features & RBD_FEATURE_JOURNALING) == 0)) {
- check_image_watchers();
- return;
- }
-
- librados::ObjectReadOperation op;
- cls_client::mirror_image_get_start(&op, m_image_id);
-
- using klass = RemoveRequest<I>;
- librados::AioCompletion *comp =
- create_rados_callback<klass, &klass::handle_get_mirror_image>(this);
- m_out_bl.clear();
- int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
- assert(r == 0);
- comp->release();
-}
-
-template<typename I>
-void RemoveRequest<I>::handle_get_mirror_image(int r) {
- ldout(m_cct, 20) << "r=" << r << dendl;
-
- if (r == -ENOENT || r == -EOPNOTSUPP) {
- check_image_watchers();
- return;
- } else if (r < 0) {
- ldout(m_cct, 5) << "error retrieving mirror image: " << cpp_strerror(r)
- << dendl;
- }
-
- list_mirror_watchers();
-}
-
-template<typename I>
-void RemoveRequest<I>::list_mirror_watchers() {
- ldout(m_cct, 20) << dendl;
-
- librados::ObjectReadOperation op;
- op.list_watchers(&m_mirror_watchers, &m_ret_val);
-
- using klass = RemoveRequest<I>;
- librados::AioCompletion *rados_completion =
- create_rados_callback<klass, &klass::handle_list_mirror_watchers>(this);
- m_out_bl.clear();
- int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, rados_completion,
- &op, &m_out_bl);
- assert(r == 0);
- rados_completion->release();
-}
-
-template<typename I>
-void RemoveRequest<I>::handle_list_mirror_watchers(int r) {
- ldout(m_cct, 20) << "r=" << r << dendl;
-
- if (r == 0 && m_ret_val < 0) {
- r = m_ret_val;
- }
- if (r < 0 && r != -ENOENT) {
- ldout(m_cct, 5) << "error listing mirror watchers: " << cpp_strerror(r)
- << dendl;
- }
-
- for (auto &watcher : m_mirror_watchers) {
- m_watchers.remove_if([watcher] (obj_watch_t &w) {
- return (strncmp(w.addr, watcher.addr, sizeof(w.addr)) == 0);
- });
- }
-
- check_image_watchers();
-}
-
-template<typename I>
-void RemoveRequest<I>::check_image_watchers() {
- if (m_watchers.size() > 1) {
- lderr(m_cct) << "image has watchers - not removing" << dendl;
- send_close_image(-EBUSY);
- return;
- }
-
- check_group();
-}
-
-template<typename I>
-void RemoveRequest<I>::check_group() {
- ldout(m_cct, 20) << dendl;
-
- librados::ObjectReadOperation op;
- librbd::cls_client::image_get_group_start(&op);
-
- using klass = RemoveRequest<I>;
- 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);
- assert(r == 0);
- rados_completion->release();
-}
-
-template<typename I>
-void RemoveRequest<I>::handle_check_group(int r) {
- ldout(m_cct, 20) << "r=" << r << dendl;
-
- cls::rbd::GroupSpec s;
- if (r == 0) {
- bufferlist::iterator it = m_out_bl.begin();
- r = librbd::cls_client::image_get_group_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;
- }
-
trim_image();
}
ldout(m_cct, 20) << "r=" << r << dendl;
if (r < 0) {
- lderr(m_cct) << "warning: failed to remove some object(s): "
+ lderr(m_cct) << "failed to remove some object(s): "
<< cpp_strerror(r) << dendl;
+ send_close_image(r);
+ return;
}
if (m_old_format) {
return;
}
- remove_child();
+ detach_child();
}
template<typename I>
-void RemoveRequest<I>::remove_child() {
+void RemoveRequest<I>::detach_child() {
ldout(m_cct, 20) << dendl;
- m_image_ctx->parent_lock.get_read();
- ParentInfo 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<I>;
- librados::AioCompletion *rados_completion =
- create_rados_callback<klass, &klass::handle_remove_child>(this);
- int r = m_image_ctx->md_ctx.aio_operate(RBD_CHILDREN, rados_completion, &op);
- assert(r == 0);
- rados_completion->release();
+ auto ctx = create_context_callback<
+ RemoveRequest<I>, &RemoveRequest<I>::handle_detach_child>(this);
+ auto req = DetachChildRequest<I>::create(*m_image_ctx, ctx);
+ req->send();
}
template<typename I>
-void RemoveRequest<I>::handle_remove_child(int r) {
+void RemoveRequest<I>::handle_detach_child(int r) {
ldout(m_cct, 20) << "r=" << r << dendl;
- if (r == -ENOENT) {
- r = 0;
- } else if (r < 0) {
- lderr(m_cct) << "error removing child from children list: "
+ if (r < 0) {
+ lderr(m_cct) << "failed to detach child from parent: "
<< cpp_strerror(r) << dendl;
send_close_image(r);
return;
}
-
send_disable_mirror();
}
librados::AioCompletion *rados_completion =
create_rados_callback<klass, &klass::handle_remove_header>(this);
int r = m_ioctx.aio_remove(m_header_oid, rados_completion);
- assert(r == 0);
+ ceph_assert(r == 0);
rados_completion->release();
}
librados::AioCompletion *rados_completion =
create_rados_callback<klass, &klass::handle_remove_header_v2>(this);
int r = m_ioctx.aio_remove(m_header_oid, rados_completion);
- assert(r == 0);
+ ceph_assert(r == 0);
rados_completion->release();
}
int r = ObjectMap<>::aio_remove(m_ioctx,
m_image_id,
rados_completion);
- assert(r == 0);
+ ceph_assert(r == 0);
rados_completion->release();
}
librados::AioCompletion *rados_completion =
create_rados_callback<klass, &klass::handle_mirror_image_remove>(this);
int r = m_ioctx.aio_operate(RBD_MIRRORING, rados_completion, &op);
- assert(r == 0);
+ ceph_assert(r == 0);
rados_completion->release();
}
create_rados_callback<klass, &klass::handle_dir_get_image_id>(this);
m_out_bl.clear();
int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
- assert(r == 0);
+ ceph_assert(r == 0);
rados_completion->release();
}
}
if (r == 0) {
- bufferlist::iterator iter = m_out_bl.begin();
+ auto iter = m_out_bl.cbegin();
r = librbd::cls_client::dir_get_id_finish(&iter, &m_image_id);
if (r < 0) {
finish(r);
create_rados_callback<klass, &klass::handle_dir_get_image_name>(this);
m_out_bl.clear();
int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
- assert(r == 0);
+ ceph_assert(r == 0);
rados_completion->release();
}
}
if (r == 0) {
- bufferlist::iterator iter = m_out_bl.begin();
+ auto iter = m_out_bl.cbegin();
r = librbd::cls_client::dir_get_name_finish(&iter, &m_image_name);
if (r < 0) {
finish(r);
librados::AioCompletion *rados_completion =
create_rados_callback<klass, &klass::handle_remove_id_object>(this);
int r = m_ioctx.aio_remove(util::id_obj_name(m_image_name), rados_completion);
- assert(r == 0);
+ ceph_assert(r == 0);
rados_completion->release();
}
librados::AioCompletion *rados_completion =
create_rados_callback<klass, &klass::handle_dir_remove_image>(this);
int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op);
- assert(r == 0);
+ ceph_assert(r == 0);
rados_completion->release();
}