]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: maintenance ops now send asynchronous requests
authorJason Dillaman <dillaman@redhat.com>
Fri, 11 Mar 2016 00:13:07 +0000 (19:13 -0500)
committerJason Dillaman <dillaman@redhat.com>
Sun, 13 Mar 2016 03:40:16 +0000 (22:40 -0500)
The RBD mirror daemon will need to request the creation/removal
of snapshots from a remote image.  These operations need to be
performed asynchronously as opposed to the current synchronous
style of the librbd API.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/ExclusiveLock.cc
src/librbd/ImageWatcher.cc
src/librbd/ImageWatcher.h
src/librbd/Operations.cc
src/librbd/Operations.h
src/test/librbd/test_ImageWatcher.cc

index 3779cc1cca1b8a48bbcf53cee2c1e1c444867e67..bd945e6a233114cab6e98243bd6f77625223db5c 100644 (file)
@@ -113,7 +113,7 @@ template <typename I>
 void ExclusiveLock<I>::try_lock(Context *on_tried_lock) {
   {
     Mutex::Locker locker(m_lock);
-    assert(m_image_ctx.owner_lock.is_wlocked());
+    assert(m_image_ctx.owner_lock.is_locked());
     assert(!is_shutdown());
 
     if (m_state != STATE_LOCKED || !m_actions_contexts.empty()) {
index 2bd3c0a61cb7abcd01c4ac9fff9cc25537d968b2..b6542807898435d34ce3138561b92a017346d64f 100644 (file)
@@ -16,6 +16,7 @@
 #include "include/encoding.h"
 #include "include/stringify.h"
 #include "common/errno.h"
+#include "common/WorkQueue.h"
 #include <sstream>
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
@@ -191,7 +192,9 @@ void ImageWatcher::handle_async_complete(const AsyncRequestId &request, int r,
   }
 }
 
-int ImageWatcher::notify_flatten(uint64_t request_id, ProgressContext &prog_ctx) {
+void ImageWatcher::notify_flatten(uint64_t request_id,
+                                  ProgressContext &prog_ctx,
+                                  Context *on_finish) {
   assert(m_image_ctx.owner_lock.is_locked());
   assert(m_image_ctx.exclusive_lock &&
          !m_image_ctx.exclusive_lock->is_lock_owner());
@@ -200,11 +203,12 @@ int ImageWatcher::notify_flatten(uint64_t request_id, ProgressContext &prog_ctx)
 
   bufferlist bl;
   ::encode(NotifyMessage(FlattenPayload(async_request_id)), bl);
-  return notify_async_request(async_request_id, std::move(bl), prog_ctx);
+  notify_async_request(async_request_id, std::move(bl), prog_ctx, on_finish);
 }
 
-int ImageWatcher::notify_resize(uint64_t request_id, uint64_t size,
-                               ProgressContext &prog_ctx) {
+void ImageWatcher::notify_resize(uint64_t request_id, uint64_t size,
+                                ProgressContext &prog_ctx,
+                                 Context *on_finish) {
   assert(m_image_ctx.owner_lock.is_locked());
   assert(m_image_ctx.exclusive_lock &&
          !m_image_ctx.exclusive_lock->is_lock_owner());
@@ -213,61 +217,68 @@ int ImageWatcher::notify_resize(uint64_t request_id, uint64_t size,
 
   bufferlist bl;
   ::encode(NotifyMessage(ResizePayload(size, async_request_id)), bl);
-  return notify_async_request(async_request_id, std::move(bl), prog_ctx);
+  notify_async_request(async_request_id, std::move(bl), prog_ctx, on_finish);
 }
 
-int ImageWatcher::notify_snap_create(const std::string &snap_name) {
+void ImageWatcher::notify_snap_create(const std::string &snap_name,
+                                      Context *on_finish) {
   assert(m_image_ctx.owner_lock.is_locked());
   assert(m_image_ctx.exclusive_lock &&
          !m_image_ctx.exclusive_lock->is_lock_owner());
 
   bufferlist bl;
   ::encode(NotifyMessage(SnapCreatePayload(snap_name)), bl);
-  return notify_lock_owner(std::move(bl));
+  notify_lock_owner(std::move(bl), on_finish);
 }
 
-int ImageWatcher::notify_snap_rename(const snapid_t &src_snap_id,
-                                    const std::string &dst_snap_name) {
+void ImageWatcher::notify_snap_rename(const snapid_t &src_snap_id,
+                                     const std::string &dst_snap_name,
+                                      Context *on_finish) {
   assert(m_image_ctx.owner_lock.is_locked());
   assert(m_image_ctx.exclusive_lock &&
          !m_image_ctx.exclusive_lock->is_lock_owner());
 
   bufferlist bl;
   ::encode(NotifyMessage(SnapRenamePayload(src_snap_id, dst_snap_name)), bl);
-  return notify_lock_owner(std::move(bl));
+  notify_lock_owner(std::move(bl), on_finish);
 }
-int ImageWatcher::notify_snap_remove(const std::string &snap_name) {
+
+void ImageWatcher::notify_snap_remove(const std::string &snap_name,
+                                      Context *on_finish) {
   assert(m_image_ctx.owner_lock.is_locked());
   assert(m_image_ctx.exclusive_lock &&
          !m_image_ctx.exclusive_lock->is_lock_owner());
 
   bufferlist bl;
   ::encode(NotifyMessage(SnapRemovePayload(snap_name)), bl);
-  return notify_lock_owner(std::move(bl));
+  notify_lock_owner(std::move(bl), on_finish);
 }
 
-int ImageWatcher::notify_snap_protect(const std::string &snap_name) {
+void ImageWatcher::notify_snap_protect(const std::string &snap_name,
+                                       Context *on_finish) {
   assert(m_image_ctx.owner_lock.is_locked());
   assert(m_image_ctx.exclusive_lock &&
          !m_image_ctx.exclusive_lock->is_lock_owner());
 
   bufferlist bl;
   ::encode(NotifyMessage(SnapProtectPayload(snap_name)), bl);
-  return notify_lock_owner(std::move(bl));
+  notify_lock_owner(std::move(bl), on_finish);
 }
 
-int ImageWatcher::notify_snap_unprotect(const std::string &snap_name) {
+void ImageWatcher::notify_snap_unprotect(const std::string &snap_name,
+                                         Context *on_finish) {
   assert(m_image_ctx.owner_lock.is_locked());
   assert(m_image_ctx.exclusive_lock &&
          !m_image_ctx.exclusive_lock->is_lock_owner());
 
   bufferlist bl;
   ::encode(NotifyMessage(SnapUnprotectPayload(snap_name)), bl);
-  return notify_lock_owner(std::move(bl));
+  notify_lock_owner(std::move(bl), on_finish);
 }
 
-int ImageWatcher::notify_rebuild_object_map(uint64_t request_id,
-                                            ProgressContext &prog_ctx) {
+void ImageWatcher::notify_rebuild_object_map(uint64_t request_id,
+                                             ProgressContext &prog_ctx,
+                                             Context *on_finish) {
   assert(m_image_ctx.owner_lock.is_locked());
   assert(m_image_ctx.exclusive_lock &&
          !m_image_ctx.exclusive_lock->is_lock_owner());
@@ -276,17 +287,18 @@ int ImageWatcher::notify_rebuild_object_map(uint64_t request_id,
 
   bufferlist bl;
   ::encode(NotifyMessage(RebuildObjectMapPayload(async_request_id)), bl);
-  return notify_async_request(async_request_id, std::move(bl), prog_ctx);
+  notify_async_request(async_request_id, std::move(bl), prog_ctx, on_finish);
 }
 
-int ImageWatcher::notify_rename(const std::string &image_name) {
+void ImageWatcher::notify_rename(const std::string &image_name,
+                                 Context *on_finish) {
   assert(m_image_ctx.owner_lock.is_locked());
   assert(m_image_ctx.exclusive_lock &&
          !m_image_ctx.exclusive_lock->is_lock_owner());
 
   bufferlist bl;
   ::encode(NotifyMessage(RenamePayload(image_name)), bl);
-  return notify_lock_owner(std::move(bl));
+  notify_lock_owner(std::move(bl), on_finish);
 }
 
 void ImageWatcher::notify_header_update(Context *on_finish) {
@@ -420,19 +432,25 @@ void ImageWatcher::handle_request_lock(int r) {
   }
 }
 
-int ImageWatcher::notify_lock_owner(bufferlist &&bl) {
-  C_SaferCond ctx;
-  notify_lock_owner(std::move(bl), &ctx);
-  return ctx.wait();
-}
-
 void ImageWatcher::notify_lock_owner(bufferlist &&bl, Context *on_finish) {
+  assert(on_finish != nullptr);
   assert(m_image_ctx.owner_lock.is_locked());
   NotifyLockOwner *notify_lock_owner = NotifyLockOwner::create(
     m_image_ctx, m_notifier, std::move(bl), on_finish);
   notify_lock_owner->send();
 }
 
+Context *ImageWatcher::remove_async_request(const AsyncRequestId &id) {
+  RWLock::WLocker async_request_locker(m_async_request_lock);
+  auto it = m_async_requests.find(id);
+  if (it != m_async_requests.end()) {
+    Context *on_complete = it->second.first;
+    m_async_requests.erase(it);
+    return on_complete;
+  }
+  return nullptr;
+}
+
 void ImageWatcher::schedule_async_request_timed_out(const AsyncRequestId &id) {
   Context *ctx = new FunctionContext(boost::bind(
     &ImageWatcher::async_request_timed_out, this, id));
@@ -444,44 +462,45 @@ void ImageWatcher::schedule_async_request_timed_out(const AsyncRequestId &id) {
 }
 
 void ImageWatcher::async_request_timed_out(const AsyncRequestId &id) {
-  RWLock::RLocker l(m_async_request_lock);
-  std::map<AsyncRequestId, AsyncRequest>::iterator it =
-    m_async_requests.find(id);
-  if (it != m_async_requests.end()) {
-    ldout(m_image_ctx.cct, 10) << this << " request timed-out: " << id << dendl;
-    it->second.first->complete(-ERESTART);
+  Context *on_complete = remove_async_request(id);
+  if (on_complete != nullptr) {
+    ldout(m_image_ctx.cct, 5) << "async request timed out: " << id << dendl;
+    m_image_ctx.op_work_queue->queue(on_complete, -ETIMEDOUT);
   }
 }
 
-int ImageWatcher::notify_async_request(const AsyncRequestId &async_request_id,
-                                      bufferlist &&in,
-                                      ProgressContext& prog_ctx) {
+void ImageWatcher::notify_async_request(const AsyncRequestId &async_request_id,
+                                       bufferlist &&in,
+                                       ProgressContext& prog_ctx,
+                                        Context *on_finish) {
+  assert(on_finish != nullptr);
   assert(m_image_ctx.owner_lock.is_locked());
 
   ldout(m_image_ctx.cct, 10) << this << " async request: " << async_request_id
                              << dendl;
 
-  C_SaferCond ctx;
+  Context *on_notify = new FunctionContext([this, async_request_id](int r) {
+    if (r < 0) {
+      // notification failed -- don't expect updates
+      Context *on_complete = remove_async_request(async_request_id);
+      if (on_complete != nullptr) {
+        on_complete->complete(r);
+      }
+    }
+  });
+  Context *on_complete = new FunctionContext(
+    [this, async_request_id, on_finish](int r) {
+      m_task_finisher->cancel(Task(TASK_CODE_ASYNC_REQUEST, async_request_id));
+      on_finish->complete(r);
+    });
 
   {
-    RWLock::WLocker l(m_async_request_lock);
-    m_async_requests[async_request_id] = AsyncRequest(&ctx, &prog_ctx);
+    RWLock::WLocker async_request_locker(m_async_request_lock);
+    m_async_requests[async_request_id] = AsyncRequest(on_complete, &prog_ctx);
   }
 
-  BOOST_SCOPE_EXIT( (&ctx)(async_request_id)(&m_task_finisher)
-                    (&m_async_requests)(&m_async_request_lock) ) {
-    m_task_finisher->cancel(Task(TASK_CODE_ASYNC_REQUEST, async_request_id));
-
-    RWLock::WLocker l(m_async_request_lock);
-    m_async_requests.erase(async_request_id);
-  } BOOST_SCOPE_EXIT_END
-
   schedule_async_request_timed_out(async_request_id);
-  int r = notify_lock_owner(std::move(in));
-  if (r < 0) {
-    return r;
-  }
-  return ctx.wait();
+  notify_lock_owner(std::move(in), on_notify);
 }
 
 int ImageWatcher::prepare_async_request(const AsyncRequestId& async_request_id,
@@ -613,14 +632,12 @@ bool ImageWatcher::handle_payload(const AsyncProgressPayload &payload,
 
 bool ImageWatcher::handle_payload(const AsyncCompletePayload &payload,
                                   C_NotifyAck *ack_ctx) {
-  RWLock::RLocker l(m_async_request_lock);
-  std::map<AsyncRequestId, AsyncRequest>::iterator req_it =
-    m_async_requests.find(payload.async_request_id);
-  if (req_it != m_async_requests.end()) {
+  Context *on_complete = remove_async_request(payload.async_request_id);
+  if (on_complete != nullptr) {
     ldout(m_image_ctx.cct, 10) << this << " request finished: "
                                << payload.async_request_id << "="
                               << payload.result << dendl;
-    req_it->second.first->complete(payload.result);
+    on_complete->complete(payload.result);
   }
   return true;
 }
index 89edb35df2c63f50039362006524e84723d7592a..da1c11b332b5b4baff3c91e994897964c8ef804f 100644 (file)
@@ -34,18 +34,20 @@ public:
   void unregister_watch(Context *on_finish);
   void flush(Context *on_finish);
 
-  int notify_flatten(uint64_t request_id, ProgressContext &prog_ctx);
-  int notify_resize(uint64_t request_id, uint64_t size,
-                    ProgressContext &prog_ctx);
-  int notify_snap_create(const std::string &snap_name);
-  int notify_snap_rename(const snapid_t &src_snap_id,
-                         const std::string &dst_snap_name);
-  int notify_snap_remove(const std::string &snap_name);
-  int notify_snap_protect(const std::string &snap_name);
-  int notify_snap_unprotect(const std::string &snap_name);
-  int notify_rebuild_object_map(uint64_t request_id,
-                                ProgressContext &prog_ctx);
-  int notify_rename(const std::string &image_name);
+  void notify_flatten(uint64_t request_id, ProgressContext &prog_ctx,
+                      Context *on_finish);
+  void notify_resize(uint64_t request_id, uint64_t size,
+                     ProgressContext &prog_ctx, Context *on_finish);
+  void notify_snap_create(const std::string &snap_name, Context *on_finish);
+  void notify_snap_rename(const snapid_t &src_snap_id,
+                          const std::string &dst_snap_name,
+                          Context *on_finish);
+  void notify_snap_remove(const std::string &snap_name, Context *on_finish);
+  void notify_snap_protect(const std::string &snap_name, Context *on_finish);
+  void notify_snap_unprotect(const std::string &snap_name, Context *on_finish);
+  void notify_rebuild_object_map(uint64_t request_id,
+                                 ProgressContext &prog_ctx, Context *on_finish);
+  void notify_rename(const std::string &image_name, Context *on_finish);
 
   void notify_acquired_lock();
   void notify_released_lock();
@@ -247,13 +249,14 @@ private:
   void handle_request_lock(int r);
   void schedule_request_lock(bool use_timer, int timer_delay = -1);
 
-  int notify_lock_owner(bufferlist &&bl);
   void notify_lock_owner(bufferlist &&bl, Context *on_finish);
 
+  Context *remove_async_request(const watch_notify::AsyncRequestId &id);
   void schedule_async_request_timed_out(const watch_notify::AsyncRequestId &id);
   void async_request_timed_out(const watch_notify::AsyncRequestId &id);
-  int notify_async_request(const watch_notify::AsyncRequestId &id,
-                           bufferlist &&in, ProgressContext& prog_ctx);
+  void notify_async_request(const watch_notify::AsyncRequestId &id,
+                            bufferlist &&in, ProgressContext& prog_ctx,
+                            Context *on_finish);
 
   void schedule_async_progress(const watch_notify::AsyncRequestId &id,
                                uint64_t offset, uint64_t total);
index ff698c28203b1547c0f1dcaef1e153cbe0ef62fb..e990304cc90686c7bfea86cc9107a410d8f21fc7 100644 (file)
@@ -8,6 +8,7 @@
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageState.h"
 #include "librbd/ImageWatcher.h"
+#include "librbd/Utils.h"
 #include "librbd/operation/FlattenRequest.h"
 #include "librbd/operation/RebuildObjectMapRequest.h"
 #include "librbd/operation/RenameRequest.h"
@@ -51,6 +52,159 @@ struct C_NotifyUpdate : public Context {
   }
 };
 
+template <typename I>
+struct C_InvokeAsyncRequest : public Context {
+  /**
+   * @verbatim
+   *
+   *               <start>
+   *                  |
+   *    . . . . . .   |   . . . . . . . . . . . . . . . . . .
+   *    .         .   |   .                                 .
+   *    .         v   v   v                                 .
+   *    .       ACQUIRE_LOCK (skip if exclusive lock        .
+   *    .             |       disabled or has lock)         .
+   *    .             |                                     .
+   *    .   /--------/ \--------\   . . . . . . . . . . . . .
+   *    .   |                   |   .
+   *    .   v                   v   .
+   *  LOCAL_REQUEST       REMOTE_REQUEST
+   *        |                   |
+   *        |                   |
+   *        \--------\ /--------/
+   *                  |
+   *                  v
+   *              <finish>
+   *
+   * @endverbatim
+   */
+
+  I &image_ctx;
+  std::string request_type;
+  bool permit_snapshot;
+  boost::function<void(Context*)> local;
+  boost::function<void(Context*)> remote;
+  Context *on_finish;
+
+  C_InvokeAsyncRequest(I &image_ctx, const std::string& request_type,
+                       bool permit_snapshot,
+                       const boost::function<void(Context*)>& local,
+                       const boost::function<void(Context*)>& remote,
+                       Context *on_finish)
+    : image_ctx(image_ctx), request_type(request_type),
+      permit_snapshot(permit_snapshot), local(local), remote(remote),
+      on_finish(on_finish) {
+  }
+
+  void send() {
+    send_acquire_exclusive_lock();
+  }
+
+  void send_acquire_exclusive_lock() {
+    RWLock::RLocker owner_locker(image_ctx.owner_lock);
+    {
+      RWLock::RLocker snap_locker(image_ctx.snap_lock);
+      if (image_ctx.read_only ||
+          (!permit_snapshot && image_ctx.snap_id != CEPH_NOSNAP)) {
+        complete(-EROFS);
+        return;
+      }
+    }
+
+    if (image_ctx.exclusive_lock == nullptr) {
+      send_local_request();
+      return;
+    } else if (image_ctx.image_watcher == nullptr) {
+      complete(-EROFS);
+      return;
+    }
+
+    if (image_ctx.exclusive_lock->is_lock_owner() &&
+        image_ctx.exclusive_lock->accept_requests()) {
+      send_local_request();
+      return;
+    }
+
+    CephContext *cct = image_ctx.cct;
+    ldout(cct, 20) << __func__ << dendl;
+
+    Context *ctx = util::create_context_callback<
+      C_InvokeAsyncRequest<I>,
+      &C_InvokeAsyncRequest<I>::handle_acquire_exclusive_lock>(
+        this);
+    image_ctx.exclusive_lock->try_lock(ctx);
+  }
+
+  void handle_acquire_exclusive_lock(int r) {
+    CephContext *cct = image_ctx.cct;
+    ldout(cct, 20) << __func__ << ": r=" << r << dendl;
+
+    RWLock::RLocker owner_locker(image_ctx.owner_lock);
+    if (r < 0) {
+      complete(-EROFS);
+      return;
+    } else if (image_ctx.exclusive_lock->is_lock_owner()) {
+      send_local_request();
+      return;
+    }
+
+    send_remote_request();
+  }
+
+  void send_remote_request() {
+    assert(image_ctx.owner_lock.is_locked());
+
+    CephContext *cct = image_ctx.cct;
+    ldout(cct, 20) << __func__ << dendl;
+
+    Context *ctx = util::create_context_callback<
+      C_InvokeAsyncRequest<I>, &C_InvokeAsyncRequest<I>::handle_remote_request>(
+        this);
+    remote(ctx);
+  }
+
+  void handle_remote_request(int r) {
+    CephContext *cct = image_ctx.cct;
+    ldout(cct, 20) << __func__ << ": r=" << r << dendl;
+
+    if (r != -ETIMEDOUT && r != -ERESTART) {
+      complete(r);
+      return;
+    }
+
+    ldout(cct, 5) << request_type << " timed out notifying lock owner"
+                  << dendl;
+    send_acquire_exclusive_lock();
+  }
+
+  void send_local_request() {
+    assert(image_ctx.owner_lock.is_locked());
+
+    CephContext *cct = image_ctx.cct;
+    ldout(cct, 20) << __func__ << dendl;
+
+    Context *ctx = util::create_context_callback<
+      C_InvokeAsyncRequest<I>, &C_InvokeAsyncRequest<I>::handle_local_request>(
+        this);
+    local(ctx);
+  }
+
+  void handle_local_request(int r) {
+    CephContext *cct = image_ctx.cct;
+    ldout(cct, 20) << __func__ << ": r=" << r << dendl;
+
+    if (r == -ERESTART) {
+      send_acquire_exclusive_lock();
+      return;
+    }
+    complete(r);
+  }
+
+  virtual void finish(int r) override {
+    on_finish->complete(r);
+  }
+};
+
 } // anonymous namespace
 
 template <typename I>
@@ -85,7 +239,7 @@ int Operations<I>::flatten(ProgressContext &prog_ctx) {
                                        boost::ref(prog_ctx), _1),
                            boost::bind(&ImageWatcher::notify_flatten,
                                        m_image_ctx.image_watcher, request_id,
-                                       boost::ref(prog_ctx)));
+                                       boost::ref(prog_ctx), _1));
 
   if (r < 0 && r != -EINVAL) {
     return r;
@@ -161,7 +315,7 @@ int Operations<I>::rebuild_object_map(ProgressContext &prog_ctx) {
                                        boost::ref(prog_ctx), _1),
                            boost::bind(&ImageWatcher::notify_rebuild_object_map,
                                        m_image_ctx.image_watcher, request_id,
-                                       boost::ref(prog_ctx)));
+                                       boost::ref(prog_ctx), _1));
 
   ldout(cct, 10) << "rebuild object map finished" << dendl;
   if (r < 0) {
@@ -217,7 +371,8 @@ int Operations<I>::rename(const char *dstname) {
                              boost::bind(&Operations<I>::rename, this,
                                          dstname, _1),
                              boost::bind(&ImageWatcher::notify_rename,
-                                         m_image_ctx.image_watcher, dstname));
+                                         m_image_ctx.image_watcher, dstname,
+                                         _1));
     if (r < 0 && r != -EEXIST) {
       return r;
     }
@@ -277,7 +432,7 @@ int Operations<I>::resize(uint64_t size, ProgressContext& prog_ctx) {
                                        size, boost::ref(prog_ctx), _1, 0),
                            boost::bind(&ImageWatcher::notify_resize,
                                        m_image_ctx.image_watcher, request_id,
-                                       size, boost::ref(prog_ctx)));
+                                       size, boost::ref(prog_ctx), _1));
 
   m_image_ctx.perfcounter->inc(l_librbd_resize);
   ldout(cct, 2) << "resize finished" << dendl;
@@ -337,7 +492,8 @@ int Operations<I>::snap_create(const char *snap_name) {
                            boost::bind(&Operations<I>::snap_create, this,
                                        snap_name, _1, 0),
                            boost::bind(&ImageWatcher::notify_snap_create,
-                                       m_image_ctx.image_watcher, snap_name));
+                                       m_image_ctx.image_watcher, snap_name,
+                                       _1));
   if (r < 0 && r != -EEXIST) {
     return r;
   }
@@ -473,7 +629,8 @@ int Operations<I>::snap_remove(const char *snap_name) {
                              boost::bind(&Operations<I>::snap_remove, this,
                                          snap_name, _1),
                              boost::bind(&ImageWatcher::notify_snap_remove,
-                                         m_image_ctx.image_watcher, snap_name));
+                                         m_image_ctx.image_watcher, snap_name,
+                                         _1));
     if (r < 0 && r != -ENOENT) {
       return r;
     }
@@ -568,7 +725,7 @@ int Operations<I>::snap_rename(const char *srcname, const char *dstname) {
                                          snap_id, dstname, _1),
                              boost::bind(&ImageWatcher::notify_snap_rename,
                                          m_image_ctx.image_watcher, snap_id,
-                                         dstname));
+                                         dstname, _1));
     if (r < 0 && r != -EEXIST) {
       return r;
     }
@@ -642,7 +799,8 @@ int Operations<I>::snap_protect(const char *snap_name) {
                              boost::bind(&Operations<I>::snap_protect, this,
                                          snap_name, _1),
                              boost::bind(&ImageWatcher::notify_snap_protect,
-                                         m_image_ctx.image_watcher, snap_name));
+                                         m_image_ctx.image_watcher, snap_name,
+                                         _1));
     if (r < 0 && r != -EBUSY) {
       return r;
     }
@@ -711,7 +869,8 @@ int Operations<I>::snap_unprotect(const char *snap_name) {
                              boost::bind(&Operations<I>::snap_unprotect, this,
                                          snap_name, _1),
                              boost::bind(&ImageWatcher::notify_snap_unprotect,
-                                         m_image_ctx.image_watcher, snap_name));
+                                         m_image_ctx.image_watcher, snap_name,
+                                         _1));
     if (r < 0 && r != -EINVAL) {
       return r;
     }
@@ -781,46 +940,16 @@ 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<int()>& remote_request) {
-  CephContext *cct = m_image_ctx.cct;
-  int r;
-  do {
-    C_SaferCond ctx;
-    {
-      RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
-      {
-        RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-        if (m_image_ctx.read_only ||
-            (!permit_snapshot && m_image_ctx.snap_id != CEPH_NOSNAP)) {
-          return -EROFS;
-        }
-      }
-
-      while (m_image_ctx.exclusive_lock != nullptr) {
-        r = prepare_image_update();
-        if (r < 0) {
-          return -EROFS;
-        } else if (m_image_ctx.exclusive_lock->is_lock_owner()) {
-          break;
-        }
-
-        r = remote_request();
-        if (r != -ETIMEDOUT && r != -ERESTART) {
-          return r;
-        }
-        ldout(cct, 5) << request_type << " timed out notifying lock owner"
-                      << dendl;
-      }
-
-      local_request(&ctx);
-    }
-
-    r = ctx.wait();
-    if (r == -ERESTART) {
-      ldout(cct, 5) << request_type << " interrupted: restarting" << dendl;
-    }
-  } while (r == -ERESTART);
-  return r;
+                                        const boost::function<void(Context*)>& remote_request) {
+  C_SaferCond ctx;
+  C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx,
+                                                             request_type,
+                                                             permit_snapshot,
+                                                             local_request,
+                                                             remote_request,
+                                                             &ctx);
+  req->send();
+  return ctx.wait();
 }
 
 } // namespace librbd
index d1f4371540036cba5d164fa5db7e5f66f1146d17..b4ae3b431bfa0059ca9a5aab4a363b0d2c05736d 100644 (file)
@@ -63,8 +63,8 @@ private:
 
   int invoke_async_request(const std::string& request_type,
                            bool permit_snapshot,
-                           const boost::function<void(Context*)>& local_request,
-                           const boost::function<int()>& remote_request);
+                           const boost::function<void(Context*)>& local,
+                           const boost::function<void(Context*)>& remote);
 };
 
 } // namespace librbd
index 7e7f9eced0fdc75ca1736b1c3c89e412278f6a7e..a698e33b10e54e51ca0745ce246266b20837b4c3 100644 (file)
@@ -257,7 +257,9 @@ struct FlattenTask {
 
   void operator()() {
     RWLock::RLocker l(ictx->owner_lock);
-    result = ictx->image_watcher->notify_flatten(0, *progress_context);
+    C_SaferCond ctx;
+    ictx->image_watcher->notify_flatten(0, *progress_context, &ctx);
+    result = ctx.wait();
   }
 };
 
@@ -271,7 +273,9 @@ struct ResizeTask {
 
   void operator()() {
     RWLock::RLocker l(ictx->owner_lock);
-    result = ictx->image_watcher->notify_resize(0, 0, *progress_context);
+    C_SaferCond ctx;
+    ictx->image_watcher->notify_resize(0, 0, *progress_context, &ctx);
+    result = ctx.wait();
   }
 };
 
@@ -285,7 +289,9 @@ struct RebuildObjectMapTask {
 
   void operator()() {
     RWLock::RLocker l(ictx->owner_lock);
-    result = ictx->image_watcher->notify_rebuild_object_map(0, *progress_context);
+    C_SaferCond ctx;
+    ictx->image_watcher->notify_rebuild_object_map(0, *progress_context, &ctx);
+    result = ctx.wait();
   }
 };
 
@@ -481,7 +487,9 @@ TEST_F(TestImageWatcher, NotifySnapCreate) {
   m_notify_acks = {{NOTIFY_OP_SNAP_CREATE, create_response_message(0)}};
 
   RWLock::RLocker l(ictx->owner_lock);
-  ASSERT_EQ(0, ictx->image_watcher->notify_snap_create("snap"));
+  C_SaferCond notify_ctx;
+  ictx->image_watcher->notify_snap_create("snap", &notify_ctx);
+  ASSERT_EQ(0, notify_ctx.wait());
 
   NotifyOps expected_notify_ops;
   expected_notify_ops += NOTIFY_OP_SNAP_CREATE;
@@ -501,7 +509,9 @@ TEST_F(TestImageWatcher, NotifySnapCreateError) {
   m_notify_acks = {{NOTIFY_OP_SNAP_CREATE, create_response_message(-EEXIST)}};
 
   RWLock::RLocker l(ictx->owner_lock);
-  ASSERT_EQ(-EEXIST, ictx->image_watcher->notify_snap_create("snap"));
+  C_SaferCond notify_ctx;
+  ictx->image_watcher->notify_snap_create("snap", &notify_ctx);
+  ASSERT_EQ(-EEXIST, notify_ctx.wait());
 
   NotifyOps expected_notify_ops;
   expected_notify_ops += NOTIFY_OP_SNAP_CREATE;
@@ -521,7 +531,9 @@ TEST_F(TestImageWatcher, NotifySnapRename) {
   m_notify_acks = {{NOTIFY_OP_SNAP_RENAME, create_response_message(0)}};
 
   RWLock::RLocker l(ictx->owner_lock);
-  ASSERT_EQ(0, ictx->image_watcher->notify_snap_rename(1, "snap-rename"));
+  C_SaferCond notify_ctx;
+  ictx->image_watcher->notify_snap_rename(1, "snap-rename", &notify_ctx);
+  ASSERT_EQ(0, notify_ctx.wait());
 
   NotifyOps expected_notify_ops;
   expected_notify_ops += NOTIFY_OP_SNAP_RENAME;
@@ -541,7 +553,9 @@ TEST_F(TestImageWatcher, NotifySnapRenameError) {
   m_notify_acks = {{NOTIFY_OP_SNAP_RENAME, create_response_message(-EEXIST)}};
 
   RWLock::RLocker l(ictx->owner_lock);
-  ASSERT_EQ(-EEXIST, ictx->image_watcher->notify_snap_rename(1, "snap-rename"));
+  C_SaferCond notify_ctx;
+  ictx->image_watcher->notify_snap_rename(1, "snap-rename", &notify_ctx);
+  ASSERT_EQ(-EEXIST, notify_ctx.wait());
 
   NotifyOps expected_notify_ops;
   expected_notify_ops += NOTIFY_OP_SNAP_RENAME;
@@ -561,7 +575,9 @@ TEST_F(TestImageWatcher, NotifySnapRemove) {
   m_notify_acks = {{NOTIFY_OP_SNAP_REMOVE, create_response_message(0)}};
 
   RWLock::RLocker l(ictx->owner_lock);
-  ASSERT_EQ(0, ictx->image_watcher->notify_snap_remove("snap"));
+  C_SaferCond notify_ctx;
+  ictx->image_watcher->notify_snap_remove("snap", &notify_ctx);
+  ASSERT_EQ(0, notify_ctx.wait());
 
   NotifyOps expected_notify_ops;
   expected_notify_ops += NOTIFY_OP_SNAP_REMOVE;
@@ -581,7 +597,9 @@ TEST_F(TestImageWatcher, NotifySnapProtect) {
   m_notify_acks = {{NOTIFY_OP_SNAP_PROTECT, create_response_message(0)}};
 
   RWLock::RLocker l(ictx->owner_lock);
-  ASSERT_EQ(0, ictx->image_watcher->notify_snap_protect("snap"));
+  C_SaferCond notify_ctx;
+  ictx->image_watcher->notify_snap_protect("snap", &notify_ctx);
+  ASSERT_EQ(0, notify_ctx.wait());
 
   NotifyOps expected_notify_ops;
   expected_notify_ops += NOTIFY_OP_SNAP_PROTECT;
@@ -601,7 +619,9 @@ TEST_F(TestImageWatcher, NotifySnapUnprotect) {
   m_notify_acks = {{NOTIFY_OP_SNAP_UNPROTECT, create_response_message(0)}};
 
   RWLock::RLocker l(ictx->owner_lock);
-  ASSERT_EQ(0, ictx->image_watcher->notify_snap_unprotect("snap"));
+  C_SaferCond notify_ctx;
+  ictx->image_watcher->notify_snap_unprotect("snap", &notify_ctx);
+  ASSERT_EQ(0, notify_ctx.wait());
 
   NotifyOps expected_notify_ops;
   expected_notify_ops += NOTIFY_OP_SNAP_UNPROTECT;
@@ -621,7 +641,9 @@ TEST_F(TestImageWatcher, NotifyRename) {
   m_notify_acks = {{NOTIFY_OP_RENAME, create_response_message(0)}};
 
   RWLock::RLocker l(ictx->owner_lock);
-  ASSERT_EQ(0, ictx->image_watcher->notify_rename("new_name"));
+  C_SaferCond notify_ctx;
+  ictx->image_watcher->notify_rename("new_name", &notify_ctx);
+  ASSERT_EQ(0, notify_ctx.wait());
 
   NotifyOps expected_notify_ops;
   expected_notify_ops += NOTIFY_OP_RENAME;
@@ -720,6 +742,6 @@ TEST_F(TestImageWatcher, NotifyAsyncRequestTimedOut) {
   ASSERT_TRUE(wait_for_notifies(*ictx));
 
   ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
-  ASSERT_EQ(-ERESTART, flatten_task.result);
+  ASSERT_EQ(-ETIMEDOUT, flatten_task.result);
 }