]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: avoid failing IO with -ESHUTDOWN when disabling exclusive-lock 37581/head
authorJason Dillaman <dillaman@redhat.com>
Wed, 7 Oct 2020 14:58:57 +0000 (10:58 -0400)
committerJason Dillaman <dillaman@redhat.com>
Wed, 7 Oct 2020 15:04:41 +0000 (11:04 -0400)
When dynamically disabling the exclusive-lock feature with in-flight IO,
it was previously possible for IO to fail with -ESHUTDOWN when it
attempts to acquire the lock due to the PreReleaseRequest setting the
lock required flag. There is also the possibility for a race with the
first IO racing with exclusive-lock shutdown when the lock was not
already acquired.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/exclusive_lock/ImageDispatch.cc
src/librbd/exclusive_lock/PreReleaseRequest.cc
src/test/librbd/exclusive_lock/test_mock_PreReleaseRequest.cc

index c4e04970a7cdf433438c900c5df137dbadf94d6f..cd7f450f2751532677076413ab612c8378464f55 100644 (file)
@@ -290,7 +290,9 @@ void ImageDispatch<I>::handle_acquire_lock(int r) {
 
   Context* failed_dispatch = nullptr;
   Contexts on_dispatches;
-  if (r < 0) {
+  if (r == -ESHUTDOWN) {
+    ldout(cct, 5) << "IO raced with exclusive lock shutdown" << dendl;
+  } else if (r < 0) {
     lderr(cct) << "failed to acquire exclusive lock: " << cpp_strerror(r)
                << dendl;
     failed_dispatch = m_on_dispatches.front();
index 83799eb5a245cafeca2fd131e082aba19d2997b5..94fe640ba2ff5261070e7d79e9b1d5c94c8aedea 100644 (file)
@@ -84,6 +84,12 @@ void PreReleaseRequest<I>::handle_cancel_op_requests(int r) {
 
 template <typename I>
 void PreReleaseRequest<I>::send_set_require_lock() {
+  if (!m_image_ctx.test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    // exclusive-lock was disabled, no need to block IOs
+    send_wait_for_ops();
+    return;
+  }
+
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << dendl;
 
index 1abf291fa5d54f0cb13362fb18e1534f9de7c3f2..c1c2aa4435a0cd0fbd08c81442223f912ebd88c0 100644 (file)
@@ -98,6 +98,7 @@ public:
   void expect_set_require_lock(MockTestImageCtx &mock_image_ctx,
                                MockImageDispatch &mock_image_dispatch,
                                bool init_shutdown, int r) {
+    expect_test_features(mock_image_ctx, RBD_FEATURE_EXCLUSIVE_LOCK, true);
     expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
                          ((mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0));
     if (mock_image_ctx.clone_copy_on_read ||
@@ -335,5 +336,48 @@ TEST_F(TestMockExclusiveLockPreReleaseRequest, Blocklisted) {
   ASSERT_EQ(0, ctx.wait());
 }
 
+TEST_F(TestMockExclusiveLockPreReleaseRequest, Disabled) {
+  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
+
+  InSequence seq;
+
+  expect_cancel_op_requests(mock_image_ctx, 0);
+  MockImageDispatch mock_image_dispatch;
+
+  expect_test_features(mock_image_ctx, RBD_FEATURE_EXCLUSIVE_LOCK, false);
+
+  expect_prepare_lock(mock_image_ctx);
+
+  expect_close_image_cache(mock_image_ctx, 0);
+
+  expect_invalidate_cache(mock_image_ctx, 0);
+
+  expect_flush_io(mock_image_ctx, 0);
+
+  expect_flush_notifies(mock_image_ctx);
+
+  MockJournal mock_journal;
+  mock_image_ctx.journal = &mock_journal;
+  expect_close_journal(mock_image_ctx, mock_journal, -EINVAL);
+
+  MockObjectMap mock_object_map;
+  mock_image_ctx.object_map = &mock_object_map;
+  expect_close_object_map(mock_image_ctx, mock_object_map);
+
+  expect_handle_prepare_lock_complete(mock_image_ctx);
+
+  C_SaferCond ctx;
+  MockPreReleaseRequest *req = MockPreReleaseRequest::create(
+    mock_image_ctx, &mock_image_dispatch, false, m_async_op_tracker, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+}
+
 } // namespace exclusive_lock
 } // namespace librbd