From: Venky Shankar Date: Mon, 20 Feb 2017 06:34:10 +0000 (+0530) Subject: librbd: acquire exclusive-lock during copy on read X-Git-Tag: v12.0.1~249^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=7dba5311b12011a4a6e8564e68150e54c5af5ddd;p=ceph.git librbd: acquire exclusive-lock during copy on read Fixes: http://tracker.ceph.com/issues/18888 Signed-off-by: Venky Shankar --- diff --git a/src/librbd/image/RefreshRequest.cc b/src/librbd/image/RefreshRequest.cc index bf64f9590c99..01db2dde0e7f 100644 --- a/src/librbd/image/RefreshRequest.cc +++ b/src/librbd/image/RefreshRequest.cc @@ -1075,6 +1075,7 @@ void RefreshRequest::apply() { // object map and journaling assert(m_exclusive_lock == nullptr); m_exclusive_lock = m_image_ctx.exclusive_lock; + m_image_ctx.io_work_queue->clear_require_lock_on_read(); } else { if (m_exclusive_lock != nullptr) { assert(m_image_ctx.exclusive_lock == nullptr); @@ -1094,6 +1095,10 @@ void RefreshRequest::apply() { m_object_map != nullptr) { std::swap(m_object_map, m_image_ctx.object_map); } + if (m_image_ctx.clone_copy_on_read && + m_image_ctx.io_work_queue->is_lock_required()) { + m_image_ctx.io_work_queue->set_require_lock_on_read(); + } } } } diff --git a/src/librbd/io/ImageRequestWQ.h b/src/librbd/io/ImageRequestWQ.h index 8bf10be4825d..a7b979e63f27 100644 --- a/src/librbd/io/ImageRequestWQ.h +++ b/src/librbd/io/ImageRequestWQ.h @@ -43,6 +43,7 @@ public: void shut_down(Context *on_shutdown); + bool is_lock_required() const; bool is_lock_request_needed() const; inline bool writes_blocked() const { @@ -114,7 +115,6 @@ private: int start_in_flight_op(AioCompletion *c); void finish_in_flight_op(); - bool is_lock_required() const; void queue(ImageRequest *req); void handle_refreshed(int r, ImageRequest *req); diff --git a/src/test/librbd/image/test_mock_RefreshRequest.cc b/src/test/librbd/image/test_mock_RefreshRequest.cc index 59932f2f8509..ea5a5dd27059 100644 --- a/src/test/librbd/image/test_mock_RefreshRequest.cc +++ b/src/test/librbd/image/test_mock_RefreshRequest.cc @@ -97,6 +97,10 @@ public: typedef RefreshRequest MockRefreshRequest; typedef RefreshParentRequest MockRefreshParentRequest; + void expect_is_lock_required(MockRefreshImageCtx &mock_image_ctx, bool require_lock) { + EXPECT_CALL(*mock_image_ctx.io_work_queue, is_lock_required()).WillOnce(Return(require_lock)); + } + void expect_set_require_lock_on_read(MockRefreshImageCtx &mock_image_ctx) { EXPECT_CALL(*mock_image_ctx.io_work_queue, set_require_lock_on_read()); } @@ -631,6 +635,7 @@ TEST_F(TestMockImageRefreshRequest, DisableExclusiveLock) { expect_get_flags(mock_image_ctx, 0); expect_get_group(mock_image_ctx, 0); expect_refresh_parent_is_required(mock_refresh_parent_request, false); + expect_clear_require_lock_on_read(mock_image_ctx); expect_shut_down_exclusive_lock(mock_image_ctx, *mock_exclusive_lock, 0); C_SaferCond ctx; @@ -735,6 +740,58 @@ TEST_F(TestMockImageRefreshRequest, JournalDisabledByPolicy) { ASSERT_EQ(0, ctx.wait()); } +TEST_F(TestMockImageRefreshRequest, ExclusiveLockWithCoR) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + std::string val; + ASSERT_EQ(0, _rados.conf_get("rbd_clone_copy_on_read", val)); + if (val == "false") { + std::cout << "SKIPPING due to disabled rbd_copy_on_read" << std::endl; + return; + } + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockRefreshImageCtx mock_image_ctx(*ictx); + MockRefreshParentRequest mock_refresh_parent_request; + + MockExclusiveLock mock_exclusive_lock; + mock_image_ctx.exclusive_lock = &mock_exclusive_lock; + + if (ictx->test_features(RBD_FEATURE_JOURNALING)) { + ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_JOURNALING, + false)); + } + + if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) { + ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_FAST_DIFF, + false)); + } + + if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { + ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_OBJECT_MAP, + false)); + } + + expect_op_work_queue(mock_image_ctx); + expect_test_features(mock_image_ctx); + + InSequence seq; + expect_get_mutable_metadata(mock_image_ctx, 0); + expect_get_flags(mock_image_ctx, 0); + expect_get_group(mock_image_ctx, 0); + expect_refresh_parent_is_required(mock_refresh_parent_request, false); + expect_is_lock_required(mock_image_ctx, true); + expect_set_require_lock_on_read(mock_image_ctx); + + C_SaferCond ctx; + MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); + req->send(); + + ASSERT_EQ(0, ctx.wait()); +} + TEST_F(TestMockImageRefreshRequest, EnableJournalWithExclusiveLock) { REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); diff --git a/src/test/librbd/mock/MockImageCtx.h b/src/test/librbd/mock/MockImageCtx.h index 1b2354df1563..61381114c3f4 100644 --- a/src/test/librbd/mock/MockImageCtx.h +++ b/src/test/librbd/mock/MockImageCtx.h @@ -51,6 +51,7 @@ struct MockImageCtx { object_set(image_ctx.object_set), old_format(image_ctx.old_format), read_only(image_ctx.read_only), + clone_copy_on_read(image_ctx.clone_copy_on_read), lockers(image_ctx.lockers), exclusive_locked(image_ctx.exclusive_locked), lock_tag(image_ctx.lock_tag), @@ -208,6 +209,8 @@ struct MockImageCtx { bool old_format; bool read_only; + bool clone_copy_on_read; + std::map lockers; bool exclusive_locked; diff --git a/src/test/librbd/mock/io/MockImageRequestWQ.h b/src/test/librbd/mock/io/MockImageRequestWQ.h index 972b75f74215..049d1bc233e0 100644 --- a/src/test/librbd/mock/io/MockImageRequestWQ.h +++ b/src/test/librbd/mock/io/MockImageRequestWQ.h @@ -18,6 +18,7 @@ struct MockImageRequestWQ { MOCK_METHOD0(set_require_lock_on_read, void()); MOCK_METHOD0(clear_require_lock_on_read, void()); + MOCK_CONST_METHOD0(is_lock_required, bool()); MOCK_CONST_METHOD0(is_lock_request_needed, bool()); };