]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: enable image cache after getting exclusive lock 35060/head
authorYuan Lu <yuan.y.lu@intel.com>
Fri, 19 Jun 2020 10:27:34 +0000 (18:27 +0800)
committerlixiaoy1 <xiaoyan.li@intel.com>
Mon, 3 Aug 2020 09:37:13 +0000 (05:37 -0400)
Signed-off-by: Peterson, Scott <scott.d.peterson@intel.com>
Signed-off-by: Li, Xiaoyan <xiaoyan.li@intel.com>
Signed-off-by: Lu, Yuan <yuan.y.lu@intel.com>
Signed-off-by: Chamarthy, Mahati <mahati.chamarthy@intel.com>
25 files changed:
src/librbd/CMakeLists.txt
src/librbd/ExclusiveLock.cc
src/librbd/ImageCtx.h
src/librbd/api/Migration.cc
src/librbd/cache/Utils.h
src/librbd/cache/rwl/ImageCacheState.cc
src/librbd/cache/rwl/ImageCacheState.h
src/librbd/exclusive_lock/PostAcquireRequest.cc
src/librbd/exclusive_lock/PostAcquireRequest.h
src/librbd/exclusive_lock/PreReleaseRequest.cc
src/librbd/exclusive_lock/PreReleaseRequest.h
src/librbd/io/ImageRequest.cc
src/test/librbd/exclusive_lock/test_mock_PostAcquireRequest.cc
src/test/librbd/exclusive_lock/test_mock_PreReleaseRequest.cc
src/test/librbd/object_map/test_mock_UpdateRequest.cc
src/test/librbd/test_Migration.cc
src/test/librbd/test_fixture.cc
src/test/librbd/test_fixture.h
src/test/librbd/test_internal.cc
src/test/librbd/test_librbd.cc
src/test/librbd/test_mirroring.cc
src/test/librbd/test_mock_ExclusiveLock.cc
src/test/librbd/test_mock_fixture.cc
src/test/librbd/test_support.cc
src/test/librbd/test_support.h

index c0d0120ce3d45281006f8321dce644671291900e..65e98ad1f369d0f21c721489cb40dec21a5445a8 100644 (file)
@@ -43,6 +43,8 @@ set(librbd_internal_srcs
   cache/ObjectCacherObjectDispatch.cc
   cache/ObjectCacherWriteback.cc
   cache/PassthroughImageCache.cc
+  cache/rwl/InitRequest.cc
+  cache/rwl/ShutdownRequest.cc
   cache/WriteAroundObjectDispatch.cc
   deep_copy/ImageCopyRequest.cc
   deep_copy/MetadataCopyRequest.cc
@@ -194,13 +196,11 @@ if(WITH_RBD_RWL)
   set(librbd_internal_srcs
     ${librbd_internal_srcs}
     cache/rwl/ImageCacheState.cc
-    cache/rwl/InitRequest.cc
     cache/rwl/LogEntry.cc
     cache/rwl/LogMap.cc
     cache/rwl/LogOperation.cc
     cache/rwl/ReadRequest.cc
     cache/rwl/Request.cc
-    cache/rwl/ShutdownRequest.cc
     cache/rwl/SyncPoint.cc
     cache/rwl/Types.cc
     cache/ReplicatedWriteLog.cc)
index bdf67238df3da53858f958cf5ba9899efe0c5567..20f594b88c885b9ff4948058bca9ccb6bd3ec652 100644 (file)
@@ -1,6 +1,7 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 // vim: ts=8 sw=2 smarttab
 
+#include "librbd/cache/Utils.h"
 #include "librbd/ExclusiveLock.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageWatcher.h"
@@ -203,8 +204,10 @@ void ExclusiveLock<I>::handle_init_complete(int r, uint64_t features,
       on_finish->complete(r);
     });
 
+  bool rwl_enabled = cache::util::is_rwl_enabled(m_image_ctx);
   if (m_image_ctx.clone_copy_on_read ||
-      (features & RBD_FEATURE_JOURNALING) != 0) {
+      (features & RBD_FEATURE_JOURNALING) != 0 ||
+      rwl_enabled) {
     m_image_dispatch->set_require_lock(io::DIRECTION_BOTH, on_finish);
   } else {
     m_image_dispatch->set_require_lock(io::DIRECTION_WRITE, on_finish);
index 26d993e4c25620b8c67876359c265995a6298c47..c8c3caf97aba5e1d1884fa6af154c1494da19ef4 100644 (file)
@@ -57,12 +57,7 @@ namespace librbd {
   template <typename> class PluginRegistry;
 
   namespace asio { struct ContextWQ; }
-  namespace cache {
-  template <typename> class ImageCache;
-  namespace rwl {
-  template <typename> class ImageCacheState;
-  } // namespace rwl
-  } // namespace cache
+  namespace cache { template <typename> class ImageCache; }
   namespace exclusive_lock { struct Policy; }
   namespace io {
   class AioCompletion;
@@ -182,7 +177,6 @@ namespace librbd {
     file_layout_t layout;
 
     cache::ImageCache<ImageCtx> *image_cache = nullptr;
-    cache::rwl::ImageCacheState<ImageCtx> *cache_state = nullptr;
 
     Readahead readahead;
     std::atomic<uint64_t> total_bytes_read = {0};
index 85733c4cab1db00cf4944abf2c9a77847cb1ee03..ec071225888089539ed29410c8a1b4df92ea1bd4 100644 (file)
@@ -401,6 +401,7 @@ int Migration<I>::prepare(librados::IoCtx& io_ctx,
     return -ENOSYS;
   }
   features &= ~RBD_FEATURES_INTERNAL;
+  features &= ~RBD_FEATURE_DIRTY_CACHE;
   features |= RBD_FEATURE_MIGRATING;
   opts.set(RBD_IMAGE_OPTION_FEATURES, features);
 
index aa08bcba1c6d8d118c21d7e20eb240574df5de5e..99752529072ea43036cc92a4c95b0e7661196acb 100644 (file)
@@ -11,7 +11,11 @@ namespace util {
 
 template <typename T>
 bool is_rwl_enabled(T& image_ctx) {
+#if defined(WITH_RBD_RWL)
   return image_ctx.config.template get_val<bool>("rbd_rwl_enabled");
+#else
+  return false;
+#endif
 }
 
 } // namespace util
index 5c491b190d2895b7905e3f771b34a3f1e7824e66..945e39ed82e00c7345d613db058be9061996e61e 100644 (file)
@@ -2,6 +2,7 @@
 // vim: ts=8 sw=2 smarttab
 
 #include "librbd/cache/Types.h"
+#include "librbd/cache/Utils.h"
 #include "librbd/cache/rwl/ImageCacheState.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/Operations.h"
@@ -111,7 +112,7 @@ ImageCacheState<I>* ImageCacheState<I>::get_image_cache_state(
                              IMAGE_CACHE_STATE, &cache_state_str);
   }
 
-  bool rwl_enabled = image_ctx->config.template get_val<bool>("rbd_rwl_enabled");
+  bool rwl_enabled = cache::util::is_rwl_enabled(*image_ctx);
   bool cache_desired = rwl_enabled;
   cache_desired &= !image_ctx->read_only;
   cache_desired &= !image_ctx->test_features(RBD_FEATURE_MIGRATING);
index f2c82cfefdd2870ccc038986df2613b66215f3a5..751978e76ec4f595163ce39f520afe71e05a035e 100644 (file)
@@ -47,7 +47,8 @@ public:
 
   void dump(ceph::Formatter *f) const;
 
-  static void get_image_cache_state(ImageCtxT* image_ctx, Context *on_finish);
+  static ImageCacheState<ImageCtxT>* get_image_cache_state(
+      ImageCtxT* image_ctx, int &r);
 
   bool is_valid();
 };
index 7075090b55c4d7c179279d0b080a762412dc2349..6c920cc8aa6a447c85d99e3f52e8ce3a76740c13 100644 (file)
@@ -7,6 +7,8 @@
 #include "common/dout.h"
 #include "common/errno.h"
 #include "include/stringify.h"
+#include "librbd/cache/rwl/InitRequest.h"
+#include "librbd/cache/rwl/ShutdownRequest.h"
 #include "librbd/ExclusiveLock.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageState.h"
@@ -114,7 +116,7 @@ void PostAcquireRequest<I>::send_open_journal() {
   }
   if (!journal_enabled) {
     apply();
-    finish();
+    send_open_image_cache();
     return;
   }
 
@@ -172,11 +174,73 @@ void PostAcquireRequest<I>::handle_allocate_journal_tag(int r) {
     return;
   }
 
+  send_open_image_cache();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::send_open_image_cache() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  using klass = PostAcquireRequest<I>;
+  Context *ctx = create_async_context_callback(
+    m_image_ctx, create_context_callback<
+    klass, &klass::handle_open_image_cache>(this));
+  cache::rwl::InitRequest<I> *req = cache::rwl::InitRequest<I>::create(
+    m_image_ctx, ctx);
+  req->send();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_open_image_cache(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << "r=" << r << dendl;
+
+  save_result(r);
+  if (r < 0) {
+    lderr(cct) << "failed to open image cache: " << cpp_strerror(r)
+               << dendl;
+    send_close_image_cache();
+    return;
+  }
+
   finish();
 }
 
+template <typename I>
+void PostAcquireRequest<I>::send_close_image_cache() {
+  if (m_image_ctx.image_cache == nullptr) {
+    send_close_journal();
+  }
+
+  using klass = PostAcquireRequest<I>;
+  Context *ctx = create_context_callback<klass, &klass::handle_close_image_cache>(
+    this);
+  cache::rwl::ShutdownRequest<I> *req = cache::rwl::ShutdownRequest<I>::create(
+    m_image_ctx, ctx);
+  req->send();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_close_image_cache(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << "r=" << r << dendl;
+
+  save_result(r);
+  if (r < 0) {
+    lderr(cct) << "failed to close image_cache: " << cpp_strerror(r) << dendl;
+  }
+
+  send_close_journal();
+}
+
 template <typename I>
 void PostAcquireRequest<I>::send_close_journal() {
+  if (m_journal == nullptr) {
+    send_close_object_map();
+    return;
+  }
+
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << dendl;
 
index 06fdce394bcf1fefcccfd42fe34b17e680fd0988..f908634263211506e5182ab737309a0034aeaf01 100644 (file)
@@ -48,7 +48,11 @@ private:
    *  ALLOCATE_JOURNAL_TAG  *
    *      |            *    *
    *      |            *    *
-   *      |            v    v
+   *      v            *    *
+   *  OPEN_IMAGE_CACHE *    *
+   *      |         *  *    *
+   *      |         *  *    *
+   *      |         v  v    v
    *      |         CLOSE_JOURNAL
    *      |               |
    *      |               v
@@ -91,6 +95,12 @@ private:
   void send_close_object_map();
   void handle_close_object_map(int r);
 
+  void send_open_image_cache();
+  void handle_open_image_cache(int r);
+
+  void send_close_image_cache();
+  void handle_close_image_cache(int r);
+
   void apply();
   void revert();
 
index 06a04f5c80ff69fcca051437d9ba51e2f3c5da97..fb1aa8322fb908d5a78fa5a3d92da77e47be1812 100644 (file)
@@ -5,6 +5,7 @@
 #include "common/AsyncOpTracker.h"
 #include "common/dout.h"
 #include "common/errno.h"
+#include "librbd/cache/rwl/ShutdownRequest.h"
 #include "librbd/ExclusiveLock.h"
 #include "librbd/ImageState.h"
 #include "librbd/ImageWatcher.h"
@@ -156,6 +157,42 @@ void PreReleaseRequest<I>::handle_wait_for_ops(int r) {
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << dendl;
 
+  send_shut_down_image_cache();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_shut_down_image_cache() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  /* Shut down existing image cache whether the feature bit is on or not */
+  if (!m_image_ctx.image_cache) {
+     send_invalidate_cache();
+    return;
+  }
+  std::shared_lock owner_lock{m_image_ctx.owner_lock};
+  Context *ctx = create_async_context_callback(m_image_ctx, create_context_callback<
+      PreReleaseRequest<I>,
+      &PreReleaseRequest<I>::handle_shut_down_image_cache>(this));
+  cache::rwl::ShutdownRequest<I> *req = cache::rwl::ShutdownRequest<I>::create(
+    m_image_ctx, ctx);
+  req->send();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_shut_down_image_cache(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << "r=" << r << dendl;
+
+  if (r < 0) {
+    lderr(cct) << "failed to shut down image cache: " << cpp_strerror(r)
+               << dendl;
+    m_image_dispatch->unset_require_lock(io::DIRECTION_BOTH);
+    save_result(r);
+    finish();
+    return;
+  }
+
   send_invalidate_cache();
 }
 
index 66d1b0155b0d45e366c183cce14291cdc4072d95..6063683e2d6b07b4d8f43b34f46f8f46ad7f6ea5 100644 (file)
@@ -49,6 +49,9 @@ private:
    * WAIT_FOR_OPS
    *    |
    *    v
+   * SHUT_DOWN_IMAGE_CACHE
+   *    |
+   *    v
    * INVALIDATE_CACHE
    *    |
    *    v
@@ -94,6 +97,9 @@ private:
   void send_wait_for_ops();
   void handle_wait_for_ops(int r);
 
+  void send_shut_down_image_cache();
+  void handle_shut_down_image_cache(int r);
+
   void send_invalidate_cache();
   void handle_invalidate_cache(int r);
 
index e8b824f0ee6f7b7f674c9ae121b843e16c2bea9e..ec1f36bc92cd1f68016f96f9fc32e4da2b0224f0 100644 (file)
@@ -754,7 +754,7 @@ void ImageFlushRequest<I>::send_image_cache_request() {
   AioCompletion *aio_comp = this->m_aio_comp;
   aio_comp->set_request_count(1);
   C_AioRequest *req_comp = new C_AioRequest(aio_comp);
-  image_ctx.image_cache->aio_flush(librbd::io::FLUSH_SOURCE_USER, req_comp);
+  image_ctx.image_cache->aio_flush(m_flush_source, req_comp);
 }
 
 template <typename I>
index b18269236a7c456399399d49812f77c74efaa7b5..9379e3ecf895597eaf360b1b95a4d6de2d091cf2 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "test/librbd/test_mock_fixture.h"
 #include "test/librbd/test_support.h"
+#include "test/librbd/mock/cache/MockImageCache.h"
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/librbd/mock/MockImageState.h"
 #include "test/librbd/mock/MockJournal.h"
 #include "test/librbd/mock/MockObjectMap.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "test/librados_test_stub/MockTestMemRadosClient.h"
+#include "librbd/cache/rwl/InitRequest.h"
+#include "librbd/cache/rwl/ShutdownRequest.h"
 #include "librbd/exclusive_lock/PostAcquireRequest.h"
 #include "librbd/image/RefreshRequest.h"
+
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include <arpa/inet.h>
@@ -57,6 +61,52 @@ struct RefreshRequest<librbd::MockTestImageCtx> {
 RefreshRequest<librbd::MockTestImageCtx> *RefreshRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
 
 } // namespace image
+
+namespace cache {
+namespace rwl {
+
+template<>
+struct InitRequest<librbd::MockTestImageCtx> {
+  static InitRequest *s_instance;
+  Context *on_finish = nullptr;
+
+  static InitRequest *create(librbd::MockTestImageCtx &image_ctx,
+                             Context *on_finish) {
+    ceph_assert(s_instance != nullptr);
+    s_instance->on_finish = on_finish;
+    return s_instance;
+  }
+
+  InitRequest() {
+    s_instance = this;
+  }
+  MOCK_METHOD0(send, void());
+};
+
+InitRequest<librbd::MockTestImageCtx> *InitRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+
+template<>
+struct ShutdownRequest<librbd::MockTestImageCtx> {
+  static ShutdownRequest *s_instance;
+  Context *on_finish = nullptr;
+
+  static ShutdownRequest *create(librbd::MockTestImageCtx &image_ctx,
+                             Context *on_finish) {
+    ceph_assert(s_instance != nullptr);
+    s_instance->on_finish = on_finish;
+    return s_instance;
+  }
+
+  ShutdownRequest() {
+    s_instance = this;
+  }
+  MOCK_METHOD0(send, void());
+};
+
+ShutdownRequest<librbd::MockTestImageCtx> *ShutdownRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace rwl
+} // namespace cache
 } // namespace librbd
 
 // template definitions
@@ -88,6 +138,8 @@ class TestMockExclusiveLockPostAcquireRequest : public TestMockFixture {
 public:
   typedef PostAcquireRequest<MockTestImageCtx> MockPostAcquireRequest;
   typedef librbd::image::RefreshRequest<MockTestImageCtx> MockRefreshRequest;
+  typedef librbd::cache::rwl::InitRequest<MockTestImageCtx> MockInitRequest;
+  typedef librbd::cache::rwl::ShutdownRequest<MockTestImageCtx> MockShutdownRequest;
 
   void expect_test_features(MockTestImageCtx &mock_image_ctx, uint64_t features,
                             bool enabled) {
@@ -172,6 +224,18 @@ public:
     EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
   }
 
+  void expect_init_image_cache(MockTestImageCtx &mock_image_ctx,
+                               MockInitRequest &mock_init_request, int r) {
+    EXPECT_CALL(mock_init_request, send())
+                  .WillOnce(FinishRequest(&mock_init_request, r, &mock_image_ctx));
+  }
+
+  void expect_close_image_cache(MockTestImageCtx &mock_image_ctx,
+      MockShutdownRequest &mock_shutdown_request, int r) {
+    EXPECT_CALL(mock_shutdown_request, send())
+                  .WillOnce(FinishRequest(&mock_shutdown_request, r, &mock_image_ctx));
+  }
+
 };
 
 TEST_F(TestMockExclusiveLockPostAcquireRequest, Success) {
@@ -203,6 +267,8 @@ TEST_F(TestMockExclusiveLockPostAcquireRequest, Success) {
   expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
   expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
 
+  MockInitRequest mock_init_request;
+  expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
   C_SaferCond acquire_ctx;
   C_SaferCond ctx;
   MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
@@ -233,6 +299,9 @@ TEST_F(TestMockExclusiveLockPostAcquireRequest, SuccessRefresh) {
                        mock_image_ctx.image_lock, false);
   expect_handle_prepare_lock_complete(mock_image_ctx);
 
+  MockInitRequest mock_init_request;
+  expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
+
   C_SaferCond acquire_ctx;
   C_SaferCond ctx;
   MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
@@ -264,6 +333,9 @@ TEST_F(TestMockExclusiveLockPostAcquireRequest, SuccessJournalDisabled) {
                        mock_image_ctx.image_lock, false);
   expect_handle_prepare_lock_complete(mock_image_ctx);
 
+  MockInitRequest mock_init_request;
+  expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
+
   C_SaferCond acquire_ctx;
   C_SaferCond ctx;
   MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
@@ -300,6 +372,9 @@ TEST_F(TestMockExclusiveLockPostAcquireRequest, SuccessObjectMapDisabled) {
   expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
   expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
 
+  MockInitRequest mock_init_request;
+  expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
+
   C_SaferCond acquire_ctx;
   C_SaferCond ctx;
   MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
@@ -354,6 +429,9 @@ TEST_F(TestMockExclusiveLockPostAcquireRequest, RefreshLockDisabled) {
                        mock_image_ctx.image_lock, false);
   expect_handle_prepare_lock_complete(mock_image_ctx);
 
+  MockInitRequest mock_init_request;
+  expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
+
   C_SaferCond acquire_ctx;
   C_SaferCond ctx;
   MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
@@ -442,6 +520,55 @@ TEST_F(TestMockExclusiveLockPostAcquireRequest, AllocateJournalTagError) {
   ASSERT_EQ(-EPERM, ctx.wait());
 }
 
+TEST_F(TestMockExclusiveLockPostAcquireRequest, InitImageCacheError) {
+  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
+
+  InSequence seq;
+  expect_is_refresh_required(mock_image_ctx, false);
+
+  MockObjectMap mock_object_map;
+  expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
+  expect_create_object_map(mock_image_ctx, &mock_object_map);
+  expect_open_object_map(mock_image_ctx, mock_object_map, 0);
+
+  MockJournal mock_journal;
+  MockJournalPolicy mock_journal_policy;
+  expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+                       mock_image_ctx.image_lock, true);
+  expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+  expect_journal_disabled(mock_journal_policy, false);
+  expect_create_journal(mock_image_ctx, &mock_journal);
+  expect_handle_prepare_lock_complete(mock_image_ctx);
+  expect_open_journal(mock_image_ctx, mock_journal, 0);
+  expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+  expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
+
+  MockInitRequest mock_init_request;
+  expect_init_image_cache(mock_image_ctx, mock_init_request, -ENOENT);
+
+  cache::MockImageCache mock_image_cache;
+  mock_image_ctx.image_cache = &mock_image_cache;
+  MockShutdownRequest mock_shutdown_request;
+  expect_close_image_cache(mock_image_ctx, mock_shutdown_request, 0);
+
+  expect_close_journal(mock_image_ctx, mock_journal);
+  expect_close_object_map(mock_image_ctx, mock_object_map);
+
+  C_SaferCond acquire_ctx;
+  C_SaferCond ctx;
+  MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+                                                               &acquire_ctx,
+                                                               &ctx);
+  req->send();
+  ASSERT_EQ(-ENOENT, ctx.wait());
+}
+
 TEST_F(TestMockExclusiveLockPostAcquireRequest, OpenObjectMapError) {
   REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
 
@@ -499,6 +626,9 @@ TEST_F(TestMockExclusiveLockPostAcquireRequest, OpenObjectMapTooBig) {
   expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
   expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
 
+  MockInitRequest mock_init_request;
+  expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
+
   C_SaferCond acquire_ctx;
   C_SaferCond ctx;
   MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
index 9812a31b818d458ac291c9f691e0c7e9ee98e3eb..d56ee1155f62586423e17c3f73b57a1e31d9e11a 100644 (file)
@@ -1,8 +1,10 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 // vim: ts=8 sw=2 smarttab
 
+#include "librbd/cache/rwl/ShutdownRequest.h"
 #include "test/librbd/test_mock_fixture.h"
 #include "test/librbd/test_support.h"
+#include "test/librbd/mock/cache/MockImageCache.h"
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/librbd/mock/MockJournal.h"
 #include "test/librbd/mock/MockObjectMap.h"
@@ -11,6 +13,7 @@
 #include "common/AsyncOpTracker.h"
 #include "librbd/exclusive_lock/ImageDispatch.h"
 #include "librbd/exclusive_lock/PreReleaseRequest.h"
+
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include <list>
@@ -35,6 +38,31 @@ struct ImageDispatch<MockTestImageCtx> {
 };
 
 } // namespace exclusive_lock
+
+namespace cache {
+namespace rwl {
+template<>
+struct ShutdownRequest<librbd::MockTestImageCtx> {
+  static ShutdownRequest *s_instance;
+  Context *on_finish = nullptr;
+
+  static ShutdownRequest *create(librbd::MockTestImageCtx &image_ctx,
+                             Context *on_finish) {
+    ceph_assert(s_instance != nullptr);
+    s_instance->on_finish = on_finish;
+    return s_instance;
+  }
+
+  ShutdownRequest() {
+    s_instance = this;
+  }
+  MOCK_METHOD0(send, void());
+};
+
+ShutdownRequest<librbd::MockTestImageCtx> *ShutdownRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace rwl
+} // namespace cache
 } // namespace librbd
 
 // template definitions
@@ -65,6 +93,7 @@ class TestMockExclusiveLockPreReleaseRequest : public TestMockFixture {
 public:
   typedef ImageDispatch<MockTestImageCtx> MockImageDispatch;
   typedef PreReleaseRequest<MockTestImageCtx> MockPreReleaseRequest;
+  typedef librbd::cache::rwl::ShutdownRequest<MockTestImageCtx> MockShutdownRequest;
 
   void expect_complete_context(MockContext &mock_context, int r) {
     EXPECT_CALL(mock_context, complete(r));
@@ -118,6 +147,12 @@ public:
                   .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
   }
 
+  void expect_close_image_cache(MockTestImageCtx &mock_image_ctx,
+                                MockShutdownRequest &mock_shutdown_req, int r) {
+    EXPECT_CALL(mock_shutdown_req, send())
+                  .WillOnce(FinishRequest(&mock_shutdown_req, r, &mock_image_ctx));
+  }
+
   void expect_invalidate_cache(MockTestImageCtx &mock_image_ctx,
                                int r) {
     EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, invalidate_cache(_))
@@ -158,6 +193,12 @@ TEST_F(TestMockExclusiveLockPreReleaseRequest, Success) {
   expect_cancel_op_requests(mock_image_ctx, 0);
   MockImageDispatch mock_image_dispatch;
   expect_set_require_lock(mock_image_ctx, mock_image_dispatch, 0);
+
+  cache::MockImageCache mock_image_cache;
+  mock_image_ctx.image_cache = &mock_image_cache;
+  MockShutdownRequest mock_shutdown_request;
+  expect_close_image_cache(mock_image_ctx, mock_shutdown_request, 0);
+
   expect_invalidate_cache(mock_image_ctx, 0);
 
   expect_flush_notifies(mock_image_ctx);
@@ -194,6 +235,12 @@ TEST_F(TestMockExclusiveLockPreReleaseRequest, SuccessJournalDisabled) {
   InSequence seq;
   expect_prepare_lock(mock_image_ctx);
   expect_cancel_op_requests(mock_image_ctx, 0);
+
+  cache::MockImageCache mock_image_cache;
+  mock_image_ctx.image_cache = &mock_image_cache;
+  MockShutdownRequest mock_shutdown_request;
+  expect_close_image_cache(mock_image_ctx, mock_shutdown_request, 0);
+
   expect_invalidate_cache(mock_image_ctx, 0);
 
   expect_flush_notifies(mock_image_ctx);
@@ -225,6 +272,12 @@ TEST_F(TestMockExclusiveLockPreReleaseRequest, SuccessObjectMapDisabled) {
 
   InSequence seq;
   expect_cancel_op_requests(mock_image_ctx, 0);
+
+  cache::MockImageCache mock_image_cache;
+  mock_image_ctx.image_cache = &mock_image_cache;
+  MockShutdownRequest mock_shutdown_request;
+  expect_close_image_cache(mock_image_ctx, mock_shutdown_request, 0);
+
   expect_invalidate_cache(mock_image_ctx, 0);
 
   expect_flush_notifies(mock_image_ctx);
@@ -251,6 +304,12 @@ TEST_F(TestMockExclusiveLockPreReleaseRequest, Blacklisted) {
   expect_cancel_op_requests(mock_image_ctx, 0);
   MockImageDispatch mock_image_dispatch;
   expect_set_require_lock(mock_image_ctx, mock_image_dispatch, -EBLACKLISTED);
+
+  cache::MockImageCache mock_image_cache;
+  mock_image_ctx.image_cache = &mock_image_cache;
+  MockShutdownRequest mock_shutdown_request;
+  expect_close_image_cache(mock_image_ctx, mock_shutdown_request, 0);
+
   expect_invalidate_cache(mock_image_ctx, -EBLACKLISTED);
 
   expect_flush_notifies(mock_image_ctx);
index 20683ac6957ea8b1de650c2d41827b87f3497674..c240dec00046e5249be707476a2b6159ae3a4f9d 100644 (file)
@@ -234,6 +234,7 @@ TEST_F(TestMockObjectMapUpdateRequest, BatchUpdate) {
                                         no_progress));
   ASSERT_EQ(0, acquire_exclusive_lock(*ictx));
 
+  expect_unlock_exclusive_lock(*ictx);
   InSequence seq;
   expect_update(ictx, CEPH_NOSNAP, 0, 262144, OBJECT_NONEXISTENT, OBJECT_EXISTS,
                 0);
@@ -241,7 +242,6 @@ TEST_F(TestMockObjectMapUpdateRequest, BatchUpdate) {
                 OBJECT_EXISTS, 0);
   expect_update(ictx, CEPH_NOSNAP, 524288, 712312, OBJECT_NONEXISTENT,
                 OBJECT_EXISTS, 0);
-  expect_unlock_exclusive_lock(*ictx);
 
   ceph::shared_mutex object_map_lock = ceph::make_shared_mutex("lock");
   ceph::BitVector<2> object_map;
index f6a631a9070442eb42f9700a5976dad23624ccbf..73ae1483cb08d1a35cbbe02f802e0354d0c5d0ad 100644 (file)
@@ -271,8 +271,8 @@ struct TestMigration : public TestFixture {
   }
 
   void flush() {
-    ASSERT_EQ(0, api::Io<>::flush(*m_ref_ictx));
-    ASSERT_EQ(0, api::Io<>::flush(*m_ictx));
+    ASSERT_EQ(0, TestFixture::flush_writeback_cache(m_ref_ictx));
+    ASSERT_EQ(0, TestFixture::flush_writeback_cache(m_ictx));
   }
 
   void snap_create(const std::string &snap_name) {
@@ -540,6 +540,7 @@ librados::IoCtx TestMigration::_other_pool_ioctx;
 TEST_F(TestMigration, Empty)
 {
   uint64_t features = m_ictx->features ^ RBD_FEATURE_LAYERING;
+  features &= ~RBD_FEATURE_DIRTY_CACHE;
   ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FEATURES, features));
 
   migrate(m_ioctx, m_image_name);
index 15409d5676ffdae866006c21a55267f911b897aa..76055e698cab5c594382267c9f4f4013c65c3ad2 100644 (file)
@@ -1,11 +1,13 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 // vim: ts=8 sw=2 smarttab
+#include "common/Cond.h"
 #include "test/librbd/test_fixture.h"
 #include "test/librbd/test_support.h"
 #include "include/stringify.h"
 #include "librbd/ExclusiveLock.h"
 #include "librbd/ImageState.h"
 #include "librbd/ImageWatcher.h"
+#include "librbd/io/ImageDispatchSpec.h"
 #include "librbd/Operations.h"
 #include "librbd/api/Io.h"
 #include "cls/lock/cls_lock_client.h"
@@ -144,3 +146,19 @@ int TestFixture::acquire_exclusive_lock(librbd::ImageCtx &ictx) {
   ceph_assert(ictx.exclusive_lock != nullptr);
   return ictx.exclusive_lock->is_lock_owner() ? 0 : -EINVAL;
 }
+
+int TestFixture::flush_writeback_cache(librbd::ImageCtx *image_ctx) {
+  if (image_ctx->test_features(RBD_FEATURE_DIRTY_CACHE)) {
+    // cache exists. Close to flush data
+    C_SaferCond ctx;
+    auto aio_comp = librbd::io::AioCompletion::create_and_start(
+      &ctx, image_ctx, librbd::io::AIO_TYPE_FLUSH);
+    auto req = librbd::io::ImageDispatchSpec<>::create_flush(
+      *image_ctx, librbd::io::IMAGE_DISPATCH_LAYER_INTERNAL_START, aio_comp,
+      librbd::io::FLUSH_SOURCE_INTERNAL, {});
+    req->send();
+    return ctx.wait();
+  } else {
+    return librbd::api::Io<>::flush(*image_ctx);
+  }
+}
index 508e4405c6cf301481b8c645bbafcfc94670a7f4..d3bd7b8121eff582a12208d45caa13b4a75c6d66 100644 (file)
@@ -36,6 +36,8 @@ public:
                  const std::string &cookie);
   int unlock_image();
 
+  int flush_writeback_cache(librbd::ImageCtx *image_ctx);
+
   int acquire_exclusive_lock(librbd::ImageCtx &ictx);
 
   static std::string _pool_name;
index 3164e3e7b7eff31249164ec121830a5581002826..222bca832ea529288386263515d1c5c9ac6abc0c 100644 (file)
@@ -538,7 +538,12 @@ TEST_F(TestInternal, Metadata) {
   map<string, bufferlist> pairs;
   r = librbd::metadata_list(ictx, "", 0, &pairs);
   ASSERT_EQ(0, r);
-  ASSERT_EQ(5u, pairs.size());
+
+  uint8_t original_pairs_num = 0;
+  if (ictx->test_features(RBD_FEATURE_DIRTY_CACHE)) {
+    original_pairs_num = 1;
+  }
+  ASSERT_EQ(original_pairs_num + 5, pairs.size());
   r = ictx->operations->metadata_remove("abcd");
   ASSERT_EQ(0, r);
   r = ictx->operations->metadata_remove("xyz");
@@ -546,7 +551,7 @@ TEST_F(TestInternal, Metadata) {
   pairs.clear();
   r = librbd::metadata_list(ictx, "", 0, &pairs);
   ASSERT_EQ(0, r);
-  ASSERT_EQ(3u, pairs.size());
+  ASSERT_EQ(original_pairs_num + 3, pairs.size());
   string val;
   r = librbd::metadata_get(ictx, it->first, &val);
   ASSERT_EQ(0, r);
@@ -611,6 +616,7 @@ TEST_F(TestInternal, SnapshotCopyup)
   ASSERT_EQ(256, api::Io<>::write(*ictx2, 256, bl.length(), bufferlist{bl},
                                   0));
 
+  ASSERT_EQ(0, flush_writeback_cache(ictx2));
   librados::IoCtx snap_ctx;
   snap_ctx.dup(ictx2->data_ctx);
   snap_ctx.snap_set_read(CEPH_SNAPDIR);
@@ -752,8 +758,9 @@ TEST_F(TestInternal, SnapshotCopyupZeros)
 
   bufferlist bl;
   bl.append(std::string(256, '1'));
-  ASSERT_EQ(256, api::Io<>::write(*ictx2, 256, bl.length(), bufferlist{bl},
-                                  0));
+  ASSERT_EQ(256, api::Io<>::write(*ictx2, 256, bl.length(), bufferlist{bl}, 0));
+
+  ASSERT_EQ(0, flush_writeback_cache(ictx2));
 
   librados::IoCtx snap_ctx;
   snap_ctx.dup(ictx2->data_ctx);
@@ -1106,7 +1113,7 @@ TEST_F(TestInternal, WriteFullCopyup) {
   bl.append(std::string(1 << ictx->order, '1'));
   ASSERT_EQ((ssize_t)bl.length(),
             api::Io<>::write(*ictx, 0, bl.length(), bufferlist{bl}, 0));
-  ASSERT_EQ(0, api::Io<>::flush(*ictx));
+  ASSERT_EQ(0, flush_writeback_cache(ictx));
 
   ASSERT_EQ(0, create_snapshot("snap1", true));
 
@@ -1417,7 +1424,8 @@ TEST_F(TestInternal, FlattenNoEmptyObjects)
     ASSERT_EQ(TEST_IO_SIZE, image.write(itr->second, TEST_IO_SIZE, bl));
   }
 
-  ASSERT_EQ(0, image.flush());
+  ASSERT_EQ(0, image.close());
+  ASSERT_EQ(0, m_rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
 
   bufferlist readbl;
   printf("verify written data by reading\n");
@@ -1602,7 +1610,7 @@ TEST_F(TestInternal, Sparsify) {
             api::Io<>::write(*ictx, (1 << ictx->order) * 10 + 4096 * 10,
                              bl2.length(), bufferlist{bl2}, 0));
 
-  ASSERT_EQ(0, api::Io<>::flush(*ictx));
+  ASSERT_EQ(0, flush_writeback_cache(ictx));
 
   ASSERT_EQ(0, ictx->operations->sparsify(4096, no_op));
 
@@ -1690,7 +1698,7 @@ TEST_F(TestInternal, SparsifyClone) {
   ASSERT_EQ((ssize_t)bl.length(),
             api::Io<>::write(*ictx, (1 << ictx->order) * 10, bl.length(),
                              bufferlist{bl}, 0));
-  ASSERT_EQ(0, api::Io<>::flush(*ictx));
+  ASSERT_EQ(0, flush_writeback_cache(ictx));
 
   ASSERT_EQ(0, ictx->operations->sparsify(4096, no_op));
 
index 1a4e41c0f2c2a985ea2e8e35474c0d52d7f44cc3..9218da393a9f9d1da336205ba60cc2c660049dc5 100644 (file)
@@ -198,7 +198,7 @@ public:
     rados_shutdown(_cluster);
     _rados.wait_for_latest_osdmap();
     _pool_names.insert(_pool_names.end(), _unique_pool_names.begin(),
-                      _unique_pool_names.end());
+                       _unique_pool_names.end());
     for (size_t i = 1; i < _pool_names.size(); ++i) {
       ASSERT_EQ(0, _rados.pool_delete(_pool_names[i].c_str()));
     }
@@ -217,6 +217,26 @@ public:
     return value == "true";
   }
 
+  bool is_skip_partial_discard_enabled(rbd_image_t image) {
+    if (is_skip_partial_discard_enabled()) {
+      rbd_flush(image);
+      uint64_t features;
+      EXPECT_EQ(0, rbd_get_features(image, &features));
+      return !(features & RBD_FEATURE_DIRTY_CACHE);
+    }
+    return false;
+  }
+
+  bool is_skip_partial_discard_enabled(librbd::Image& image) {
+    if (is_skip_partial_discard_enabled()) {
+      image.flush();
+      uint64_t features;
+      EXPECT_EQ(0, image.features(&features));
+      return !(features & RBD_FEATURE_DIRTY_CACHE);
+    }
+    return false;
+  }
+
   void validate_object_map(rbd_image_t image, bool *passed) {
     uint64_t flags;
     ASSERT_EQ(0, rbd_get_flags(image, &flags));
@@ -984,7 +1004,7 @@ TEST_F(TestLibRBD, TestCopy)
   ASSERT_EQ(0, rbd_copy(image, ioctx, name2.c_str()));
   ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
   ASSERT_EQ(0, rbd_open(ioctx, name2.c_str(), &image2, NULL));
-  ASSERT_EQ(0, rbd_metadata_list(image2, "", 70, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image2, "key", 70, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, sum_key_len);
   ASSERT_EQ(vals_len, sum_value_len);
@@ -1005,7 +1025,7 @@ TEST_F(TestLibRBD, TestCopy)
   keys_len = sizeof(keys);
   vals_len = sizeof(vals);
   ASSERT_EQ(0, rbd_open(ioctx, name3.c_str(), &image3, NULL));
-  ASSERT_EQ(0, rbd_metadata_list(image3, "", 70, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image3, "key", 70, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, sum_key_len);
   ASSERT_EQ(vals_len, sum_value_len);
@@ -1168,7 +1188,7 @@ TEST_F(TestLibRBD, TestDeepCopy)
   BOOST_SCOPE_EXIT_ALL( (&image2) ) {
     ASSERT_EQ(0, rbd_close(image2));
   };
-  ASSERT_EQ(0, rbd_metadata_list(image2, "", 70, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image2, "key", 70, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, sum_key_len);
   ASSERT_EQ(vals_len, sum_value_len);
@@ -1192,7 +1212,7 @@ TEST_F(TestLibRBD, TestDeepCopy)
   BOOST_SCOPE_EXIT_ALL( (&image3) ) {
     ASSERT_EQ(0, rbd_close(image3));
   };
-  ASSERT_EQ(0, rbd_metadata_list(image3, "", 70, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image3, "key", 70, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, sum_key_len);
   ASSERT_EQ(vals_len, sum_value_len);
@@ -1228,7 +1248,7 @@ TEST_F(TestLibRBD, TestDeepCopy)
   BOOST_SCOPE_EXIT_ALL( (&image5) ) {
     ASSERT_EQ(0, rbd_close(image5));
   };
-  ASSERT_EQ(0, rbd_metadata_list(image5, "", 70, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image5, "key", 70, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, sum_key_len);
   ASSERT_EQ(vals_len, sum_value_len);
@@ -1253,7 +1273,7 @@ TEST_F(TestLibRBD, TestDeepCopy)
   BOOST_SCOPE_EXIT_ALL( (&image6) ) {
     ASSERT_EQ(0, rbd_close(image6));
   };
-  ASSERT_EQ(0, rbd_metadata_list(image6, "", 70, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image6, "key", 70, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, sum_key_len);
   ASSERT_EQ(vals_len, sum_value_len);
@@ -1941,8 +1961,6 @@ TEST_F(TestLibRBD, TestIO)
   rados_ioctx_t ioctx;
   rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
 
-  bool skip_discard = is_skip_partial_discard_enabled();
-
   rbd_image_t image;
   int order = 0;
   std::string name = get_temp_image_name();
@@ -1951,7 +1969,9 @@ TEST_F(TestLibRBD, TestIO)
   ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
   ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_read_from_replica_policy", "balance"));
   ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
-  
+
+  bool skip_discard = is_skip_partial_discard_enabled(image);
+
   char test_data[TEST_IO_SIZE + 1];
   char zero_data[TEST_IO_SIZE + 1];
   char mismatch_data[TEST_IO_SIZE + 1];
@@ -2063,8 +2083,6 @@ TEST_F(TestLibRBD, TestIOWithIOHint)
   rados_ioctx_t ioctx;
   rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
 
-  bool skip_discard = is_skip_partial_discard_enabled();
-
   rbd_image_t image;
   int order = 0;
   std::string name = get_temp_image_name();
@@ -2073,6 +2091,8 @@ TEST_F(TestLibRBD, TestIOWithIOHint)
   ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
   ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
 
+  bool skip_discard = is_skip_partial_discard_enabled(image);
+
   char test_data[TEST_IO_SIZE + 1];
   char zero_data[TEST_IO_SIZE + 1];
   char mismatch_data[TEST_IO_SIZE + 1];
@@ -2209,8 +2229,6 @@ TEST_F(TestLibRBD, TestDataPoolIO)
 
   std::string data_pool_name = create_pool(true);
 
-  bool skip_discard = is_skip_partial_discard_enabled();
-
   rbd_image_t image;
   std::string name = get_temp_image_name();
   uint64_t size = 2 << 20;
@@ -2237,6 +2255,8 @@ TEST_F(TestLibRBD, TestDataPoolIO)
   ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
   ASSERT_NE(-1, rbd_get_data_pool_id(image));
 
+  bool skip_discard = is_skip_partial_discard_enabled(image);
+
   char test_data[TEST_IO_SIZE + 1];
   char zero_data[TEST_IO_SIZE + 1];
   int i;
@@ -2685,8 +2705,6 @@ TEST_F(TestLibRBD, TestIOPP)
   librados::IoCtx ioctx;
   ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
 
-  bool skip_discard = is_skip_partial_discard_enabled();
-
   {
     librbd::RBD rbd;
     librbd::Image image;
@@ -2697,6 +2715,8 @@ TEST_F(TestLibRBD, TestIOPP)
     ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
     ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
 
+    bool skip_discard = this->is_skip_partial_discard_enabled(image);
+
     char test_data[TEST_IO_SIZE + 1];
     char zero_data[TEST_IO_SIZE + 1];
     int i;
@@ -3050,7 +3070,7 @@ TEST_F(TestLibRBD, TestClone)
   printf("sizes and overlaps are good between parent and child\n");
 
   // check key/value pairs in child image
-  ASSERT_EQ(0, rbd_metadata_list(child, "", 70, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(child, "key", 70, keys, &keys_len, vals,
                                 &vals_len));
   ASSERT_EQ(sum_key_len, keys_len);
   ASSERT_EQ(sum_value_len, vals_len);
@@ -3184,7 +3204,7 @@ TEST_F(TestLibRBD, TestClone2)
   printf("made and opened clone \"child\"\n");
 
   // check key/value pairs in child image
-  ASSERT_EQ(0, rbd_metadata_list(child, "", 70, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(child, "key", 70, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(sum_key_len, keys_len);
   ASSERT_EQ(sum_value_len, vals_len);
@@ -3950,8 +3970,6 @@ TYPED_TEST(DiffIterateTest, DiffIterate)
   librados::IoCtx ioctx;
   ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
 
-  bool skip_discard = this->is_skip_partial_discard_enabled();
-
   {
     librbd::RBD rbd;
     librbd::Image image;
@@ -3962,6 +3980,8 @@ TYPED_TEST(DiffIterateTest, DiffIterate)
     ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
     ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
 
+    bool skip_discard = this->is_skip_partial_discard_enabled(image);
+
     uint64_t object_size = 0;
     if (this->whole_object) {
       object_size = 1 << order;
@@ -4097,11 +4117,10 @@ TYPED_TEST(DiffIterateTest, DiffIterateDiscard)
 
 TYPED_TEST(DiffIterateTest, DiffIterateStress)
 {
+  REQUIRE(!is_rbd_rwl_enabled((CephContext *)this->_rados.cct()));
   librados::IoCtx ioctx;
   ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
 
-  bool skip_discard = this->is_skip_partial_discard_enabled();
-
   librbd::RBD rbd;
   librbd::Image image;
   int order = 0;
@@ -4111,6 +4130,8 @@ TYPED_TEST(DiffIterateTest, DiffIterateStress)
   ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
   ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
 
+  bool skip_discard = this->is_skip_partial_discard_enabled(image);
+
   uint64_t object_size = 0;
   if (this->whole_object) {
     object_size = 1 << order;
@@ -4221,8 +4242,6 @@ TYPED_TEST(DiffIterateTest, DiffIterateIgnoreParent)
   librados::IoCtx ioctx;
   ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
 
-  bool skip_discard = this->is_skip_partial_discard_enabled();
-
   librbd::RBD rbd;
   librbd::Image image;
   std::string name = this->get_temp_image_name();
@@ -4232,6 +4251,8 @@ TYPED_TEST(DiffIterateTest, DiffIterateIgnoreParent)
   ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
   ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
 
+  bool skip_discard = this->is_skip_partial_discard_enabled(image);
+
   uint64_t object_size = 0;
   if (this->whole_object) {
     object_size = 1 << order;
@@ -4272,8 +4293,6 @@ TYPED_TEST(DiffIterateTest, DiffIterateCallbackError)
   librados::IoCtx ioctx;
   ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
 
-  bool skip_discard = this->is_skip_partial_discard_enabled();
-
   {
     librbd::RBD rbd;
     librbd::Image image;
@@ -4284,6 +4303,8 @@ TYPED_TEST(DiffIterateTest, DiffIterateCallbackError)
     ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
     ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
 
+    bool skip_discard = this->is_skip_partial_discard_enabled(image);
+
     interval_set<uint64_t> exists;
     interval_set<uint64_t> one;
     scribble(image, 10, 102400, skip_discard, &exists, &one);
@@ -4304,8 +4325,6 @@ TYPED_TEST(DiffIterateTest, DiffIterateParentDiscard)
   librados::IoCtx ioctx;
   ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
 
-  bool skip_discard = this->is_skip_partial_discard_enabled();
-
   librbd::RBD rbd;
   librbd::Image image;
   std::string name = this->get_temp_image_name();
@@ -4315,6 +4334,8 @@ TYPED_TEST(DiffIterateTest, DiffIterateParentDiscard)
   ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
   ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
 
+  bool skip_discard = this->is_skip_partial_discard_enabled(image);
+
   uint64_t object_size = 0;
   if (this->whole_object) {
     object_size = 1 << order;
@@ -5413,7 +5434,7 @@ TEST_F(TestLibRBD, Metadata)
   memset_rand(keys, keys_len);
   memset_rand(vals, vals_len);
 
-  ASSERT_EQ(0, rbd_metadata_list(image, "", 0, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image, "key", 0, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(0U, keys_len);
   ASSERT_EQ(0U, vals_len);
@@ -5430,13 +5451,13 @@ TEST_F(TestLibRBD, Metadata)
   ASSERT_EQ(-ERANGE, rbd_metadata_get(image1, "key1", value, &value_len));
   ASSERT_EQ(value_len, strlen("value1") + 1);
 
-  ASSERT_EQ(-ERANGE, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
+  ASSERT_EQ(-ERANGE, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
                                        &vals_len));
   keys_len = sizeof(keys);
   vals_len = sizeof(vals);
   memset_rand(keys, keys_len);
   memset_rand(vals, vals_len);
-  ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
   ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
@@ -5449,7 +5470,7 @@ TEST_F(TestLibRBD, Metadata)
   ASSERT_EQ(-ENOENT, rbd_metadata_remove(image1, "key3"));
   value_len = sizeof(value);
   ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key3", value, &value_len));
-  ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, strlen("key2") + 1);
   ASSERT_EQ(vals_len, strlen("value2") + 1);
@@ -5473,7 +5494,7 @@ TEST_F(TestLibRBD, Metadata)
   vals_len = sizeof(vals);
   memset_rand(keys, keys_len);
   memset_rand(vals, vals_len);
-  ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len,
             strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
@@ -5491,7 +5512,7 @@ TEST_F(TestLibRBD, Metadata)
   vals_len = sizeof(vals);
   memset_rand(keys, keys_len);
   memset_rand(vals, vals_len);
-  ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len,
             strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
@@ -5519,7 +5540,7 @@ TEST_F(TestLibRBD, Metadata)
   vals_len = sizeof(vals);
   memset_rand(keys, keys_len);
   memset_rand(vals, vals_len);
-  ASSERT_EQ(0, rbd_metadata_list(image2, "", 0, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image2, "key", 0, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
             1 + strlen("key4") + 1);
@@ -5530,7 +5551,7 @@ TEST_F(TestLibRBD, Metadata)
   ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1 +
                strlen("value3") + 1, "value4");
 
-  ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len,
             strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
@@ -5543,19 +5564,19 @@ TEST_F(TestLibRBD, Metadata)
   vals_len = strlen("value1") + 1;
   memset_rand(keys, keys_len);
   memset_rand(vals, vals_len);
-  ASSERT_EQ(0, rbd_metadata_list(image2, "", 1, keys, &keys_len, vals,
+  ASSERT_EQ(0, rbd_metadata_list(image2, "key", 1, keys, &keys_len, vals,
                                  &vals_len));
   ASSERT_EQ(keys_len, strlen("key1") + 1);
   ASSERT_EQ(vals_len, strlen("value1") + 1);
   ASSERT_STREQ(keys, "key1");
   ASSERT_STREQ(vals, "value1");
 
-  ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "", 2, keys, &keys_len, vals,
+  ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "key", 2, keys, &keys_len, vals,
                                        &vals_len));
   ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
   ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
 
-  ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "", 0, keys, &keys_len, vals,
+  ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "key", 0, keys, &keys_len, vals,
                                        &vals_len));
   ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
             1 + strlen("key4") + 1);
@@ -5598,14 +5619,14 @@ TEST_F(TestLibRBD, MetadataPP)
   librbd::Image image1;
   ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
   map<string, bufferlist> pairs;
-  ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
+  ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
   ASSERT_TRUE(pairs.empty());
 
   ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
   ASSERT_EQ(0, image1.metadata_set("key2", "value2"));
   ASSERT_EQ(0, image1.metadata_get("key1", &value));
   ASSERT_EQ(0, strcmp("value1", value.c_str()));
-  ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
+  ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
   ASSERT_EQ(2U, pairs.size());
   ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
   ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
@@ -5614,7 +5635,7 @@ TEST_F(TestLibRBD, MetadataPP)
   ASSERT_EQ(0, image1.metadata_remove("key1"));
   ASSERT_EQ(-ENOENT, image1.metadata_remove("key3"));
   ASSERT_TRUE(image1.metadata_get("key3", &value) < 0);
-  ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
+  ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
   ASSERT_EQ(1U, pairs.size());
   ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
 
@@ -5631,14 +5652,14 @@ TEST_F(TestLibRBD, MetadataPP)
   pairs.clear();
   ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
   ASSERT_EQ(0, image1.metadata_set("key3", "value3"));
-  ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
+  ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
   ASSERT_EQ(3U, pairs.size());
   ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
   ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
   ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
 
   ASSERT_EQ(0, image1.snap_set(NULL));
-  ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
+  ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
   ASSERT_EQ(3U, pairs.size());
   ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
   ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
@@ -5653,10 +5674,10 @@ TEST_F(TestLibRBD, MetadataPP)
   ASSERT_EQ(0, rbd.open(ioctx, image2, cname.c_str(), NULL));
   ASSERT_EQ(0, image2.metadata_set("key4", "value4"));
   pairs.clear();
-  ASSERT_EQ(0, image2.metadata_list("", 0, &pairs));
+  ASSERT_EQ(0, image2.metadata_list("key", 0, &pairs));
   ASSERT_EQ(4U, pairs.size());
   pairs.clear();
-  ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
+  ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
   ASSERT_EQ(3U, pairs.size());
   ASSERT_EQ(-ENOENT, image1.metadata_get("key4", &value));
 }
@@ -5949,8 +5970,6 @@ TEST_F(TestLibRBD, BlockingAIO)
   librados::IoCtx ioctx;
   ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
 
-  bool skip_discard = is_skip_partial_discard_enabled();
-
   librbd::RBD rbd;
   std::string name = get_temp_image_name();
   uint64_t size = 1 << 20;
@@ -5968,6 +5987,8 @@ TEST_F(TestLibRBD, BlockingAIO)
   librbd::Image image;
   ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
 
+  bool skip_discard = this->is_skip_partial_discard_enabled(image);
+
   bufferlist bl;
   ASSERT_EQ(0, image.write(0, bl.length(), bl));
 
@@ -6826,6 +6847,7 @@ TEST_F(TestLibRBD, ExclusiveLock)
 TEST_F(TestLibRBD, BreakLock)
 {
   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+  REQUIRE(!is_rbd_rwl_enabled((CephContext *)_rados.cct()));
 
   static char buf[10];
 
@@ -6877,8 +6899,6 @@ TEST_F(TestLibRBD, BreakLock)
 
 TEST_F(TestLibRBD, DiscardAfterWrite)
 {
-  REQUIRE(!is_skip_partial_discard_enabled());
-
   librados::IoCtx ioctx;
   ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
 
@@ -6891,6 +6911,10 @@ TEST_F(TestLibRBD, DiscardAfterWrite)
   librbd::Image image;
   ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
 
+  if (this->is_skip_partial_discard_enabled(image)) {
+    return;
+  }
+
   // enable writeback cache
   ASSERT_EQ(0, image.flush());
 
index e3277a0a25185e24f686bb7fd9836e9f97eb083c..840ac33b1195220eff86ffae8c487dff316116ab 100644 (file)
@@ -1377,7 +1377,7 @@ TEST_F(TestMirroring, SnapshotImageState)
   ASSERT_EQ(features & ~RBD_FEATURES_IMPLICIT_ENABLE, image_state.features);
   ASSERT_EQ(1U, image_state.snapshots.size());
   ASSERT_EQ("snap", image_state.snapshots.begin()->second.name);
-  ASSERT_TRUE(image_state.metadata.empty());
+  uint8_t original_pairs_num = image_state.metadata.size();
 
   {
     C_SaferCond cond;
@@ -1413,7 +1413,7 @@ TEST_F(TestMirroring, SnapshotImageState)
 
   ASSERT_EQ(image_name, image_state.name);
   ASSERT_EQ(features & ~RBD_FEATURES_IMPLICIT_ENABLE, image_state.features);
-  ASSERT_EQ(10U, image_state.metadata.size());
+  ASSERT_EQ(original_pairs_num + 10, image_state.metadata.size());
   for (int i = 0; i < 10; i++) {
     auto &bl = image_state.metadata[stringify(i)];
     ASSERT_EQ(0, strncmp(std::string(1024, 'A' + i).c_str(), bl.c_str(),
index c0693f78a1d0116b3b7c4179b90588ef3156804c..65f7da64e605b26de65ad5fb7116c55ea56feb81 100644 (file)
@@ -262,7 +262,8 @@ public:
   void expect_set_require_lock(MockExclusiveLockImageCtx &mock_image_ctx,
                                MockImageDispatch &mock_image_dispatch) {
     if (mock_image_ctx.clone_copy_on_read ||
-        (mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0) {
+        (mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0 ||
+        is_rbd_rwl_enabled(mock_image_ctx.cct)) {
       expect_set_require_lock(mock_image_dispatch, io::DIRECTION_BOTH);
     } else {
       expect_set_require_lock(mock_image_dispatch, io::DIRECTION_WRITE);
index 166175c9bd44165c900fd1a8cfdd566648f3f398..d2a6837c6eb1a364eb90beeb8cc4ecf6b37ae532 100644 (file)
@@ -55,6 +55,17 @@ void TestMockFixture::expect_unlock_exclusive_lock(librbd::ImageCtx &ictx) {
   EXPECT_CALL(get_mock_io_ctx(ictx.md_ctx),
               exec(_, _, StrEq("lock"), StrEq("unlock"), _, _, _, _))
                 .WillRepeatedly(DoDefault());
+  if (ictx.test_features(RBD_FEATURE_DIRTY_CACHE)) {
+    EXPECT_CALL(get_mock_io_ctx(ictx.md_ctx),
+                exec(ictx.header_oid, _, StrEq("rbd"), StrEq("set_features"), _, _, _, _))
+                  .WillOnce(DoDefault());
+    EXPECT_CALL(get_mock_io_ctx(ictx.md_ctx),
+                exec(ictx.header_oid, _, StrEq("rbd"), StrEq("metadata_set"), _, _, _, _))
+                  .WillOnce(DoDefault());
+    EXPECT_CALL(get_mock_io_ctx(ictx.md_ctx),
+                exec(ictx.header_oid, _, StrEq("rbd"), StrEq("metadata_remove"), _, _, _, _))
+                  .WillOnce(DoDefault());
+  }
 }
 
 void TestMockFixture::expect_op_work_queue(librbd::MockImageCtx &mock_image_ctx) {
index e74068e6600a124b861967564106ef0e5507a5da..25b34436bb18ece02bfd3ddd4960700e983d0d22 100644 (file)
@@ -3,6 +3,7 @@
 #include "test/librbd/test_support.h"
 #include "include/rbd_types.h"
 #include "gtest/gtest.h"
+#include "common/ceph_context.h"
 #include <sstream>
 
 bool get_features(uint64_t *features) {
@@ -126,3 +127,10 @@ bool is_librados_test_stub(librados::Rados &rados) {
   return fsid == "00000000-1111-2222-3333-444444444444";
 }
 
+bool is_rbd_rwl_enabled(ceph::common::CephContext *cct) {
+#if defined(WITH_RBD_RWL)
+  return cct->_conf.get_val<bool>("rbd_rwl_enabled");
+#else
+  return false;
+#endif
+}
index abb7c4702cd197144691ae60343cd5730ca3383d..a428d32b393bd44edf80850272a23f7026fdcec9 100644 (file)
@@ -26,6 +26,8 @@ int create_image_data_pool(librados::Rados &rados, std::string &data_pool, bool
 
 bool is_librados_test_stub(librados::Rados &rados);
 
+bool is_rbd_rwl_enabled(ceph::common::CephContext *ctx);
+
 #define REQUIRE(x) {                     \
   if (!(x)) {                            \
     std::cout << "SKIPPING" << std::endl; \