From 0514480b16b0a1e76a9ba31cc3ba58a32b7bee18 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Thu, 8 Mar 2018 17:26:27 +0100 Subject: [PATCH] librbd: create+truncate for whole-object layered discards A whole-object layered discard is implemented as a truncate rather than a delete: a dummy object is needed to prevent the CoW machinery from kicking in. However, a truncate on a non-existent object is a no-op. If the object doesn't exist in HEAD, a discard request is effectively ignored -- parent blocks are still seen afterwards. A non-exclusive create on an existing object is also a no-op, so the fix is to do a compound create+truncate instead. Fixes: http://tracker.ceph.com/issues/23285 Signed-off-by: Ilya Dryomov --- src/librbd/io/ObjectRequest.h | 4 +++- src/test/librbd/io/test_mock_ObjectRequest.cc | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librbd/io/ObjectRequest.h b/src/librbd/io/ObjectRequest.h index f51263326937d..3ea10c04058c2 100644 --- a/src/librbd/io/ObjectRequest.h +++ b/src/librbd/io/ObjectRequest.h @@ -357,7 +357,7 @@ public: case DISCARD_ACTION_REMOVE: return "remove"; case DISCARD_ACTION_REMOVE_TRUNCATE: - return "remove (truncate)"; + return "remove (create+truncate)"; case DISCARD_ACTION_TRUNCATE: return "truncate"; case DISCARD_ACTION_ZERO: @@ -395,6 +395,8 @@ protected: wr->remove(); break; case DISCARD_ACTION_REMOVE_TRUNCATE: + wr->create(false); + // fall through case DISCARD_ACTION_TRUNCATE: wr->truncate(this->m_object_off); break; diff --git a/src/test/librbd/io/test_mock_ObjectRequest.cc b/src/test/librbd/io/test_mock_ObjectRequest.cc index 1953b067a2f78..449f8058c321d 100644 --- a/src/test/librbd/io/test_mock_ObjectRequest.cc +++ b/src/test/librbd/io/test_mock_ObjectRequest.cc @@ -288,6 +288,11 @@ struct TestMockIoObjectRequest : public TestMockFixture { } } + void expect_create(MockTestImageCtx &mock_image_ctx, bool exclusive) { + EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx), create(_, exclusive)) + .Times(1); + } + void expect_truncate(MockTestImageCtx &mock_image_ctx, int offset, int r) { auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx), truncate(_, offset, _)); @@ -1000,6 +1005,7 @@ TEST_F(TestMockIoObjectRequest, DiscardRemoveTruncate) { expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096); expect_object_may_exist(mock_image_ctx, 0, false); expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0); + expect_create(mock_image_ctx, false); expect_truncate(mock_image_ctx, 0, 0); C_SaferCond ctx; -- 2.39.5