Operations.cc
Utils.cc
exclusive_lock/AcquireRequest.cc
+ exclusive_lock/ReacquireRequest.cc
exclusive_lock/ReleaseRequest.cc
exclusive_lock/StandardPolicy.cc
image/CloseRequest.cc
librbd/Operations.cc \
librbd/Utils.cc \
librbd/exclusive_lock/AcquireRequest.cc \
+ librbd/exclusive_lock/ReacquireRequest.cc \
librbd/exclusive_lock/ReleaseRequest.cc \
librbd/exclusive_lock/StandardPolicy.cc \
librbd/image/CloseRequest.cc \
librbd/WatchNotifyTypes.h \
librbd/exclusive_lock/AcquireRequest.h \
librbd/exclusive_lock/Policy.h \
+ librbd/exclusive_lock/ReacquireRequest.h \
librbd/exclusive_lock/ReleaseRequest.h \
librbd/exclusive_lock/StandardPolicy.h \
librbd/image/CloseRequest.h \
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/exclusive_lock/ReacquireRequest.h"
+#include "cls/lock/cls_lock_client.h"
+#include "cls/lock/cls_lock_types.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "librbd/ExclusiveLock.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/Utils.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::exclusive_lock::ReacquireRequest: " \
+ << this << ": " << __func__
+
+namespace librbd {
+namespace exclusive_lock {
+
+using librbd::util::create_rados_safe_callback;
+
+template <typename I>
+ReacquireRequest<I>::ReacquireRequest(I &image_ctx,
+ const std::string &old_cookie,
+ const std::string &new_cookie,
+ Context *on_finish)
+ : m_image_ctx(image_ctx), m_old_cookie(old_cookie), m_new_cookie(new_cookie),
+ m_on_finish(on_finish) {
+}
+
+template <typename I>
+void ReacquireRequest<I>::send() {
+ set_cookie();
+}
+
+template <typename I>
+void ReacquireRequest<I>::set_cookie() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << dendl;
+
+ librados::ObjectWriteOperation op;
+ rados::cls::lock::set_cookie(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, m_old_cookie,
+ ExclusiveLock<>::WATCHER_LOCK_TAG, m_new_cookie);
+
+ librados::AioCompletion *rados_completion = create_rados_safe_callback<
+ ReacquireRequest<I>, &ReacquireRequest<I>::handle_set_cookie>(this);
+ int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
+ rados_completion, &op);
+ assert(r == 0);
+ rados_completion->release();
+}
+
+template <typename I>
+void ReacquireRequest<I>::handle_set_cookie(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << ": r=" << r << dendl;
+
+ if (r == -EOPNOTSUPP) {
+ ldout(cct, 10) << ": OSD doesn't support updating lock" << dendl;
+ } else if (r < 0) {
+ lderr(cct) << ": failed to update lock: " << cpp_strerror(r) << dendl;
+ }
+
+ m_on_finish->complete(r);
+ delete this;
+}
+
+} // namespace exclusive_lock
+} // namespace librbd
+
+template class librbd::exclusive_lock::ReacquireRequest<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_LIBRBD_EXCLUSIVE_LOCK_REACQUIRE_REQUEST_H
+#define CEPH_LIBRBD_EXCLUSIVE_LOCK_REACQUIRE_REQUEST_H
+
+#include "include/int_types.h"
+#include <string>
+
+class Context;
+
+namespace librbd {
+
+class ImageCtx;
+
+namespace exclusive_lock {
+
+template <typename ImageCtxT = ImageCtx>
+class ReacquireRequest {
+public:
+
+ static ReacquireRequest *create(ImageCtxT &image_ctx,
+ const std::string &old_cookie,
+ const std::string &new_cookie,
+ Context *on_finish) {
+ return new ReacquireRequest(image_ctx, old_cookie, new_cookie, on_finish);
+ }
+
+ ReacquireRequest(ImageCtxT &image_ctx, const std::string &old_cookie,
+ const std::string &new_cookie, Context *on_finish);
+
+ void send();
+
+private:
+ /**
+ * @verbatim
+ *
+ * <start>
+ * |
+ * v
+ * SET_COOKIE
+ * |
+ * v
+ * <finish>
+ *
+ * @endverbatim
+ */
+ ImageCtxT &m_image_ctx;
+ std::string m_old_cookie;
+ std::string m_new_cookie;
+ Context *m_on_finish;
+
+ void set_cookie();
+ void handle_set_cookie(int r);
+
+};
+
+} // namespace exclusive_lock
+} // namespace librbd
+
+extern template class librbd::exclusive_lock::ReacquireRequest<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_EXCLUSIVE_LOCK_REACQUIRE_REQUEST_H
test/librbd/test_mock_Journal.cc \
test/librbd/test_mock_ObjectWatcher.cc \
test/librbd/exclusive_lock/test_mock_AcquireRequest.cc \
+ test/librbd/exclusive_lock/test_mock_ReacquireRequest.cc \
test/librbd/exclusive_lock/test_mock_ReleaseRequest.cc \
test/librbd/image/test_mock_RefreshRequest.cc \
test/librbd/journal/test_mock_Replay.cc \
test_mock_Journal.cc
test_mock_ObjectWatcher.cc
exclusive_lock/test_mock_AcquireRequest.cc
+ exclusive_lock/test_mock_ReacquireRequest.cc
exclusive_lock/test_mock_ReleaseRequest.cc
image/test_mock_RefreshRequest.cc
journal/test_mock_Replay.cc
--- /dev/null
+// -*- 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/librbd/mock/MockImageState.h"
+#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "test/librados_test_stub/MockTestMemRadosClient.h"
+#include "cls/lock/cls_lock_ops.h"
+#include "librbd/ExclusiveLock.h"
+#include "librbd/exclusive_lock/ReacquireRequest.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <arpa/inet.h>
+#include <list>
+
+namespace librbd {
+namespace {
+
+struct MockTestImageCtx : public librbd::MockImageCtx {
+ MockTestImageCtx(librbd::ImageCtx &image_ctx)
+ : librbd::MockImageCtx(image_ctx) {
+ }
+};
+
+} // anonymous namespace
+} // namespace librbd
+
+// template definitions
+#include "librbd/exclusive_lock/ReacquireRequest.cc"
+
+namespace librbd {
+namespace exclusive_lock {
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::StrEq;
+
+class TestMockExclusiveLockReacquireRequest : public TestMockFixture {
+public:
+ typedef ReacquireRequest<MockTestImageCtx> MockReacquireRequest;
+ typedef ExclusiveLock<MockTestImageCtx> MockExclusiveLock;
+
+ void expect_set_cookie(MockTestImageCtx &mock_image_ctx, int r) {
+ EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+ exec(mock_image_ctx.header_oid, _, StrEq("lock"),
+ StrEq("set_cookie"), _, _, _))
+ .WillOnce(Return(r));
+ }
+};
+
+TEST_F(TestMockExclusiveLockReacquireRequest, Success) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+
+ InSequence seq;
+ expect_set_cookie(mock_image_ctx, 0);
+
+ C_SaferCond ctx;
+ MockReacquireRequest *req = MockReacquireRequest::create(mock_image_ctx,
+ "old cookie",
+ "new cookie", &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockReacquireRequest, NotSupported) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+
+ InSequence seq;
+ expect_set_cookie(mock_image_ctx, -EOPNOTSUPP);
+
+ C_SaferCond ctx;
+ MockReacquireRequest *req = MockReacquireRequest::create(mock_image_ctx,
+ "old cookie",
+ "new cookie", &ctx);
+ req->send();
+ ASSERT_EQ(-EOPNOTSUPP, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockReacquireRequest, Error) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+
+ InSequence seq;
+ expect_set_cookie(mock_image_ctx, -EBUSY);
+
+ C_SaferCond ctx;
+ MockReacquireRequest *req = MockReacquireRequest::create(mock_image_ctx,
+ "old cookie",
+ "new cookie", &ctx);
+ req->send();
+ ASSERT_EQ(-EBUSY, ctx.wait());
+}
+
+} // namespace exclusive_lock
+} // namespace librbd