]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: added async image rename op
authorJason Dillaman <dillaman@redhat.com>
Tue, 25 Aug 2015 20:12:53 +0000 (16:12 -0400)
committerJason Dillaman <dillaman@redhat.com>
Thu, 19 Nov 2015 01:34:42 +0000 (20:34 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/ImageWatcher.cc
src/librbd/Makefile.am
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/operation/RenameRequest.cc [new file with mode: 0644]
src/librbd/operation/RenameRequest.h [new file with mode: 0644]

index 6cbab0022173a6da43c5cd60d5e3ee3e9689d978..62cf77f263074a4aa063fb7181f06c4caf6c4e8b 100644 (file)
@@ -1142,8 +1142,12 @@ void ImageWatcher::handle_payload(const RenamePayload& payload,
     ldout(m_image_ctx.cct, 10) << this << " remote rename request: "
                                << payload.image_name << dendl;
 
-    // TODO
-    ::encode(ResponseMessage(-EOPNOTSUPP), *out);
+    C_SaferCond cond_ctx;
+    librbd::rename_helper(&m_image_ctx, &cond_ctx,
+                          payload.image_name.c_str());
+
+    int r = cond_ctx.wait();
+    ::encode(ResponseMessage(r), *out);
   }
 }
 
index ee3b1e829d57afb81e7d5d6def6cdf0856f3c6ef..3bf4122cfd0e74de0e56059f18de2dbaf16f4b2b 100644 (file)
@@ -34,6 +34,7 @@ librbd_internal_la_SOURCES = \
        librbd/object_map/UpdateRequest.cc \
        librbd/operation/FlattenRequest.cc \
        librbd/operation/RebuildObjectMapRequest.cc \
+       librbd/operation/RenameRequest.cc \
        librbd/operation/Request.cc \
        librbd/operation/ResizeRequest.cc \
        librbd/operation/SnapshotCreateRequest.cc \
@@ -99,6 +100,7 @@ noinst_HEADERS += \
        librbd/object_map/UpdateRequest.h \
        librbd/operation/FlattenRequest.h \
        librbd/operation/RebuildObjectMapRequest.h \
+       librbd/operation/RenameRequest.h \
        librbd/operation/Request.h \
        librbd/operation/ResizeRequest.h \
        librbd/operation/SnapshotCreateRequest.h \
index 8efec10d2f5cf379f4270675898b471db9633113..86c520e8434659c4911e7e599ed191f4d2fb99d3 100644 (file)
@@ -32,6 +32,7 @@
 #include "librbd/parent_types.h"
 #include "librbd/operation/FlattenRequest.h"
 #include "librbd/operation/RebuildObjectMapRequest.h"
+#include "librbd/operation/RenameRequest.h"
 #include "librbd/operation/ResizeRequest.h"
 #include "librbd/operation/SnapshotCreateRequest.h"
 #include "librbd/operation/SnapshotProtectRequest.h"
@@ -1567,13 +1568,16 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
     ldout(cct, 20) << "rename " << &io_ctx << " " << srcname << " -> "
                   << dstname << dendl;
 
-    bool old_format;
-    uint64_t src_size;
-    int r = detect_format(io_ctx, srcname, &old_format, &src_size);
+    ImageCtx *ictx = new ImageCtx(srcname, "", "", io_ctx, false);
+    int r = open_image(ictx);
     if (r < 0) {
-      lderr(cct) << "error finding source object: " << cpp_strerror(r) << dendl;
+      lderr(ictx->cct) << "error opening source image: " << cpp_strerror(r)
+                      << dendl;
       return r;
     }
+    BOOST_SCOPE_EXIT((ictx)) {
+      close_image(ictx);
+    } BOOST_SCOPE_EXIT_END
 
     r = detect_format(io_ctx, dstname, NULL, NULL);
     if (r < 0 && r != -ENOENT) {
@@ -1586,92 +1590,54 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       return -EEXIST;
     }
 
-    string src_oid =
-      old_format ? old_header_name(srcname) : id_obj_name(srcname);
-    string dst_oid =
-      old_format ? old_header_name(dstname) : id_obj_name(dstname);
-
-    string id;
-    if (!old_format) {
-      r = cls_client::get_id(&io_ctx, src_oid, &id);
-      if (r < 0) {
-       lderr(cct) << "error reading image id: " << cpp_strerror(r) << dendl;
-       return r;
+    if (ictx->test_features(RBD_FEATURE_JOURNALING)) {
+      r = invoke_async_request(ictx, "rename", true,
+                               boost::bind(&rename_helper, ictx, _1,
+                                           dstname),
+                               boost::bind(&ImageWatcher::notify_rename,
+                                           ictx->image_watcher, dstname));
+      if (r < 0 && r != -EEXIST) {
+        return r;
       }
-    }
-
-    bufferlist databl;
-    map<string, bufferlist> omap_values;
-    r = io_ctx.read(src_oid, databl, src_size, 0);
-    if (r < 0) {
-      lderr(cct) << "error reading source object: " << src_oid << ": "
-                << cpp_strerror(r) << dendl;
-      return r;
-    }
+    } else {
+      RWLock::RLocker owner_lock(ictx->owner_lock);
+      C_SaferCond cond_ctx;
+      rename_helper(ictx, &cond_ctx, dstname);
 
-    int MAX_READ = 1024;
-    string last_read = "";
-    do {
-      map<string, bufferlist> outbl;
-      r = io_ctx.omap_get_vals(src_oid, last_read, MAX_READ, &outbl);
+      r = cond_ctx.wait();
       if (r < 0) {
-       lderr(cct) << "error reading source object omap values: "
-                  << cpp_strerror(r) << dendl;
-       return r;
+        return r;
       }
-      omap_values.insert(outbl.begin(), outbl.end());
-      if (!outbl.empty())
-       last_read = outbl.rbegin()->first;
-    } while (r == MAX_READ);
-
-    librados::ObjectWriteOperation op;
-    op.create(true);
-    op.write_full(databl);
-    if (!omap_values.empty())
-      op.omap_set(omap_values);
-    r = io_ctx.operate(dst_oid, &op);
-    if (r < 0) {
-      lderr(cct) << "error writing destination object: " << dst_oid << ": "
-                << cpp_strerror(r) << dendl;
-      return r;
     }
 
-    if (old_format) {
-      r = tmap_set(io_ctx, dstname);
-      if (r < 0) {
-       io_ctx.remove(dst_oid);
-       lderr(cct) << "couldn't add " << dstname << " to directory: "
-                  << cpp_strerror(r) << dendl;
-       return r;
-      }
-      r = tmap_rm(io_ctx, srcname);
-      if (r < 0) {
-       lderr(cct) << "warning: couldn't remove old entry from directory ("
-                  << srcname << ")" << dendl;
-      }
-    } else {
-      r = cls_client::dir_rename_image(&io_ctx, RBD_DIRECTORY,
-                                      srcname, dstname, id);
-      if (r < 0) {
-       lderr(cct) << "error updating directory: " << cpp_strerror(r) << dendl;
-       return r;
-      }
+    if (ictx->old_format) {
+      notify_change(ictx->md_ctx, ictx->header_oid, ictx);
     }
+    return 0;
+  }
 
-    r = io_ctx.remove(src_oid);
-    if (r < 0 && r != -ENOENT) {
-      lderr(cct) << "warning: couldn't remove old source object ("
-                << src_oid << ")" << dendl;
+  void rename_helper(ImageCtx *ictx, Context *ctx, const char *dstname)
+  {
+    assert(ictx->owner_lock.is_locked());
+    if (ictx->test_features(RBD_FEATURE_JOURNALING)) {
+      assert(!ictx->image_watcher->is_lock_supported() ||
+            ictx->image_watcher->is_lock_owner());
     }
 
-    if (old_format) {
-      notify_change(io_ctx, old_header_name(srcname), NULL);
+    ldout(ictx->cct, 20) << "rename_helper " << ictx << " " << dstname
+                         << dendl;
+
+    int r = ictx_check(ictx, ictx->owner_lock);
+    if (r < 0) {
+      ctx->complete(r);
+      return;
     }
 
-    return 0;
+    operation::RenameRequest *req =
+      new operation::RenameRequest(*ictx, ctx, dstname);
+    req->send();
   }
 
-
   int info(ImageCtx *ictx, image_info_t& info, size_t infosize)
   {
     ldout(ictx->cct, 20) << "info " << ictx << dendl;
index 964dde68d21bf653edd81a535b0dbe70b3c0d5bc..04f5a24e87eac351ff913d502f6fd0a8df50531f 100644 (file)
@@ -111,6 +111,7 @@ namespace librbd {
   int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
            IoCtx& c_ioctx, const char *c_name, ImageOptions& c_opts);
   int rename(librados::IoCtx& io_ctx, const char *srcname, const char *dstname);
+  void rename_helper(ImageCtx *ictx, Context *ctx, const char *dstname);
   int info(ImageCtx *ictx, image_info_t& info, size_t image_size);
   int get_old_format(ImageCtx *ictx, uint8_t *old);
   int get_size(ImageCtx *ictx, uint64_t *size);
diff --git a/src/librbd/operation/RenameRequest.cc b/src/librbd/operation/RenameRequest.cc
new file mode 100644 (file)
index 0000000..1a9c82d
--- /dev/null
@@ -0,0 +1,175 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/operation/RenameRequest.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "include/rados/librados.hpp"
+#include "librbd/ImageCtx.h"
+#include "librbd/internal.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::operation::RenameRequest: "
+
+namespace librbd {
+namespace operation {
+
+namespace {
+
+std::ostream& operator<<(std::ostream& os,
+                         const RenameRequest::State& state) {
+  switch(state) {
+  case RenameRequest::STATE_READ_SOURCE_HEADER:
+    os << "READ_SOURCE_HEADER";
+    break;
+  case RenameRequest::STATE_WRITE_DEST_HEADER:
+    os << "WRITE_DEST_HEADER";
+    break;
+  case RenameRequest::STATE_UPDATE_DIRECTORY:
+    os << "UPDATE_DIRECTORY";
+    break;
+  case RenameRequest::STATE_REMOVE_SOURCE_HEADER:
+    os << "REMOVE_SOURCE_HEADER";
+    break;
+  default:
+    os << "UNKNOWN (" << static_cast<uint32_t>(state) << ")";
+    break;
+  }
+  return os;
+}
+
+} // anonymous namespace
+
+RenameRequest::RenameRequest(ImageCtx &image_ctx, Context *on_finish,
+                             const std::string &dest_name)
+  : Request(image_ctx, on_finish), m_dest_name(dest_name),
+    m_source_oid(image_ctx.old_format ? old_header_name(image_ctx.name) :
+                                        id_obj_name(image_ctx.name)),
+    m_dest_oid(image_ctx.old_format ? old_header_name(dest_name) :
+                                      id_obj_name(dest_name)) {
+}
+
+void RenameRequest::send_op() {
+  send_read_source_header();
+}
+
+bool RenameRequest::should_complete(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", "
+                << "r=" << r << dendl;
+  r = filter_state_return_code(r);
+  if (r < 0) {
+    lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl;
+    return true;
+  }
+
+  RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
+  bool finished = false;
+  switch (m_state) {
+  case STATE_READ_SOURCE_HEADER:
+    send_write_destination_header();
+    break;
+  case STATE_WRITE_DEST_HEADER:
+    send_update_directory();
+    break;
+  case STATE_UPDATE_DIRECTORY:
+    send_remove_source_header();
+    break;
+  case STATE_REMOVE_SOURCE_HEADER:
+    finished = true;
+    break;
+  default:
+    assert(false);
+    break;
+  }
+  return finished;
+}
+
+int RenameRequest::filter_state_return_code(int r) {
+  CephContext *cct = m_image_ctx.cct;
+
+  if (m_state == STATE_REMOVE_SOURCE_HEADER && r < 0) {
+    if (r != -ENOENT) {
+      lderr(cct) << "warning: couldn't remove old source object ("
+                 << m_source_oid << ")" << dendl;
+    }
+    return 0;
+  }
+  return r;
+}
+
+void RenameRequest::send_read_source_header() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 5) << this << " " << __func__ << dendl;
+  m_state = STATE_READ_SOURCE_HEADER;
+
+  librados::ObjectReadOperation op;
+  op.read(0, 0, NULL, NULL);
+
+  // TODO: old code read omap values but there are no omap values on the
+  //       old format header nor the new format id object
+  librados::AioCompletion *rados_completion = create_callback_completion();
+  int r = m_image_ctx.md_ctx.aio_operate(m_source_oid, rados_completion, &op,
+                                         &m_header_bl);
+  assert(r == 0);
+  rados_completion->release();
+}
+
+void RenameRequest::send_write_destination_header() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 5) << this << " " << __func__ << dendl;
+  m_state = STATE_WRITE_DEST_HEADER;
+
+  librados::ObjectWriteOperation op;
+  op.create(true);
+  op.write_full(m_header_bl);
+
+  librados::AioCompletion *rados_completion = create_callback_completion();
+  int r = m_image_ctx.md_ctx.aio_operate(m_dest_oid, rados_completion, &op);
+  assert(r == 0);
+  rados_completion->release();
+}
+
+void RenameRequest::send_update_directory() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 5) << this << " " << __func__ << dendl;
+  m_state = STATE_UPDATE_DIRECTORY;
+
+  librados::ObjectWriteOperation op;
+  if (m_image_ctx.old_format) {
+    bufferlist cmd_bl;
+    bufferlist empty_bl;
+    ::encode(static_cast<__u8>(CEPH_OSD_TMAP_SET), cmd_bl);
+    ::encode(m_dest_name, cmd_bl);
+    ::encode(empty_bl, cmd_bl);
+    ::encode(static_cast<__u8>(CEPH_OSD_TMAP_RM), cmd_bl);
+    ::encode(m_image_ctx.name, cmd_bl);
+    op.tmap_update(cmd_bl);
+  } else {
+    cls_client::dir_rename_image(&op, m_image_ctx.name, m_dest_name,
+                                 m_image_ctx.id);
+  }
+
+  librados::AioCompletion *rados_completion = create_callback_completion();
+  int r = m_image_ctx.md_ctx.aio_operate(RBD_DIRECTORY, rados_completion, &op);
+  assert(r == 0);
+  rados_completion->release();
+}
+
+void RenameRequest::send_remove_source_header() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 5) << this << " " << __func__ << dendl;
+  m_state = STATE_REMOVE_SOURCE_HEADER;
+
+  librados::ObjectWriteOperation op;
+  op.remove();
+
+  librados::AioCompletion *rados_completion = create_callback_completion();
+  int r = m_image_ctx.md_ctx.aio_operate(m_source_oid, rados_completion, &op);
+  assert(r == 0);
+  rados_completion->release();
+}
+
+} // namespace operation
+} // namespace librbd
diff --git a/src/librbd/operation/RenameRequest.h b/src/librbd/operation/RenameRequest.h
new file mode 100644 (file)
index 0000000..b07293f
--- /dev/null
@@ -0,0 +1,83 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_RENAME_REQUEST_HH
+#define CEPH_LIBRBD_RENAME_REQUEST_H
+
+#include "librbd/operation/Request.h"
+#include <iosfwd>
+#include <string>
+
+class Context;
+
+namespace librbd {
+
+class ImageCtx;
+
+namespace operation {
+
+class RenameRequest : public Request
+{
+public:
+  /**
+   * Rename goes through the following state machine:
+   *
+   * @verbatim
+   *
+   * <start>
+   *    |
+   *    v
+   * STATE_READ_SOURCE_HEADER
+   *    |
+   *    v
+   * STATE_WRITE_DEST_HEADER
+   *    |
+   *    v
+   * STATE_UPDATE_DIRECTORY
+   *    |
+   *    v
+   * STATE_REMOVE_SOURCE_HEADER
+   *    |
+   *    v
+   * <finish>
+   *
+   * @endverbatim
+   *
+   */
+  enum State {
+    STATE_READ_SOURCE_HEADER,
+    STATE_WRITE_DEST_HEADER,
+    STATE_UPDATE_DIRECTORY,
+    STATE_REMOVE_SOURCE_HEADER
+  };
+
+  RenameRequest(ImageCtx &image_ctx, Context *on_finish,
+                const std::string &dest_name);
+
+protected:
+  virtual void send_op();
+  virtual bool should_complete(int r);
+
+private:
+  std::string m_dest_name;
+
+  std::string m_source_oid;
+  std::string m_dest_oid;
+
+  State m_state;
+
+  bufferlist m_header_bl;
+
+  int filter_state_return_code(int r);
+
+  void send_read_source_header();
+  void send_write_destination_header();
+  void send_update_directory();
+  void send_remove_source_header();
+
+};
+
+} // namespace operation
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_RENAME_REQUEST_H