diff --git a/src/librbd/exclusive_lock/BreakRequest.cc b/src/librbd/exclusive_lock/BreakRequest.cc index 8b889e704da84..c4315200ebdfa 100644 --- a/src/librbd/exclusive_lock/BreakRequest.cc +++ b/src/librbd/exclusive_lock/BreakRequest.cc @@ -112,7 +112,16 @@ void BreakRequest::send_blacklist() { } CephContext *cct = m_image_ctx.cct; - ldout(cct, 10) << dendl; + entity_name_t entity_name = entity_name_t::CLIENT( + m_image_ctx.md_ctx.get_instance_id()); + ldout(cct, 10) << "local entity=" << entity_name << ", " + << "locker entity=" << m_locker.entity << dendl; + + if (m_locker.entity == entity_name) { + lderr(cct) << "attempting to self-blacklist" << dendl; + finish(-EINVAL); + return; + } // TODO: need async version of RadosClient::blacklist_add using klass = BreakRequest; diff --git a/src/test/librados_test_stub/MockTestMemIoCtxImpl.h b/src/test/librados_test_stub/MockTestMemIoCtxImpl.h index adfe6f8d0a0e5..99c2ee2c8fba5 100644 --- a/src/test/librados_test_stub/MockTestMemIoCtxImpl.h +++ b/src/test/librados_test_stub/MockTestMemIoCtxImpl.h @@ -60,6 +60,11 @@ class MockTestMemIoCtxImpl : public TestMemIoCtxImpl { snapc); } + MOCK_CONST_METHOD0(get_instance_id, uint64_t()); + uint64_t do_get_instance_id() const { + return TestMemIoCtxImpl::get_instance_id(); + } + MOCK_METHOD2(list_snaps, int(const std::string& o, snap_set_t *out_snaps)); int do_list_snaps(const std::string& o, snap_set_t *out_snaps) { return TestMemIoCtxImpl::list_snaps(o, out_snaps); @@ -143,6 +148,7 @@ class MockTestMemIoCtxImpl : public TestMemIoCtxImpl { ON_CALL(*this, aio_watch(_, _, _, _)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_aio_watch)); ON_CALL(*this, aio_unwatch(_, _)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_aio_unwatch)); ON_CALL(*this, exec(_, _, _, _, _, _, _)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_exec)); + ON_CALL(*this, get_instance_id()).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_get_instance_id)); ON_CALL(*this, list_snaps(_, _)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_list_snaps)); ON_CALL(*this, list_watchers(_, _)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_list_watchers)); ON_CALL(*this, notify(_, _, _, _)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_notify)); diff --git a/src/test/librbd/exclusive_lock/test_mock_BreakRequest.cc b/src/test/librbd/exclusive_lock/test_mock_BreakRequest.cc index 27bb8e1272552..802a4e97fcf31 100644 --- a/src/test/librbd/exclusive_lock/test_mock_BreakRequest.cc +++ b/src/test/librbd/exclusive_lock/test_mock_BreakRequest.cc @@ -72,6 +72,11 @@ class TestMockExclusiveLockBreakRequest : public TestMockFixture { exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("break_lock"), _, _, _)) .WillOnce(Return(r)); } + + void expect_get_instance_id(MockTestImageCtx &mock_image_ctx, uint64_t id) { + EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), get_instance_id()) + .WillOnce(Return(id)); + } }; TEST_F(TestMockExclusiveLockBreakRequest, DeadLockOwner) { @@ -179,6 +184,27 @@ TEST_F(TestMockExclusiveLockBreakRequest, BlacklistDisabled) { ASSERT_EQ(0, ctx.wait()); } +TEST_F(TestMockExclusiveLockBreakRequest, BlacklistSelf) { + 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_list_watchers(mock_image_ctx, 0, "dead client", 456); + expect_get_instance_id(mock_image_ctx, 456); + + C_SaferCond ctx; + Locker locker{entity_name_t::CLIENT(456), "auto 123", "1.2.3.4:0/0", 123}; + MockBreakRequest *req = MockBreakRequest::create(mock_image_ctx, locker, + true, false, &ctx); + req->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + TEST_F(TestMockExclusiveLockBreakRequest, BlacklistError) { REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);