]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: introduce a way to allow proxied trash snap remove
authorMykola Golub <mgolub@suse.com>
Wed, 30 Oct 2019 13:30:35 +0000 (15:30 +0200)
committerMykola Golub <mgolub@suse.com>
Wed, 20 Nov 2019 08:17:57 +0000 (10:17 +0200)
(while other operations are still blocked)

Signed-off-by: Mykola Golub <mgolub@suse.com>
(cherry picked from commit 42dd83a20538e25cbf55ea9a1f235e9e0d7f5102)

Conflicts:
src/librbd/ExclusiveLock.cc (Mutex::Locker vs std::lock_guard)
src/librbd/ImageWatcher.cc (no migrate and sparsify in mimic)
src/librbd/Operations.cc (RWLock::RLocker vs std::shared_lock,
                          assert vs ceph_assert,
                          no migrate and sparsify)
src/librbd/Operations.h (no migrate and sparsify)
src/librbd/api/Migration.cc (does not exist)
src/librbd/api/Trash.cc (does not exist, update internal.cc instead)

src/librbd/ExclusiveLock.cc
src/librbd/ExclusiveLock.h
src/librbd/ImageWatcher.cc
src/librbd/Operations.cc
src/librbd/Operations.h
src/librbd/exclusive_lock/Policy.h
src/librbd/internal.cc
src/test/librbd/mock/MockExclusiveLock.h
src/test/librbd/mock/exclusive_lock/MockPolicy.h
src/test/librbd/test_mock_ExclusiveLock.cc

index a70e77e917c053594b6038c6017a342282ece78c..151193a335fac85dec96baff91cb6e7198c84b10 100644 (file)
@@ -37,18 +37,22 @@ ExclusiveLock<I>::ExclusiveLock(I &image_ctx)
 }
 
 template <typename I>
-bool ExclusiveLock<I>::accept_requests(int *ret_val) const {
+bool ExclusiveLock<I>::accept_request(OperationRequestType request_type,
+                                      int *ret_val) const {
   Mutex::Locker locker(ML<I>::m_lock);
 
-  bool accept_requests = (!ML<I>::is_state_shutdown() &&
-                          ML<I>::is_state_locked() &&
-                          m_request_blocked_count == 0);
+  bool accept_request =
+    (!ML<I>::is_state_shutdown() && ML<I>::is_state_locked() &&
+     (m_request_blocked_count == 0 ||
+      m_image_ctx.get_exclusive_lock_policy()->accept_blocked_request(
+        request_type)));
   if (ret_val != nullptr) {
-    *ret_val = m_request_blocked_ret_val;
+    *ret_val = accept_request ? 0 : m_request_blocked_ret_val;
   }
 
-  ldout(m_image_ctx.cct, 20) << "=" << accept_requests << dendl;
-  return accept_requests;
+  ldout(m_image_ctx.cct, 20) << "=" << accept_request << " (request_type="
+                             << request_type << ")" << dendl;
+  return accept_request;
 }
 
 template <typename I>
@@ -74,7 +78,7 @@ void ExclusiveLock<I>::block_requests(int r) {
     m_request_blocked_ret_val = r;
   }
 
-  ldout(m_image_ctx.cct, 20) << dendl;
+  ldout(m_image_ctx.cct, 20) << "r=" << r << dendl;
 }
 
 template <typename I>
index 8b2a411f44232debfed2996337bf48b0ec1789f5..824cb00d0b0620e0e61ae1611d8a08a61139af79 100644 (file)
@@ -4,8 +4,9 @@
 #ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_H
 #define CEPH_LIBRBD_EXCLUSIVE_LOCK_H
 
-#include "librbd/ManagedLock.h"
 #include "common/AsyncOpTracker.h"
+#include "librbd/ManagedLock.h"
+#include "librbd/exclusive_lock/Policy.h"
 
 namespace librbd {
 
@@ -18,7 +19,8 @@ public:
 
   ExclusiveLock(ImageCtxT &image_ctx);
 
-  bool accept_requests(int *ret_val = nullptr) const;
+  bool accept_request(exclusive_lock::OperationRequestType request_type,
+                      int *ret_val) const;
   bool accept_ops() const;
 
   void block_requests(int r);
index f8c525b3c6a5cb1d9420cdd5927b659e0703a33c..1dfb55447d733937ad0b7c1a8db00774d631235d 100644 (file)
@@ -632,7 +632,8 @@ bool ImageWatcher<I>::handle_payload(const RequestLockPayload &payload,
   if (m_image_ctx.exclusive_lock != nullptr &&
       m_image_ctx.exclusive_lock->is_lock_owner()) {
     int r = 0;
-    bool accept_request = m_image_ctx.exclusive_lock->accept_requests(&r);
+    bool accept_request = m_image_ctx.exclusive_lock->accept_request(
+      exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r);
 
     if (accept_request) {
       assert(r == 0);
@@ -688,7 +689,8 @@ bool ImageWatcher<I>::handle_payload(const FlattenPayload &payload,
   RWLock::RLocker l(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
       bool new_request;
       Context *ctx;
       ProgressContext *prog_ctx;
@@ -714,7 +716,8 @@ bool ImageWatcher<I>::handle_payload(const ResizePayload &payload,
   RWLock::RLocker l(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
       bool new_request;
       Context *ctx;
       ProgressContext *prog_ctx;
@@ -742,7 +745,8 @@ bool ImageWatcher<I>::handle_payload(const SnapCreatePayload &payload,
   RWLock::RLocker l(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
       ldout(m_image_ctx.cct, 10) << this << " remote snap_create request: "
                                 << payload.snap_name << dendl;
 
@@ -764,7 +768,8 @@ bool ImageWatcher<I>::handle_payload(const SnapRenamePayload &payload,
   RWLock::RLocker l(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
       ldout(m_image_ctx.cct, 10) << this << " remote snap_rename request: "
                                 << payload.snap_id << " to "
                                 << payload.snap_name << dendl;
@@ -785,8 +790,13 @@ bool ImageWatcher<I>::handle_payload(const SnapRemovePayload &payload,
                                     C_NotifyAck *ack_ctx) {
   RWLock::RLocker l(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
+    auto request_type = exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL;
+    if (cls::rbd::get_snap_namespace_type(payload.snap_namespace) ==
+        cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
+      request_type = exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE;
+    }
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(request_type, &r)) {
       ldout(m_image_ctx.cct, 10) << this << " remote snap_remove request: "
                                 << payload.snap_name << dendl;
 
@@ -807,7 +817,8 @@ bool ImageWatcher<I>::handle_payload(const SnapProtectPayload& payload,
   RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
       ldout(m_image_ctx.cct, 10) << this << " remote snap_protect request: "
                                  << payload.snap_name << dendl;
 
@@ -828,7 +839,8 @@ bool ImageWatcher<I>::handle_payload(const SnapUnprotectPayload& payload,
   RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
       ldout(m_image_ctx.cct, 10) << this << " remote snap_unprotect request: "
                                  << payload.snap_name << dendl;
 
@@ -849,7 +861,8 @@ bool ImageWatcher<I>::handle_payload(const RebuildObjectMapPayload& payload,
   RWLock::RLocker l(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
       bool new_request;
       Context *ctx;
       ProgressContext *prog_ctx;
@@ -876,7 +889,8 @@ bool ImageWatcher<I>::handle_payload(const RenamePayload& payload,
   RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
       ldout(m_image_ctx.cct, 10) << this << " remote rename request: "
                                  << payload.image_name << dendl;
 
@@ -896,7 +910,8 @@ bool ImageWatcher<I>::handle_payload(const UpdateFeaturesPayload& payload,
   RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
       ldout(m_image_ctx.cct, 10) << this << " remote update_features request: "
                                  << payload.features << " "
                                  << (payload.enabled ? "enabled" : "disabled")
@@ -918,7 +933,8 @@ bool ImageWatcher<I>::handle_payload(const UnknownPayload &payload,
   RWLock::RLocker l(m_image_ctx.owner_lock);
   if (m_image_ctx.exclusive_lock != nullptr) {
     int r;
-    if (m_image_ctx.exclusive_lock->accept_requests(&r) || r < 0) {
+    if (m_image_ctx.exclusive_lock->accept_request(
+          exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r) || r < 0) {
       encode(ResponseMessage(-EOPNOTSUPP), ack_ctx->out);
     }
   }
index 8c467b61f093dbfbcc88c9ff4aca2e763b0bad3d..b268113a99dde3cd602e26937c086badb67461dd 100644 (file)
@@ -120,7 +120,8 @@ struct C_InvokeAsyncRequest : public Context {
    */
 
   I &image_ctx;
-  std::string request_type;
+  std::string name;
+  exclusive_lock::OperationRequestType request_type;
   bool permit_snapshot;
   boost::function<void(Context*)> local;
   boost::function<void(Context*)> remote;
@@ -128,13 +129,14 @@ struct C_InvokeAsyncRequest : public Context {
   Context *on_finish;
   bool request_lock = false;
 
-  C_InvokeAsyncRequest(I &image_ctx, const std::string& request_type,
+  C_InvokeAsyncRequest(I &image_ctx, const std::string& name,
+                       exclusive_lock::OperationRequestType request_type,
                        bool permit_snapshot,
                        const boost::function<void(Context*)>& local,
                        const boost::function<void(Context*)>& remote,
                        const std::set<int> &filter_error_codes,
                        Context *on_finish)
-    : image_ctx(image_ctx), request_type(request_type),
+    : image_ctx(image_ctx), name(name), request_type(request_type),
       permit_snapshot(permit_snapshot), local(local), remote(remote),
       filter_error_codes(filter_error_codes), on_finish(on_finish) {
   }
@@ -196,7 +198,7 @@ struct C_InvokeAsyncRequest : public Context {
     }
 
     if (image_ctx.exclusive_lock->is_lock_owner() &&
-        image_ctx.exclusive_lock->accept_requests()) {
+        image_ctx.exclusive_lock->accept_request(request_type, nullptr)) {
       send_local_request();
       owner_lock.put_read();
       return;
@@ -261,8 +263,7 @@ struct C_InvokeAsyncRequest : public Context {
     ldout(cct, 20) << __func__ << ": r=" << r << dendl;
 
     if (r == -EOPNOTSUPP) {
-      ldout(cct, 5) << request_type << " not supported by current lock owner"
-                    << dendl;
+      ldout(cct, 5) << name << " not supported by current lock owner" << dendl;
       request_lock = true;
       send_refresh_image();
       return;
@@ -273,8 +274,7 @@ struct C_InvokeAsyncRequest : public Context {
       return;
     }
 
-    ldout(cct, 5) << request_type << " timed out notifying lock owner"
-                  << dendl;
+    ldout(cct, 5) << name << " timed out notifying lock owner" << dendl;
     send_refresh_image();
   }
 
@@ -352,7 +352,9 @@ int Operations<I>::flatten(ProgressContext &prog_ctx) {
   }
 
   uint64_t request_id = ++m_async_request_seq;
-  r = invoke_async_request("flatten", false,
+  r = invoke_async_request("flatten",
+                           exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                           false,
                            boost::bind(&Operations<I>::execute_flatten, this,
                                        boost::ref(prog_ctx), _1),
                            boost::bind(&ImageWatcher<I>::notify_flatten,
@@ -430,7 +432,8 @@ int Operations<I>::rebuild_object_map(ProgressContext &prog_ctx) {
   }
 
   uint64_t request_id = ++m_async_request_seq;
-  r = invoke_async_request("rebuild object map", true,
+  r = invoke_async_request("rebuild object map",
+                           exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
                            boost::bind(&Operations<I>::execute_rebuild_object_map,
                                        this, boost::ref(prog_ctx), _1),
                            boost::bind(&ImageWatcher<I>::notify_rebuild_object_map,
@@ -480,7 +483,8 @@ int Operations<I>::check_object_map(ProgressContext &prog_ctx) {
     return r;
   }
 
-  r = invoke_async_request("check object map", true,
+  r = invoke_async_request("check object map",
+                           exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
                            boost::bind(&Operations<I>::check_object_map, this,
                                        boost::ref(prog_ctx), _1),
                           [this](Context *c) {
@@ -533,7 +537,9 @@ int Operations<I>::rename(const char *dstname) {
   }
 
   if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
-    r = invoke_async_request("rename", true,
+    r = invoke_async_request("rename",
+                             exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                             true,
                              boost::bind(&Operations<I>::execute_rename, this,
                                          dstname, _1),
                              boost::bind(&ImageWatcher<I>::notify_rename,
@@ -630,7 +636,9 @@ int Operations<I>::resize(uint64_t size, bool allow_shrink, ProgressContext& pro
   }
 
   uint64_t request_id = ++m_async_request_seq;
-  r = invoke_async_request("resize", false,
+  r = invoke_async_request("resize",
+                           exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                           false,
                            boost::bind(&Operations<I>::execute_resize, this,
                                        size, allow_shrink, boost::ref(prog_ctx), _1, 0),
                            boost::bind(&ImageWatcher<I>::notify_resize,
@@ -722,7 +730,8 @@ void Operations<I>::snap_create(const cls::rbd::SnapshotNamespace &snap_namespac
   m_image_ctx.snap_lock.put_read();
 
   C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
-    m_image_ctx, "snap_create", true,
+    m_image_ctx, "snap_create", exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+    true,
     boost::bind(&Operations<I>::execute_snap_create, this, snap_namespace, snap_name,
                _1, 0, false),
     boost::bind(&ImageWatcher<I>::notify_snap_create, m_image_ctx.image_watcher,
@@ -798,7 +807,8 @@ int Operations<I>::snap_rollback(const cls::rbd::SnapshotNamespace& snap_namespa
       }
     }
 
-    r = prepare_image_update(false);
+    r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                             false);
     if (r < 0) {
       return r;
     }
@@ -900,8 +910,13 @@ void Operations<I>::snap_remove(const cls::rbd::SnapshotNamespace& snap_namespac
   m_image_ctx.snap_lock.put_read();
 
   if (proxy_op) {
+    auto request_type = exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL;
+    if (cls::rbd::get_snap_namespace_type(snap_namespace) ==
+        cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
+      request_type = exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE;
+    }
     C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
-      m_image_ctx, "snap_remove", true,
+      m_image_ctx, "snap_remove", request_type, true,
       boost::bind(&Operations<I>::execute_snap_remove, this, snap_namespace, snap_name, _1),
       boost::bind(&ImageWatcher<I>::notify_snap_remove, m_image_ctx.image_watcher,
                   snap_namespace, snap_name, _1),
@@ -992,7 +1007,9 @@ int Operations<I>::snap_rename(const char *srcname, const char *dstname) {
   }
 
   if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
-    r = invoke_async_request("snap_rename", true,
+    r = invoke_async_request("snap_rename",
+                             exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                             true,
                              boost::bind(&Operations<I>::execute_snap_rename,
                                          this, snap_id, dstname, _1),
                              boost::bind(&ImageWatcher<I>::notify_snap_rename,
@@ -1091,7 +1108,9 @@ int Operations<I>::snap_protect(const cls::rbd::SnapshotNamespace& snap_namespac
   }
 
   if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
-    r = invoke_async_request("snap_protect", true,
+    r = invoke_async_request("snap_protect",
+                             exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                             true,
                              boost::bind(&Operations<I>::execute_snap_protect,
                                          this, snap_namespace, snap_name, _1),
                              boost::bind(&ImageWatcher<I>::notify_snap_protect,
@@ -1186,7 +1205,9 @@ int Operations<I>::snap_unprotect(const cls::rbd::SnapshotNamespace& snap_namesp
   }
 
   if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
-    r = invoke_async_request("snap_unprotect", true,
+    r = invoke_async_request("snap_unprotect",
+                             exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                             true,
                              boost::bind(&Operations<I>::execute_snap_unprotect,
                                          this, snap_namespace, snap_name, _1),
                              boost::bind(&ImageWatcher<I>::notify_snap_unprotect,
@@ -1267,7 +1288,8 @@ int Operations<I>::snap_set_limit(uint64_t limit) {
   C_SaferCond limit_ctx;
   {
     RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
-    r = prepare_image_update(true);
+    r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                             true);
     if (r < 0) {
       return r;
     }
@@ -1360,7 +1382,8 @@ int Operations<I>::update_features(uint64_t features, bool enabled) {
     C_SaferCond cond_ctx;
     {
       RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
-      r = prepare_image_update(true);
+      r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                               true);
       if (r < 0) {
         return r;
       }
@@ -1370,7 +1393,9 @@ int Operations<I>::update_features(uint64_t features, bool enabled) {
 
     r = cond_ctx.wait();
   } else {
-    r = invoke_async_request("update_features", false,
+    r = invoke_async_request("update_features",
+                             exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                             false,
                              boost::bind(&Operations<I>::execute_update_features,
                                          this, features, enabled, _1, 0),
                              boost::bind(&ImageWatcher<I>::notify_update_features,
@@ -1440,7 +1465,8 @@ int Operations<I>::metadata_set(const std::string &key,
   C_SaferCond metadata_ctx;
   {
     RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
-    r = prepare_image_update(true);
+    r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                             true);
     if (r < 0) {
       return r;
     }
@@ -1501,7 +1527,8 @@ int Operations<I>::metadata_remove(const std::string &key) {
   C_SaferCond metadata_ctx;
   {
     RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
-    r = prepare_image_update(true);
+    r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                             true);
     if (r < 0) {
       return r;
     }
@@ -1541,7 +1568,8 @@ void Operations<I>::execute_metadata_remove(const std::string &key,
 }
 
 template <typename I>
-int Operations<I>::prepare_image_update(bool request_lock) {
+int Operations<I>::prepare_image_update(
+    exclusive_lock::OperationRequestType request_type, bool request_lock) {
   assert(m_image_ctx.owner_lock.is_locked() &&
          !m_image_ctx.owner_lock.is_wlocked());
   if (m_image_ctx.image_watcher == nullptr) {
@@ -1556,7 +1584,7 @@ int Operations<I>::prepare_image_update(bool request_lock) {
     RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
     if (m_image_ctx.exclusive_lock != nullptr &&
         (!m_image_ctx.exclusive_lock->is_lock_owner() ||
-         !m_image_ctx.exclusive_lock->accept_requests())) {
+         !m_image_ctx.exclusive_lock->accept_request(request_type, nullptr))) {
 
       attempting_lock = true;
       m_image_ctx.exclusive_lock->block_requests(0);
@@ -1593,12 +1621,12 @@ int Operations<I>::prepare_image_update(bool request_lock) {
 }
 
 template <typename I>
-int Operations<I>::invoke_async_request(const std::string& request_type,
-                                        bool permit_snapshot,
-                                        const boost::function<void(Context*)>& local_request,
-                                        const boost::function<void(Context*)>& remote_request) {
+int Operations<I>::invoke_async_request(
+    const std::string& name, exclusive_lock::OperationRequestType request_type,
+    bool permit_snapshot, const boost::function<void(Context*)>& local_request,
+    const boost::function<void(Context*)>& remote_request) {
   C_SaferCond ctx;
-  C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx,
+  C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx, name,
                                                              request_type,
                                                              permit_snapshot,
                                                              local_request,
index ff1238ff50e549e28711c7284730a29723318cfb..e4f2cb084926b42dff5c6b1451a93de50e1d64bc 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "cls/rbd/cls_rbd_types.h"
 #include "include/int_types.h"
+#include "librbd/exclusive_lock/Policy.h"
 #include "librbd/operation/ObjectMapIterate.h"
 #include <atomic>
 #include <string>
@@ -100,13 +101,15 @@ public:
   int metadata_remove(const std::string &key);
   void execute_metadata_remove(const std::string &key, Context *on_finish);
 
-  int prepare_image_update(bool request_lock);
+  int prepare_image_update(exclusive_lock::OperationRequestType request_type,
+                           bool request_lock);
 
 private:
   ImageCtxT &m_image_ctx;
   std::atomic<int> m_async_request_seq;
 
-  int invoke_async_request(const std::string& request_type,
+  int invoke_async_request(const std::string& name,
+                           exclusive_lock::OperationRequestType request_type,
                            bool permit_snapshot,
                            const boost::function<void(Context*)>& local,
                            const boost::function<void(Context*)>& remote);
index 72b2945f58e1f5b50f61393d5528120f006a1ead..8dcbf444441068e2e9d4dc19377f5bcbb0deaa78 100644 (file)
@@ -7,12 +7,21 @@
 namespace librbd {
 namespace exclusive_lock {
 
+enum OperationRequestType {
+  OPERATION_REQUEST_TYPE_GENERAL           = 0,
+  OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE = 1,
+};
+
 struct Policy {
   virtual ~Policy() {
   }
 
   virtual bool may_auto_request_lock() = 0;
   virtual int lock_requested(bool force) = 0;
+
+  virtual bool accept_blocked_request(OperationRequestType) {
+    return false;
+  }
 };
 
 } // namespace exclusive_lock
index 3ae697d580d9d191491789b67e506fdc9e00d591..3db3c4d4ab737cb74198df7a888adc9f644768b2 100644 (file)
@@ -1489,7 +1489,8 @@ int enable_mirroring(IoCtx &io_ctx, const std::string &image_id) {
     if (ictx->exclusive_lock != nullptr) {
       ictx->exclusive_lock->block_requests(0);
 
-      r = ictx->operations->prepare_image_update(false);
+      r = ictx->operations->prepare_image_update(
+        exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, false);
       if (r < 0) {
         lderr(cct) << "cannot obtain exclusive lock - not removing" << dendl;
         ictx->owner_lock.put_read();
index 1b49fa6a75dc18cb983d48fdeeb63fbfbb9e1d77..efb4fa4e33ed30dacdd25785318d0bbcde31cc02 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "include/int_types.h"
 #include "include/rados/librados.hpp"
+#include "librbd/exclusive_lock/Policy.h"
 #include "gmock/gmock.h"
 
 class Context;
@@ -27,7 +28,8 @@ struct MockExclusiveLock {
   MOCK_METHOD1(acquire_lock, void(Context *));
   MOCK_METHOD1(release_lock, void(Context *));
 
-  MOCK_METHOD0(accept_requests, bool());
+  MOCK_METHOD2(accept_request, bool(exclusive_lock::OperationRequestType,
+                                    int *));
   MOCK_METHOD0(accept_ops, bool());
   MOCK_METHOD0(get_unlocked_op_error, int());
 
index d403568e365337d63ab292204690f10e5fc29a4e..f49eeb23f204d92214c5ddcd07b6636ade518809 100644 (file)
@@ -14,7 +14,7 @@ struct MockPolicy : public Policy {
 
   MOCK_METHOD0(may_auto_request_lock, bool());
   MOCK_METHOD1(lock_requested, int(bool));
-
+  MOCK_METHOD1(accept_blocked_request, bool(OperationRequestType));
 };
 
 } // namespace exclusive_lock
index 3aa26f092e670f848708a672b36bdf05cf9bcf9d..ad8b273aed4e3ebde7764c9994bfcc34e58e3779 100644 (file)
@@ -4,6 +4,7 @@
 #include "test/librbd/test_mock_fixture.h"
 #include "test/librbd/test_support.h"
 #include "test/librbd/mock/MockImageCtx.h"
+#include "test/librbd/mock/exclusive_lock/MockPolicy.h"
 #include "librbd/ExclusiveLock.h"
 #include "librbd/ManagedLock.h"
 #include "librbd/exclusive_lock/PreAcquireRequest.h"
@@ -290,6 +291,16 @@ public:
       .WillOnce(CompleteContext(0, static_cast<ContextWQ*>(nullptr)));
   }
 
+  void expect_accept_blocked_request(
+      MockExclusiveLockImageCtx &mock_image_ctx,
+      exclusive_lock::MockPolicy &policy,
+      exclusive_lock::OperationRequestType request_type, bool value) {
+    EXPECT_CALL(mock_image_ctx, get_exclusive_lock_policy())
+      .WillOnce(Return(&policy));
+    EXPECT_CALL(policy, accept_blocked_request(request_type))
+      .WillOnce(Return(value));
+  }
+
   int when_init(MockExclusiveLockImageCtx &mock_image_ctx,
                 MockExclusiveLock &exclusive_lock) {
     C_SaferCond ctx;
@@ -663,6 +674,7 @@ TEST_F(TestMockExclusiveLock, BlockRequests) {
 
   MockExclusiveLockImageCtx mock_image_ctx(*ictx);
   MockExclusiveLock exclusive_lock(mock_image_ctx);
+  exclusive_lock::MockPolicy mock_exclusive_lock_policy;
 
   expect_op_work_queue(mock_image_ctx);
 
@@ -675,19 +687,35 @@ TEST_F(TestMockExclusiveLock, BlockRequests) {
   int ret_val;
   expect_is_state_shutdown(exclusive_lock, false);
   expect_is_state_locked(exclusive_lock, true);
-  ASSERT_TRUE(exclusive_lock.accept_requests(&ret_val));
+  ASSERT_TRUE(exclusive_lock.accept_request(
+                exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &ret_val));
   ASSERT_EQ(0, ret_val);
 
   exclusive_lock.block_requests(-EROFS);
   expect_is_state_shutdown(exclusive_lock, false);
   expect_is_state_locked(exclusive_lock, true);
-  ASSERT_FALSE(exclusive_lock.accept_requests(&ret_val));
+  expect_accept_blocked_request(mock_image_ctx, mock_exclusive_lock_policy,
+                                exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+                                false);
+  ASSERT_FALSE(exclusive_lock.accept_request(
+                 exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &ret_val));
   ASSERT_EQ(-EROFS, ret_val);
 
+  expect_is_state_shutdown(exclusive_lock, false);
+  expect_is_state_locked(exclusive_lock, true);
+  expect_accept_blocked_request(
+    mock_image_ctx, mock_exclusive_lock_policy,
+    exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE, true);
+  ASSERT_TRUE(exclusive_lock.accept_request(
+                exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE,
+                &ret_val));
+  ASSERT_EQ(0, ret_val);
+
   exclusive_lock.unblock_requests();
   expect_is_state_shutdown(exclusive_lock, false);
   expect_is_state_locked(exclusive_lock, true);
-  ASSERT_TRUE(exclusive_lock.accept_requests(&ret_val));
+  ASSERT_TRUE(exclusive_lock.accept_request(
+                exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &ret_val));
   ASSERT_EQ(0, ret_val);
 }