#include "cls/rbd/cls_rbd_types.h"
#include "librbd/ExclusiveLock.h"
#include "librbd/Utils.h"
+#include "librbd/image/AttachParentRequest.h"
#include "librbd/image/DetachParentRequest.h"
#define dout_subsys ceph_subsys_rbd
(m_image_ctx->parent_md.spec == m_parent_spec &&
m_image_ctx->parent_md.overlap == m_parent_overlap)) {
m_image_ctx->parent_lock.put_read();
- send_set_parent();
+ send_attach_parent();
return;
}
m_image_ctx->parent_lock.put_read();
m_image_ctx->parent_md.overlap = 0;
}
- send_set_parent();
+ send_attach_parent();
}
template <typename I>
-void SetHeadRequest<I>::send_set_parent() {
+void SetHeadRequest<I>::send_attach_parent() {
m_image_ctx->parent_lock.get_read();
if (m_image_ctx->parent_md.spec == m_parent_spec &&
m_image_ctx->parent_md.overlap == m_parent_overlap) {
m_image_ctx->parent_lock.put_read();
ldout(m_cct, 20) << dendl;
-
- librados::ObjectWriteOperation op;
- librbd::cls_client::set_parent(&op, m_parent_spec, m_parent_overlap);
-
auto finish_op_ctx = start_lock_op();
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
}
auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
- handle_set_parent(r);
+ handle_attach_parent(r);
finish_op_ctx->complete(0);
});
- librados::AioCompletion *comp = create_rados_callback(ctx);
- int r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op);
- ceph_assert(r == 0);
- comp->release();
+ auto req = image::AttachParentRequest<I>::create(
+ *m_image_ctx,
+ {m_parent_spec.pool_id, "", m_parent_spec.image_id,
+ m_parent_spec.snap_id},
+ m_parent_overlap, ctx);
+ req->send();
}
template <typename I>
-void SetHeadRequest<I>::handle_set_parent(int r) {
+void SetHeadRequest<I>::handle_attach_parent(int r) {
ldout(m_cct, 20) << "r=" << r << dendl;
if (r < 0) {
- lderr(m_cct) << "failed to set parent: " << cpp_strerror(r) << dendl;
+ lderr(m_cct) << "failed to attach parent: " << cpp_strerror(r) << dendl;
finish(r);
return;
}
#include "common/errno.h"
#include "include/ceph_assert.h"
#include "librbd/ImageState.h"
+#include "librbd/image/AttachParentRequest.h"
#include "librbd/image/CloneRequest.h"
#include "librbd/image/CreateRequest.h"
#include "librbd/image/RemoveRequest.h"
return;
}
- set_parent();
+ attach_parent();
}
template <typename I>
-void CloneRequest<I>::set_parent() {
+void CloneRequest<I>::attach_parent() {
ldout(m_cct, 20) << dendl;
- librados::ObjectWriteOperation op;
- librbd::cls_client::set_parent(&op, m_pspec, m_size);
-
- using klass = CloneRequest<I>;
- librados::AioCompletion *comp =
- create_rados_callback<klass, &klass::handle_set_parent>(this);
- int r = m_imctx->md_ctx.aio_operate(m_imctx->header_oid, comp, &op);
- ceph_assert(r == 0);
- comp->release();
+ auto ctx = create_context_callback<
+ CloneRequest<I>, &CloneRequest<I>::handle_attach_parent>(this);
+ auto req = AttachParentRequest<I>::create(
+ *m_imctx, {m_pspec.pool_id, "", m_pspec.image_id, m_pspec.snap_id},
+ m_size, ctx);
+ req->send();
}
template <typename I>
-void CloneRequest<I>::handle_set_parent(int r) {
+void CloneRequest<I>::handle_attach_parent(int r) {
ldout(m_cct, 20) << "r=" << r << dendl;
if (r < 0) {
- lderr(m_cct) << "couldn't set parent: " << cpp_strerror(r) << dendl;
+ lderr(m_cct) << "failed to attach parent: " << cpp_strerror(r) << dendl;
m_r_saved = r;
close_child();
return;
#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
#include "test/librbd/mock/MockImageCtx.h"
#include "librbd/deep_copy/SetHeadRequest.h"
+#include "librbd/image/AttachParentRequest.h"
#include "librbd/image/DetachParentRequest.h"
namespace librbd {
namespace image {
+template <>
+struct AttachParentRequest<MockTestImageCtx> {
+ Context* on_finish = nullptr;
+ static AttachParentRequest* s_instance;
+ static AttachParentRequest* create(MockTestImageCtx&,
+ const cls::rbd::ParentImageSpec& pspec,
+ uint64_t parent_overlap,
+ Context *on_finish) {
+ ceph_assert(s_instance != nullptr);
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ MOCK_METHOD0(send, void());
+
+ AttachParentRequest() {
+ s_instance = this;
+ }
+};
+
+AttachParentRequest<MockTestImageCtx>* AttachParentRequest<MockTestImageCtx>::s_instance = nullptr;
+
template <>
class DetachParentRequest<MockTestImageCtx> {
public:
class TestMockDeepCopySetHeadRequest : public TestMockFixture {
public:
typedef SetHeadRequest<librbd::MockTestImageCtx> MockSetHeadRequest;
+ typedef image::AttachParentRequest<MockTestImageCtx> MockAttachParentRequest;
typedef image::DetachParentRequest<MockTestImageCtx> MockDetachParentRequest;
librbd::ImageCtx *m_image_ctx;
.WillOnce(FinishRequest(&mock_request, r, &mock_image_ctx));
}
- void expect_set_parent(librbd::MockTestImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("set_parent"), _, _, _))
- .WillOnce(Return(r));
+ void expect_attach_parent(MockImageCtx &mock_image_ctx,
+ MockAttachParentRequest& mock_request, int r) {
+ EXPECT_CALL(mock_request, send())
+ .WillOnce(FinishRequest(&mock_request, r, &mock_image_ctx));
}
MockSetHeadRequest *create_request(
MockDetachParentRequest mock_detach_parent;
expect_detach_parent(mock_image_ctx, mock_detach_parent, 0);
expect_start_op(mock_exclusive_lock);
- expect_set_parent(mock_image_ctx, 0);
+ MockAttachParentRequest mock_attach_parent;
+ expect_attach_parent(mock_image_ctx, mock_attach_parent, 0);
C_SaferCond ctx;
auto request = create_request(mock_image_ctx, m_image_ctx->size,
InSequence seq;
expect_start_op(mock_exclusive_lock);
- expect_set_parent(mock_image_ctx, 0);
+ MockAttachParentRequest mock_attach_parent;
+ expect_attach_parent(mock_image_ctx, mock_attach_parent, 0);
C_SaferCond ctx;
auto request = create_request(mock_image_ctx, m_image_ctx->size,
InSequence seq;
expect_start_op(mock_exclusive_lock);
- expect_set_parent(mock_image_ctx, -ESTALE);
+ MockAttachParentRequest mock_attach_parent;
+ expect_attach_parent(mock_image_ctx, mock_attach_parent, -ESTALE);
C_SaferCond ctx;
auto request = create_request(mock_image_ctx, m_image_ctx->size,
#include "librbd/ImageState.h"
#include "librbd/Operations.h"
#include "librbd/image/TypeTraits.h"
+#include "librbd/image/AttachParentRequest.h"
#include "librbd/image/CreateRequest.h"
#include "librbd/image/RemoveRequest.h"
#include "librbd/image/RefreshRequest.h"
namespace image {
+template <>
+struct AttachParentRequest<MockTestImageCtx> {
+ Context* on_finish = nullptr;
+ static AttachParentRequest* s_instance;
+ static AttachParentRequest* create(MockTestImageCtx&,
+ const cls::rbd::ParentImageSpec& pspec,
+ uint64_t parent_overlap,
+ Context *on_finish) {
+ ceph_assert(s_instance != nullptr);
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ MOCK_METHOD0(send, void());
+
+ AttachParentRequest() {
+ s_instance = this;
+ }
+};
+
+AttachParentRequest<MockTestImageCtx>* AttachParentRequest<MockTestImageCtx>::s_instance = nullptr;
+
template <>
struct CreateRequest<MockTestImageCtx> {
Context* on_finish = nullptr;
class TestMockImageCloneRequest : public TestMockFixture {
public:
typedef CloneRequest<MockTestImageCtx> MockCloneRequest;
+ typedef AttachParentRequest<MockTestImageCtx> MockAttachParentRequest;
typedef CreateRequest<MockTestImageCtx> MockCreateRequest;
typedef RefreshRequest<MockTestImageCtx> MockRefreshRequest;
typedef RemoveRequest<MockTestImageCtx> MockRemoveRequest;
}
}
- void expect_set_parent(MockImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
- StrEq("set_parent"), _, _, _))
- .WillOnce(InvokeWithoutArgs([r]() {
- return r;
+ void expect_attach_parent(MockAttachParentRequest& mock_request, int r) {
+ EXPECT_CALL(mock_request, send())
+ .WillOnce(Invoke([this, &mock_request, r]() {
+ image_ctx->op_work_queue->queue(mock_request.on_finish, r);
}));
}
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
+
expect_add_child(m_ioctx, 0);
MockRefreshRequest mock_refresh_request;
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
expect_op_features_set(m_ioctx, mock_image_ctx.id, 0);
expect_child_attach(mock_image_ctx, 0);
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
+
expect_add_child(m_ioctx, 0);
MockRefreshRequest mock_refresh_request;
ASSERT_EQ(-EINVAL, ctx.wait());
}
-TEST_F(TestMockImageCloneRequest, SetParentError) {
+TEST_F(TestMockImageCloneRequest, AttachParentError) {
REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
MockTestImageCtx mock_image_ctx(*image_ctx);
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, -EINVAL);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, -EINVAL);
+
expect_close(mock_image_ctx, 0);
MockRemoveRequest mock_remove_request;
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
+
expect_add_child(m_ioctx, -EINVAL);
expect_close(mock_image_ctx, 0);
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
+
expect_add_child(m_ioctx, 0);
MockRefreshRequest mock_refresh_request;
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
+
expect_add_child(m_ioctx, 0);
MockRefreshRequest mock_refresh_request;
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
expect_op_features_set(m_ioctx, mock_image_ctx.id, 0);
expect_child_attach(mock_image_ctx, 0);
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
+
expect_add_child(m_ioctx, 0);
MockRefreshRequest mock_refresh_request;
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
expect_op_features_set(m_ioctx, mock_image_ctx.id, 0);
expect_child_attach(mock_image_ctx, 0);
expect_create(mock_create_request, 0);
expect_open(mock_image_ctx, 0);
- expect_set_parent(mock_image_ctx, 0);
+
+ MockAttachParentRequest mock_attach_parent_request;
+ expect_attach_parent(mock_attach_parent_request, 0);
expect_op_features_set(m_ioctx, mock_image_ctx.id, 0);
expect_child_attach(mock_image_ctx, 0);