From: Jason Dillaman Date: Mon, 24 Sep 2018 18:45:09 +0000 (-0400) Subject: librbd: do not invalidate object map if update races with copyup X-Git-Tag: v13.2.3~137^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=82c02fb0cbb510a653dbcc1b51f97359800b8946;p=ceph.git 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 (cherry picked from commit 5a1cb469879157297ab456261f9335d8b855684f) Conflicts: src/librbd/ObjectMap.cc: trivial resolution src/librbd/ObjectMap.h: trivial resolution src/librbd/io/CopyupRequest.cc: trivial resolution src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc: trivial resolution src/test/librbd/test_mock_ObjectMap.cc: trivial resolution --- diff --git a/src/librbd/ObjectMap.cc b/src/librbd/ObjectMap.cc index b91f42d3cb8b..2b151275b16a 100644 --- a/src/librbd/ObjectMap.cc +++ b/src/librbd/ObjectMap.cc @@ -259,7 +259,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 @@ -287,13 +287,14 @@ 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) { assert(m_image_ctx.snap_lock.is_locked()); assert((m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0); assert(m_image_ctx.image_watcher != nullptr); assert(m_image_ctx.exclusive_lock == nullptr || m_image_ctx.exclusive_lock->is_lock_owner()); - assert(snap_id != CEPH_NOSNAP || m_image_ctx.object_map_lock.is_wlocked()); + assert(snap_id != CEPH_NOSNAP || + m_image_ctx.object_map_lock.is_wlocked()); assert(start_object_no < end_object_no); CephContext *cct = m_image_ctx.cct; @@ -326,7 +327,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 dab91c04cf53..8b4d67cbbd67 100644 --- a/src/librbd/ObjectMap.h +++ b/src/librbd/ObjectMap.h @@ -56,17 +56,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) { assert(start_object_no < end_object_no); if (snap_id == CEPH_NOSNAP) { end_object_no = std::min(end_object_no, m_object_map.size()); @@ -88,12 +90,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; @@ -110,15 +113,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) { } }; @@ -137,7 +143,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 19072aee7eb1..9870b6ddaab2 100644 --- a/src/librbd/deep_copy/ObjectCopyRequest.cc +++ b/src/librbd/deep_copy/ObjectCopyRequest.cc @@ -463,7 +463,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 cb7cbfb93bf3..44f4ce93418e 100644 --- a/src/librbd/io/CopyupRequest.cc +++ b/src/librbd/io/CopyupRequest.cc @@ -49,7 +49,7 @@ public: assert(m_image_ctx.exclusive_lock->is_lock_owner()); 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); } @@ -66,7 +66,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); assert(sent); return 0; } @@ -346,7 +346,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 23f38ee64141..3d09b5044828 100644 --- a/src/librbd/io/ObjectRequest.cc +++ b/src/librbd/io/ObjectRequest.cc @@ -450,7 +450,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; @@ -592,7 +593,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 36ccc6159aa4..6841a16a7de4 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 cb9804d07c9f..f5dcce153102 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 99d144e064b9..bc3cf1184e63 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 1120bad1805a..a433ba8b51b4 100644 --- a/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc +++ b/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc @@ -283,18 +283,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) { assert(mock_image_ctx.image_ctx->snap_lock.is_locked()); 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 27eff02bd95a..1bd5d60946c5 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 61dcedc38c3e..e756178b3a94 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 380a0350ad88..b7de4d1868ea 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 0203395929ad..15e9bdd055e2 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 59f21ea43160..aa8009da71ba 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) { 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