]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd/cache: discard writeback cache
authorlixiaoy1 <xiaoyan.li@intel.com>
Fri, 11 Sep 2020 14:24:56 +0000 (10:24 -0400)
committerlixiaoy1 <xiaoyan.li@intel.com>
Thu, 29 Oct 2020 15:33:10 +0000 (23:33 +0800)
Add an interface in ImageCache to discard writeback cache.

Signed-off-by: Li, Xiaoyan <xiaoyan.li@intel.com>
src/librbd/CMakeLists.txt
src/librbd/cache/Utils.cc [new file with mode: 0644]
src/librbd/cache/Utils.h
src/librbd/cache/pwl/DiscardRequest.cc [new file with mode: 0644]
src/librbd/cache/pwl/DiscardRequest.h [new file with mode: 0644]
src/librbd/cache/pwl/ImageCacheState.cc
src/librbd/cache/pwl/ImageCacheState.h
src/librbd/cache/pwl/InitRequest.cc

index c0aae05bd11ec7755643a240d4383d85ebb95462..eafbef9430f1b8afeee0e84f26edc7af764e3df9 100644 (file)
@@ -42,8 +42,10 @@ set(librbd_internal_srcs
   cache/ImageWriteback.cc
   cache/ObjectCacherObjectDispatch.cc
   cache/ObjectCacherWriteback.cc
+  cache/pwl/DiscardRequest.cc
   cache/pwl/InitRequest.cc
   cache/pwl/ShutdownRequest.cc
+  cache/Utils.cc
   cache/WriteAroundObjectDispatch.cc
   crypto/BlockCrypto.cc
   crypto/CryptoContextPool.cc
@@ -222,6 +224,8 @@ target_include_directories(rbd_internal PRIVATE ${OPENSSL_INCLUDE_DIR})
 if(WITH_RBD_RWL)
   target_link_libraries(rbd_internal
     PUBLIC blk)
+  target_link_libraries(rbd_internal PRIVATE
+    StdFilesystem::filesystem)
 endif()
 
 add_custom_target(librbd_plugins)
diff --git a/src/librbd/cache/Utils.cc b/src/librbd/cache/Utils.cc
new file mode 100644 (file)
index 0000000..c65c575
--- /dev/null
@@ -0,0 +1,24 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/cache/pwl/DiscardRequest.h"
+#include "librbd/cache/Utils.h"
+#include "include/Context.h"
+
+namespace librbd {
+namespace cache {
+namespace util {
+
+template <typename I>
+void discard_cache(I &image_ctx, Context *ctx) {
+  cache::pwl::DiscardRequest<I> *req = cache::pwl::DiscardRequest<I>::create(
+    image_ctx, ctx);
+  req->send();
+}
+
+} // namespace util
+} // namespace cache
+} // namespace librbd
+
+template void librbd::cache::util::discard_cache(
+  librbd::ImageCtx &image_ctx, Context *ctx);
index 827dcc5daa6a5ed78f5c6ac7ec6d638a9a10ddd5..67c0b6fbc735881872d2a3f9f005fc4511ec4a7c 100644 (file)
@@ -6,8 +6,12 @@
 
 #include "acconfig.h"
 
+class Context;
+
 namespace librbd {
 
+struct ImageCtx;
+
 namespace cache {
 namespace util {
 
@@ -20,6 +24,9 @@ bool is_pwl_enabled(T& image_ctx) {
 #endif // WITH_RBD_RWL
 }
 
+template <typename T = librbd::ImageCtx>
+void discard_cache(T &image_ctx, Context *ctx);
+
 } // namespace util
 } // namespace cache
 } // namespace librbd
diff --git a/src/librbd/cache/pwl/DiscardRequest.cc b/src/librbd/cache/pwl/DiscardRequest.cc
new file mode 100644 (file)
index 0000000..32a0077
--- /dev/null
@@ -0,0 +1,167 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "common/dout.h"
+#include "common/errno.h"
+#include "common/hostname.h"
+#include "librbd/asio/ContextWQ.h"
+#include "librbd/cache/pwl/DiscardRequest.h"
+
+#if defined(WITH_RBD_RWL)
+#if __has_include(<filesystem>)
+#include <filesystem>
+namespace fs = std::filesystem;
+#elif __has_include(<experimental/filesystem>)
+#include <experimental/filesystem>
+namespace fs = std::experimental::filesystem;
+#endif
+
+#include "librbd/cache/pwl/ImageCacheState.h"
+#endif // WITH_RBD_RWL
+
+#include "librbd/cache/Types.h"
+#include "librbd/io/ImageDispatcherInterface.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/Utils.h"
+
+
+#define dout_subsys ceph_subsys_rbd_pwl
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::cache::pwl:DiscardRequest: " \
+                           << this << " " << __func__ << ": "
+
+namespace librbd {
+namespace cache {
+namespace pwl {
+
+using librbd::util::create_async_context_callback;
+using librbd::util::create_context_callback;
+
+template <typename I>
+DiscardRequest<I>* DiscardRequest<I>::create(
+    I &image_ctx,
+    Context *on_finish) {
+  return new DiscardRequest(image_ctx, on_finish);
+}
+
+template <typename I>
+DiscardRequest<I>::DiscardRequest(
+    I &image_ctx,
+    Context *on_finish)
+  : m_image_ctx(image_ctx),
+    m_on_finish(create_async_context_callback(image_ctx, on_finish)),
+    m_error_result(0) {
+}
+
+template <typename I>
+void DiscardRequest<I>::send() {
+#if defined(WITH_RBD_RWL)
+  delete_image_cache_file();
+#else
+  finish();
+#endif
+}
+
+template <typename I>
+void DiscardRequest<I>::delete_image_cache_file() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  m_cache_state = ImageCacheState<I>::get_image_cache_state(&m_image_ctx);
+  if (!m_cache_state) {
+    remove_feature_bit();
+    return;
+  }
+  if (m_cache_state->present &&
+      !m_cache_state->host.compare(ceph_get_short_hostname()) &&
+      fs::exists(m_cache_state->path)) {
+    fs::remove(m_cache_state->path);
+  }
+
+  remove_image_cache_state();
+}
+
+template <typename I>
+void DiscardRequest<I>::remove_image_cache_state() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  using klass = DiscardRequest<I>;
+  Context *ctx = create_context_callback<klass, &klass::handle_remove_image_cache_state>(
+    this);
+
+  m_cache_state->clear_image_cache_state(ctx);
+}
+
+template <typename I>
+void DiscardRequest<I>::handle_remove_image_cache_state(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  if (r < 0) {
+    lderr(cct) << "failed to remove the image cache state: " << cpp_strerror(r)
+               << dendl;
+    save_result(r);
+    finish();
+    return;
+  }
+
+  remove_feature_bit();
+}
+
+template <typename I>
+void DiscardRequest<I>::remove_feature_bit() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  if (!(m_image_ctx.features &&RBD_FEATURE_DIRTY_CACHE)) {
+    finish();
+    return;
+  }
+  uint64_t new_features = m_image_ctx.features & ~RBD_FEATURE_DIRTY_CACHE;
+  uint64_t features_mask = RBD_FEATURE_DIRTY_CACHE;
+  ldout(cct, 10) << "old_features=" << m_image_ctx.features
+                 << ", new_features=" << new_features
+                 << ", features_mask=" << features_mask
+                 << dendl;
+
+  int r = librbd::cls_client::set_features(&m_image_ctx.md_ctx, m_image_ctx.header_oid,
+                                           new_features, features_mask);
+  m_image_ctx.features &= ~RBD_FEATURE_DIRTY_CACHE;
+  using klass = DiscardRequest<I>;
+  Context *ctx = create_context_callback<klass, &klass::handle_remove_feature_bit>(
+    this);
+  ctx->complete(r);
+}
+
+template <typename I>
+void DiscardRequest<I>::handle_remove_feature_bit(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  if (r < 0) {
+    lderr(cct) << "failed to remove the feature bit: " << cpp_strerror(r)
+               << dendl;
+    save_result(r);
+  }
+  finish();
+}
+
+template <typename I>
+void DiscardRequest<I>::finish() {
+#if defined(WITH_RBD_RWL)
+  if (m_cache_state) {
+    delete m_cache_state;
+    m_cache_state = nullptr;
+  }
+#endif // WITH_RBD_RWL
+
+  m_on_finish->complete(m_error_result);
+  delete this;
+}
+
+} // namespace pwl
+} // namespace cache
+} // namespace librbd
+
+template class librbd::cache::pwl::DiscardRequest<librbd::ImageCtx>;
diff --git a/src/librbd/cache/pwl/DiscardRequest.h b/src/librbd/cache/pwl/DiscardRequest.h
new file mode 100644 (file)
index 0000000..6edd194
--- /dev/null
@@ -0,0 +1,86 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_CACHE_PWL_SHUTDOWN_REQUEST_H
+#define CEPH_LIBRBD_CACHE_PWL_SHUTDOWN_REQUEST_H
+
+class Context;
+
+namespace librbd {
+
+class ImageCtx;
+
+namespace cache {
+
+namespace pwl {
+
+template<typename>
+class ImageCacheState;
+
+template <typename ImageCtxT = ImageCtx>
+class DiscardRequest {
+public:
+  static DiscardRequest* create(
+      ImageCtxT &image_ctx,
+      Context *on_finish);
+
+  void send();
+
+private:
+
+  /**
+   * @verbatim
+   *
+   * Shutdown request goes through the following state machine:
+   *
+   * <start>
+   *    |
+   *    v
+   * REMOVE_IMAGE_CACHE_FILE
+   *    |
+   *    v
+   * REMOVE_IMAGE_CACHE_STATE
+   *    |
+   *    v
+   * REMOVE_IMAGE_FEATURE_BIT
+   *    |
+   *    v
+   * <finish>
+   *
+   * @endverbatim
+   */
+
+  DiscardRequest(ImageCtxT &image_ctx,
+    Context *on_finish);
+
+  ImageCtxT &m_image_ctx;
+  ImageCacheState<ImageCtxT>* m_cache_state;
+  Context *m_on_finish;
+
+  int m_error_result;
+
+  void delete_image_cache_file();
+
+  void remove_image_cache_state();
+  void handle_remove_image_cache_state(int r);
+
+  void remove_feature_bit();
+  void handle_remove_feature_bit(int r);
+
+  void finish();
+
+  void save_result(int result) {
+    if (m_error_result == 0 && result < 0) {
+      m_error_result = result;
+    }
+  }
+
+};
+
+} // namespace pwl
+} // namespace cache
+} // namespace librbd
+
+extern template class librbd::cache::pwl::DiscardRequest<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_CACHE_PWL_SHUTDOWN_REQUEST_H
index b36896a6915dcd65cabb43edf85df57de952dc49..dba7b971d226e9012a49dcbe54abc987da4f4a59 100644 (file)
@@ -96,7 +96,7 @@ void ImageCacheState<I>::dump(ceph::Formatter *f) const {
 }
 
 template <typename I>
-ImageCacheState<I>* ImageCacheState<I>::get_image_cache_state(
+ImageCacheState<I>* ImageCacheState<I>::create_image_cache_state(
     I* image_ctx, int &r) {
   std::string cache_state_str;
   ImageCacheState<I>* cache_state = nullptr;
@@ -153,6 +153,24 @@ ImageCacheState<I>* ImageCacheState<I>::get_image_cache_state(
   return cache_state;
 }
 
+template <typename I>
+ImageCacheState<I>* ImageCacheState<I>::get_image_cache_state(I* image_ctx) {
+  ImageCacheState<I>* cache_state = nullptr;
+  string cache_state_str;
+  cls_client::metadata_get(&image_ctx->md_ctx, image_ctx->header_oid,
+                          IMAGE_CACHE_STATE, &cache_state_str);
+  if (!cache_state_str.empty()) {
+    JSONFormattable f;
+    bool success = get_json_format(cache_state_str, &f);
+    if (!success) {
+      cache_state = new ImageCacheState<I>(image_ctx);
+    } else {
+      cache_state = new ImageCacheState<I>(image_ctx, f);
+    }
+  }
+  return cache_state;
+}
+
 template <typename I>
 bool ImageCacheState<I>::is_valid() {
   if (this->present &&
index bdc8cb080ff65e64dd49742243acf6721a49169a..453316e866136ae9f833a67f25846c55f9d89635 100644 (file)
@@ -47,8 +47,11 @@ public:
 
   void dump(ceph::Formatter *f) const;
 
+  static ImageCacheState<ImageCtxT>* create_image_cache_state(
+    ImageCtxT* image_ctx, int &r);
+
   static ImageCacheState<ImageCtxT>* get_image_cache_state(
-      ImageCtxT* image_ctx, int &r);
+    ImageCtxT* image_ctx);
 
   bool is_valid();
 };
index 1f696d518bd33aa3d765090b4fc35e99d81abde5..bcf66ede3efb977537050999449eb8d9e081ef57 100644 (file)
@@ -58,7 +58,7 @@ void InitRequest<I>::get_image_cache_state() {
   ldout(cct, 10) << dendl;
 
   int r;
-  auto cache_state = ImageCacheState<I>::get_image_cache_state(&m_image_ctx, r);
+  auto cache_state = ImageCacheState<I>::create_image_cache_state(&m_image_ctx, r);
 
   if (r < 0 || !cache_state) {
     save_result(r);