This will be used in the case where the journal is being disabled.
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
librbd/image/SetSnapRequest.h \
librbd/image_watcher/Notifier.h \
librbd/image_watcher/NotifyLockOwner.h \
- librbd/journal/RemoveRequest.h \
librbd/journal/CreateRequest.h \
+ librbd/journal/DisabledPolicy.h \
librbd/journal/Policy.h \
+ librbd/journal/RemoveRequest.h \
librbd/journal/Replay.h \
librbd/journal/StandardPolicy.h \
librbd/journal/Types.h \
m_on_acquire->complete(0);
m_on_acquire = nullptr;
- if (!m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
+ bool journal_enabled;
+ {
+ RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+ journal_enabled = (m_image_ctx.test_features(RBD_FEATURE_JOURNALING,
+ m_image_ctx.snap_lock) &&
+ !m_image_ctx.get_journal_policy()->journal_disabled());
+ }
+ if (!journal_enabled) {
apply();
return m_on_finish;
}
#include "librbd/ObjectMap.h"
#include "librbd/Utils.h"
#include "librbd/image/RefreshParentRequest.h"
+#include "librbd/journal/Policy.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
template <typename I>
void RefreshRequest<I>::send_v2_open_journal() {
- if ((m_features & RBD_FEATURE_JOURNALING) == 0 ||
- m_image_ctx.read_only ||
- !m_image_ctx.snap_name.empty() ||
- m_image_ctx.journal != nullptr ||
- m_image_ctx.exclusive_lock == nullptr ||
- !m_image_ctx.exclusive_lock->is_lock_owner()) {
+ bool journal_disabled = (
+ (m_features & RBD_FEATURE_JOURNALING) == 0 ||
+ m_image_ctx.read_only ||
+ !m_image_ctx.snap_name.empty() ||
+ m_image_ctx.journal != nullptr ||
+ m_image_ctx.exclusive_lock == nullptr ||
+ !m_image_ctx.exclusive_lock->is_lock_owner());
+ bool journal_disabled_by_policy;
+ {
+ RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+ journal_disabled_by_policy = (
+ !journal_disabled &&
+ m_image_ctx.get_journal_policy()->journal_disabled());
+ }
+ if (journal_disabled || journal_disabled_by_policy) {
// journal dynamically enabled -- doesn't own exclusive lock
if ((m_features & RBD_FEATURE_JOURNALING) != 0 &&
+ !journal_disabled_by_policy &&
m_image_ctx.exclusive_lock != nullptr &&
m_image_ctx.journal == nullptr) {
m_image_ctx.aio_work_queue->set_require_lock_on_read();
--- /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_DISABLED_POLICY_H
+#define CEPH_LIBRBD_JOURNAL_DISABLED_POLICY_H
+
+#include "librbd/journal/Policy.h"
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace journal {
+
+class DisabledPolicy : public Policy {
+public:
+ virtual bool append_disabled() const {
+ assert(false);
+ return false;
+ }
+ virtual bool journal_disabled() const {
+ return true;
+ }
+ virtual void allocate_tag_on_lock(Context *on_finish) {
+ assert(false);
+ }
+};
+
+} // namespace journal
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_JOURNAL_DISABLED_POLICY_H
}
virtual bool append_disabled() const = 0;
+ virtual bool journal_disabled() const = 0;
virtual void allocate_tag_on_lock(Context *on_finish) = 0;
};
virtual bool append_disabled() const {
return false;
}
+ virtual bool journal_disabled() const {
+ return false;
+ }
virtual void allocate_tag_on_lock(Context *on_finish);
private:
.WillOnce(Return(enabled));
}
+ void expect_test_features(MockImageCtx &mock_image_ctx, uint64_t features,
+ RWLock &lock, bool enabled) {
+ EXPECT_CALL(mock_image_ctx, test_features(features, _))
+ .WillOnce(Return(enabled));
+ }
+
void expect_lock(MockImageCtx &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("lock"), _, _, _))
.WillOnce(Return(&mock_journal_policy));
}
+ void expect_journal_disabled(MockJournalPolicy &mock_journal_policy,
+ bool disabled) {
+ EXPECT_CALL(mock_journal_policy, journal_disabled())
+ .WillOnce(Return(disabled));
+ }
+
void expect_allocate_journal_tag(MockImageCtx &mock_image_ctx,
MockJournalPolicy &mock_journal_policy,
int r) {
MockJournal mock_journal;
MockJournalPolicy mock_journal_policy;
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
expect_create_journal(mock_image_ctx, &mock_journal);
expect_open_journal(mock_image_ctx, mock_journal, 0);
expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
MockObjectMap mock_object_map;
expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, false);
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, false);
C_SaferCond acquire_ctx;
C_SaferCond ctx;
expect_create_object_map(mock_image_ctx, &mock_object_map);
expect_open_object_map(mock_image_ctx, mock_object_map, 0);
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, false);
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, false);
C_SaferCond acquire_ctx;
C_SaferCond ctx;
MockJournal mock_journal;
MockJournalPolicy mock_journal_policy;
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
expect_create_journal(mock_image_ctx, &mock_journal);
expect_open_journal(mock_image_ctx, mock_journal, 0);
expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
expect_open_object_map(mock_image_ctx, *mock_object_map, 0);
MockJournal *mock_journal = new MockJournal();
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
+ MockJournalPolicy mock_journal_policy;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
expect_create_journal(mock_image_ctx, mock_journal);
expect_open_journal(mock_image_ctx, *mock_journal, -EINVAL);
expect_close_journal(mock_image_ctx, *mock_journal);
MockJournal *mock_journal = new MockJournal();
MockJournalPolicy mock_journal_policy;
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
expect_create_journal(mock_image_ctx, mock_journal);
expect_open_journal(mock_image_ctx, *mock_journal, 0);
expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
MockJournal mock_journal;
MockJournalPolicy mock_journal_policy;
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
expect_create_journal(mock_image_ctx, &mock_journal);
expect_open_journal(mock_image_ctx, mock_journal, 0);
expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
#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"
EXPECT_CALL(mock_exclusive_lock, is_lock_owner()).WillOnce(Return(is_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_journal_disabled(MockJournalPolicy &mock_journal_policy,
+ bool disabled) {
+ EXPECT_CALL(mock_journal_policy, journal_disabled())
+ .WillOnce(Return(disabled));
+ }
+
void expect_open_journal(MockRefreshImageCtx &mock_image_ctx,
MockJournal &mock_journal, int r) {
EXPECT_CALL(mock_image_ctx, create_journal())
ASSERT_EQ(-ERESTART, ctx.wait());
}
+
+TEST_F(TestMockImageRefreshRequest, JournalDisabledByPolicy) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) {
+ ASSERT_EQ(0, update_features(ictx, RBD_FEATURE_FAST_DIFF , false));
+ }
+
+ if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+ ASSERT_EQ(0, update_features(ictx, RBD_FEATURE_OBJECT_MAP , false));
+ }
+
+ MockRefreshImageCtx mock_image_ctx(*ictx);
+ MockRefreshParentRequest mock_refresh_parent_request;
+
+ MockExclusiveLock mock_exclusive_lock;
+ mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
+ MockJournal mock_journal;
+
+ expect_op_work_queue(mock_image_ctx);
+ expect_test_features(mock_image_ctx);
+ expect_is_exclusive_lock_owner(mock_exclusive_lock, true);
+
+ InSequence seq;
+ expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_flags(mock_image_ctx, 0);
+ expect_refresh_parent_is_required(mock_refresh_parent_request, false);
+
+ MockJournalPolicy mock_journal_policy;
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, true);
+
+ C_SaferCond ctx;
+ MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, &ctx);
+ req->send();
+
+ ASSERT_EQ(0, ctx.wait());
+}
+
TEST_F(TestMockImageRefreshRequest, EnableJournalWithExclusiveLock) {
REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
expect_get_mutable_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
+
+ MockJournalPolicy mock_journal_policy;
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
expect_open_journal(mock_image_ctx, mock_journal, 0);
C_SaferCond ctx;
struct MockJournalPolicy : public journal::Policy {
MOCK_CONST_METHOD0(append_disabled, bool());
+ MOCK_CONST_METHOD0(journal_disabled, bool());
MOCK_METHOD1(allocate_tag_on_lock, void(Context*));
};
virtual bool append_disabled() const {
return true;
}
+ virtual bool journal_disabled() const {
+ return false;
+ }
virtual void allocate_tag_on_lock(Context *on_finish) {
on_finish->complete(0);
// avoid recording any events to the local journal
return true;
}
+ virtual bool journal_disabled() const {
+ return false;
+ }
virtual void allocate_tag_on_lock(Context *on_finish) {
// rbd-mirror will manually create tags by copying them from the peer