From 5a1cb469879157297ab456261f9335d8b855684f Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Mon, 24 Sep 2018 14:45:09 -0400 Subject: [PATCH] librbd: do not invalidate object map if update races with copyup The copyup state machine needs to iterate over all object maps to update the existence for the object. If an snapshot is being removed concurrently, it's possible to invalidate the object map for the image. Fixes: http://tracker.ceph.com/issues/24516 Signed-off-by: Jason Dillaman --- src/librbd/ObjectMap.cc | 6 +-- src/librbd/ObjectMap.h | 21 ++++++---- src/librbd/deep_copy/ObjectCopyRequest.cc | 2 +- src/librbd/io/CopyupRequest.cc | 6 +-- src/librbd/io/ObjectRequest.cc | 5 ++- src/librbd/object_map/UpdateRequest.cc | 9 +++- src/librbd/object_map/UpdateRequest.h | 13 ++++-- src/librbd/operation/TrimRequest.cc | 4 +- .../deep_copy/test_mock_ObjectCopyRequest.cc | 8 ++-- src/test/librbd/io/test_mock_ObjectRequest.cc | 4 +- src/test/librbd/mock/MockObjectMap.h | 15 ++++--- .../object_map/test_mock_UpdateRequest.cc | 39 +++++++++++++++--- .../librbd/operation/test_mock_TrimRequest.cc | 4 +- src/test/librbd/test_mock_ObjectMap.cc | 41 +++++++++++-------- 14 files changed, 116 insertions(+), 61 deletions(-) diff --git a/src/librbd/ObjectMap.cc b/src/librbd/ObjectMap.cc index 870049be71da1..50cbfda89220e 100644 --- a/src/librbd/ObjectMap.cc +++ b/src/librbd/ObjectMap.cc @@ -286,7 +286,7 @@ void ObjectMap::detained_aio_update(UpdateOperation &&op) { handle_detained_aio_update(cell, r, on_finish); }); aio_update(CEPH_NOSNAP, op.start_object_no, op.end_object_no, op.new_state, - op.current_state, op.parent_trace, ctx); + op.current_state, op.parent_trace, op.ignore_enoent, ctx); } template @@ -314,7 +314,7 @@ void ObjectMap::aio_update(uint64_t snap_id, uint64_t start_object_no, uint64_t end_object_no, uint8_t new_state, const boost::optional ¤t_state, const ZTracer::Trace &parent_trace, - Context *on_finish) { + bool ignore_enoent, Context *on_finish) { ceph_assert(m_image_ctx.snap_lock.is_locked()); ceph_assert((m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0); ceph_assert(m_image_ctx.image_watcher != nullptr); @@ -354,7 +354,7 @@ void ObjectMap::aio_update(uint64_t snap_id, uint64_t start_object_no, auto req = object_map::UpdateRequest::create( m_image_ctx, &m_object_map, snap_id, start_object_no, end_object_no, - new_state, current_state, parent_trace, on_finish); + new_state, current_state, parent_trace, ignore_enoent, on_finish); req->send(); } diff --git a/src/librbd/ObjectMap.h b/src/librbd/ObjectMap.h index ad393ef15d9e7..bfde572a1d18d 100644 --- a/src/librbd/ObjectMap.h +++ b/src/librbd/ObjectMap.h @@ -57,17 +57,19 @@ public: template bool aio_update(uint64_t snap_id, uint64_t start_object_no, uint8_t new_state, const boost::optional ¤t_state, - const ZTracer::Trace &parent_trace, T *callback_object) { + const ZTracer::Trace &parent_trace, bool ignore_enoent, + T *callback_object) { return aio_update(snap_id, start_object_no, start_object_no + 1, new_state, current_state, parent_trace, - callback_object); + ignore_enoent, callback_object); } template bool aio_update(uint64_t snap_id, uint64_t start_object_no, uint64_t end_object_no, uint8_t new_state, const boost::optional ¤t_state, - const ZTracer::Trace &parent_trace, T *callback_object) { + const ZTracer::Trace &parent_trace, bool ignore_enoent, + T *callback_object) { ceph_assert(start_object_no < end_object_no); if (snap_id == CEPH_NOSNAP) { end_object_no = std::min(end_object_no, m_object_map.size()); @@ -89,12 +91,13 @@ public: UpdateOperation update_operation(start_object_no, end_object_no, new_state, current_state, parent_trace, + ignore_enoent, util::create_context_callback( callback_object)); detained_aio_update(std::move(update_operation)); } else { aio_update(snap_id, start_object_no, end_object_no, new_state, - current_state, parent_trace, + current_state, parent_trace, ignore_enoent, util::create_context_callback(callback_object)); } return true; @@ -111,15 +114,18 @@ private: uint8_t new_state; boost::optional current_state; ZTracer::Trace parent_trace; + bool ignore_enoent; Context *on_finish; UpdateOperation(uint64_t start_object_no, uint64_t end_object_no, uint8_t new_state, const boost::optional ¤t_state, - const ZTracer::Trace &parent_trace, Context *on_finish) + const ZTracer::Trace &parent_trace, + bool ignore_enoent, Context *on_finish) : start_object_no(start_object_no), end_object_no(end_object_no), new_state(new_state), current_state(current_state), - parent_trace(parent_trace), on_finish(on_finish) { + parent_trace(parent_trace), ignore_enoent(ignore_enoent), + on_finish(on_finish) { } }; @@ -138,7 +144,8 @@ private: void aio_update(uint64_t snap_id, uint64_t start_object_no, uint64_t end_object_no, uint8_t new_state, const boost::optional ¤t_state, - const ZTracer::Trace &parent_trace, Context *on_finish); + const ZTracer::Trace &parent_trace, bool ignore_enoent, + Context *on_finish); bool update_required(const ceph::BitVector<2>::Iterator &it, uint8_t new_state); diff --git a/src/librbd/deep_copy/ObjectCopyRequest.cc b/src/librbd/deep_copy/ObjectCopyRequest.cc index 78ef97fb47163..096b3cb1a3a7a 100644 --- a/src/librbd/deep_copy/ObjectCopyRequest.cc +++ b/src/librbd/deep_copy/ObjectCopyRequest.cc @@ -473,7 +473,7 @@ void ObjectCopyRequest::send_update_object_map() { m_dst_image_ctx->object_map_lock.get_write(); bool sent = m_dst_image_ctx->object_map->template aio_update< Context, &Context::complete>(dst_snap_id, m_dst_object_number, object_state, - {}, {}, ctx); + {}, {}, false, ctx); m_dst_image_ctx->object_map_lock.put_write(); m_dst_image_ctx->snap_lock.put_read(); m_dst_image_ctx->owner_lock.put_read(); diff --git a/src/librbd/io/CopyupRequest.cc b/src/librbd/io/CopyupRequest.cc index dbb3f0f89e5d6..0def795f1a845 100644 --- a/src/librbd/io/CopyupRequest.cc +++ b/src/librbd/io/CopyupRequest.cc @@ -50,7 +50,7 @@ public: ceph_assert(m_image_ctx.exclusive_lock->is_lock_owner()); ceph_assert(m_image_ctx.object_map != nullptr); bool sent = m_image_ctx.object_map->aio_update( - CEPH_NOSNAP, m_object_no, OBJECT_EXISTS, {}, m_trace, this); + CEPH_NOSNAP, m_object_no, OBJECT_EXISTS, {}, m_trace, false, this); return (sent ? 0 : 1); } @@ -67,7 +67,7 @@ public: } bool sent = m_image_ctx.object_map->aio_update( - snap_id, m_object_no, state, {}, m_trace, this); + snap_id, m_object_no, state, {}, m_trace, true, this); ceph_assert(sent); return 0; } @@ -454,7 +454,7 @@ bool CopyupRequest::send_object_map_head() { if (may_update && (new_state != current_state) && m_ictx->object_map->aio_update( CEPH_NOSNAP, m_object_no, new_state, current_state, m_trace, - this)) { + false, this)) { return false; } } diff --git a/src/librbd/io/ObjectRequest.cc b/src/librbd/io/ObjectRequest.cc index 1250e03cdff7c..a66a06f4da237 100644 --- a/src/librbd/io/ObjectRequest.cc +++ b/src/librbd/io/ObjectRequest.cc @@ -459,7 +459,8 @@ void AbstractObjectWriteRequest::pre_write_object_map_update() { if (image_ctx->object_map->template aio_update< AbstractObjectWriteRequest, &AbstractObjectWriteRequest::handle_pre_write_object_map_update>( - CEPH_NOSNAP, this->m_object_no, new_state, {}, this->m_trace, this)) { + CEPH_NOSNAP, this->m_object_no, new_state, {}, this->m_trace, false, + this)) { image_ctx->object_map_lock.put_write(); image_ctx->snap_lock.put_read(); return; @@ -611,7 +612,7 @@ void AbstractObjectWriteRequest::post_write_object_map_update() { AbstractObjectWriteRequest, &AbstractObjectWriteRequest::handle_post_write_object_map_update>( CEPH_NOSNAP, this->m_object_no, OBJECT_NONEXISTENT, OBJECT_PENDING, - this->m_trace, this)) { + this->m_trace, false, this)) { image_ctx->object_map_lock.put_write(); image_ctx->snap_lock.put_read(); return; diff --git a/src/librbd/object_map/UpdateRequest.cc b/src/librbd/object_map/UpdateRequest.cc index 36f72dd40a7a9..4b30533498a3e 100644 --- a/src/librbd/object_map/UpdateRequest.cc +++ b/src/librbd/object_map/UpdateRequest.cc @@ -72,6 +72,13 @@ template void UpdateRequest::handle_update_object_map(int r) { ldout(m_image_ctx.cct, 20) << "r=" << r << dendl; + if (r == -ENOENT && m_ignore_enoent) { + r = 0; + } + if (r < 0 && m_ret_val == 0) { + m_ret_val = r; + } + { RWLock::RLocker snap_locker(m_image_ctx.snap_lock); RWLock::WLocker object_map_locker(m_image_ctx.object_map_lock); @@ -85,7 +92,7 @@ void UpdateRequest::handle_update_object_map(int r) { } // no more batch updates to send - complete(r); + complete(m_ret_val); } template diff --git a/src/librbd/object_map/UpdateRequest.h b/src/librbd/object_map/UpdateRequest.h index cb9804d07c9f0..f5dcce1531027 100644 --- a/src/librbd/object_map/UpdateRequest.h +++ b/src/librbd/object_map/UpdateRequest.h @@ -28,22 +28,24 @@ public: uint64_t end_object_no, uint8_t new_state, const boost::optional ¤t_state, const ZTracer::Trace &parent_trace, - Context *on_finish) { + bool ignore_enoent, Context *on_finish) { return new UpdateRequest(image_ctx, object_map, snap_id, start_object_no, end_object_no, new_state, current_state, - parent_trace, on_finish); + parent_trace, ignore_enoent, on_finish); } UpdateRequest(ImageCtx &image_ctx, ceph::BitVector<2> *object_map, uint64_t snap_id, uint64_t start_object_no, uint64_t end_object_no, uint8_t new_state, const boost::optional ¤t_state, - const ZTracer::Trace &parent_trace, Context *on_finish) + const ZTracer::Trace &parent_trace, bool ignore_enoent, + Context *on_finish) : Request(image_ctx, snap_id, on_finish), m_object_map(*object_map), m_start_object_no(start_object_no), m_end_object_no(end_object_no), m_update_start_object_no(start_object_no), m_new_state(new_state), m_current_state(current_state), - m_trace(util::create_trace(image_ctx, "update object map", parent_trace)) + m_trace(util::create_trace(image_ctx, "update object map", parent_trace)), + m_ignore_enoent(ignore_enoent) { m_trace.event("start"); } @@ -80,6 +82,9 @@ private: uint8_t m_new_state; boost::optional m_current_state; ZTracer::Trace m_trace; + bool m_ignore_enoent; + + int m_ret_val = 0; void update_object_map(); void handle_update_object_map(int r); diff --git a/src/librbd/operation/TrimRequest.cc b/src/librbd/operation/TrimRequest.cc index 9ba563589dcd3..8609235e558ef 100644 --- a/src/librbd/operation/TrimRequest.cc +++ b/src/librbd/operation/TrimRequest.cc @@ -200,7 +200,7 @@ void TrimRequest::send_pre_trim() { RWLock::WLocker object_map_locker(image_ctx.object_map_lock); if (image_ctx.object_map->template aio_update >( CEPH_NOSNAP, m_delete_start_min, m_num_objects, OBJECT_PENDING, - OBJECT_EXISTS, {}, this)) { + OBJECT_EXISTS, {}, false, this)) { return; } } @@ -294,7 +294,7 @@ void TrimRequest::send_post_trim() { RWLock::WLocker object_map_locker(image_ctx.object_map_lock); if (image_ctx.object_map->template aio_update >( CEPH_NOSNAP, m_delete_start_min, m_num_objects, OBJECT_NONEXISTENT, - OBJECT_PENDING, {}, this)) { + OBJECT_PENDING, {}, false, this)) { return; } } diff --git a/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc b/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc index f004291b820a9..6b4b8929af389 100644 --- a/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc +++ b/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc @@ -284,18 +284,18 @@ public: librados::snap_t snap_id, uint8_t state, int r) { if (mock_image_ctx.image_ctx->object_map != nullptr) { - auto &expect = EXPECT_CALL(mock_object_map, aio_update(snap_id, 0, 1, state, _, _, _)); + auto &expect = EXPECT_CALL(mock_object_map, aio_update(snap_id, 0, 1, state, _, _, false, _)); if (r < 0) { - expect.WillOnce(DoAll(WithArg<6>(Invoke([this, r](Context *ctx) { + expect.WillOnce(DoAll(WithArg<7>(Invoke([this, r](Context *ctx) { m_work_queue->queue(ctx, r); })), Return(true))); } else { - expect.WillOnce(DoAll(WithArg<6>(Invoke([&mock_image_ctx, snap_id, state](Context *ctx) { + expect.WillOnce(DoAll(WithArg<7>(Invoke([&mock_image_ctx, snap_id, state](Context *ctx) { ceph_assert(mock_image_ctx.image_ctx->snap_lock.is_locked()); ceph_assert(mock_image_ctx.image_ctx->object_map_lock.is_wlocked()); mock_image_ctx.image_ctx->object_map->aio_update( - snap_id, 0, 1, state, boost::none, {}, ctx); + snap_id, 0, 1, state, boost::none, {}, false, ctx); })), Return(true))); } diff --git a/src/test/librbd/io/test_mock_ObjectRequest.cc b/src/test/librbd/io/test_mock_ObjectRequest.cc index 0a4aeda733f14..72ae152517264 100644 --- a/src/test/librbd/io/test_mock_ObjectRequest.cc +++ b/src/test/librbd/io/test_mock_ObjectRequest.cc @@ -215,8 +215,8 @@ struct TestMockIoObjectRequest : public TestMockFixture { if (mock_image_ctx.object_map != nullptr) { EXPECT_CALL(*mock_image_ctx.object_map, aio_update(CEPH_NOSNAP, start_object, end_object, state, - current_state, _, _)) - .WillOnce(WithArg<6>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) { + current_state, _, false, _)) + .WillOnce(WithArg<7>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) { if (updated) { mock_image_ctx.op_work_queue->queue(ctx, ret_val); } diff --git a/src/test/librbd/mock/MockObjectMap.h b/src/test/librbd/mock/MockObjectMap.h index 61dcedc38c3e1..e756178b3a946 100644 --- a/src/test/librbd/mock/MockObjectMap.h +++ b/src/test/librbd/mock/MockObjectMap.h @@ -24,30 +24,33 @@ struct MockObjectMap { template bool aio_update(uint64_t snap_id, uint64_t start_object_no, uint8_t new_state, const boost::optional ¤t_state, - const ZTracer::Trace &parent_trace, T *callback_object) { + const ZTracer::Trace &parent_trace, bool ignore_enoent, + T *callback_object) { return aio_update(snap_id, start_object_no, start_object_no + 1, new_state, current_state, parent_trace, - callback_object); + ignore_enoent, callback_object); } template bool aio_update(uint64_t snap_id, uint64_t start_object_no, uint64_t end_object_no, uint8_t new_state, const boost::optional ¤t_state, - const ZTracer::Trace &parent_trace, T *callback_object) { + const ZTracer::Trace &parent_trace, bool ignore_enoent, + T *callback_object) { auto ctx = util::create_context_callback(callback_object); bool updated = aio_update(snap_id, start_object_no, end_object_no, - new_state, current_state, parent_trace, ctx); + new_state, current_state, parent_trace, + ignore_enoent, ctx); if (!updated) { delete ctx; } return updated; } - MOCK_METHOD7(aio_update, bool(uint64_t snap_id, uint64_t start_object_no, + MOCK_METHOD8(aio_update, bool(uint64_t snap_id, uint64_t start_object_no, uint64_t end_object_no, uint8_t new_state, const boost::optional ¤t_state, const ZTracer::Trace &parent_trace, - Context *on_finish)); + bool ignore_enoent, Context *on_finish)); MOCK_METHOD2(snapshot_add, void(uint64_t snap_id, Context *on_finish)); MOCK_METHOD2(snapshot_remove, void(uint64_t snap_id, Context *on_finish)); diff --git a/src/test/librbd/object_map/test_mock_UpdateRequest.cc b/src/test/librbd/object_map/test_mock_UpdateRequest.cc index 380a0350ad884..b7de4d1868ea8 100644 --- a/src/test/librbd/object_map/test_mock_UpdateRequest.cc +++ b/src/test/librbd/object_map/test_mock_UpdateRequest.cc @@ -81,7 +81,7 @@ TEST_F(TestMockObjectMapUpdateRequest, UpdateInMemory) { C_SaferCond cond_ctx; AsyncRequest<> *req = new UpdateRequest<>( *ictx, &object_map, CEPH_NOSNAP, 0, object_map.size(), OBJECT_NONEXISTENT, - OBJECT_EXISTS, {}, &cond_ctx); + OBJECT_EXISTS, {}, false, &cond_ctx); { RWLock::RLocker snap_locker(ictx->snap_lock); RWLock::WLocker object_map_locker(ictx->object_map_lock); @@ -113,7 +113,7 @@ TEST_F(TestMockObjectMapUpdateRequest, UpdateHeadOnDisk) { C_SaferCond cond_ctx; AsyncRequest<> *req = new UpdateRequest<>( *ictx, &object_map, CEPH_NOSNAP, 0, object_map.size(), OBJECT_NONEXISTENT, - OBJECT_EXISTS, {}, &cond_ctx); + OBJECT_EXISTS, {}, false, &cond_ctx); { RWLock::RLocker snap_locker(ictx->snap_lock); RWLock::WLocker object_map_locker(ictx->object_map_lock); @@ -143,7 +143,7 @@ TEST_F(TestMockObjectMapUpdateRequest, UpdateSnapOnDisk) { C_SaferCond cond_ctx; AsyncRequest<> *req = new UpdateRequest<>( *ictx, &object_map, snap_id, 0, object_map.size(), OBJECT_NONEXISTENT, - OBJECT_EXISTS, {}, &cond_ctx); + OBJECT_EXISTS, {}, false, &cond_ctx); { RWLock::RLocker snap_locker(ictx->snap_lock); RWLock::WLocker object_map_locker(ictx->object_map_lock); @@ -171,7 +171,7 @@ TEST_F(TestMockObjectMapUpdateRequest, UpdateOnDiskError) { C_SaferCond cond_ctx; AsyncRequest<> *req = new UpdateRequest<>( *ictx, &object_map, CEPH_NOSNAP, 0, object_map.size(), OBJECT_NONEXISTENT, - OBJECT_EXISTS, {}, &cond_ctx); + OBJECT_EXISTS, {}, false, &cond_ctx); { RWLock::RLocker snap_locker(ictx->snap_lock); RWLock::WLocker object_map_locker(ictx->object_map_lock); @@ -202,7 +202,7 @@ TEST_F(TestMockObjectMapUpdateRequest, RebuildSnapOnDisk) { C_SaferCond cond_ctx; AsyncRequest<> *req = new UpdateRequest<>( *ictx, &object_map, snap_id, 0, object_map.size(), OBJECT_EXISTS_CLEAN, - boost::optional(), {}, &cond_ctx); + boost::optional(), {}, false, &cond_ctx); { RWLock::RLocker snap_locker(ictx->snap_lock); RWLock::WLocker object_map_locker(ictx->object_map_lock); @@ -240,7 +240,7 @@ TEST_F(TestMockObjectMapUpdateRequest, BatchUpdate) { C_SaferCond cond_ctx; AsyncRequest<> *req = new UpdateRequest<>( *ictx, &object_map, CEPH_NOSNAP, 0, object_map.size(), OBJECT_NONEXISTENT, - OBJECT_EXISTS, {}, &cond_ctx); + OBJECT_EXISTS, {}, false, &cond_ctx); { RWLock::RLocker snap_locker(ictx->snap_lock); RWLock::WLocker object_map_locker(ictx->object_map_lock); @@ -249,5 +249,32 @@ TEST_F(TestMockObjectMapUpdateRequest, BatchUpdate) { ASSERT_EQ(0, cond_ctx.wait()); } +TEST_F(TestMockObjectMapUpdateRequest, IgnoreMissingObjectMap) { + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + ASSERT_EQ(0, acquire_exclusive_lock(*ictx)); + + expect_update(ictx, CEPH_NOSNAP, 0, 1, OBJECT_NONEXISTENT, OBJECT_EXISTS, + -ENOENT); + + ceph::BitVector<2> object_map; + object_map.resize(1); + + C_SaferCond cond_ctx; + AsyncRequest<> *req = new UpdateRequest<>( + *ictx, &object_map, CEPH_NOSNAP, 0, object_map.size(), OBJECT_NONEXISTENT, + OBJECT_EXISTS, {}, true, &cond_ctx); + { + RWLock::RLocker snap_locker(ictx->snap_lock); + RWLock::WLocker object_map_locker(ictx->object_map_lock); + req->send(); + } + ASSERT_EQ(0, cond_ctx.wait()); + + expect_unlock_exclusive_lock(*ictx); +} + } // namespace object_map } // namespace librbd diff --git a/src/test/librbd/operation/test_mock_TrimRequest.cc b/src/test/librbd/operation/test_mock_TrimRequest.cc index 0203395929add..15e9bdd055e29 100644 --- a/src/test/librbd/operation/test_mock_TrimRequest.cc +++ b/src/test/librbd/operation/test_mock_TrimRequest.cc @@ -137,8 +137,8 @@ public: if (mock_image_ctx.object_map != nullptr) { EXPECT_CALL(*mock_image_ctx.object_map, aio_update(CEPH_NOSNAP, start_object, end_object, state, - boost::optional(current_state), _, _)) - .WillOnce(WithArg<6>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) { + boost::optional(current_state), _, false, _)) + .WillOnce(WithArg<7>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) { if (updated) { mock_image_ctx.op_work_queue->queue(ctx, ret_val); } diff --git a/src/test/librbd/test_mock_ObjectMap.cc b/src/test/librbd/test_mock_ObjectMap.cc index 1d739a7c858c5..41672c73f33f1 100644 --- a/src/test/librbd/test_mock_ObjectMap.cc +++ b/src/test/librbd/test_mock_ObjectMap.cc @@ -71,17 +71,18 @@ struct UpdateRequest { uint8_t new_state, const boost::optional ¤t_state, const ZTracer::Trace &parent_trace, - Context *on_finish) { + bool ignore_enoent, Context *on_finish) { ceph_assert(s_instance != nullptr); s_instance->on_finish = on_finish; s_instance->construct(snap_id, start_object_no, end_object_no, new_state, - current_state); + current_state, ignore_enoent); return s_instance; } - MOCK_METHOD5(construct, void(uint64_t snap_id, uint64_t start_object_no, + MOCK_METHOD6(construct, void(uint64_t snap_id, uint64_t start_object_no, uint64_t end_object_no, uint8_t new_state, - const boost::optional ¤t_state)); + const boost::optional ¤t_state, + bool ignore_enoent)); MOCK_METHOD0(send, void()); UpdateRequest() { s_instance = this; @@ -133,10 +134,10 @@ public: uint64_t snap_id, uint64_t start_object_no, uint64_t end_object_no, uint8_t new_state, const boost::optional ¤t_state, - Context **on_finish) { + bool ignore_enoent, Context **on_finish) { EXPECT_CALL(mock_update_request, construct(snap_id, start_object_no, end_object_no, new_state, - current_state)) + current_state, ignore_enoent)) .Times(1); EXPECT_CALL(mock_update_request, send()) .WillOnce(Invoke([&mock_update_request, on_finish]() { @@ -163,10 +164,10 @@ TEST_F(TestMockObjectMap, NonDetainedUpdate) { MockUpdateRequest mock_update_request; Context *finish_update_1; expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP, - 0, 1, 1, {}, &finish_update_1); + 0, 1, 1, {}, false, &finish_update_1); Context *finish_update_2; expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP, - 1, 2, 1, {}, &finish_update_2); + 1, 2, 1, {}, false, &finish_update_2); MockUnlockRequest mock_unlock_request; expect_unlock(mock_image_ctx, mock_unlock_request, 0); @@ -181,8 +182,8 @@ TEST_F(TestMockObjectMap, NonDetainedUpdate) { { RWLock::RLocker snap_locker(mock_image_ctx.snap_lock); RWLock::WLocker object_map_locker(mock_image_ctx.object_map_lock); - mock_object_map.aio_update(CEPH_NOSNAP, 0, 1, {}, {}, &update_ctx1); - mock_object_map.aio_update(CEPH_NOSNAP, 1, 1, {}, {}, &update_ctx2); + mock_object_map.aio_update(CEPH_NOSNAP, 0, 1, {}, {}, false, &update_ctx1); + mock_object_map.aio_update(CEPH_NOSNAP, 1, 1, {}, {}, false, &update_ctx2); } finish_update_2->complete(0); @@ -213,16 +214,16 @@ TEST_F(TestMockObjectMap, DetainedUpdate) { MockUpdateRequest mock_update_request; Context *finish_update_1; expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP, - 1, 4, 1, {}, &finish_update_1); + 1, 4, 1, {}, false, &finish_update_1); Context *finish_update_2 = nullptr; expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP, - 1, 3, 1, {}, &finish_update_2); + 1, 3, 1, {}, false, &finish_update_2); Context *finish_update_3 = nullptr; expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP, - 2, 3, 1, {}, &finish_update_3); + 2, 3, 1, {}, false, &finish_update_3); Context *finish_update_4 = nullptr; expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP, - 0, 2, 1, {}, &finish_update_4); + 0, 2, 1, {}, false, &finish_update_4); MockUnlockRequest mock_unlock_request; expect_unlock(mock_image_ctx, mock_unlock_request, 0); @@ -239,10 +240,14 @@ TEST_F(TestMockObjectMap, DetainedUpdate) { { RWLock::RLocker snap_locker(mock_image_ctx.snap_lock); RWLock::WLocker object_map_locker(mock_image_ctx.object_map_lock); - mock_object_map.aio_update(CEPH_NOSNAP, 1, 4, 1, {}, {}, &update_ctx1); - mock_object_map.aio_update(CEPH_NOSNAP, 1, 3, 1, {}, {}, &update_ctx2); - mock_object_map.aio_update(CEPH_NOSNAP, 2, 3, 1, {}, {}, &update_ctx3); - mock_object_map.aio_update(CEPH_NOSNAP, 0, 2, 1, {}, {}, &update_ctx4); + mock_object_map.aio_update(CEPH_NOSNAP, 1, 4, 1, {}, {}, false, + &update_ctx1); + mock_object_map.aio_update(CEPH_NOSNAP, 1, 3, 1, {}, {}, false, + &update_ctx2); + mock_object_map.aio_update(CEPH_NOSNAP, 2, 3, 1, {}, {}, false, + &update_ctx3); + mock_object_map.aio_update(CEPH_NOSNAP, 0, 2, 1, {}, {}, false, + &update_ctx4); } // updates 2, 3, and 4 are blocked on update 1 -- 2.39.5