#include "librbd/ImageState.h"
#include "librbd/ImageWatcher.h"
#include "librbd/Journal.h"
+#include "librbd/journal/StandardPolicy.h"
#include "librbd/LibrbdAdminSocketHook.h"
#include "librbd/ObjectMap.h"
#include "librbd/Operations.h"
thread_pool_singleton);
exclusive_lock_policy = new exclusive_lock::StandardPolicy(this);
+ journal_policy = new journal::StandardPolicy(this);
}
ImageCtx::~ImageCtx() {
op_work_queue->drain();
aio_work_queue->drain();
+ delete journal_policy;
delete exclusive_lock_policy;
delete op_work_queue;
delete aio_work_queue;
delete exclusive_lock_policy;
exclusive_lock_policy = policy;
}
+
+ journal::Policy *ImageCtx::get_journal_policy() const {
+ assert(snap_lock.is_locked());
+ assert(journal_policy != nullptr);
+ return journal_policy;
+ }
+
+ void ImageCtx::set_journal_policy(journal::Policy *policy) {
+ assert(snap_lock.is_wlocked());
+ assert(policy != nullptr);
+ delete journal_policy;
+ journal_policy = policy;
+ }
}
template <typename> class Operations;
namespace exclusive_lock { struct Policy; }
+ namespace journal { struct Policy; }
namespace operation {
template <typename> class ResizeRequest;
LibrbdAdminSocketHook *asok_hook;
exclusive_lock::Policy *exclusive_lock_policy = nullptr;
+ journal::Policy *journal_policy = nullptr;
static bool _filter_metadata_confs(const string &prefix, std::map<string, bool> &configs,
map<string, bufferlist> &pairs, map<string, bufferlist> *res);
exclusive_lock::Policy *get_exclusive_lock_policy() const;
void set_exclusive_lock_policy(exclusive_lock::Policy *policy);
+
+ journal::Policy *get_journal_policy() const;
+ void set_journal_policy(journal::Policy *policy);
};
}
librbd/image_watcher/Notifier.cc \
librbd/image_watcher/NotifyLockOwner.cc \
librbd/journal/Replay.cc \
+ librbd/journal/StandardPolicy.cc \
librbd/object_map/InvalidateRequest.cc \
librbd/object_map/LockRequest.cc \
librbd/object_map/Request.cc \
librbd/image/SetSnapRequest.h \
librbd/image_watcher/Notifier.h \
librbd/image_watcher/NotifyLockOwner.h \
+ librbd/journal/Policy.h \
librbd/journal/Replay.h \
+ librbd/journal/StandardPolicy.h \
librbd/journal/Types.h \
librbd/journal/TypeTraits.h \
librbd/object_map/InvalidateRequest.h \
#include "librbd/Journal.h"
#include "librbd/ObjectMap.h"
#include "librbd/Utils.h"
+#include "librbd/journal/Policy.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
this);
m_journal = m_image_ctx.create_journal();
- // journal playback required object map (if enabled) and itself
+ // journal playback requires object map (if enabled) and itself
apply();
m_journal->open(ctx);
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << __func__ << dendl;
- if (!m_journal->is_tag_owner()) {
- lderr(cct) << "local image not promoted" << dendl;
- m_error_result = -EPERM;
- send_close_journal();
- return;
- }
-
+ RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
using klass = AcquireRequest<I>;
Context *ctx = create_context_callback<
klass, &klass::handle_allocate_journal_tag>(this);
- m_journal->allocate_tag(Journal<I>::LOCAL_MIRROR_UUID, ctx);
+ m_image_ctx.get_journal_policy()->allocate_tag_on_lock(ctx);
}
template <typename I>
ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
if (*ret_val < 0) {
+ lderr(cct) << "failed to allocate journal tag: " << cpp_strerror(*ret_val)
+ << dendl;
m_error_result = *ret_val;
send_close_journal();
return nullptr;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_JOURNAL_POLICY_H
+#define CEPH_LIBRBD_JOURNAL_POLICY_H
+
+class Context;
+
+namespace librbd {
+
+namespace journal {
+
+struct Policy {
+ virtual ~Policy() {
+ }
+
+ virtual void allocate_tag_on_lock(Context *on_finish) = 0;
+ virtual void cancel_external_replay(Context *on_finish) = 0;
+};
+
+} // namespace journal
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_JOURNAL_POLICY_H
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/journal/StandardPolicy.h"
+#include "common/WorkQueue.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/Journal.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::journal::StandardPolicy: "
+
+namespace librbd {
+namespace journal {
+
+void StandardPolicy::allocate_tag_on_lock(Context *on_finish) {
+ assert(m_image_ctx->journal != nullptr);
+
+ if (!m_image_ctx->journal->is_tag_owner()) {
+ lderr(m_image_ctx->cct) << "local image not promoted" << dendl;
+ m_image_ctx->op_work_queue->queue(on_finish, -EPERM);
+ return;
+ }
+
+ m_image_ctx->journal->allocate_tag(Journal<>::LOCAL_MIRROR_UUID, on_finish);
+}
+
+void StandardPolicy::cancel_external_replay(Context *on_finish) {
+ // external replay is only handled by rbd-mirror
+ assert(false);
+}
+
+} // namespace journal
+} // namespace librbd
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_JOURNAL_STANDARD_POLICY_H
+#define CEPH_LIBRBD_JOURNAL_STANDARD_POLICY_H
+
+#include "librbd/journal/Policy.h"
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace journal {
+
+class StandardPolicy : public Policy {
+public:
+ StandardPolicy(ImageCtx *image_ctx) : m_image_ctx(image_ctx) {
+ }
+
+ virtual void allocate_tag_on_lock(Context *on_finish);
+ virtual void cancel_external_replay(Context *on_finish);
+
+private:
+ ImageCtx *m_image_ctx;
+};
+
+} // namespace journal
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_JOURNAL_STANDARD_POLICY_H
test/librbd/mock/MockImageState.h \
test/librbd/mock/MockImageWatcher.h \
test/librbd/mock/MockJournal.h \
+ test/librbd/mock/MockJournalPolicy.h \
test/librbd/mock/MockObjectMap.h \
test/librbd/mock/MockOperations.h \
test/librbd/mock/MockReadahead.h \
#include "test/librbd/test_support.h"
#include "test/librbd/mock/MockImageCtx.h"
#include "test/librbd/mock/MockJournal.h"
+#include "test/librbd/mock/MockJournalPolicy.h"
#include "test/librbd/mock/MockObjectMap.h"
#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
#include "test/librados_test_stub/MockTestMemRadosClient.h"
.WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
}
- void expect_is_journal_tag_owner(MockJournal &mock_journal, bool owner) {
- EXPECT_CALL(mock_journal, is_tag_owner()).WillOnce(Return(owner));
+ void expect_get_journal_policy(MockImageCtx &mock_image_ctx,
+ MockJournalPolicy &mock_journal_policy) {
+ EXPECT_CALL(mock_image_ctx, get_journal_policy())
+ .WillOnce(Return(&mock_journal_policy));
}
void expect_allocate_journal_tag(MockImageCtx &mock_image_ctx,
- MockJournal &mock_journal, int r) {
- EXPECT_CALL(mock_journal, allocate_tag("", _))
- .WillOnce(WithArg<1>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)));
+ MockJournalPolicy &mock_journal_policy,
+ int r) {
+ EXPECT_CALL(mock_journal_policy, allocate_tag_on_lock(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
}
void expect_get_lock_info(MockImageCtx &mock_image_ctx, int r,
expect_open_object_map(mock_image_ctx, mock_object_map);
MockJournal mock_journal;
+ MockJournalPolicy mock_journal_policy;
expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
expect_create_journal(mock_image_ctx, &mock_journal);
expect_open_journal(mock_image_ctx, mock_journal, 0);
- expect_is_journal_tag_owner(mock_journal, true);
- expect_allocate_journal_tag(mock_image_ctx, mock_journal, 0);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
C_SaferCond acquire_ctx;
C_SaferCond ctx;
expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
MockJournal mock_journal;
+ MockJournalPolicy mock_journal_policy;
expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
expect_create_journal(mock_image_ctx, &mock_journal);
expect_open_journal(mock_image_ctx, mock_journal, 0);
- expect_is_journal_tag_owner(mock_journal, true);
- expect_allocate_journal_tag(mock_image_ctx, mock_journal, 0);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
C_SaferCond acquire_ctx;
C_SaferCond ctx;
ASSERT_EQ(-EINVAL, ctx.wait());
}
-TEST_F(TestMockExclusiveLockAcquireRequest, NotJournalTagOwner) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
-
- MockObjectMap *mock_object_map = new MockObjectMap();
- expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
- expect_create_object_map(mock_image_ctx, mock_object_map);
- expect_open_object_map(mock_image_ctx, *mock_object_map);
-
- MockJournal *mock_journal = new MockJournal();
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
- expect_create_journal(mock_image_ctx, mock_journal);
- expect_open_journal(mock_image_ctx, *mock_journal, 0);
- expect_is_journal_tag_owner(*mock_journal, false);
- expect_close_journal(mock_image_ctx, *mock_journal);
- expect_close_object_map(mock_image_ctx, *mock_object_map);
-
- C_SaferCond acquire_ctx;
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(-EPERM, ctx.wait());
-}
-
TEST_F(TestMockExclusiveLockAcquireRequest, AllocateJournalTagError) {
REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
expect_open_object_map(mock_image_ctx, *mock_object_map);
MockJournal *mock_journal = new MockJournal();
+ MockJournalPolicy mock_journal_policy;
expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
expect_create_journal(mock_image_ctx, mock_journal);
expect_open_journal(mock_image_ctx, *mock_journal, 0);
- expect_is_journal_tag_owner(*mock_journal, true);
- expect_allocate_journal_tag(mock_image_ctx, *mock_journal, -ESTALE);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, -EPERM);
expect_close_journal(mock_image_ctx, *mock_journal);
expect_close_object_map(mock_image_ctx, *mock_object_map);
TEST_COOKIE,
&acquire_ctx, &ctx);
req->send();
- ASSERT_EQ(-ESTALE, ctx.wait());
+ ASSERT_EQ(-EPERM, ctx.wait());
}
TEST_F(TestMockExclusiveLockAcquireRequest, LockBusy) {
MOCK_METHOD0(notify_update, void());
MOCK_METHOD1(notify_update, void(Context *));
+ MOCK_CONST_METHOD0(get_journal_policy, journal::Policy*());
+
ImageCtx *image_ctx;
CephContext *cct;
--- /dev/null
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_TEST_LIBRBD_MOCK_JOURNAL_POLICY_H
+#define CEPH_TEST_LIBRBD_MOCK_JOURNAL_POLICY_H
+
+#include "librbd/journal/Policy.h"
+#include "gmock/gmock.h"
+
+namespace librbd {
+
+struct MockJournalPolicy : public journal::Policy {
+
+ MOCK_METHOD1(allocate_tag_on_lock, void(Context*));
+ MOCK_METHOD1(cancel_external_replay, void(Context*));
+
+};
+
+} // namespace librbd
+
+#endif // CEPH_TEST_LIBRBD_MOCK_JOURNAL_POLICY_H