]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
librbd: added trash methods to API
authorRicardo Dias <rdias@suse.com>
Fri, 24 Feb 2017 18:36:55 +0000 (18:36 +0000)
committerRicardo Dias <rdias@suse.com>
Tue, 11 Apr 2017 11:09:41 +0000 (12:09 +0100)
Signed-off-by: Ricardo Dias <rdias@suse.com>
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/image/CloneRequest.cc
src/librbd/image/RemoveRequest.cc
src/librbd/image/RemoveRequest.h
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/test/librbd/image/test_mock_RemoveRequest.cc
src/test/librbd/test_librbd.cc
src/tracing/librbd.tp

index c24d89dde71aa4b2324cf49b66dfc3a05097c350..8f95b526a303d9e334155ab7592c5f9a1e9509e7 100644 (file)
@@ -183,6 +183,19 @@ enum {
   RBD_IMAGE_OPTION_DATA_POOL = 10
 };
 
+typedef enum {
+  RBD_TRASH_IMAGE_SOURCE_USER = 0,
+  RBD_TRASH_IMAGE_SOURCE_MIRRORING = 1
+} rbd_trash_image_source_t;
+
+typedef struct {
+  char *id;
+  char *name;
+  rbd_trash_image_source_t source;
+  time_t deletion_time;
+  time_t deferment_end_time;
+} rbd_trash_image_info_t;
+
 CEPH_RBD_API void rbd_image_options_create(rbd_image_options_t* opts);
 CEPH_RBD_API void rbd_image_options_destroy(rbd_image_options_t opts);
 CEPH_RBD_API int rbd_image_options_set_string(rbd_image_options_t opts,
@@ -242,6 +255,19 @@ CEPH_RBD_API int rbd_remove(rados_ioctx_t io, const char *name);
 CEPH_RBD_API int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
                                          librbd_progress_fn_t cb,
                                           void *cbdata);
+CEPH_RBD_API int rbd_trash_move(rados_ioctx_t io, const char *name,
+                                uint64_t delay);
+CEPH_RBD_API int rbd_trash_list(rados_ioctx_t io,
+                                rbd_trash_image_info_t *trash_entries,
+                                size_t *num_entries);
+CEPH_RBD_API void rbd_trash_list_cleanup(rbd_trash_image_info_t *trash_entries,
+                                         size_t num_entries);
+CEPH_RBD_API int rbd_trash_remove(rados_ioctx_t io, const char *id, bool force);
+CEPH_RBD_API int rbd_trash_remove_with_progress(rados_ioctx_t io, const char *id,
+                                                bool force, librbd_progress_fn_t cb,
+                                                void *cbdata);
+CEPH_RBD_API int rbd_trash_restore(rados_ioctx_t io, const char *id,
+                                   const char *name);
 CEPH_RBD_API int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname,
                             const char *destname);
 
index dfd4e8b60b9d527002be2d63e7d4c58e909ba319..2881e0094b9fbda1f9e2703cde481bce6440ac2c 100644 (file)
@@ -93,6 +93,14 @@ namespace librbd {
     virtual int update_progress(uint64_t offset, uint64_t total) = 0;
   };
 
+  typedef struct {
+    std::string id;
+    std::string name;
+    rbd_trash_image_source_t source;
+    time_t deletion_time;
+    time_t deferment_end_time;
+  } trash_image_info_t;
+
 class CEPH_RBD_API RBD
 {
 public:
@@ -150,6 +158,13 @@ public:
             IoCtx& c_ioctx, const char *c_name, ImageOptions& opts);
   int remove(IoCtx& io_ctx, const char *name);
   int remove_with_progress(IoCtx& io_ctx, const char *name, ProgressContext& pctx);
+  int trash_move(IoCtx &io_ctx, const char *name, uint64_t delay);
+  int trash_list(IoCtx &io_ctx, std::vector<trash_image_info_t> &entries);
+  int trash_remove(IoCtx &io_ctx, const char *image_id, bool force);
+  int trash_remove_with_progress(IoCtx &io_ctx, const char *image_id, bool force,
+                                 ProgressContext &pctx);
+  int trash_restore(IoCtx &io_ctx, const char *id, const char *name);
+
   int rename(IoCtx& src_io_ctx, const char *srcname, const char *destname);
 
   // RBD pool mirroring support functions
index 6e0ef901a64c7b90ca1dea279e98bf7eec2c68e5..c7d2ddca1b5d09e11c4e4175c79aace897112908 100644 (file)
@@ -532,7 +532,7 @@ void CloneRequest<I>::send_remove() {
   Context *ctx = create_context_callback<klass, &klass::handle_remove>(this);
 
   librbd::image::RemoveRequest<> *req = librbd::image::RemoveRequest<>::create(
-   m_ioctx, m_name, m_id, false, m_no_op, m_op_work_queue, ctx);
+   m_ioctx, m_name, m_id, false, false, m_no_op, m_op_work_queue, ctx);
   req->send();
 }
 
index 64b83efffc0da6b8dd74aebe23cc049a968250ce..629fc7c799344abb3a86bbfd8a026677b4601a48 100644 (file)
@@ -30,10 +30,12 @@ using util::create_rados_callback;
 template<typename I>
 RemoveRequest<I>::RemoveRequest(IoCtx &ioctx, const std::string &image_name,
                                 const std::string &image_id, bool force,
+                                bool from_trash_remove,
                                 ProgressContext &prog_ctx,
                                 ContextWQ *op_work_queue, Context *on_finish)
   : m_ioctx(ioctx), m_image_name(image_name), m_image_id(image_id),
-    m_force(force), m_prog_ctx(prog_ctx), m_op_work_queue(op_work_queue),
+    m_force(force), m_from_trash_remove(from_trash_remove),
+    m_prog_ctx(prog_ctx), m_op_work_queue(op_work_queue),
     m_on_finish(on_finish) {
   m_cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
 
@@ -565,6 +567,14 @@ Context *RemoveRequest<I>::handle_mirror_image_remove(int *result) {
     *result = 0;
   }
 
+  if (m_from_trash_remove) {
+    // both the id object and the directory entry have been removed in
+    // a previous call to trash_move.
+
+    *result = 0;
+    return m_on_finish;
+  }
+
   remove_id_object();
   return nullptr;
 }
index 6fe50b9a266a02982b0820bd90f24cea63d156ad..939abd49dd028ca72c858d8068b356fddf4cf6a1 100644 (file)
@@ -27,11 +27,13 @@ public:
   static RemoveRequest *create(librados::IoCtx &ioctx,
                                const std::string &image_name,
                                const std::string &image_id,
-                               bool force, ProgressContext &prog_ctx,
+                               bool force, bool from_trash_remove,
+                               ProgressContext &prog_ctx,
                                ContextWQ *op_work_queue,
                                Context *on_finish) {
-    return new RemoveRequest(ioctx, image_name, image_id, force, prog_ctx,
-                             op_work_queue, on_finish);
+    return new RemoveRequest(ioctx, image_name, image_id, force,
+                             from_trash_remove, prog_ctx, op_work_queue,
+                             on_finish);
   }
 
   void send();
@@ -97,7 +99,7 @@ private:
    */
 
   RemoveRequest(librados::IoCtx &ioctx, const std::string &image_name,
-                const std::string &image_id, bool force,
+                const std::string &image_id, bool force, bool from_trash_remove,
                 ProgressContext &prog_ctx, ContextWQ *op_work_queue,
                 Context *on_finish);
 
@@ -105,6 +107,7 @@ private:
   std::string m_image_name;
   std::string m_image_id;
   bool m_force;
+  bool m_from_trash_remove;
   ProgressContext &m_prog_ctx;
   ContextWQ *m_op_work_queue;
   Context *m_on_finish;
index dc8bd54ccec9cd0f4d0454a2dd005bad8cffdddd..d9a151d1404d76d6bd10131a1a04f5a425afa83b 100644 (file)
@@ -1306,7 +1306,7 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
 
   int remove(IoCtx& io_ctx, const std::string &image_name,
              const std::string &image_id, ProgressContext& prog_ctx,
-             bool force)
+             bool force, bool from_trash_remove)
   {
     CephContext *cct((CephContext *)io_ctx.cct());
     ldout(cct, 20) << "remove " << &io_ctx << " "
@@ -1318,12 +1318,237 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
 
     C_SaferCond cond;
     auto req = librbd::image::RemoveRequest<>::create(
-      io_ctx, image_name, image_id, force, prog_ctx, op_work_queue, &cond);
+      io_ctx, image_name, image_id, force, from_trash_remove, prog_ctx,
+      op_work_queue, &cond);
     req->send();
 
     return cond.wait();
   }
 
+  int trash_move(librados::IoCtx &io_ctx, rbd_trash_image_source_t source,
+                 const std::string &image_name, uint64_t delay) {
+    CephContext *cct((CephContext *)io_ctx.cct());
+    ldout(cct, 20) << "trash_move " << &io_ctx << " " << image_name
+                   << dendl;
+
+    std::string image_id;
+    ImageCtx *ictx = new ImageCtx(image_name, "", nullptr, io_ctx, false);
+    int r = ictx->state->open(true);
+    if (r < 0) {
+      ldout(cct, 2) << "error opening image: " << cpp_strerror(-r) << dendl;
+      delete ictx;
+      if (r != -ENOENT) {
+       return r;
+      }
+    } else {
+      if (ictx->old_format) {
+        ictx->state->close();
+        return -EOPNOTSUPP;
+      }
+
+      image_id = ictx->id;
+      ictx->owner_lock.get_read();
+      if (ictx->exclusive_lock != nullptr) {
+        r = ictx->operations->prepare_image_update();
+        if (r < 0 || (ictx->exclusive_lock != nullptr &&
+                      !ictx->exclusive_lock->is_lock_owner())) {
+         lderr(cct) << "cannot obtain exclusive lock - not removing" << dendl;
+         ictx->owner_lock.put_read();
+         ictx->state->close();
+          return -EBUSY;
+        }
+      }
+    }
+
+    BOOST_SCOPE_EXIT_ALL(ictx, cct) {
+      bool is_locked = ictx->exclusive_lock != nullptr &&
+                       ictx->exclusive_lock->is_lock_owner();
+      if (is_locked) {
+        C_SaferCond ctx;
+        ictx->exclusive_lock->shut_down(&ctx);
+        ictx->owner_lock.put_read();
+        int r = ctx.wait();
+        if (r < 0) {
+          lderr(cct) << "error shutting down exclusive lock" << dendl;
+        }
+      } else {
+        ictx->owner_lock.put_read();
+      }
+      ictx->state->close();
+    };
+
+    ldout(cct, 2) << "adding image entry to rbd_trash" << dendl;
+    utime_t ts = ceph_clock_now();
+    utime_t deferment_end_time = ts;
+    deferment_end_time += (double)delay;
+    cls::rbd::TrashImageSource trash_source =
+        static_cast<cls::rbd::TrashImageSource>(source);
+    cls::rbd::TrashImageSpec trash_spec(trash_source, image_name, ts,
+                                        deferment_end_time);
+    r = cls_client::trash_add(&io_ctx, image_id, trash_spec);
+    if (r < 0 && r != -EEXIST) {
+      lderr(cct) << "error adding image " << image_name << " to rbd_trash"
+                 << dendl;
+      return r;
+    } else if (r == -EEXIST) {
+      ldout(cct, 10) << "found previous unfinished deferred remove for image:"
+                     << image_id << dendl;
+      // continue with removing image from directory
+    }
+
+    ldout(cct, 2) << "removing id object..." << dendl;
+    r = io_ctx.remove(util::id_obj_name(image_name));
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "error removing id object: " << cpp_strerror(r)
+                 << dendl;
+      return r;
+    }
+
+    ldout(cct, 2) << "removing rbd image from v2 directory..." << dendl;
+    r = cls_client::dir_remove_image(&io_ctx, RBD_DIRECTORY, image_name,
+                                     image_id);
+    if (r < 0) {
+      if (r != -ENOENT) {
+        lderr(cct) << "error removing image from v2 directory: "
+                   << cpp_strerror(-r) << dendl;
+      }
+      return r;
+    }
+
+    return 0;
+  }
+
+  int trash_list(IoCtx &io_ctx, vector<trash_image_info_t> &entries) {
+    CephContext *cct((CephContext *)io_ctx.cct());
+    ldout(cct, 20) << "trash_list " << &io_ctx << dendl;
+
+    map<string, cls::rbd::TrashImageSpec> trash_entries;
+    int r = cls_client::trash_list(&io_ctx,  &trash_entries);
+    if (r < 0) {
+      if (r != -ENOENT) {
+        lderr(cct) << "error listing rbd_trash entries: " << cpp_strerror(r)
+                   << dendl;
+      }
+      return r;
+    }
+
+    for (const auto &entry : trash_entries) {
+      rbd_trash_image_source_t source =
+          static_cast<rbd_trash_image_source_t>(entry.second.source);
+      entries.push_back({entry.first, entry.second.name, source,
+                         entry.second.deletion_time.sec(),
+                         entry.second.deferment_end_time.sec()});
+    }
+    return 0;
+  }
+
+  int trash_remove(IoCtx &io_ctx, const std::string &image_id, bool force,
+                   ProgressContext& prog_ctx) {
+    CephContext *cct((CephContext *)io_ctx.cct());
+    ldout(cct, 20) << "trash_remove " << &io_ctx << " " << image_id
+                   << " " << force << dendl;
+
+    cls::rbd::TrashImageSpec trash_spec;
+    int r = cls_client::trash_get(&io_ctx, image_id, &trash_spec);
+    if (r < 0) {
+      lderr(cct) << "error getting image id " << image_id
+                 << " info from trash: " << cpp_strerror(r) << dendl;
+      return r;
+    }
+
+    utime_t now = ceph_clock_now();
+    if (now < trash_spec.deferment_end_time && !force) {
+      lderr(cct) << "error: deferment time has not expired." << dendl;
+      return -EPERM;
+    }
+
+    r = remove(io_ctx, "", image_id, prog_ctx, false, true);
+    if (r < 0) {
+      lderr(cct) << "error removing image " << image_id
+                 << ", which is pending deletion" << dendl;
+      return r;
+    }
+    r = cls_client::trash_remove(&io_ctx, image_id);
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "error removing image " << image_id
+                 << " from rbd_trash object" << dendl;
+      return r;
+    }
+    return 0;
+  }
+
+  int trash_restore(librados::IoCtx &io_ctx, const std::string &image_id,
+                    const std::string &image_new_name) {
+    CephContext *cct((CephContext *)io_ctx.cct());
+    ldout(cct, 20) << "trash_restore " << &io_ctx << " " << image_id << " "
+                   << image_new_name << dendl;
+
+    cls::rbd::TrashImageSpec trash_spec;
+    int r = cls_client::trash_get(&io_ctx, image_id, &trash_spec);
+    if (r < 0) {
+      lderr(cct) << "error getting image id " << image_id
+                 << " info from trash: " << cpp_strerror(r) << dendl;
+      return r;
+    }
+
+    std::string image_name = image_new_name;
+    if (image_name.empty()) {
+      // if user didn't specify a new name, let's try using the old name
+      image_name = trash_spec.name;
+      ldout(cct, 20) << "restoring image id " << image_id << " with name "
+                     << image_name << dendl;
+    }
+
+    // check if no image exists with the same name
+    bool create_id_obj = true;
+    std::string existing_id;
+    r = cls_client::get_id(&io_ctx, util::id_obj_name(image_name), &existing_id);
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "error checking if image " << image_name << " exists: "
+                 << cpp_strerror(r) << dendl;
+      return r;
+    } else if (r != -ENOENT){
+      // checking if we are recovering from an incomplete restore
+      if (existing_id != image_id) {
+        ldout(cct, 2) << "an image with the same name already exists" << dendl;
+        return -EEXIST;
+      }
+      create_id_obj = false;
+    }
+
+    if (create_id_obj) {
+      ldout(cct, 2) << "adding id object" << dendl;
+      librados::ObjectWriteOperation op;
+      op.create(true);
+      cls_client::set_id(&op, image_id);
+      r = io_ctx.operate(util::id_obj_name(image_name), &op);
+      if (r < 0) {
+        lderr(cct) << "error adding id object for image " << image_name
+                   << ": " << cpp_strerror(r) << dendl;
+        return r;
+      }
+    }
+
+    ldout(cct, 2) << "adding rbd image from v2 directory..." << dendl;
+    r = cls_client::dir_add_image(&io_ctx, RBD_DIRECTORY, image_name,
+                                  image_id);
+    if (r < 0 && r != -EEXIST) {
+      lderr(cct) << "error adding image to v2 directory: "
+                 << cpp_strerror(r) << dendl;
+      return r;
+    }
+
+    ldout(cct, 2) << "removing image from trash..." << dendl;
+    r = cls_client::trash_remove(&io_ctx, image_id);
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "error removing image id " << image_id << " from trash: "
+                 << cpp_strerror(r) << dendl;
+      return r;
+    }
+
+    return 0;
+  }
+
   int snap_list(ImageCtx *ictx, vector<snap_info_t>& snaps)
   {
     ldout(ictx->cct, 20) << "snap_list " << ictx << dendl;
index b9ccdeec2d4eb7ab8e5afb1e5168a2d21f786e29..ebf703dc78693de10f0bac9bf7791b6ad37ecacc 100644 (file)
@@ -141,7 +141,16 @@ namespace librbd {
 
   int remove(librados::IoCtx& io_ctx, const std::string &image_name,
              const std::string &image_id, ProgressContext& prog_ctx,
-             bool force=false);
+             bool force=false, bool from_trash_remove=false);
+  int trash_move(librados::IoCtx &io_ctx, rbd_trash_image_source_t source,
+                 const std::string &image_name, uint64_t delay);
+  int trash_list(librados::IoCtx &io_ctx,
+                 std::vector<trash_image_info_t> &entries);
+  int trash_remove(librados::IoCtx &io_ctx, const std::string &image_id,
+                   bool force, ProgressContext& prog_ctx);
+  int trash_restore(librados::IoCtx &io_ctx, const std::string &image_id,
+                    const std::string &image_new_name);
+
   int snap_list(ImageCtx *ictx, std::vector<snap_info_t>& snaps);
   int snap_exists(ImageCtx *ictx, const cls::rbd::SnapshotNamespace& snap_namespace,
                  const char *snap_name, bool *exists);
index 14b2318fc50966c9c8e69f2d15ba5c927dffa794..5be4e460bd2a2489eed57b66b49a69fd4cb092fc 100644 (file)
@@ -541,6 +541,59 @@ namespace librbd {
     return r;
   }
 
+  int RBD::trash_move(IoCtx &io_ctx, const char *name, uint64_t delay) {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+    tracepoint(librbd, trash_move_enter, io_ctx.get_pool_name().c_str(),
+               io_ctx.get_id(), name);
+    int r = librbd::trash_move(io_ctx, RBD_TRASH_IMAGE_SOURCE_USER, name,
+                               delay);
+    tracepoint(librbd, trash_move_exit, r);
+    return r;
+  }
+
+  int RBD::trash_list(IoCtx &io_ctx, vector<trash_image_info_t> &entries) {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+    tracepoint(librbd, trash_list_enter,
+               io_ctx.get_pool_name().c_str(), io_ctx.get_id());
+    int r = librbd::trash_list(io_ctx, entries);
+    if (r >= 0) {
+      for (const auto& entry : entries) {
+       tracepoint(librbd, trash_list_entry, entry.id.c_str());
+      }
+    }
+    tracepoint(librbd, trash_list_exit, r, r);
+    return r;
+  }
+
+  int RBD::trash_remove(IoCtx &io_ctx, const char *image_id, bool force) {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+    tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
+               io_ctx.get_id(), image_id, force);
+    librbd::NoOpProgressContext prog_ctx;
+    int r = librbd::trash_remove(io_ctx, image_id, force, prog_ctx);
+    tracepoint(librbd, trash_remove_exit, r);
+    return r;
+  }
+
+  int RBD::trash_remove_with_progress(IoCtx &io_ctx, const char *image_id,
+                                      bool force, ProgressContext &pctx) {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+    tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
+               io_ctx.get_id(), image_id, force);
+    int r = librbd::trash_remove(io_ctx, image_id, force, pctx);
+    tracepoint(librbd, trash_remove_exit, r);
+    return r;
+  }
+
+  int RBD::trash_restore(IoCtx &io_ctx, const char *id, const char *name) {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+    tracepoint(librbd, trash_undelete_enter, io_ctx.get_pool_name().c_str(),
+               io_ctx.get_id(), id, name);
+    int r = librbd::trash_restore(io_ctx, id, name);
+    tracepoint(librbd, trash_undelete_exit, r);
+    return r;
+  }
+
   int RBD::list(IoCtx& io_ctx, vector<string>& names)
   {
     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
@@ -2203,6 +2256,102 @@ extern "C" int rbd_remove_with_progress(rados_ioctx_t p, const char *name,
   return r;
 }
 
+extern "C" int rbd_trash_move(rados_ioctx_t p, const char *name,
+                              uint64_t delay) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+  tracepoint(librbd, trash_move_enter, io_ctx.get_pool_name().c_str(),
+             io_ctx.get_id(), name);
+  int r = librbd::trash_move(io_ctx, RBD_TRASH_IMAGE_SOURCE_USER, name, delay);
+  tracepoint(librbd, trash_move_exit, r);
+  return r;
+}
+
+extern "C" int rbd_trash_list(rados_ioctx_t p, rbd_trash_image_info_t *entries,
+                              size_t *num_entries) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+  tracepoint(librbd, trash_list_enter,
+             io_ctx.get_pool_name().c_str(), io_ctx.get_id());
+
+  vector<librbd::trash_image_info_t> cpp_entries;
+  int r = librbd::trash_list(io_ctx, cpp_entries);
+  if (r < 0) {
+    tracepoint(librbd, trash_list_exit, r, *num_entries);
+    return r;
+  }
+
+  if (*num_entries < cpp_entries.size()) {
+    *num_entries = cpp_entries.size();
+    tracepoint(librbd, trash_list_exit, -ERANGE, *num_entries);
+    return -ERANGE;
+  }
+
+  int i=0;
+  for (const auto &entry : cpp_entries) {
+    entries[i].id = strdup(entry.id.c_str());
+    entries[i].name = strdup(entry.name.c_str());
+    entries[i].source = entry.source;
+    entries[i].deletion_time = entry.deletion_time;
+    entries[i].deferment_end_time = entry.deferment_end_time;
+    i++;
+  }
+  *num_entries = cpp_entries.size();
+
+  return *num_entries;
+}
+
+extern "C" void rbd_trash_list_cleanup(rbd_trash_image_info_t *entries,
+                                       size_t num_entries) {
+  for (size_t i=0; i < num_entries; i++) {
+    free(entries[i].id);
+    free(entries[i].name);
+  }
+}
+
+extern "C" int rbd_trash_remove(rados_ioctx_t p, const char *image_id,
+                                bool force) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+  tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
+             io_ctx.get_id(), image_id, force);
+  librbd::NoOpProgressContext prog_ctx;
+  int r = librbd::trash_remove(io_ctx, image_id, force, prog_ctx);
+  tracepoint(librbd, trash_remove_exit, r);
+  return r;
+}
+
+extern "C" int rbd_trash_remove_with_progress(rados_ioctx_t p,
+                                              const char *image_id,
+                                              bool force,
+                                              librbd_progress_fn_t cb,
+                                              void *cbdata) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+  tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
+             io_ctx.get_id(), image_id, force);
+  librbd::CProgressContext prog_ctx(cb, cbdata);
+  int r = librbd::trash_remove(io_ctx, image_id, force, prog_ctx);
+  tracepoint(librbd, trash_remove_exit, r);
+  return r;
+}
+
+extern "C" int rbd_trash_restore(rados_ioctx_t p, const char *id,
+                                 const char *name) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+  tracepoint(librbd, trash_undelete_enter, io_ctx.get_pool_name().c_str(),
+             io_ctx.get_id(), id, name);
+  int r = librbd::trash_restore(io_ctx, id, name);
+  tracepoint(librbd, trash_undelete_exit, r);
+  return r;
+}
+
 extern "C" int rbd_copy(rbd_image_t image, rados_ioctx_t dest_p,
                        const char *destname)
 {
index 74c66c10d321aa5884a33617a6ffcc89198eef65..4b271a454c95e4338883f18cf43552e381e6349f 100644 (file)
@@ -247,7 +247,7 @@ TEST_F(TestMockImageRemoveRequest, SuccessV1) {
   expect_wq_queue(op_work_queue, 0);
 
   MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "",
-                                             true, no_op, &op_work_queue, &ctx);
+                                             true, false, no_op, &op_work_queue, &ctx);
   req->send();
 
   ASSERT_EQ(0, ctx.wait());
@@ -269,7 +269,7 @@ TEST_F(TestMockImageRemoveRequest, OpenFailV1) {
   expect_wq_queue(op_work_queue, 0);
 
   MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "",
-                                             true, no_op, &op_work_queue, &ctx);
+                                             true, false, no_op, &op_work_queue, &ctx);
   req->send();
 
   ASSERT_EQ(0, ctx.wait());
@@ -303,7 +303,7 @@ TEST_F(TestMockImageRemoveRequest, SuccessV2) {
   expect_dir_remove_image(m_ioctx, 0);
 
   MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "",
-                                             true, no_op, &op_work_queue, &ctx);
+                                             true, false, no_op, &op_work_queue, &ctx);
   req->send();
 
   ASSERT_EQ(0, ctx.wait());
@@ -337,7 +337,7 @@ TEST_F(TestMockImageRemoveRequest, NotExistsV2) {
   expect_dir_remove_image(m_ioctx, -ENOENT);
 
   MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "",
-                                             true, no_op, &op_work_queue, &ctx);
+                                             true, false, no_op, &op_work_queue, &ctx);
   req->send();
   ASSERT_EQ(-ENOENT, ctx.wait());
 
index 983ee504578147a83689b5448d240378a1b9ea4f..0dd7d17c369bdcc49e29c609d6d67c58c3490dc2 100644 (file)
@@ -5503,3 +5503,137 @@ TEST_F(TestLibRBD, DefaultFeatures) {
     ASSERT_EQ(pair.second, features);
   }
 }
+
+TEST_F(TestLibRBD, TestTrashMoveAndPurge) {
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
+
+  librbd::RBD rbd;
+  std::string name = get_temp_image_name();
+
+  uint64_t size = 1 << 18;
+  int order = 12;
+  ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
+
+  librbd::Image image;
+  ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
+  uint8_t old_format;
+  ASSERT_EQ(0, image.old_format(&old_format));
+
+  if (old_format) {
+    ASSERT_EQ(-EOPNOTSUPP, rbd.trash_move(ioctx, name.c_str(), 0));
+    image.close();
+    return;
+  }
+  std::string image_id;
+  ASSERT_EQ(0, image.get_id(&image_id));
+  image.close();
+
+  ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 0));
+
+  std::vector<std::string> images;
+  ASSERT_EQ(0, rbd.list(ioctx, images));
+  for (const auto& image : images) {
+    ASSERT_TRUE(image != name);
+  }
+
+  std::vector<librbd::trash_image_info_t> entries;
+  ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
+  ASSERT_FALSE(entries.empty());
+  ASSERT_EQ(entries.begin()->id, image_id);
+
+  entries.clear();
+  PrintProgress pp;
+  ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
+                                              false, pp));
+  ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
+  ASSERT_TRUE(entries.empty());
+}
+
+TEST_F(TestLibRBD, TestTrashMoveAndPurgeNonExpiredDelay) {
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
+
+  librbd::RBD rbd;
+  std::string name = get_temp_image_name();
+
+  uint64_t size = 1 << 18;
+  int order = 12;
+  ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
+
+  librbd::Image image;
+  ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
+  uint8_t old_format;
+  ASSERT_EQ(0, image.old_format(&old_format));
+
+  if (old_format) {
+    ASSERT_EQ(-EOPNOTSUPP, rbd.trash_move(ioctx, name.c_str(), 0));
+    image.close();
+    return;
+  }
+  std::string image_id;
+  ASSERT_EQ(0, image.get_id(&image_id));
+  image.close();
+
+  ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 100));
+
+  PrintProgress pp;
+  ASSERT_EQ(-EPERM, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
+                                                   false, pp));
+
+  PrintProgress pp2;
+  ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
+                                              true, pp2));
+}
+
+TEST_F(TestLibRBD, TestTrashMoveAndRestore) {
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
+
+  librbd::RBD rbd;
+  std::string name = get_temp_image_name();
+
+  uint64_t size = 1 << 18;
+  int order = 12;
+  ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
+
+  librbd::Image image;
+  ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
+  uint8_t old_format;
+  ASSERT_EQ(0, image.old_format(&old_format));
+
+  if (old_format) {
+    ASSERT_EQ(-EOPNOTSUPP, rbd.trash_move(ioctx, name.c_str(), 0));
+    image.close();
+    return;
+  }
+  std::string image_id;
+  ASSERT_EQ(0, image.get_id(&image_id));
+  image.close();
+
+  ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 10));
+
+  std::vector<std::string> images;
+  ASSERT_EQ(0, rbd.list(ioctx, images));
+  for (const auto& image : images) {
+    ASSERT_TRUE(image != name);
+  }
+
+  std::vector<librbd::trash_image_info_t> entries;
+  ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
+  ASSERT_FALSE(entries.empty());
+  ASSERT_EQ(entries.begin()->id, image_id);
+
+  images.clear();
+  ASSERT_EQ(0, rbd.trash_restore(ioctx, image_id.c_str(), ""));
+  ASSERT_EQ(0, rbd.list(ioctx, images));
+  ASSERT_FALSE(images.empty());
+  bool found = false;
+  for (const auto& image : images) {
+    if (image == name) {
+      found = true;
+      break;
+    }
+  }
+  ASSERT_TRUE(found);
+}
index 1df20396a3975d8eca0bc7046eb1952951e9e6bf..c5a23eb1547aecfdc0d012f03513c41603f932ad 100644 (file)
@@ -204,6 +204,28 @@ TRACEPOINT_EVENT(librbd, writesame_exit,
     )
 )
 
+TRACEPOINT_EVENT(librbd, open_image_by_id_enter,
+    TP_ARGS(
+        void*, imagectx,
+        const char*, id,
+        const char*, snap_name,
+        int, read_only),
+    TP_FIELDS(
+        ctf_integer_hex(void*, imagectx, imagectx)
+        ctf_string(id, id)
+        ctf_string(snap_name, snap_name)
+        ctf_integer(uint8_t, read_only, read_only ? 1 : 0)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, open_image_by_id_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
 TRACEPOINT_EVENT(librbd, aio_open_image_enter,
     TP_ARGS(
         void*, imagectx,
@@ -230,6 +252,30 @@ TRACEPOINT_EVENT(librbd, aio_open_image_exit,
     )
 )
 
+TRACEPOINT_EVENT(librbd, aio_open_image_by_id_enter,
+    TP_ARGS(
+        void*, imagectx,
+        const char*, id,
+        const char*, snap_name,
+        int, read_only,
+        const void*, completion),
+    TP_FIELDS(
+        ctf_integer_hex(void*, imagectx, imagectx)
+        ctf_string(id, id)
+        ctf_string(snap_name, snap_name)
+        ctf_integer(uint8_t, read_only, read_only ? 1 : 0)
+        ctf_integer_hex(const void*, completion, completion)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, aio_open_image_by_id_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
 TRACEPOINT_EVENT(librbd, close_image_enter,
     TP_ARGS(
         void*, imagectx,
@@ -427,6 +473,98 @@ TRACEPOINT_EVENT(librbd, remove_exit,
     )
 )
 
+TRACEPOINT_EVENT(librbd, trash_move_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, imgname),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(imgname, imgname)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, trash_move_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, trash_list_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, trash_list_entry,
+    TP_ARGS(
+        const char*, id),
+    TP_FIELDS(
+        ctf_string(id, id)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, trash_list_exit,
+    TP_ARGS(
+        int, retval,
+        int, size),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+        ctf_integer(size_t, size, size)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, trash_remove_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, imgid,
+        uint8_t, force),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(imgid, imgid)
+        ctf_integer(uint8_t, force, force)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, trash_remove_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, trash_undelete_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, imgid,
+        const char*, imgnewname),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(imgid, imgid)
+        ctf_string(imgnewname, imgnewname)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, trash_undelete_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
 TRACEPOINT_EVENT(librbd, aio_write_enter,
     TP_ARGS(
         void*, imagectx,