From 1a2709c35a12f458f236ea0e0d936fd4fdedf5cc Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Thu, 30 Aug 2018 15:12:27 -0400 Subject: [PATCH] librbd: assume lock is unlocked if blacklisted or object deleted This will ensure that it's possible to potentially re-acquire the lock should the blacklist expire before the image is closed. Fixes: http://tracker.ceph.com/issues/34534 Signed-off-by: Jason Dillaman (cherry picked from commit 60064f68f5dd2bbf5fbab95564fa522335091f4a) --- src/librbd/ManagedLock.cc | 7 ++-- src/test/librbd/test_mock_ManagedLock.cc | 47 +++++++++++++++++++++++- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/librbd/ManagedLock.cc b/src/librbd/ManagedLock.cc index 6900427ccf403..86b63c062c364 100644 --- a/src/librbd/ManagedLock.cc +++ b/src/librbd/ManagedLock.cc @@ -696,12 +696,13 @@ void ManagedLock::handle_release_lock(int r) { Mutex::Locker locker(m_lock); assert(m_state == STATE_RELEASING); - if (r >= 0) { + if (r >= 0 || r == -EBLACKLISTED || r == -ENOENT) { m_cookie = ""; + m_post_next_state = STATE_UNLOCKED; + } else { + m_post_next_state = STATE_LOCKED; } - m_post_next_state = r < 0 ? STATE_LOCKED : STATE_UNLOCKED; - m_work_queue->queue(new FunctionContext([this, r](int ret) { post_release_lock_handler(false, r, create_context_callback< ManagedLock, &ManagedLock::handle_post_release_lock>(this)); diff --git a/src/test/librbd/test_mock_ManagedLock.cc b/src/test/librbd/test_mock_ManagedLock.cc index f93961afbd5d1..8668485acc273 100644 --- a/src/test/librbd/test_mock_ManagedLock.cc +++ b/src/test/librbd/test_mock_ManagedLock.cc @@ -35,7 +35,11 @@ struct MockMockManagedLock : public ManagedLock { librbd::managed_lock::EXCLUSIVE, true, 0) { }; virtual ~MockMockManagedLock() = default; + MOCK_METHOD2(post_reacquire_lock_handler, void(int, Context*)); + + MOCK_METHOD2(pre_release_lock_handler, void(bool, Context*)); + MOCK_METHOD3(post_release_lock_handler, void(bool, int, Context*)); }; namespace managed_lock { @@ -158,6 +162,7 @@ using ::testing::DoAll; using ::testing::Invoke; using ::testing::InSequence; using ::testing::Return; +using ::testing::WithArg; class TestMockManagedLock : public TestMockFixture { public: @@ -212,6 +217,23 @@ public: on_finish->complete(r);})); } + void expect_pre_release_lock_handler(MockMockManagedLock &managed_lock, + bool shutting_down, int r) { + EXPECT_CALL(managed_lock, pre_release_lock_handler(shutting_down, _)) + .WillOnce(WithArg<1>(Invoke([r](Context *on_finish){ + on_finish->complete(r); + }))); + } + + void expect_post_release_lock_handler(MockMockManagedLock &managed_lock, + bool shutting_down, int expect_r, + int r) { + EXPECT_CALL(managed_lock, post_release_lock_handler(shutting_down, expect_r, _)) + .WillOnce(WithArg<2>(Invoke([r](Context *on_finish){ + on_finish->complete(r); + }))); + } + int when_acquire_lock(MockManagedLock &managed_lock) { C_SaferCond ctx; { @@ -379,6 +401,28 @@ TEST_F(TestMockManagedLock, ReleaseLockUnlockedState) { ASSERT_EQ(0, when_shut_down(managed_lock)); } +TEST_F(TestMockManagedLock, ReleaseLockBlacklist) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockManagedLockImageCtx mock_image_ctx(*ictx); + MockMockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, + ictx->header_oid, mock_image_ctx.image_watcher, + librbd::managed_lock::EXCLUSIVE, true, 0); + InSequence seq; + + MockAcquireRequest try_lock_acquire; + expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, try_lock_acquire, 0); + ASSERT_EQ(0, when_acquire_lock(managed_lock)); + + expect_pre_release_lock_handler(managed_lock, false, -EBLACKLISTED); + expect_post_release_lock_handler(managed_lock, false, -EBLACKLISTED, -EBLACKLISTED); + ASSERT_EQ(-EBLACKLISTED, when_release_lock(managed_lock)); + ASSERT_FALSE(is_lock_owner(managed_lock)); + + ASSERT_EQ(0, when_shut_down(managed_lock)); +} + TEST_F(TestMockManagedLock, ReleaseLockError) { librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -549,8 +593,9 @@ TEST_F(TestMockManagedLock, ReacquireWithSameCookie) { ASSERT_TRUE(is_lock_owner(managed_lock)); MockReleaseRequest shutdown_release; + expect_pre_release_lock_handler(managed_lock, true, 0); expect_release_lock(ictx->op_work_queue, shutdown_release, 0); - //ASSERT_EQ(0, when_release_lock(managed_lock)); + expect_post_release_lock_handler(managed_lock, true, 0, 0); ASSERT_EQ(0, when_shut_down(managed_lock)); } -- 2.39.5