--- /dev/null
+// -*- 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>;
--- /dev/null
+// -*- 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
}
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;
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 &&