From b70dbccb674d6d7ac0eb3b763eb1c66479aa23d9 Mon Sep 17 00:00:00 2001 From: Ricardo Dias Date: Fri, 24 Feb 2017 18:36:55 +0000 Subject: [PATCH] librbd: added trash methods to API Signed-off-by: Ricardo Dias --- src/include/rbd/librbd.h | 26 ++ src/include/rbd/librbd.hpp | 15 ++ src/librbd/image/CloneRequest.cc | 2 +- src/librbd/image/RemoveRequest.cc | 12 +- src/librbd/image/RemoveRequest.h | 11 +- src/librbd/internal.cc | 229 +++++++++++++++++- src/librbd/internal.h | 11 +- src/librbd/librbd.cc | 149 ++++++++++++ .../librbd/image/test_mock_RemoveRequest.cc | 8 +- src/test/librbd/test_librbd.cc | 134 ++++++++++ src/tracing/librbd.tp | 138 +++++++++++ 11 files changed, 722 insertions(+), 13 deletions(-) diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index c24d89dde71..8f95b526a30 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -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); diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index dfd4e8b60b9..2881e0094b9 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -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 &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 diff --git a/src/librbd/image/CloneRequest.cc b/src/librbd/image/CloneRequest.cc index 6e0ef901a64..c7d2ddca1b5 100644 --- a/src/librbd/image/CloneRequest.cc +++ b/src/librbd/image/CloneRequest.cc @@ -532,7 +532,7 @@ void CloneRequest::send_remove() { Context *ctx = create_context_callback(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(); } diff --git a/src/librbd/image/RemoveRequest.cc b/src/librbd/image/RemoveRequest.cc index 64b83efffc0..629fc7c7993 100644 --- a/src/librbd/image/RemoveRequest.cc +++ b/src/librbd/image/RemoveRequest.cc @@ -30,10 +30,12 @@ using util::create_rados_callback; template RemoveRequest::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(m_ioctx.cct()); @@ -565,6 +567,14 @@ Context *RemoveRequest::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; } diff --git a/src/librbd/image/RemoveRequest.h b/src/librbd/image/RemoveRequest.h index 6fe50b9a266..939abd49dd0 100644 --- a/src/librbd/image/RemoveRequest.h +++ b/src/librbd/image/RemoveRequest.h @@ -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; diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index dc8bd54ccec..d9a151d1404 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -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(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 &entries) { + CephContext *cct((CephContext *)io_ctx.cct()); + ldout(cct, 20) << "trash_list " << &io_ctx << dendl; + + map 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(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& snaps) { ldout(ictx->cct, 20) << "snap_list " << ictx << dendl; diff --git a/src/librbd/internal.h b/src/librbd/internal.h index b9ccdeec2d4..ebf703dc786 100644 --- a/src/librbd/internal.h +++ b/src/librbd/internal.h @@ -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 &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& snaps); int snap_exists(ImageCtx *ictx, const cls::rbd::SnapshotNamespace& snap_namespace, const char *snap_name, bool *exists); diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 14b2318fc50..5be4e460bd2 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -541,6 +541,59 @@ namespace librbd { return r; } + int RBD::trash_move(IoCtx &io_ctx, const char *name, uint64_t delay) { + TracepointProvider::initialize(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 &entries) { + TracepointProvider::initialize(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(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(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(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& names) { TracepointProvider::initialize(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(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(get_cct(io_ctx)); + tracepoint(librbd, trash_list_enter, + io_ctx.get_pool_name().c_str(), io_ctx.get_id()); + + vector 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(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(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(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) { diff --git a/src/test/librbd/image/test_mock_RemoveRequest.cc b/src/test/librbd/image/test_mock_RemoveRequest.cc index 74c66c10d32..4b271a454c9 100644 --- a/src/test/librbd/image/test_mock_RemoveRequest.cc +++ b/src/test/librbd/image/test_mock_RemoveRequest.cc @@ -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()); diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index 983ee504578..0dd7d17c369 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -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 images; + ASSERT_EQ(0, rbd.list(ioctx, images)); + for (const auto& image : images) { + ASSERT_TRUE(image != name); + } + + std::vector 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 images; + ASSERT_EQ(0, rbd.list(ioctx, images)); + for (const auto& image : images) { + ASSERT_TRUE(image != name); + } + + std::vector 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); +} diff --git a/src/tracing/librbd.tp b/src/tracing/librbd.tp index 1df20396a39..c5a23eb1547 100644 --- a/src/tracing/librbd.tp +++ b/src/tracing/librbd.tp @@ -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, -- 2.39.5