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: v12.2.9~15^2~1 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=fb18769fa486f37549f540234d72b07ebf6942e5;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/deep_copy/ObjectCopyRequest.cc: moved to rbd-mirror image sync src/librbd/io/CopyupRequest.cc: trivial resolution src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc: moved to rbd-mirror image sync src/test/librbd/test_mock_ObjectMap.cc: trivial resolution --- diff --git a/src/librbd/ObjectMap.cc b/src/librbd/ObjectMap.cc index ed2c9ecbca0c7..db5b741909691 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; @@ -325,7 +326,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 f82f11b72b496..4491f714b16f3 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) { auto it = m_object_map.begin() + start_object_no; @@ -83,12 +85,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; @@ -105,15 +108,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) { } }; @@ -132,7 +138,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/io/CopyupRequest.cc b/src/librbd/io/CopyupRequest.cc index 4ae6878bcc996..b03923983972f 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 15babcaeff655..f6a8a2530c932 100644 --- a/src/librbd/io/ObjectRequest.cc +++ b/src/librbd/io/ObjectRequest.cc @@ -485,7 +485,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; @@ -627,7 +628,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 9ceb28a177379..f92c7e4bab3e4 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..8ea6b51ca3f4c 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 4ae63260334f6..a6da69af9528b 100644 --- a/src/librbd/operation/TrimRequest.cc +++ b/src/librbd/operation/TrimRequest.cc @@ -198,7 +198,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; } } @@ -292,7 +292,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/io/test_mock_ObjectRequest.cc b/src/test/librbd/io/test_mock_ObjectRequest.cc index 5f21416909afe..265c32e962f91 100644 --- a/src/test/librbd/io/test_mock_ObjectRequest.cc +++ b/src/test/librbd/io/test_mock_ObjectRequest.cc @@ -232,8 +232,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 26e979eed5c20..7b0d2c3860df2 100644 --- a/src/test/librbd/mock/MockObjectMap.h +++ b/src/test/librbd/mock/MockObjectMap.h @@ -22,30 +22,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 453e49cd6367e..8bffd7212c7a2 100644 --- a/src/test/librbd/object_map/test_mock_UpdateRequest.cc +++ b/src/test/librbd/object_map/test_mock_UpdateRequest.cc @@ -80,7 +80,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); @@ -112,7 +112,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); @@ -142,7 +142,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); @@ -170,7 +170,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); @@ -201,7 +201,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); @@ -239,7 +239,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); @@ -248,5 +248,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 09b3187320c02..4fdec0649dcd1 100644 --- a/src/test/librbd/operation/test_mock_TrimRequest.cc +++ b/src/test/librbd/operation/test_mock_TrimRequest.cc @@ -155,8 +155,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 7deaef03bb8ea..3b5ecc911eb5f 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_image_ctx, &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 diff --git a/src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc index f70df5c0582f5..a48ea550b727b 100644 --- a/src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc +++ b/src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc @@ -206,18 +206,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_threads->work_queue->queue(ctx, r); })), Return(true))); } else { - expect.WillOnce(DoAll(WithArg<6>(Invoke([&mock_image_ctx, snap_id, state, r](Context *ctx) { + expect.WillOnce(DoAll(WithArg<7>(Invoke([&mock_image_ctx, snap_id, state, r](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/tools/rbd_mirror/image_sync/ObjectCopyRequest.cc b/src/tools/rbd_mirror/image_sync/ObjectCopyRequest.cc index 533f175f9ff30..9f85696cfd244 100644 --- a/src/tools/rbd_mirror/image_sync/ObjectCopyRequest.cc +++ b/src/tools/rbd_mirror/image_sync/ObjectCopyRequest.cc @@ -372,7 +372,7 @@ void ObjectCopyRequest::send_update_object_map() { bool sent = m_local_image_ctx->object_map->template aio_update< Context, &Context::complete>( snap_object_state.first, m_object_number, snap_object_state.second, {}, - {}, ctx); + {}, false, ctx); assert(sent); m_local_image_ctx->snap_lock.put_read(); m_local_image_ctx->owner_lock.put_read();