test_mock_LeaderWatcher.cc
test_mock_PoolReplayer.cc
test_mock_PoolWatcher.cc
- image_deleter/test_mock_RemoveRequest.cc
image_deleter/test_mock_SnapshotPurgeRequest.cc
image_deleter/test_mock_TrashMoveRequest.cc
+ image_deleter/test_mock_TrashRemoveRequest.cc
image_deleter/test_mock_TrashWatcher.cc
image_replayer/test_mock_BootstrapRequest.cc
image_replayer/test_mock_CreateImageRequest.cc
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "test/rbd_mirror/test_mock_fixture.h"
-#include "cls/rbd/cls_rbd_types.h"
-#include "librbd/ImageCtx.h"
-#include "librbd/Utils.h"
-#include "librbd/image/RemoveRequest.h"
-#include "tools/rbd_mirror/Threads.h"
-#include "tools/rbd_mirror/image_deleter/RemoveRequest.h"
-#include "tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.h"
-#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
-#include "test/librbd/mock/MockImageCtx.h"
-
-namespace librbd {
-
-namespace {
-
-struct MockTestImageCtx : public librbd::MockImageCtx {
- MockTestImageCtx(librbd::ImageCtx &image_ctx)
- : librbd::MockImageCtx(image_ctx) {
- }
-};
-
-} // anonymous namespace
-
-namespace image {
-
-template <>
-struct RemoveRequest<librbd::MockTestImageCtx> {
- static RemoveRequest *s_instance;
- Context *on_finish = nullptr;
-
- static RemoveRequest *create(librados::IoCtx &io_ctx,
- const std::string &image_name,
- const std::string &image_id,
- bool force,
- bool remove_from_trash,
- librbd::ProgressContext &progress_ctx,
- ContextWQ *work_queue,
- Context *on_finish) {
- ceph_assert(s_instance != nullptr);
- EXPECT_TRUE(image_name.empty());
- EXPECT_TRUE(force);
- EXPECT_TRUE(remove_from_trash);
- s_instance->construct(image_id);
- s_instance->on_finish = on_finish;
- return s_instance;
- }
-
- MOCK_METHOD1(construct, void(const std::string&));
- MOCK_METHOD0(send, void());
-
- RemoveRequest() {
- s_instance = this;
- }
-};
-
-RemoveRequest<librbd::MockTestImageCtx>* RemoveRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-
-} // namespace image
-} // namespace librbd
-
-namespace rbd {
-namespace mirror {
-namespace image_deleter {
-
-template <>
-struct SnapshotPurgeRequest<librbd::MockTestImageCtx> {
- static SnapshotPurgeRequest *s_instance;
- Context *on_finish = nullptr;
-
- static SnapshotPurgeRequest *create(librados::IoCtx &io_ctx,
- const std::string &image_id,
- Context *on_finish) {
- ceph_assert(s_instance != nullptr);
- s_instance->construct(image_id);
- s_instance->on_finish = on_finish;
- return s_instance;
- }
-
- MOCK_METHOD1(construct, void(const std::string&));
- MOCK_METHOD0(send, void());
-
- SnapshotPurgeRequest() {
- s_instance = this;
- }
-};
-
-SnapshotPurgeRequest<librbd::MockTestImageCtx>* SnapshotPurgeRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-
-} // namespace image_deleter
-} // namespace mirror
-} // namespace rbd
-
-#include "tools/rbd_mirror/image_deleter/RemoveRequest.cc"
-
-namespace rbd {
-namespace mirror {
-namespace image_deleter {
-
-using ::testing::_;
-using ::testing::Invoke;
-using ::testing::InSequence;
-using ::testing::Return;
-using ::testing::StrEq;
-using ::testing::WithArg;
-using ::testing::WithArgs;
-
-class TestMockImageDeleterRemoveRequest : public TestMockFixture {
-public:
- typedef RemoveRequest<librbd::MockTestImageCtx> MockRemoveRequest;
- typedef SnapshotPurgeRequest<librbd::MockTestImageCtx> MockSnapshotPurgeRequest;
- typedef librbd::image::RemoveRequest<librbd::MockTestImageCtx> MockImageRemoveRequest;
-
- void expect_get_snapcontext(const std::string& image_id,
- const ::SnapContext &snapc, int r) {
- bufferlist bl;
- encode(snapc, bl);
-
- EXPECT_CALL(get_mock_io_ctx(m_local_io_ctx),
- exec(librbd::util::header_name(image_id), _, StrEq("rbd"),
- StrEq("get_snapcontext"), _, _, _))
- .WillOnce(DoAll(WithArg<5>(Invoke([bl](bufferlist *out_bl) {
- *out_bl = bl;
- })),
- Return(r)));
- }
-
- void expect_snapshot_purge(MockSnapshotPurgeRequest &snapshot_purge_request,
- const std::string &image_id, int r) {
- EXPECT_CALL(snapshot_purge_request, construct(image_id));
- EXPECT_CALL(snapshot_purge_request, send())
- .WillOnce(Invoke([this, &snapshot_purge_request, r]() {
- m_threads->work_queue->queue(snapshot_purge_request.on_finish, r);
- }));
- }
-
- void expect_image_remove(MockImageRemoveRequest &image_remove_request,
- const std::string &image_id, int r) {
- EXPECT_CALL(image_remove_request, construct(image_id));
- EXPECT_CALL(image_remove_request, send())
- .WillOnce(Invoke([this, &image_remove_request, r]() {
- m_threads->work_queue->queue(image_remove_request.on_finish, r);
- }));
- }
-};
-
-TEST_F(TestMockImageDeleterRemoveRequest, Success) {
- InSequence seq;
- expect_get_snapcontext("image id", {1, {1}}, 0);
-
- MockSnapshotPurgeRequest mock_snapshot_purge_request;
- expect_snapshot_purge(mock_snapshot_purge_request, "image id", 0);
-
- MockImageRemoveRequest mock_image_remove_request;
- expect_image_remove(mock_image_remove_request, "image id", 0);
-
- C_SaferCond ctx;
- ErrorResult error_result;
- auto req = MockRemoveRequest::create(m_local_io_ctx, "image id",
- &error_result, m_threads->work_queue,
- &ctx);
- req->send();
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockImageDeleterRemoveRequest, GetSnapContextDNE) {
- InSequence seq;
- expect_get_snapcontext("image id", {1, {1}}, -ENOENT);
-
- MockImageRemoveRequest mock_image_remove_request;
- expect_image_remove(mock_image_remove_request, "image id", 0);
-
- C_SaferCond ctx;
- ErrorResult error_result;
- auto req = MockRemoveRequest::create(m_local_io_ctx, "image id",
- &error_result, m_threads->work_queue,
- &ctx);
- req->send();
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockImageDeleterRemoveRequest, GetSnapContextError) {
- InSequence seq;
- expect_get_snapcontext("image id", {1, {1}}, -EINVAL);
-
- C_SaferCond ctx;
- ErrorResult error_result;
- auto req = MockRemoveRequest::create(m_local_io_ctx, "image id",
- &error_result, m_threads->work_queue,
- &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockImageDeleterRemoveRequest, PurgeSnapshotBusy) {
- InSequence seq;
- expect_get_snapcontext("image id", {1, {1}}, 0);
-
- MockSnapshotPurgeRequest mock_snapshot_purge_request;
- expect_snapshot_purge(mock_snapshot_purge_request, "image id", -EBUSY);
-
- C_SaferCond ctx;
- ErrorResult error_result;
- auto req = MockRemoveRequest::create(m_local_io_ctx, "image id",
- &error_result, m_threads->work_queue,
- &ctx);
- req->send();
- ASSERT_EQ(-EBUSY, ctx.wait());
- ASSERT_EQ(ERROR_RESULT_RETRY_IMMEDIATELY, error_result);
-}
-
-TEST_F(TestMockImageDeleterRemoveRequest, PurgeSnapshotError) {
- InSequence seq;
- expect_get_snapcontext("image id", {1, {1}}, 0);
-
- MockSnapshotPurgeRequest mock_snapshot_purge_request;
- expect_snapshot_purge(mock_snapshot_purge_request, "image id", -EINVAL);
-
- C_SaferCond ctx;
- ErrorResult error_result;
- auto req = MockRemoveRequest::create(m_local_io_ctx, "image id",
- &error_result, m_threads->work_queue,
- &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockImageDeleterRemoveRequest, RemoveError) {
- InSequence seq;
- expect_get_snapcontext("image id", {1, {1}}, 0);
-
- MockSnapshotPurgeRequest mock_snapshot_purge_request;
- expect_snapshot_purge(mock_snapshot_purge_request, "image id", 0);
-
- MockImageRemoveRequest mock_image_remove_request;
- expect_image_remove(mock_image_remove_request, "image id", -EINVAL);
-
- C_SaferCond ctx;
- ErrorResult error_result;
- auto req = MockRemoveRequest::create(m_local_io_ctx, "image id",
- &error_result, m_threads->work_queue,
- &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-} // namespace image_deleter
-} // namespace mirror
-} // namespace rbd
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/rbd_mirror/test_mock_fixture.h"
+#include "cls/rbd/cls_rbd_types.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/Utils.h"
+#include "librbd/image/RemoveRequest.h"
+#include "tools/rbd_mirror/Threads.h"
+#include "tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.h"
+#include "tools/rbd_mirror/image_deleter/TrashRemoveRequest.h"
+#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "test/librbd/mock/MockImageCtx.h"
+
+namespace librbd {
+
+namespace {
+
+struct MockTestImageCtx : public librbd::MockImageCtx {
+ MockTestImageCtx(librbd::ImageCtx &image_ctx)
+ : librbd::MockImageCtx(image_ctx) {
+ }
+};
+
+} // anonymous namespace
+
+namespace image {
+
+template <>
+struct RemoveRequest<librbd::MockTestImageCtx> {
+ static RemoveRequest *s_instance;
+ Context *on_finish = nullptr;
+
+ static RemoveRequest *create(librados::IoCtx &io_ctx,
+ const std::string &image_name,
+ const std::string &image_id,
+ bool force,
+ bool remove_from_trash,
+ librbd::ProgressContext &progress_ctx,
+ ContextWQ *work_queue,
+ Context *on_finish) {
+ ceph_assert(s_instance != nullptr);
+ EXPECT_TRUE(image_name.empty());
+ EXPECT_TRUE(force);
+ EXPECT_TRUE(remove_from_trash);
+ s_instance->construct(image_id);
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ MOCK_METHOD1(construct, void(const std::string&));
+ MOCK_METHOD0(send, void());
+
+ RemoveRequest() {
+ s_instance = this;
+ }
+};
+
+RemoveRequest<librbd::MockTestImageCtx>* RemoveRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace image
+} // namespace librbd
+
+namespace rbd {
+namespace mirror {
+namespace image_deleter {
+
+template <>
+struct SnapshotPurgeRequest<librbd::MockTestImageCtx> {
+ static SnapshotPurgeRequest *s_instance;
+ Context *on_finish = nullptr;
+
+ static SnapshotPurgeRequest *create(librados::IoCtx &io_ctx,
+ const std::string &image_id,
+ Context *on_finish) {
+ ceph_assert(s_instance != nullptr);
+ s_instance->construct(image_id);
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ MOCK_METHOD1(construct, void(const std::string&));
+ MOCK_METHOD0(send, void());
+
+ SnapshotPurgeRequest() {
+ s_instance = this;
+ }
+};
+
+SnapshotPurgeRequest<librbd::MockTestImageCtx>* SnapshotPurgeRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace image_deleter
+} // namespace mirror
+} // namespace rbd
+
+#include "tools/rbd_mirror/image_deleter/TrashRemoveRequest.cc"
+
+namespace rbd {
+namespace mirror {
+namespace image_deleter {
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::WithArg;
+using ::testing::WithArgs;
+
+class TestMockImageDeleterTrashRemoveRequest : public TestMockFixture {
+public:
+ typedef TrashRemoveRequest<librbd::MockTestImageCtx> MockTrashRemoveRequest;
+ typedef SnapshotPurgeRequest<librbd::MockTestImageCtx> MockSnapshotPurgeRequest;
+ typedef librbd::image::RemoveRequest<librbd::MockTestImageCtx> MockImageRemoveRequest;
+
+ void expect_get_snapcontext(const std::string& image_id,
+ const ::SnapContext &snapc, int r) {
+ bufferlist bl;
+ encode(snapc, bl);
+
+ EXPECT_CALL(get_mock_io_ctx(m_local_io_ctx),
+ exec(librbd::util::header_name(image_id), _, StrEq("rbd"),
+ StrEq("get_snapcontext"), _, _, _))
+ .WillOnce(DoAll(WithArg<5>(Invoke([bl](bufferlist *out_bl) {
+ *out_bl = bl;
+ })),
+ Return(r)));
+ }
+
+ void expect_snapshot_purge(MockSnapshotPurgeRequest &snapshot_purge_request,
+ const std::string &image_id, int r) {
+ EXPECT_CALL(snapshot_purge_request, construct(image_id));
+ EXPECT_CALL(snapshot_purge_request, send())
+ .WillOnce(Invoke([this, &snapshot_purge_request, r]() {
+ m_threads->work_queue->queue(
+ snapshot_purge_request.on_finish, r);
+ }));
+ }
+
+ void expect_image_remove(MockImageRemoveRequest &image_remove_request,
+ const std::string &image_id, int r) {
+ EXPECT_CALL(image_remove_request, construct(image_id));
+ EXPECT_CALL(image_remove_request, send())
+ .WillOnce(Invoke([this, &image_remove_request, r]() {
+ m_threads->work_queue->queue(
+ image_remove_request.on_finish, r);
+ }));
+ }
+};
+
+TEST_F(TestMockImageDeleterTrashRemoveRequest, Success) {
+ InSequence seq;
+ expect_get_snapcontext("image id", {1, {1}}, 0);
+
+ MockSnapshotPurgeRequest mock_snapshot_purge_request;
+ expect_snapshot_purge(mock_snapshot_purge_request, "image id", 0);
+
+ MockImageRemoveRequest mock_image_remove_request;
+ expect_image_remove(mock_image_remove_request, "image id", 0);
+
+ C_SaferCond ctx;
+ ErrorResult error_result;
+ auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
+ &error_result,
+ m_threads->work_queue, &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockImageDeleterTrashRemoveRequest, GetSnapContextDNE) {
+ InSequence seq;
+ expect_get_snapcontext("image id", {1, {1}}, -ENOENT);
+
+ MockImageRemoveRequest mock_image_remove_request;
+ expect_image_remove(mock_image_remove_request, "image id", 0);
+
+ C_SaferCond ctx;
+ ErrorResult error_result;
+ auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
+ &error_result,
+ m_threads->work_queue, &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockImageDeleterTrashRemoveRequest, GetSnapContextError) {
+ InSequence seq;
+ expect_get_snapcontext("image id", {1, {1}}, -EINVAL);
+
+ C_SaferCond ctx;
+ ErrorResult error_result;
+ auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
+ &error_result,
+ m_threads->work_queue, &ctx);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockImageDeleterTrashRemoveRequest, PurgeSnapshotBusy) {
+ InSequence seq;
+ expect_get_snapcontext("image id", {1, {1}}, 0);
+
+ MockSnapshotPurgeRequest mock_snapshot_purge_request;
+ expect_snapshot_purge(mock_snapshot_purge_request, "image id", -EBUSY);
+
+ C_SaferCond ctx;
+ ErrorResult error_result;
+ auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
+ &error_result,
+ m_threads->work_queue, &ctx);
+ req->send();
+ ASSERT_EQ(-EBUSY, ctx.wait());
+ ASSERT_EQ(ERROR_RESULT_RETRY_IMMEDIATELY, error_result);
+}
+
+TEST_F(TestMockImageDeleterTrashRemoveRequest, PurgeSnapshotError) {
+ InSequence seq;
+ expect_get_snapcontext("image id", {1, {1}}, 0);
+
+ MockSnapshotPurgeRequest mock_snapshot_purge_request;
+ expect_snapshot_purge(mock_snapshot_purge_request, "image id", -EINVAL);
+
+ C_SaferCond ctx;
+ ErrorResult error_result;
+ auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
+ &error_result,
+ m_threads->work_queue, &ctx);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockImageDeleterTrashRemoveRequest, RemoveError) {
+ InSequence seq;
+ expect_get_snapcontext("image id", {1, {1}}, 0);
+
+ MockSnapshotPurgeRequest mock_snapshot_purge_request;
+ expect_snapshot_purge(mock_snapshot_purge_request, "image id", 0);
+
+ MockImageRemoveRequest mock_image_remove_request;
+ expect_image_remove(mock_image_remove_request, "image id", -EINVAL);
+
+ C_SaferCond ctx;
+ ErrorResult error_result;
+ auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
+ &error_result,
+ m_threads->work_queue, &ctx);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+} // namespace image_deleter
+} // namespace mirror
+} // namespace rbd
ServiceDaemon.cc
Threads.cc
Types.cc
- image_deleter/RemoveRequest.cc
image_deleter/SnapshotPurgeRequest.cc
image_deleter/TrashMoveRequest.cc
+ image_deleter/TrashRemoveRequest.cc
image_deleter/TrashWatcher.cc
image_map/LoadRequest.cc
image_map/Policy.cc
#include "librbd/ImageState.h"
#include "librbd/Journal.h"
#include "librbd/Operations.h"
-#include "librbd/image/RemoveRequest.h"
#include "cls/rbd/cls_rbd_client.h"
#include "cls/rbd/cls_rbd_types.h"
#include "librbd/Utils.h"
#include "ImageDeleter.h"
#include "tools/rbd_mirror/Threads.h"
-#include "tools/rbd_mirror/image_deleter/RemoveRequest.h"
#include "tools/rbd_mirror/image_deleter/TrashMoveRequest.h"
+#include "tools/rbd_mirror/image_deleter/TrashRemoveRequest.h"
#include "tools/rbd_mirror/image_deleter/TrashWatcher.h"
#include <map>
#include <sstream>
m_async_op_tracker.finish_op();
});
- auto req = image_deleter::RemoveRequest<I>::create(
+ auto req = image_deleter::TrashRemoveRequest<I>::create(
m_local_io_ctx, delete_info->image_id, &delete_info->error_result,
m_threads->work_queue, ctx);
req->send();
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "tools/rbd_mirror/image_deleter/RemoveRequest.h"
-#include "include/ceph_assert.h"
-#include "common/debug.h"
-#include "common/errno.h"
-#include "common/WorkQueue.h"
-#include "cls/rbd/cls_rbd_client.h"
-#include "librbd/ImageCtx.h"
-#include "librbd/Journal.h"
-#include "librbd/Utils.h"
-#include "librbd/image/RemoveRequest.h"
-#include "tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.h"
-
-#define dout_context g_ceph_context
-#define dout_subsys ceph_subsys_rbd_mirror
-#undef dout_prefix
-#define dout_prefix *_dout << "rbd::mirror::image_deleter::RemoveRequest: " \
- << this << " " << __func__ << ": "
-
-namespace rbd {
-namespace mirror {
-namespace image_deleter {
-
-using librbd::util::create_context_callback;
-using librbd::util::create_rados_callback;
-
-template <typename I>
-void RemoveRequest<I>::send() {
- *m_error_result = ERROR_RESULT_RETRY;
-
- get_snap_context();
-}
-
-template <typename I>
-void RemoveRequest<I>::get_snap_context() {
- dout(10) << dendl;
-
- librados::ObjectReadOperation op;
- librbd::cls_client::get_snapcontext_start(&op);
-
- std::string header_oid = librbd::util::header_name(m_image_id);
-
- auto aio_comp = create_rados_callback<
- RemoveRequest<I>, &RemoveRequest<I>::handle_get_snap_context>(this);
- m_out_bl.clear();
- int r = m_io_ctx.aio_operate(header_oid, aio_comp, &op, &m_out_bl);
- ceph_assert(r == 0);
- aio_comp->release();
-}
-
-template <typename I>
-void RemoveRequest<I>::handle_get_snap_context(int r) {
- dout(10) << "r=" << r << dendl;
-
- ::SnapContext snapc;
- if (r == 0) {
- auto bl_it = m_out_bl.cbegin();
- r = librbd::cls_client::get_snapcontext_finish(&bl_it, &snapc);
- }
- if (r < 0 && r != -ENOENT) {
- derr << "error retrieving snapshot context for image "
- << m_image_id << ": " << cpp_strerror(r) << dendl;
- finish(r);
- return;
- }
-
- m_has_snapshots = (!snapc.empty());
- purge_snapshots();
-}
-
-template <typename I>
-void RemoveRequest<I>::purge_snapshots() {
- if (!m_has_snapshots) {
- remove_image();
- return;
- }
-
- dout(10) << dendl;
- auto ctx = create_context_callback<
- RemoveRequest<I>, &RemoveRequest<I>::handle_purge_snapshots>(this);
- auto req = SnapshotPurgeRequest<I>::create(m_io_ctx, m_image_id, ctx);
- req->send();
-}
-
-template <typename I>
-void RemoveRequest<I>::handle_purge_snapshots(int r) {
- dout(10) << "r=" << r << dendl;
-
- if (r == -EBUSY) {
- dout(10) << "snapshots still in-use" << dendl;
- *m_error_result = ERROR_RESULT_RETRY_IMMEDIATELY;
- finish(r);
- return;
- } else if (r < 0) {
- derr << "failed to purge image snapshots: " << cpp_strerror(r) << dendl;
- finish(r);
- return;
- }
-
- remove_image();
-}
-
-template <typename I>
-void RemoveRequest<I>::remove_image() {
- dout(10) << dendl;
-
- auto ctx = create_context_callback<
- RemoveRequest<I>, &RemoveRequest<I>::handle_remove_image>(this);
- auto req = librbd::image::RemoveRequest<I>::create(
- m_io_ctx, "", m_image_id, true, true, m_progress_ctx, m_op_work_queue,
- ctx);
- req->send();
-}
-
-template <typename I>
-void RemoveRequest<I>::handle_remove_image(int r) {
- dout(10) << "r=" << r << dendl;
- if (r == -ENOTEMPTY) {
- // image must have clone v2 snapshot still associated to child
- dout(10) << "snapshots still in-use" << dendl;
- *m_error_result = ERROR_RESULT_RETRY_IMMEDIATELY;
- finish(-EBUSY);
- return;
- }
-
- if (r < 0 && r != -ENOENT) {
- derr << "error removing image " << m_image_id << " "
- << "(" << m_image_id << ") from local pool: "
- << cpp_strerror(r) << dendl;
- finish(r);
- return;
- }
-
- finish(0);
-}
-
-template <typename I>
-void RemoveRequest<I>::finish(int r) {
- dout(10) << "r=" << r << dendl;
-
- m_on_finish->complete(r);
- delete this;
-}
-
-} // namespace image_deleter
-} // namespace mirror
-} // namespace rbd
-
-template class rbd::mirror::image_deleter::RemoveRequest<librbd::ImageCtx>;
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#ifndef CEPH_RBD_MIRROR_IMAGE_DELETER_REMOVE_REQUEST_H
-#define CEPH_RBD_MIRROR_IMAGE_DELETER_REMOVE_REQUEST_H
-
-#include "include/rados/librados.hpp"
-#include "include/buffer.h"
-#include "librbd/internal.h"
-#include "tools/rbd_mirror/image_deleter/Types.h"
-#include <string>
-#include <vector>
-
-class Context;
-class ContextWQ;
-namespace librbd { struct ImageCtx; }
-
-namespace rbd {
-namespace mirror {
-namespace image_deleter {
-
-template <typename ImageCtxT = librbd::ImageCtx>
-class RemoveRequest {
-public:
- static RemoveRequest* create(librados::IoCtx &io_ctx,
- const std::string &image_id,
- ErrorResult *error_result,
- ContextWQ *op_work_queue, Context *on_finish) {
- return new RemoveRequest(io_ctx, image_id, error_result, op_work_queue,
- on_finish);
- }
-
- RemoveRequest(librados::IoCtx &io_ctx, const std::string &image_id,
- ErrorResult *error_result, ContextWQ *op_work_queue,
- Context *on_finish)
- : m_io_ctx(io_ctx), m_image_id(image_id), m_error_result(error_result),
- m_op_work_queue(op_work_queue), m_on_finish(on_finish) {
- }
-
- void send();
-
-private:
- /*
- * @verbatim
- *
- * <start>
- * |
- * v
- * GET_SNAP_CONTEXT
- * |
- * v
- * PURGE_SNAPSHOTS
- * |
- * v
- * REMOVE_IMAGE
- * |
- * v
- * <finish>
- *
- * @endverbatim
- */
-
- librados::IoCtx &m_io_ctx;
- std::string m_image_id;
- ErrorResult *m_error_result;
- ContextWQ *m_op_work_queue;
- Context *m_on_finish;
-
- ceph::bufferlist m_out_bl;
- bool m_has_snapshots = false;
- librbd::NoOpProgressContext m_progress_ctx;
-
- void get_snap_context();
- void handle_get_snap_context(int r);
-
- void purge_snapshots();
- void handle_purge_snapshots(int r);
-
- void remove_image();
- void handle_remove_image(int r);
-
- void finish(int r);
-
-};
-
-} // namespace image_deleter
-} // namespace mirror
-} // namespace rbd
-
-extern template class rbd::mirror::image_deleter::RemoveRequest<librbd::ImageCtx>;
-
-#endif // CEPH_RBD_MIRROR_IMAGE_DELETER_REMOVE_REQUEST_H
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "tools/rbd_mirror/image_deleter/TrashRemoveRequest.h"
+#include "include/ceph_assert.h"
+#include "common/debug.h"
+#include "common/errno.h"
+#include "common/WorkQueue.h"
+#include "cls/rbd/cls_rbd_client.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/Journal.h"
+#include "librbd/Utils.h"
+#include "librbd/image/RemoveRequest.h"
+#include "tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.h"
+
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_rbd_mirror
+#undef dout_prefix
+#define dout_prefix *_dout << "rbd::mirror::image_deleter::TrashRemoveRequest: " \
+ << this << " " << __func__ << ": "
+
+namespace rbd {
+namespace mirror {
+namespace image_deleter {
+
+using librbd::util::create_context_callback;
+using librbd::util::create_rados_callback;
+
+template <typename I>
+void TrashRemoveRequest<I>::send() {
+ *m_error_result = ERROR_RESULT_RETRY;
+
+ get_snap_context();
+}
+
+template <typename I>
+void TrashRemoveRequest<I>::get_snap_context() {
+ dout(10) << dendl;
+
+ librados::ObjectReadOperation op;
+ librbd::cls_client::get_snapcontext_start(&op);
+
+ std::string header_oid = librbd::util::header_name(m_image_id);
+
+ auto aio_comp = create_rados_callback<
+ TrashRemoveRequest<I>,
+ &TrashRemoveRequest<I>::handle_get_snap_context>(this);
+ m_out_bl.clear();
+ int r = m_io_ctx.aio_operate(header_oid, aio_comp, &op, &m_out_bl);
+ ceph_assert(r == 0);
+ aio_comp->release();
+}
+
+template <typename I>
+void TrashRemoveRequest<I>::handle_get_snap_context(int r) {
+ dout(10) << "r=" << r << dendl;
+
+ ::SnapContext snapc;
+ if (r == 0) {
+ auto bl_it = m_out_bl.cbegin();
+ r = librbd::cls_client::get_snapcontext_finish(&bl_it, &snapc);
+ }
+ if (r < 0 && r != -ENOENT) {
+ derr << "error retrieving snapshot context for image "
+ << m_image_id << ": " << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
+
+ m_has_snapshots = (!snapc.empty());
+ purge_snapshots();
+}
+
+template <typename I>
+void TrashRemoveRequest<I>::purge_snapshots() {
+ if (!m_has_snapshots) {
+ remove_image();
+ return;
+ }
+
+ dout(10) << dendl;
+ auto ctx = create_context_callback<
+ TrashRemoveRequest<I>,
+ &TrashRemoveRequest<I>::handle_purge_snapshots>(this);
+ auto req = SnapshotPurgeRequest<I>::create(m_io_ctx, m_image_id, ctx);
+ req->send();
+}
+
+template <typename I>
+void TrashRemoveRequest<I>::handle_purge_snapshots(int r) {
+ dout(10) << "r=" << r << dendl;
+
+ if (r == -EBUSY) {
+ dout(10) << "snapshots still in-use" << dendl;
+ *m_error_result = ERROR_RESULT_RETRY_IMMEDIATELY;
+ finish(r);
+ return;
+ } else if (r < 0) {
+ derr << "failed to purge image snapshots: " << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
+
+ remove_image();
+}
+
+template <typename I>
+void TrashRemoveRequest<I>::remove_image() {
+ dout(10) << dendl;
+
+ auto ctx = create_context_callback<
+ TrashRemoveRequest<I>,
+ &TrashRemoveRequest<I>::handle_remove_image>(this);
+ auto req = librbd::image::RemoveRequest<I>::create(
+ m_io_ctx, "", m_image_id, true, true, m_progress_ctx, m_op_work_queue,
+ ctx);
+ req->send();
+}
+
+template <typename I>
+void TrashRemoveRequest<I>::handle_remove_image(int r) {
+ dout(10) << "r=" << r << dendl;
+ if (r == -ENOTEMPTY) {
+ // image must have clone v2 snapshot still associated to child
+ dout(10) << "snapshots still in-use" << dendl;
+ *m_error_result = ERROR_RESULT_RETRY_IMMEDIATELY;
+ finish(-EBUSY);
+ return;
+ }
+
+ if (r < 0 && r != -ENOENT) {
+ derr << "error removing image " << m_image_id << " "
+ << "(" << m_image_id << ") from local pool: "
+ << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
+
+ finish(0);
+}
+
+template <typename I>
+void TrashRemoveRequest<I>::finish(int r) {
+ dout(10) << "r=" << r << dendl;
+
+ m_on_finish->complete(r);
+ delete this;
+}
+
+} // namespace image_deleter
+} // namespace mirror
+} // namespace rbd
+
+template class rbd::mirror::image_deleter::TrashRemoveRequest<librbd::ImageCtx>;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_RBD_MIRROR_IMAGE_DELETER_TRASH_REMOVE_REQUEST_H
+#define CEPH_RBD_MIRROR_IMAGE_DELETER_TRASH_REMOVE_REQUEST_H
+
+#include "include/rados/librados.hpp"
+#include "include/buffer.h"
+#include "librbd/internal.h"
+#include "tools/rbd_mirror/image_deleter/Types.h"
+#include <string>
+#include <vector>
+
+class Context;
+class ContextWQ;
+namespace librbd { struct ImageCtx; }
+
+namespace rbd {
+namespace mirror {
+namespace image_deleter {
+
+template <typename ImageCtxT = librbd::ImageCtx>
+class TrashRemoveRequest {
+public:
+ static TrashRemoveRequest* create(librados::IoCtx &io_ctx,
+ const std::string &image_id,
+ ErrorResult *error_result,
+ ContextWQ *op_work_queue,
+ Context *on_finish) {
+ return new TrashRemoveRequest(io_ctx, image_id, error_result, op_work_queue,
+ on_finish);
+ }
+
+ TrashRemoveRequest(librados::IoCtx &io_ctx, const std::string &image_id,
+ ErrorResult *error_result, ContextWQ *op_work_queue,
+ Context *on_finish)
+ : m_io_ctx(io_ctx), m_image_id(image_id), m_error_result(error_result),
+ m_op_work_queue(op_work_queue), m_on_finish(on_finish) {
+ }
+
+ void send();
+
+private:
+ /*
+ * @verbatim
+ *
+ * <start>
+ * |
+ * v
+ * GET_SNAP_CONTEXT
+ * |
+ * v
+ * PURGE_SNAPSHOTS
+ * |
+ * v
+ * REMOVE_IMAGE
+ * |
+ * v
+ * <finish>
+ *
+ * @endverbatim
+ */
+
+ librados::IoCtx &m_io_ctx;
+ std::string m_image_id;
+ ErrorResult *m_error_result;
+ ContextWQ *m_op_work_queue;
+ Context *m_on_finish;
+
+ ceph::bufferlist m_out_bl;
+ bool m_has_snapshots = false;
+ librbd::NoOpProgressContext m_progress_ctx;
+
+ void get_snap_context();
+ void handle_get_snap_context(int r);
+
+ void purge_snapshots();
+ void handle_purge_snapshots(int r);
+
+ void remove_image();
+ void handle_remove_image(int r);
+
+ void finish(int r);
+
+};
+
+} // namespace image_deleter
+} // namespace mirror
+} // namespace rbd
+
+extern template class rbd::mirror::image_deleter::TrashRemoveRequest<librbd::ImageCtx>;
+
+#endif // CEPH_RBD_MIRROR_IMAGE_DELETER_TRASH_REMOVE_REQUEST_H