]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: do not invalidate object map if update races with copyup
authorJason Dillaman <dillaman@redhat.com>
Mon, 24 Sep 2018 18:45:09 +0000 (14:45 -0400)
committerJason Dillaman <dillaman@redhat.com>
Thu, 4 Oct 2018 12:05:42 +0000 (08:05 -0400)
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 <dillaman@redhat.com>
(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

14 files changed:
src/librbd/ObjectMap.cc
src/librbd/ObjectMap.h
src/librbd/io/CopyupRequest.cc
src/librbd/io/ObjectRequest.cc
src/librbd/object_map/UpdateRequest.cc
src/librbd/object_map/UpdateRequest.h
src/librbd/operation/TrimRequest.cc
src/test/librbd/io/test_mock_ObjectRequest.cc
src/test/librbd/mock/MockObjectMap.h
src/test/librbd/object_map/test_mock_UpdateRequest.cc
src/test/librbd/operation/test_mock_TrimRequest.cc
src/test/librbd/test_mock_ObjectMap.cc
src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc
src/tools/rbd_mirror/image_sync/ObjectCopyRequest.cc

index ed2c9ecbca0c733d3bcb123046148ea4b6d84927..db5b741909691663faf44c711de1b8c80b2fe94c 100644 (file)
@@ -259,7 +259,7 @@ void ObjectMap<I>::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 <typename I>
@@ -287,13 +287,14 @@ void ObjectMap<I>::aio_update(uint64_t snap_id, uint64_t start_object_no,
                               uint64_t end_object_no, uint8_t new_state,
                               const boost::optional<uint8_t> &current_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<I>::aio_update(uint64_t snap_id, uint64_t start_object_no,
 
   auto req = object_map::UpdateRequest<I>::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();
 }
 
index f82f11b72b496cfe9d43b9269497b560b22757b9..4491f714b16f3f0a5071fbd0896a5a88a2dcf5fa 100644 (file)
@@ -56,17 +56,19 @@ public:
   template <typename T, void(T::*MF)(int) = &T::complete>
   bool aio_update(uint64_t snap_id, uint64_t start_object_no, uint8_t new_state,
                   const boost::optional<uint8_t> &current_state,
-                  const ZTracer::Trace &parent_trace, T *callback_object) {
+                  const ZTracer::Trace &parent_trace, bool ignore_enoent,
+                  T *callback_object) {
     return aio_update<T, MF>(snap_id, start_object_no, start_object_no + 1,
                              new_state, current_state, parent_trace,
-                             callback_object);
+                             ignore_enoent, callback_object);
   }
 
   template <typename T, void(T::*MF)(int) = &T::complete>
   bool aio_update(uint64_t snap_id, uint64_t start_object_no,
                   uint64_t end_object_no, uint8_t new_state,
                   const boost::optional<uint8_t> &current_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<T, MF>(
                                          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<T, MF>(callback_object));
     }
     return true;
@@ -105,15 +108,18 @@ private:
     uint8_t new_state;
     boost::optional<uint8_t> 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<uint8_t> &current_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<uint8_t> &current_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);
 
index 4ae6878bcc99661b10bc134ac324f9b8d09ffec0..b03923983972fa0a51351c2dd086f6e621f28cd3 100644 (file)
@@ -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<Context>(
-        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<Context>(
-      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<I>::send_object_map_head() {
       if (may_update && (new_state != current_state) &&
           m_ictx->object_map->aio_update<CopyupRequest>(
             CEPH_NOSNAP, m_object_no, new_state, current_state, m_trace,
-            this)) {
+            false, this)) {
         return false;
       }
     }
index 15babcaeff655f2c1d774c6ef15d68ad397962d7..f6a8a2530c932a16ee07729a805609e7fdf5a268 100644 (file)
@@ -485,7 +485,8 @@ void AbstractObjectWriteRequest<I>::pre_write_object_map_update() {
   if (image_ctx->object_map->template aio_update<
         AbstractObjectWriteRequest<I>,
         &AbstractObjectWriteRequest<I>::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<I>::post_write_object_map_update() {
         AbstractObjectWriteRequest<I>,
         &AbstractObjectWriteRequest<I>::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;
index 9ceb28a177379b1fbeae984d1e09c3d4b99bce52..f92c7e4bab3e4827b2d5432e8dae9798f41cb336 100644 (file)
@@ -72,6 +72,13 @@ template <typename I>
 void UpdateRequest<I>::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<I>::handle_update_object_map(int r) {
   }
 
   // no more batch updates to send
-  complete(r);
+  complete(m_ret_val);
 }
 
 template <typename I>
index cb9804d07c9f0e09dc2f2110ab5fd70c7383d857..8ea6b51ca3f4c2867fe4b09637d99c861570ed63 100644 (file)
@@ -28,22 +28,24 @@ public:
                                uint64_t end_object_no, uint8_t new_state,
                                const boost::optional<uint8_t> &current_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<uint8_t> &current_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<uint8_t> 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);
index 4ae63260334f6b56d132dee6ea7d0675081a26a0..a6da69af9528b30a0d8a99b62f960980b2f6740f 100644 (file)
@@ -198,7 +198,7 @@ void TrimRequest<I>::send_pre_trim() {
       RWLock::WLocker object_map_locker(image_ctx.object_map_lock);
       if (image_ctx.object_map->template aio_update<AsyncRequest<I> >(
             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<I>::send_post_trim() {
       RWLock::WLocker object_map_locker(image_ctx.object_map_lock);
       if (image_ctx.object_map->template aio_update<AsyncRequest<I> >(
             CEPH_NOSNAP, m_delete_start_min, m_num_objects, OBJECT_NONEXISTENT,
-            OBJECT_PENDING, {}, this)) {
+            OBJECT_PENDING, {}, false, this)) {
         return;
       }
     }
index 5f21416909afeec33ce2b95baf7f9fd262d15953..265c32e962f91eedeb8a306eab6e90f242b25cd2 100644 (file)
@@ -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);
                                }
index 26e979eed5c201b384d4adff61ebf6f632a1142d..7b0d2c3860df2ba6b65c16105f427c3ef609c642 100644 (file)
@@ -22,30 +22,33 @@ struct MockObjectMap {
   template <typename T, void(T::*MF)(int) = &T::complete>
   bool aio_update(uint64_t snap_id, uint64_t start_object_no, uint8_t new_state,
                   const boost::optional<uint8_t> &current_state,
-                  const ZTracer::Trace &parent_trace, T *callback_object) {
+                  const ZTracer::Trace &parent_trace, bool ignore_enoent,
+                  T *callback_object) {
     return aio_update<T, MF>(snap_id, start_object_no, start_object_no + 1,
                              new_state, current_state, parent_trace,
-                             callback_object);
+                             ignore_enoent, callback_object);
   }
 
   template <typename T, void(T::*MF)(int) = &T::complete>
   bool aio_update(uint64_t snap_id, uint64_t start_object_no,
                   uint64_t end_object_no, uint8_t new_state,
                   const boost::optional<uint8_t> &current_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<T, MF>(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<uint8_t> &current_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));
index 453e49cd6367e8bba7b3caa93dda2fa68e65fb0a..8bffd7212c7a28cd14f6f263633ab8d56f87cf9f 100644 (file)
@@ -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<uint8_t>(), {}, &cond_ctx);
+    boost::optional<uint8_t>(), {}, 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
index 09b3187320c02f7b5499c13f859f9e2f74fda39f..4fdec0649dcd13058fbd7bf87500b9dc2478bc30 100644 (file)
@@ -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<uint8_t>(current_state), _, _))
-        .WillOnce(WithArg<6>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) {
+                             boost::optional<uint8_t>(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);
                                }
index 7deaef03bb8ea6cf587ccd6851394ada9d9d22a1..3b5ecc911eb5f2f067fb47703cd2f46d6e0794e7 100644 (file)
@@ -71,17 +71,18 @@ struct UpdateRequest<MockTestImageCtx> {
                                uint8_t new_state,
                                const boost::optional<uint8_t> &current_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<uint8_t> &current_state));
+                               const boost::optional<uint8_t> &current_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<uint8_t> &current_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
index f70df5c0582f58251047b442b06fda3c13fb9465..a48ea550b727bb10988ccb3fa20cd0b9154c5ce5 100644 (file)
@@ -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<Context>(
-                                    snap_id, 0, 1, state, boost::none, {}, ctx);
+                                    snap_id, 0, 1, state, boost::none, {}, false, ctx);
                                 })),
                               Return(true)));
       }
index 533f175f9ff3011cfc5f054d277c1bb52ccf6421..9f85696cfd244b6942d2d5b6759587515ffa97c0 100644 (file)
@@ -372,7 +372,7 @@ void ObjectCopyRequest<I>::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();