]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/librbd/exclusive_lock/PreReleaseRequest.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / exclusive_lock / PreReleaseRequest.cc
index fc833a1c80bcac398d7263735b71aa1d70bbcfd0..3adc3b54a45b248bd65338186bf94f72e4086611 100644 (file)
 #include "librbd/Journal.h"
 #include "librbd/ObjectMap.h"
 #include "librbd/Utils.h"
-#include "librbd/io/ImageRequestWQ.h"
-#include "librbd/io/ObjectDispatcher.h"
+#include "librbd/exclusive_lock/ImageDispatch.h"
+#include "librbd/io/AioCompletion.h"
+#include "librbd/io/ImageDispatchSpec.h"
+#include "librbd/io/ImageDispatcherInterface.h"
+#include "librbd/io/ObjectDispatcherInterface.h"
+#include "librbd/io/Types.h"
+#include "librbd/PluginRegistry.h"
 
 #define dout_subsys ceph_subsys_rbd
 #undef dout_prefix
@@ -27,18 +32,20 @@ using util::create_context_callback;
 
 template <typename I>
 PreReleaseRequest<I>* PreReleaseRequest<I>::create(
-    I &image_ctx, bool shutting_down, AsyncOpTracker &async_op_tracker,
-    Context *on_finish) {
-  return new PreReleaseRequest(image_ctx, shutting_down, async_op_tracker,
-                               on_finish);
+    I &image_ctx, ImageDispatch<I>* image_dispatch, bool shutting_down,
+    AsyncOpTracker &async_op_tracker, Context *on_finish) {
+  return new PreReleaseRequest(image_ctx, image_dispatch, shutting_down,
+                               async_op_tracker, on_finish);
 }
 
 template <typename I>
-PreReleaseRequest<I>::PreReleaseRequest(I &image_ctx, bool shutting_down,
+PreReleaseRequest<I>::PreReleaseRequest(I &image_ctx,
+                                        ImageDispatch<I>* image_dispatch,
+                                        bool shutting_down,
                                         AsyncOpTracker &async_op_tracker,
                                         Context *on_finish)
-  : m_image_ctx(image_ctx), m_shutting_down(shutting_down),
-    m_async_op_tracker(async_op_tracker),
+  : m_image_ctx(image_ctx), m_image_dispatch(image_dispatch),
+    m_shutting_down(shutting_down), m_async_op_tracker(async_op_tracker),
     m_on_finish(create_async_context_callback(image_ctx, on_finish)) {
 }
 
@@ -51,30 +58,6 @@ PreReleaseRequest<I>::~PreReleaseRequest() {
 
 template <typename I>
 void PreReleaseRequest<I>::send() {
-  send_prepare_lock();
-}
-
-template <typename I>
-void PreReleaseRequest<I>::send_prepare_lock() {
-  if (m_shutting_down) {
-    send_cancel_op_requests();
-    return;
-  }
-
-  CephContext *cct = m_image_ctx.cct;
-  ldout(cct, 10) << dendl;
-
-  // release the lock if the image is not busy performing other actions
-  Context *ctx = create_context_callback<
-    PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_prepare_lock>(this);
-  m_image_ctx.state->prepare_lock(ctx);
-}
-
-template <typename I>
-void PreReleaseRequest<I>::handle_prepare_lock(int r) {
-  CephContext *cct = m_image_ctx.cct;
-  ldout(cct, 10) << "r=" << r << dendl;
-
   send_cancel_op_requests();
 }
 
@@ -96,47 +79,44 @@ void PreReleaseRequest<I>::handle_cancel_op_requests(int r) {
 
   ceph_assert(r == 0);
 
-  send_block_writes();
+  send_set_require_lock();
 }
 
 template <typename I>
-void PreReleaseRequest<I>::send_block_writes() {
+void PreReleaseRequest<I>::send_set_require_lock() {
+  if (!m_image_ctx.test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    // exclusive-lock was disabled, no need to block IOs
+    send_wait_for_ops();
+    return;
+  }
+
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << dendl;
 
   using klass = PreReleaseRequest<I>;
   Context *ctx = create_context_callback<
-    klass, &klass::handle_block_writes>(this);
-
-  {
-    std::shared_lock owner_locker{m_image_ctx.owner_lock};
-    // setting the lock as required will automatically cause the IO
-    // queue to re-request the lock if any IO is queued
-    if (m_image_ctx.clone_copy_on_read ||
-        m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
-      m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_BOTH, true);
-    } else {
-      m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_WRITE, true);
-    }
-    m_image_ctx.io_work_queue->block_writes(ctx);
+    klass, &klass::handle_set_require_lock>(this);
+
+  // setting the lock as required will automatically cause the IO
+  // queue to re-request the lock if any IO is queued
+  if (m_image_ctx.clone_copy_on_read ||
+      m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
+    m_image_dispatch->set_require_lock(m_shutting_down,
+                                       io::DIRECTION_BOTH, ctx);
+  } else {
+    m_image_dispatch->set_require_lock(m_shutting_down,
+                                       io::DIRECTION_WRITE, ctx);
   }
 }
 
 template <typename I>
-void PreReleaseRequest<I>::handle_block_writes(int r) {
+void PreReleaseRequest<I>::handle_set_require_lock(int r) {
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << "r=" << r << dendl;
 
-  if (r == -EBLACKLISTED) {
-    // allow clean shut down if blacklisted
-    lderr(cct) << "failed to block writes because client is blacklisted"
-               << dendl;
-  } else if (r < 0) {
-    lderr(cct) << "failed to block writes: " << cpp_strerror(r) << dendl;
-    m_image_ctx.io_work_queue->unblock_writes();
-    save_result(r);
-    finish();
-    return;
+  if (r < 0) {
+    // IOs are still flushed regardless of the error
+    lderr(cct) << "failed to set lock: " << cpp_strerror(r) << dendl;
   }
 
   send_wait_for_ops();
@@ -157,6 +137,59 @@ void PreReleaseRequest<I>::handle_wait_for_ops(int r) {
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << dendl;
 
+  send_prepare_lock();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_prepare_lock() {
+  if (m_shutting_down) {
+    send_process_plugin_release_lock();
+    return;
+  }
+
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  // release the lock if the image is not busy performing other actions
+  Context *ctx = create_context_callback<
+    PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_prepare_lock>(this);
+  m_image_ctx.state->prepare_lock(ctx);
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_prepare_lock(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << "r=" << r << dendl;
+
+  send_process_plugin_release_lock();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_process_plugin_release_lock() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  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_process_plugin_release_lock>(this));
+  m_image_ctx.plugin_registry->prerelease_exclusive_lock(ctx);
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_process_plugin_release_lock(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << "r=" << r << dendl;
+
+  if (r < 0) {
+    lderr(cct) << "failed to handle plugins before releasing lock: "
+               << cpp_strerror(r) << dendl;
+    m_image_dispatch->unset_require_lock(io::DIRECTION_BOTH);
+    save_result(r);
+    finish();
+    return;
+  }
+
   send_invalidate_cache();
 }
 
@@ -165,11 +198,10 @@ void PreReleaseRequest<I>::send_invalidate_cache() {
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << dendl;
 
-  std::shared_lock owner_lock{m_image_ctx.owner_lock};
   Context *ctx = create_context_callback<
       PreReleaseRequest<I>,
       &PreReleaseRequest<I>::handle_invalidate_cache>(this);
-  m_image_ctx.io_object_dispatcher->invalidate_cache(ctx);
+  m_image_ctx.io_image_dispatcher->invalidate_cache(ctx);
 }
 
 template <typename I>
@@ -177,15 +209,45 @@ void PreReleaseRequest<I>::handle_invalidate_cache(int r) {
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 10) << "r=" << r << dendl;
 
-  if (r < 0 && r != -EBLACKLISTED && r != -EBUSY) {
+  if (r < 0 && r != -EBLOCKLISTED && r != -EBUSY) {
     lderr(cct) << "failed to invalidate cache: " << cpp_strerror(r)
                << dendl;
-    m_image_ctx.io_work_queue->unblock_writes();
+    m_image_dispatch->unset_require_lock(io::DIRECTION_BOTH);
     save_result(r);
     finish();
     return;
   }
 
+  send_flush_io();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_flush_io() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << dendl;
+
+  // ensure that all in-flight IO is flushed -- skipping the refresh layer
+  // since it should have been flushed when the lock was required and now
+  // refreshes are disabled / interlocked w/ this state machine.
+  auto ctx = create_context_callback<
+      PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_flush_io>(this);
+  auto aio_comp = io::AioCompletion::create_and_start(
+    ctx, util::get_image_ctx(&m_image_ctx), librbd::io::AIO_TYPE_FLUSH);
+  auto req = io::ImageDispatchSpec::create_flush(
+    m_image_ctx, io::IMAGE_DISPATCH_LAYER_EXCLUSIVE_LOCK, aio_comp,
+    io::FLUSH_SOURCE_EXCLUSIVE_LOCK_SKIP_REFRESH, {});
+  req->send();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_flush_io(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << "r=" << r << dendl;
+
+  if (r < 0) {
+    lderr(cct) << "failed to flush IO: " << cpp_strerror(r) << dendl;
+  }
+
   send_flush_notifies();
 }