]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: switch to new metadata retrieval state machine
authorJason Dillaman <dillaman@redhat.com>
Thu, 13 Feb 2020 19:04:07 +0000 (14:04 -0500)
committerJason Dillaman <dillaman@redhat.com>
Fri, 21 Feb 2020 14:03:09 +0000 (09:03 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
12 files changed:
src/librbd/api/Config.cc
src/librbd/api/PoolMetadata.cc
src/librbd/deep_copy/MetadataCopyRequest.cc
src/librbd/deep_copy/MetadataCopyRequest.h
src/librbd/image/CloneRequest.cc
src/librbd/image/CloneRequest.h
src/librbd/image/RefreshRequest.cc
src/librbd/image/RefreshRequest.h
src/librbd/internal.cc
src/test/librbd/deep_copy/test_mock_MetadataCopyRequest.cc
src/test/librbd/image/test_mock_CloneRequest.cc
src/test/librbd/image/test_mock_RefreshRequest.cc

index 60598f8d15b3a1597693c9feec5499f15e5b1f30..3d781d8b034978a6b6a5f8c5cd999c38e4862ca1 100644 (file)
@@ -2,12 +2,14 @@
 // vim: ts=8 sw=2 smarttab
 
 #include "librbd/api/Config.h"
-#include "cls/rbd/cls_rbd_client.h"
 #include "common/dout.h"
 #include "common/errno.h"
+#include "common/Cond.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/Utils.h"
 #include "librbd/api/PoolMetadata.h"
+#include "librbd/image/GetMetadataRequest.h"
+#include <algorithm>
 #include <boost/algorithm/string/predicate.hpp>
 
 #define dout_subsys ceph_subsys_rbd
@@ -167,38 +169,29 @@ int Config<I>::list(I *image_ctx, std::vector<config_option_t> *options) {
     return r;
   }
 
-  std::string last_key = ImageCtx::METADATA_CONF_PREFIX;
-  bool more_results = true;
+  std::map<std::string, bufferlist> pairs;
+  C_SaferCond ctx;
+  auto req = image::GetMetadataRequest<I>::create(
+    image_ctx->md_ctx, image_ctx->header_oid, ImageCtx::METADATA_CONF_PREFIX,
+    ImageCtx::METADATA_CONF_PREFIX, 0U, &pairs, &ctx);
+  req->send();
 
-  while (more_results) {
-    std::map<std::string, bufferlist> pairs;
-
-    r = cls_client::metadata_list(&image_ctx->md_ctx, image_ctx->header_oid,
-                                  last_key, MAX_KEYS, &pairs);
-    if (r < 0) {
-      lderr(cct) << "failed reading image metadata: " << cpp_strerror(r)
-                 << dendl;
-      return r;
-    }
+  r = ctx.wait();
+  if (r < 0) {
+    lderr(cct) << "failed reading image metadata: " << cpp_strerror(r)
+               << dendl;
+    return r;
+  }
 
-    if (pairs.empty()) {
+  for (auto kv : pairs) {
+    std::string key;
+    if (!util::is_metadata_config_override(kv.first, &key)) {
       break;
     }
-
-    more_results = (pairs.size() == MAX_KEYS);
-    last_key = pairs.rbegin()->first;
-
-    for (auto kv : pairs) {
-      std::string key;
-      if (!util::is_metadata_config_override(kv.first, &key)) {
-        more_results = false;
-        break;
-      }
-      auto it = opts.find(key);
-      if (it != opts.end()) {
-        it->second = {{kv.second.c_str(), kv.second.length()},
-                      RBD_CONFIG_SOURCE_IMAGE};
-      }
+    auto it = opts.find(key);
+    if (it != opts.end()) {
+      it->second = {{kv.second.c_str(), kv.second.length()},
+                    RBD_CONFIG_SOURCE_IMAGE};
     }
   }
 
index 2f65e0ad9b02f6cf1b4fa4ec00ddbb97a9622c56..1449cba9ef31e28a653cfdc5fa584fc8440fc4a7 100644 (file)
@@ -5,8 +5,10 @@
 #include "cls/rbd/cls_rbd_client.h"
 #include "common/dout.h"
 #include "common/errno.h"
+#include "common/Cond.h"
 #include "librbd/Utils.h"
 #include "librbd/api/Config.h"
+#include "librbd/image/GetMetadataRequest.h"
 
 #define dout_subsys ceph_subsys_rbd
 #undef dout_prefix
@@ -94,15 +96,18 @@ int PoolMetadata<I>::list(librados::IoCtx& io_ctx, const std::string &start,
                           std::map<std::string, ceph::bufferlist> *pairs) {
   CephContext *cct = (CephContext *)io_ctx.cct();
 
-  int r = cls_client::metadata_list(&io_ctx, RBD_INFO, start, max, pairs);
-  if (r == -ENOENT) {
-    r = 0;
-  } else if (r < 0) {
+  pairs->clear();
+  C_SaferCond ctx;
+  auto req = image::GetMetadataRequest<I>::create(
+    io_ctx, RBD_INFO, "", start, max, pairs, &ctx);
+  req->send();
+
+  int r = ctx.wait();
+  if (r < 0) {
     lderr(cct) << "failed listing metadata: " << cpp_strerror(r)
                << dendl;
     return r;
   }
-
   return 0;
 }
 
index cbce9a19eacefe0831118874d96d8277ddc9a549..283e927332d17b3faf58a37a4f6c87a14f3f0c09 100644 (file)
@@ -6,6 +6,7 @@
 #include "common/errno.h"
 #include "cls/rbd/cls_rbd_client.h"
 #include "librbd/Utils.h"
+#include "librbd/image/GetMetadataRequest.h"
 
 #define dout_subsys ceph_subsys_rbd
 #undef dout_prefix
@@ -21,6 +22,7 @@ const uint64_t MAX_METADATA_ITEMS = 128;
 
 } // anonymous namespace
 
+using librbd::util::create_context_callback;
 using librbd::util::create_rados_callback;
 
 template <typename I>
@@ -39,50 +41,42 @@ template <typename I>
 void MetadataCopyRequest<I>::list_src_metadata() {
   ldout(m_cct, 20) << "start_key=" << m_last_metadata_key << dendl;
 
-  librados::ObjectReadOperation op;
-  librbd::cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS);
-
-  librados::AioCompletion *aio_comp = create_rados_callback<
+  m_metadata.clear();
+  auto ctx = create_context_callback<
     MetadataCopyRequest<I>,
     &MetadataCopyRequest<I>::handle_list_src_metadata>(this);
-  m_out_bl.clear();
-  m_src_image_ctx->md_ctx.aio_operate(m_src_image_ctx->header_oid,
-                                      aio_comp, &op, &m_out_bl);
-  aio_comp->release();
+  auto req = image::GetMetadataRequest<I>::create(
+    m_src_image_ctx->md_ctx, m_src_image_ctx->header_oid, "",
+    m_last_metadata_key, MAX_METADATA_ITEMS, &m_metadata, ctx);
+  req->send();
 }
 
 template <typename I>
 void MetadataCopyRequest<I>::handle_list_src_metadata(int r) {
   ldout(m_cct, 20) << "r=" << r << dendl;
 
-  Metadata metadata;
-  if (r == 0) {
-    auto it = m_out_bl.cbegin();
-    r = librbd::cls_client::metadata_list_finish(&it, &metadata);
-  }
-
   if (r < 0) {
     lderr(m_cct) << "failed to retrieve metadata: " << cpp_strerror(r) << dendl;
     finish(r);
     return;
   }
 
-  if (metadata.empty()) {
+  if (m_metadata.empty()) {
     finish(0);
     return;
   }
 
-  m_last_metadata_key = metadata.rbegin()->first;
-  m_more_metadata = (metadata.size() >= MAX_METADATA_ITEMS);
-  set_dst_metadata(metadata);
+  m_last_metadata_key = m_metadata.rbegin()->first;
+  m_more_metadata = (m_metadata.size() >= MAX_METADATA_ITEMS);
+  set_dst_metadata();
 }
 
 template <typename I>
-void MetadataCopyRequest<I>::set_dst_metadata(const Metadata& metadata) {
-  ldout(m_cct, 20) << "count=" << metadata.size() << dendl;
+void MetadataCopyRequest<I>::set_dst_metadata() {
+  ldout(m_cct, 20) << "count=" << m_metadata.size() << dendl;
 
   librados::ObjectWriteOperation op;
-  librbd::cls_client::metadata_set(&op, metadata);
+  librbd::cls_client::metadata_set(&op, m_metadata);
 
   librados::AioCompletion *aio_comp = create_rados_callback<
     MetadataCopyRequest<I>,
index 5bd69d8bb97b5855aa142ac553efe50b1f7868e0..8db55db967e9a10329c09d71955a55a914868070 100644 (file)
@@ -56,13 +56,14 @@ private:
   CephContext *m_cct;
   bufferlist m_out_bl;
 
+  std::map<std::string, bufferlist> m_metadata;
   std::string m_last_metadata_key;
   bool m_more_metadata = false;
 
   void list_src_metadata();
   void handle_list_src_metadata(int r);
 
-  void set_dst_metadata(const Metadata& metadata);
+  void set_dst_metadata();
   void handle_set_dst_metadata(int r);
 
   void finish(int r);
index cdf1fd7a911efceea9fc25a8c3b53cf9230f7fe5..5da8769a3ef86c661fa283c86d2e5dde7f42b735 100644 (file)
@@ -8,6 +8,7 @@
 #include "include/ceph_assert.h"
 #include "librbd/ImageState.h"
 #include "librbd/Utils.h"
+#include "librbd/deep_copy/MetadataCopyRequest.h"
 #include "librbd/image/AttachChildRequest.h"
 #include "librbd/image/AttachParentRequest.h"
 #include "librbd/image/CloneRequest.h"
@@ -391,90 +392,32 @@ void CloneRequest<I>::handle_attach_child(int r) {
     return;
   }
 
-  metadata_list();
+  copy_metadata();
 }
 
 template <typename I>
-void CloneRequest<I>::metadata_list() {
-  ldout(m_cct, 15) << "start_key=" << m_last_metadata_key << dendl;
-
-  librados::ObjectReadOperation op;
-  cls_client::metadata_list_start(&op, m_last_metadata_key, 0);
-
-  using klass = CloneRequest<I>;
-  librados::AioCompletion *comp =
-    create_rados_callback<klass, &klass::handle_metadata_list>(this);
-  m_out_bl.clear();
-  m_parent_image_ctx->md_ctx.aio_operate(m_parent_image_ctx->header_oid,
-                               comp, &op, &m_out_bl);
-  comp->release();
-}
-
-template <typename I>
-void CloneRequest<I>::handle_metadata_list(int r) {
-  ldout(m_cct, 15) << "r=" << r << dendl;
-
-  map<string, bufferlist> metadata;
-  if (r == 0) {
-    auto it = m_out_bl.cbegin();
-    r = cls_client::metadata_list_finish(&it, &metadata);
-  }
-
-  if (r < 0) {
-    if (r == -EOPNOTSUPP || r == -EIO) {
-      ldout(m_cct, 10) << "config metadata not supported by OSD" << dendl;
-      get_mirror_mode();
-    } else {
-      lderr(m_cct) << "couldn't list metadata: " << cpp_strerror(r) << dendl;
-      m_r_saved = r;
-      close_child();
-    }
-    return;
-  }
-
-  if (!metadata.empty()) {
-    m_pairs.insert(metadata.begin(), metadata.end());
-    m_last_metadata_key = m_pairs.rbegin()->first;
-  }
-
-  if (metadata.size() == MAX_KEYS) {
-    metadata_list();
-  } else {
-    metadata_set();
-  }
-}
-
-template <typename I>
-void CloneRequest<I>::metadata_set() {
-  if (m_pairs.empty()) {
-    get_mirror_mode();
-    return;
-  }
-
+void CloneRequest<I>::copy_metadata() {
   ldout(m_cct, 15) << dendl;
 
-  librados::ObjectWriteOperation op;
-  cls_client::metadata_set(&op, m_pairs);
-
-  using klass = CloneRequest<I>;
-  librados::AioCompletion *comp =
-    create_rados_callback<klass, &klass::handle_metadata_set>(this);
-  int r = m_ioctx.aio_operate(m_imctx->header_oid, comp, &op);
-  ceph_assert(r == 0);
-  comp->release();
+  auto ctx = create_context_callback<
+    CloneRequest<I>, &CloneRequest<I>::handle_copy_metadata>(this);
+  auto req = deep_copy::MetadataCopyRequest<I>::create(
+    m_parent_image_ctx, m_imctx, ctx);
+  req->send();
 }
 
 template <typename I>
-void CloneRequest<I>::handle_metadata_set(int r) {
+void CloneRequest<I>::handle_copy_metadata(int r) {
   ldout(m_cct, 15) << "r=" << r << dendl;
 
   if (r < 0) {
-    lderr(m_cct) << "couldn't set metadata: " << cpp_strerror(r) << dendl;
+    lderr(m_cct) << "failed to copy metadata: " << cpp_strerror(r) << dendl;
     m_r_saved = r;
     close_child();
-  } else {
-    get_mirror_mode();
+    return;
   }
+
+  get_mirror_mode();
 }
 
 template <typename I>
index c7bfc823c0db11782b966642ce9cb391eb4b3bd3..9a792657ba4ee7347a8d05864a0e50673909ffab 100644 (file)
@@ -77,10 +77,7 @@ private:
    * ATTACH CHILD * * * * * * * * * * * *
    *    |                               *
    *    v                               *
-   * GET PARENT META  * * * * * * * * * ^
-   *    |                               *
-   *    v (skip if not needed)          *
-   * SET CHILD META * * * * * * * * * * ^
+   * COPY META DATA * * * * * * * * * * ^
    *    |                               *
    *    v (skip if not needed)          *
    * GET MIRROR MODE  * * * * * * * * * ^
@@ -126,8 +123,6 @@ private:
   uint64_t m_clone_format = 2;
   bool m_use_p_features;
   uint64_t m_features;
-  map<string, bufferlist> m_pairs;
-  std::string m_last_metadata_key;
   bufferlist m_out_bl;
   uint64_t m_size;
   int m_r_saved = 0;
@@ -154,11 +149,8 @@ private:
   void attach_child();
   void handle_attach_child(int r);
 
-  void metadata_list();
-  void handle_metadata_list(int r);
-
-  void metadata_set();
-  void handle_metadata_set(int r);
+  void copy_metadata();
+  void handle_copy_metadata(int r);
 
   void get_mirror_mode();
   void handle_get_mirror_mode(int r);
index adc0afb4b8faf8c7f0771f9c10649f3741e2123b..82963c8869306c5704a95590bf5b8d5ba829b1bf 100644 (file)
@@ -1,7 +1,6 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 // vim: ts=8 sw=2 smarttab
 
-#include <boost/algorithm/string/predicate.hpp>
 #include "include/ceph_assert.h"
 
 #include "librbd/image/RefreshRequest.h"
@@ -16,6 +15,7 @@
 #include "librbd/ObjectMap.h"
 #include "librbd/Utils.h"
 #include "librbd/deep_copy/Utils.h"
+#include "librbd/image/GetMetadataRequest.h"
 #include "librbd/image/RefreshParentRequest.h"
 #include "librbd/io/AioCompletion.h"
 #include "librbd/io/ImageDispatchSpec.h"
@@ -495,19 +495,15 @@ Context *RefreshRequest<I>::handle_v2_get_parent(int *result) {
 template <typename I>
 void RefreshRequest<I>::send_v2_get_metadata() {
   CephContext *cct = m_image_ctx.cct;
-  ldout(cct, 10) << this << " " << __func__ << ": "
-                 << "start_key=" << m_last_metadata_key << dendl;
-
-  librados::ObjectReadOperation op;
-  cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS);
+  ldout(cct, 10) << this << " " << __func__ << dendl;
 
-  using klass = RefreshRequest<I>;
-  librados::AioCompletion *comp =
-    create_rados_callback<klass, &klass::handle_v2_get_metadata>(this);
-  m_out_bl.clear();
-  m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
-                                  &m_out_bl);
-  comp->release();
+  auto ctx = create_context_callback<
+    RefreshRequest<I>, &RefreshRequest<I>::handle_v2_get_metadata>(this);
+  auto req = GetMetadataRequest<I>::create(
+    m_image_ctx.md_ctx, m_image_ctx.header_oid,
+    ImageCtx::METADATA_CONF_PREFIX, ImageCtx::METADATA_CONF_PREFIX, 0U,
+    &m_metadata, ctx);
+  req->send();
 }
 
 template <typename I>
@@ -515,29 +511,12 @@ Context *RefreshRequest<I>::handle_v2_get_metadata(int *result) {
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
 
-  std::map<std::string, bufferlist> metadata;
-  if (*result == 0) {
-    auto it = m_out_bl.cbegin();
-    *result = cls_client::metadata_list_finish(&it, &metadata);
-  }
-
   if (*result < 0) {
     lderr(cct) << "failed to retrieve metadata: " << cpp_strerror(*result)
                << dendl;
     return m_on_finish;
   }
 
-  if (!metadata.empty()) {
-    m_metadata.insert(metadata.begin(), metadata.end());
-    m_last_metadata_key = metadata.rbegin()->first;
-    if (boost::starts_with(m_last_metadata_key,
-                           ImageCtx::METADATA_CONF_PREFIX)) {
-      send_v2_get_metadata();
-      return nullptr;
-    }
-  }
-
-  m_last_metadata_key.clear();
   send_v2_get_pool_metadata();
   return nullptr;
 }
@@ -545,18 +524,14 @@ Context *RefreshRequest<I>::handle_v2_get_metadata(int *result) {
 template <typename I>
 void RefreshRequest<I>::send_v2_get_pool_metadata() {
   CephContext *cct = m_image_ctx.cct;
-  ldout(cct, 10) << this << " " << __func__ << ": "
-                 << "start_key=" << m_last_metadata_key << dendl;
-
-  librados::ObjectReadOperation op;
-  cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS);
+  ldout(cct, 10) << this << " " << __func__ << dendl;
 
-  using klass = RefreshRequest<I>;
-  librados::AioCompletion *comp =
-    create_rados_callback<klass, &klass::handle_v2_get_pool_metadata>(this);
-  m_out_bl.clear();
-  m_pool_metadata_io_ctx.aio_operate(RBD_INFO, comp, &op, &m_out_bl);
-  comp->release();
+  auto ctx = create_context_callback<
+    RefreshRequest<I>, &RefreshRequest<I>::handle_v2_get_pool_metadata>(this);
+  auto req = GetMetadataRequest<I>::create(
+    m_pool_metadata_io_ctx, RBD_INFO, ImageCtx::METADATA_CONF_PREFIX,
+    ImageCtx::METADATA_CONF_PREFIX, 0U, &m_metadata, ctx);
+  req->send();
 }
 
 template <typename I>
@@ -564,30 +539,12 @@ Context *RefreshRequest<I>::handle_v2_get_pool_metadata(int *result) {
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
 
-  std::map<std::string, bufferlist> metadata;
-  if (*result == 0) {
-    auto it = m_out_bl.cbegin();
-    *result = cls_client::metadata_list_finish(&it, &metadata);
-  }
-
-  if (*result == -EOPNOTSUPP || *result == -ENOENT) {
-    ldout(cct, 10) << "pool metadata not supported by OSD" << dendl;
-  } else if (*result < 0) {
+  if (*result < 0) {
     lderr(cct) << "failed to retrieve pool metadata: " << cpp_strerror(*result)
                << dendl;
     return m_on_finish;
   }
 
-  if (!metadata.empty()) {
-    m_metadata.insert(metadata.begin(), metadata.end());
-    m_last_metadata_key = metadata.rbegin()->first;
-    if (boost::starts_with(m_last_metadata_key,
-                           ImageCtx::METADATA_CONF_PREFIX)) {
-      send_v2_get_pool_metadata();
-      return nullptr;
-    }
-  }
-
   bool thread_safe = m_image_ctx.image_watcher->is_unregistered();
   m_image_ctx.apply_metadata(m_metadata, thread_safe);
 
index 9dd21157ee26d0b319511a8032b33a6d262b7433..bd3fda40fc56c847ffe1f51c018961ececaf2afc 100644 (file)
@@ -146,7 +146,6 @@ private:
   uint64_t m_op_features = 0;
 
   librados::IoCtx m_pool_metadata_io_ctx;
-  std::string m_last_metadata_key;
   std::map<std::string, bufferlist> m_metadata;
 
   std::string m_object_prefix;
index 662bfa18fa65a95525bded10eb0d46559404fd9a..a2900e3111d4049ae8fab38f9ef117743e101420 100644 (file)
 #include "librbd/api/Image.h"
 #include "librbd/exclusive_lock/AutomaticPolicy.h"
 #include "librbd/exclusive_lock/StandardPolicy.h"
+#include "librbd/deep_copy/MetadataCopyRequest.h"
 #include "librbd/image/CloneRequest.h"
 #include "librbd/image/CreateRequest.h"
+#include "librbd/image/GetMetadataRequest.h"
 #include "librbd/io/AioCompletion.h"
 #include "librbd/io/ImageRequest.h"
 #include "librbd/io/ImageRequestWQ.h"
@@ -1263,29 +1265,16 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
                 << dest_size << dendl;
       return -EINVAL;
     }
-    int r;
-    const uint32_t MAX_KEYS = 64;
-    map<string, bufferlist> pairs;
-    std::string last_key = "";
-    bool more_results = true;
-
-    while (more_results) {
-      r = cls_client::metadata_list(&src->md_ctx, src->header_oid, last_key, 0, &pairs);
-      if (r < 0 && r != -EOPNOTSUPP && r != -EIO) {
-        lderr(cct) << "couldn't list metadata: " << cpp_strerror(r) << dendl;
-        return r;
-      } else if (r == 0 && !pairs.empty()) {
-        r = cls_client::metadata_set(&dest->md_ctx, dest->header_oid, pairs);
-        if (r < 0) {
-          lderr(cct) << "couldn't set metadata: " << cpp_strerror(r) << dendl;
-          return r;
-        }
 
-        last_key = pairs.rbegin()->first;
-      }
+    C_SaferCond ctx;
+    auto req = deep_copy::MetadataCopyRequest<>::create(
+      src, dest, &ctx);
+    req->send();
 
-      more_results = (pairs.size() == MAX_KEYS);
-      pairs.clear();
+    int r = ctx.wait();
+    if (r < 0) {
+      lderr(cct) << "failed to copy metadata: " << cpp_strerror(r) << dendl;
+      return r;
     }
 
     ZTracer::Trace trace;
@@ -1648,7 +1637,12 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
       return r;
     }
 
-    return cls_client::metadata_list(&ictx->md_ctx, ictx->header_oid, start, max, pairs);
+    C_SaferCond ctx;
+    auto req = image::GetMetadataRequest<>::create(
+      ictx->md_ctx, ictx->header_oid, "", start, max, pairs, &ctx);
+    req->send();
+
+    return ctx.wait();
   }
 
   int list_watchers(ImageCtx *ictx,
index 8717f684a8ed2fe21efc46e8376673207e98913d..11dd5158cc2ce5f5be3fa079794fe517d3a6311f 100644 (file)
@@ -6,6 +6,7 @@
 #include "include/stringify.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/deep_copy/MetadataCopyRequest.h"
+#include "librbd/image/GetMetadataRequest.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/librbd/test_support.h"
@@ -21,6 +22,38 @@ struct MockTestImageCtx : public librbd::MockImageCtx {
 };
 
 } // anonymous namespace
+
+namespace image {
+
+template <>
+struct GetMetadataRequest<MockTestImageCtx> {
+  std::map<std::string, bufferlist>* pairs = nullptr;
+  Context* on_finish = nullptr;
+
+  static GetMetadataRequest* s_instance;
+  static GetMetadataRequest* create(librados::IoCtx&,
+                                    const std::string& oid,
+                                    const std::string& filter,
+                                    const std::string& last_key,
+                                    uint32_t max_results,
+                                    std::map<std::string, bufferlist>* pairs,
+                                    Context* on_finish) {
+    ceph_assert(s_instance != nullptr);
+    s_instance->pairs = pairs;
+    s_instance->on_finish = on_finish;
+    return s_instance;
+  }
+
+  GetMetadataRequest() {
+    s_instance = this;
+  }
+
+  MOCK_METHOD0(send, void());
+};
+
+GetMetadataRequest<MockTestImageCtx>* GetMetadataRequest<MockTestImageCtx>::s_instance = nullptr;
+
+} // namspace image
 } // namespace librbd
 
 // template definitions
@@ -32,6 +65,7 @@ namespace deep_copy {
 using ::testing::_;
 using ::testing::DoAll;
 using ::testing::InSequence;
+using ::testing::Invoke;
 using ::testing::Return;
 using ::testing::StrEq;
 using ::testing::WithArg;
@@ -39,6 +73,7 @@ using ::testing::WithArg;
 class TestMockDeepCopyMetadataCopyRequest : public TestMockFixture {
 public:
   typedef MetadataCopyRequest<librbd::MockTestImageCtx> MockMetadataCopyRequest;
+  typedef image::GetMetadataRequest<MockTestImageCtx> MockGetMetadataRequest;
   typedef std::map<std::string, bufferlist> Metadata;
 
   librbd::ImageCtx *m_src_image_ctx;
@@ -60,16 +95,13 @@ public:
                                                &m_thread_pool, &m_work_queue);
   }
 
-  void expect_metadata_list(librbd::MockTestImageCtx &mock_image_ctx,
-                            const Metadata& metadata, int r) {
-    bufferlist out_bl;
-    encode(metadata, out_bl);
-
-    EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
-                exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
-                     StrEq("metadata_list"), _, _, _))
-                  .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(out_bl)),
-                                  Return(r)));
+  void expect_get_metadata(MockGetMetadataRequest& mock_request,
+                           const Metadata& metadata, int r) {
+    EXPECT_CALL(mock_request, send())
+      .WillOnce(Invoke([this, &mock_request, metadata, r]() {
+        *mock_request.pairs = metadata;
+        m_work_queue->queue(mock_request.on_finish, r);
+      }));
   }
 
   void expect_metadata_set(librbd::MockTestImageCtx &mock_image_ctx,
@@ -104,9 +136,10 @@ TEST_F(TestMockDeepCopyMetadataCopyRequest, Success) {
   }
 
   InSequence seq;
-  expect_metadata_list(mock_src_image_ctx, key_values_1, 0);
+  MockGetMetadataRequest mock_request;
+  expect_get_metadata(mock_request, key_values_1, 0);
   expect_metadata_set(mock_dst_image_ctx, key_values_1, 0);
-  expect_metadata_list(mock_src_image_ctx, key_values_2, 0);
+  expect_get_metadata(mock_request, key_values_2, 0);
   expect_metadata_set(mock_dst_image_ctx, key_values_2, 0);
 
   C_SaferCond ctx;
@@ -125,7 +158,8 @@ TEST_F(TestMockDeepCopyMetadataCopyRequest, Empty) {
   Metadata key_values;
 
   InSequence seq;
-  expect_metadata_list(mock_src_image_ctx, key_values, 0);
+  MockGetMetadataRequest mock_request;
+  expect_get_metadata(mock_request, key_values, 0);
 
   C_SaferCond ctx;
   auto request = MockMetadataCopyRequest::create(&mock_src_image_ctx,
@@ -143,7 +177,8 @@ TEST_F(TestMockDeepCopyMetadataCopyRequest, MetadataListError) {
   Metadata key_values;
 
   InSequence seq;
-  expect_metadata_list(mock_src_image_ctx, key_values, -EINVAL);
+  MockGetMetadataRequest mock_request;
+  expect_get_metadata(mock_request, key_values, -EINVAL);
 
   C_SaferCond ctx;
   auto request = MockMetadataCopyRequest::create(&mock_src_image_ctx,
@@ -164,7 +199,8 @@ TEST_F(TestMockDeepCopyMetadataCopyRequest, MetadataSetError) {
   key_values.emplace("key", bl);
 
   InSequence seq;
-  expect_metadata_list(mock_src_image_ctx, key_values, 0);
+  MockGetMetadataRequest mock_request;
+  expect_get_metadata(mock_request, key_values, 0);
   expect_metadata_set(mock_dst_image_ctx, key_values, -EINVAL);
 
   C_SaferCond ctx;
index 46c4ce96e8672c6a39e47d96ed1261926f9eeb81..d21a83a40e3b7737cbf67fa27a0b3b14d824a63b 100644 (file)
@@ -9,6 +9,7 @@
 #include "test/librados_test_stub/MockTestMemRadosClient.h"
 #include "librbd/ImageState.h"
 #include "librbd/Operations.h"
+#include "librbd/deep_copy/MetadataCopyRequest.h"
 #include "librbd/image/TypeTraits.h"
 #include "librbd/image/AttachChildRequest.h"
 #include "librbd/image/AttachParentRequest.h"
@@ -47,6 +48,32 @@ MockTestImageCtx* MockTestImageCtx::s_instance = nullptr;
 
 } // anonymous namespace
 
+namespace deep_copy {
+
+template <>
+struct MetadataCopyRequest<MockTestImageCtx> {
+  Context* on_finish = nullptr;
+
+  static MetadataCopyRequest* s_instance;
+  static MetadataCopyRequest* create(MockTestImageCtx* src_image_ctx,
+                                     MockTestImageCtx* dst_image_ctx,
+                                     Context* on_finish) {
+    ceph_assert(s_instance != nullptr);
+    s_instance->on_finish = on_finish;
+    return s_instance;
+  }
+
+  MetadataCopyRequest() {
+    s_instance = this;
+  }
+
+  MOCK_METHOD0(send, void());
+};
+
+MetadataCopyRequest<MockTestImageCtx>* MetadataCopyRequest<MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace deep_copy
+
 namespace image {
 
 template <>
@@ -202,6 +229,7 @@ public:
   typedef AttachParentRequest<MockTestImageCtx> MockAttachParentRequest;
   typedef CreateRequest<MockTestImageCtx> MockCreateRequest;
   typedef RemoveRequest<MockTestImageCtx> MockRemoveRequest;
+  typedef deep_copy::MetadataCopyRequest<MockTestImageCtx> MockMetadataCopyRequest;
   typedef mirror::EnableRequest<MockTestImageCtx> MockMirrorEnableRequest;
 
   void SetUp() override {
@@ -284,31 +312,11 @@ public:
                 }));
   }
 
-  void expect_metadata_list(MockTestImageCtx &mock_image_ctx,
-                            const std::map<std::string, bufferlist>& metadata,
-                            int r) {
-    bufferlist out_bl;
-    encode(metadata, out_bl);
-
-    EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
-                exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("metadata_list"), _, _, _))
-      .WillOnce(WithArg<5>(Invoke([out_bl, r](bufferlist *out) {
-                             *out = out_bl;
-                             return r;
-                           })));
-  }
-
-  void expect_metadata_set(librados::IoCtx& io_ctx,
-                           MockTestImageCtx& mock_image_ctx,
-                           const std::map<std::string, bufferlist>& metadata,
-                           int r) {
-    bufferlist in_bl;
-    encode(metadata, in_bl);
-
-    EXPECT_CALL(get_mock_io_ctx(io_ctx),
-                exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("metadata_set"),
-                     ContentsEqual(in_bl), _, _))
-      .WillOnce(Return(r));
+  void expect_metadata_copy(MockMetadataCopyRequest& mock_request, int r) {
+    EXPECT_CALL(mock_request, send())
+      .WillOnce(Invoke([this, &mock_request, r]() {
+        image_ctx->op_work_queue->queue(mock_request.on_finish, r);
+       }));
   }
 
   void expect_test_features(MockTestImageCtx &mock_image_ctx,
@@ -381,8 +389,8 @@ TEST_F(TestMockImageCloneRequest, SuccessV1) {
   MockAttachChildRequest mock_attach_child_request;
   expect_attach_child(mock_attach_child_request, 1, 0);
 
-  expect_metadata_list(mock_image_ctx, {{"key", {}}}, 0);
-  expect_metadata_set(m_ioctx, mock_image_ctx, {{"key", {}}}, 0);
+  MockMetadataCopyRequest mock_request;
+  expect_metadata_copy(mock_request, 0);
 
   MockMirrorEnableRequest mock_mirror_enable_request;
   if (is_feature_enabled(RBD_FEATURE_JOURNALING)) {
@@ -431,8 +439,8 @@ TEST_F(TestMockImageCloneRequest, SuccessV2) {
   MockAttachChildRequest mock_attach_child_request;
   expect_attach_child(mock_attach_child_request, 2, 0);
 
-  expect_metadata_list(mock_image_ctx, {{"key", {}}}, 0);
-  expect_metadata_set(m_ioctx, mock_image_ctx, {{"key", {}}}, 0);
+  MockMetadataCopyRequest mock_request;
+  expect_metadata_copy(mock_request, 0);
 
   MockMirrorEnableRequest mock_mirror_enable_request;
   if (is_feature_enabled(RBD_FEATURE_JOURNALING)) {
@@ -481,8 +489,8 @@ TEST_F(TestMockImageCloneRequest, SuccessAuto) {
   MockAttachChildRequest mock_attach_child_request;
   expect_attach_child(mock_attach_child_request, 2, 0);
 
-  expect_metadata_list(mock_image_ctx, {{"key", {}}}, 0);
-  expect_metadata_set(m_ioctx, mock_image_ctx, {{"key", {}}}, 0);
+  MockMetadataCopyRequest mock_request;
+  expect_metadata_copy(mock_request, 0);
 
   MockMirrorEnableRequest mock_mirror_enable_request;
   if (is_feature_enabled(RBD_FEATURE_JOURNALING)) {
@@ -662,49 +670,7 @@ TEST_F(TestMockImageCloneRequest, AttachChildError) {
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
 
-TEST_F(TestMockImageCloneRequest, MetadataListError) {
-  REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
-
-  MockTestImageCtx mock_image_ctx(*image_ctx);
-  expect_op_work_queue(mock_image_ctx);
-
-  InSequence seq;
-  expect_open(mock_image_ctx, 0);
-
-  expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
-  expect_is_snap_protected(mock_image_ctx, true, 0);
-
-  MockCreateRequest mock_create_request;
-  expect_create(mock_create_request, 0);
-
-  expect_open(mock_image_ctx, 0);
-
-  MockAttachParentRequest mock_attach_parent_request;
-  expect_attach_parent(mock_attach_parent_request, 0);
-
-  MockAttachChildRequest mock_attach_child_request;
-  expect_attach_child(mock_attach_child_request, 2, 0);
-
-  expect_metadata_list(mock_image_ctx, {{"key", {}}}, -EINVAL);
-
-  expect_close(mock_image_ctx, 0);
-
-  MockRemoveRequest mock_remove_request;
-  expect_remove(mock_remove_request, 0);
-
-  expect_close(mock_image_ctx, 0);
-
-  C_SaferCond ctx;
-  ImageOptions clone_opts;
-  auto req = new MockCloneRequest(m_cct->_conf, m_ioctx, "parent id", "", {}, 123,
-                                  m_ioctx, "clone name", "clone id", clone_opts,
-                                  cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "", "",
-                                  image_ctx->op_work_queue, &ctx);
-  req->send();
-  ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockImageCloneRequest, MetadataSetError) {
+TEST_F(TestMockImageCloneRequest, MetadataCopyError) {
   REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
 
   MockTestImageCtx mock_image_ctx(*image_ctx);
@@ -727,8 +693,8 @@ TEST_F(TestMockImageCloneRequest, MetadataSetError) {
   MockAttachChildRequest mock_attach_child_request;
   expect_attach_child(mock_attach_child_request, 2, 0);
 
-  expect_metadata_list(mock_image_ctx, {{"key", {}}}, 0);
-  expect_metadata_set(m_ioctx, mock_image_ctx, {{"key", {}}}, -EINVAL);
+  MockMetadataCopyRequest mock_request;
+  expect_metadata_copy(mock_request, -EINVAL);
 
   expect_close(mock_image_ctx, 0);
 
@@ -770,7 +736,8 @@ TEST_F(TestMockImageCloneRequest, GetMirrorModeError) {
   MockAttachChildRequest mock_attach_child_request;
   expect_attach_child(mock_attach_child_request, 2, 0);
 
-  expect_metadata_list(mock_image_ctx, {}, 0);
+  MockMetadataCopyRequest mock_request;
+  expect_metadata_copy(mock_request, 0);
 
   expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
   expect_mirror_mode_get(mock_image_ctx, cls::rbd::MIRROR_MODE_POOL, -EINVAL);
@@ -815,7 +782,8 @@ TEST_F(TestMockImageCloneRequest, MirrorEnableError) {
   MockAttachChildRequest mock_attach_child_request;
   expect_attach_child(mock_attach_child_request, 2, 0);
 
-  expect_metadata_list(mock_image_ctx, {}, 0);
+  MockMetadataCopyRequest mock_request;
+  expect_metadata_copy(mock_request, 0);
 
   expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
   expect_mirror_mode_get(mock_image_ctx, cls::rbd::MIRROR_MODE_POOL, 0);
@@ -863,7 +831,9 @@ TEST_F(TestMockImageCloneRequest, CloseError) {
   MockAttachChildRequest mock_attach_child_request;
   expect_attach_child(mock_attach_child_request, 2, 0);
 
-  expect_metadata_list(mock_image_ctx, {}, 0);
+  MockMetadataCopyRequest mock_request;
+  expect_metadata_copy(mock_request, 0);
+
   expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, false);
 
   expect_close(mock_image_ctx, -EINVAL);
index babbfe425be8105aa9779b66bed9e12a9eb48453..bfc9cfe2959748f3b9c98ab3cd77bc36e5e100a7 100644 (file)
@@ -14,6 +14,7 @@
 #include "librbd/internal.h"
 #include "librbd/Operations.h"
 #include "librbd/api/Image.h"
+#include "librbd/image/GetMetadataRequest.h"
 #include "librbd/image/RefreshRequest.h"
 #include "librbd/image/RefreshParentRequest.h"
 #include "librbd/io/ImageDispatchSpec.h"
@@ -36,6 +37,36 @@ struct MockRefreshImageCtx : public MockImageCtx {
 
 namespace image {
 
+template <>
+struct GetMetadataRequest<MockRefreshImageCtx> {
+  std::string oid;
+  std::map<std::string, bufferlist>* pairs = nullptr;
+  Context* on_finish = nullptr;
+
+  static GetMetadataRequest* s_instance;
+  static GetMetadataRequest* create(librados::IoCtx&,
+                                    const std::string& oid,
+                                    const std::string& filter,
+                                    const std::string& last_key,
+                                    uint32_t max_results,
+                                    std::map<std::string, bufferlist>* pairs,
+                                    Context* on_finish) {
+    ceph_assert(s_instance != nullptr);
+    EXPECT_EQ("conf_", filter);
+    EXPECT_EQ("conf_", last_key);
+    s_instance->oid = oid;
+    s_instance->pairs = pairs;
+    s_instance->on_finish = on_finish;
+    return s_instance;
+  }
+
+  GetMetadataRequest() {
+    s_instance = this;
+  }
+
+  MOCK_METHOD0(send, void());
+};
+
 template <>
 struct RefreshParentRequest<MockRefreshImageCtx> {
   static RefreshParentRequest* s_instance;
@@ -66,6 +97,7 @@ struct RefreshParentRequest<MockRefreshImageCtx> {
   MOCK_METHOD1(finalize, void(Context *));
 };
 
+GetMetadataRequest<MockRefreshImageCtx>* GetMetadataRequest<MockRefreshImageCtx>::s_instance = nullptr;
 RefreshParentRequest<MockRefreshImageCtx>* RefreshParentRequest<MockRefreshImageCtx>::s_instance = nullptr;
 
 } // namespace image
@@ -132,9 +164,11 @@ using ::testing::StrEq;
 
 class TestMockImageRefreshRequest : public TestMockFixture {
 public:
+  typedef GetMetadataRequest<MockRefreshImageCtx> MockGetMetadataRequest;
   typedef RefreshRequest<MockRefreshImageCtx> MockRefreshRequest;
   typedef RefreshParentRequest<MockRefreshImageCtx> MockRefreshParentRequest;
   typedef io::ImageDispatchSpec<librbd::MockRefreshImageCtx> MockIoImageDispatchSpec;
+  typedef std::map<std::string, bufferlist> Metadata;
 
   void set_v1_migration_header(ImageCtx *ictx) {
     bufferlist hdr;
@@ -257,16 +291,17 @@ public:
     }
   }
 
-  void expect_get_metadata(MockRefreshImageCtx &mock_image_ctx, int r) {
-    auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
-                               exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("metadata_list"), _, _, _));
-    if (r < 0) {
-      expect.WillOnce(Return(r));
-    } else {
-      expect.WillOnce(DoDefault());
-      EXPECT_CALL(*mock_image_ctx.image_watcher, is_unregistered())
-        .WillOnce(Return(false));
-    }
+  void expect_get_metadata(MockRefreshImageCtx& mock_image_ctx,
+                           MockGetMetadataRequest& mock_request,
+                           const std::string& oid,
+                           const Metadata& metadata, int r) {
+    EXPECT_CALL(mock_request, send())
+      .WillOnce(Invoke([&mock_image_ctx, &mock_request, oid, metadata, r]() {
+        ASSERT_EQ(oid, mock_request.oid);
+        *mock_request.pairs = metadata;
+        mock_image_ctx.image_ctx->op_work_queue->queue(
+          mock_request.on_finish, r);
+      }));
   }
 
   void expect_get_flags(MockRefreshImageCtx &mock_image_ctx, int r) {
@@ -348,6 +383,8 @@ public:
 
   void expect_apply_metadata(MockRefreshImageCtx &mock_image_ctx,
                             int r) {
+    EXPECT_CALL(*mock_image_ctx.image_watcher, is_unregistered())
+      .WillOnce(Return(false));
     EXPECT_CALL(mock_image_ctx, apply_metadata(_, false))
                  .WillOnce(Return(r));
   }
@@ -544,7 +581,11 @@ TEST_F(TestMockImageRefreshRequest, SuccessV2) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -575,7 +616,11 @@ TEST_F(TestMockImageRefreshRequest, SuccessSnapshotV2) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_get_snapshots(mock_image_ctx, false, 0);
@@ -609,7 +654,11 @@ TEST_F(TestMockImageRefreshRequest, SuccessLegacySnapshotV2) {
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, -EOPNOTSUPP);
   expect_get_parent_legacy(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_get_snapshots(mock_image_ctx, true, -EOPNOTSUPP);
@@ -646,7 +695,11 @@ TEST_F(TestMockImageRefreshRequest, SuccessSetSnapshotV2) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_get_snapshots(mock_image_ctx, false, 0);
@@ -699,7 +752,11 @@ TEST_F(TestMockImageRefreshRequest, SuccessChild) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx2->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_op_features(mock_image_ctx, RBD_OPERATION_FEATURE_CLONE_CHILD, 0);
   expect_get_group(mock_image_ctx, 0);
@@ -752,7 +809,11 @@ TEST_F(TestMockImageRefreshRequest, SuccessChildDontOpenParent) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx2->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_op_features(mock_image_ctx, RBD_OPERATION_FEATURE_CLONE_CHILD, 0);
   expect_get_group(mock_image_ctx, 0);
@@ -784,7 +845,11 @@ TEST_F(TestMockImageRefreshRequest, SuccessOpFeatures) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, mock_image_ctx.features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_op_features(mock_image_ctx, 4096, 0);
   expect_get_group(mock_image_ctx, 0);
@@ -849,7 +914,11 @@ TEST_F(TestMockImageRefreshRequest, DisableExclusiveLock) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -899,7 +968,11 @@ TEST_F(TestMockImageRefreshRequest, DisableExclusiveLockWhileAcquiringLock) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -939,7 +1012,11 @@ TEST_F(TestMockImageRefreshRequest, JournalDisabledByPolicy) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -984,7 +1061,11 @@ TEST_F(TestMockImageRefreshRequest, EnableJournalWithExclusiveLock) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -1028,7 +1109,11 @@ TEST_F(TestMockImageRefreshRequest, EnableJournalWithoutExclusiveLock) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -1075,7 +1160,11 @@ TEST_F(TestMockImageRefreshRequest, DisableJournal) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -1122,7 +1211,11 @@ TEST_F(TestMockImageRefreshRequest, EnableObjectMapWithExclusiveLock) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -1162,7 +1255,11 @@ TEST_F(TestMockImageRefreshRequest, EnableObjectMapWithoutExclusiveLock) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -1208,7 +1305,11 @@ TEST_F(TestMockImageRefreshRequest, DisableObjectMap) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -1250,7 +1351,11 @@ TEST_F(TestMockImageRefreshRequest, OpenObjectMapError) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -1294,7 +1399,11 @@ TEST_F(TestMockImageRefreshRequest, OpenObjectMapTooLarge) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
@@ -1324,7 +1433,11 @@ TEST_F(TestMockImageRefreshRequest, ApplyMetadataError) {
   InSequence seq;
   expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
   expect_get_parent(mock_image_ctx, 0);
-  expect_get_metadata(mock_image_ctx, 0);
+  MockGetMetadataRequest mock_get_metadata_request;
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+                      mock_image_ctx.header_oid, {}, 0);
+  expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+                      0);
   expect_apply_metadata(mock_image_ctx, -EINVAL);
   expect_get_group(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);