diff options
author | Theofilos Mouratidis <t.mour@cern.ch> | 2018-10-03 13:42:26 +0200 |
---|---|---|
committer | Jason Dillaman <dillaman@redhat.com> | 2019-01-11 15:18:45 +0100 |
commit | b6f9aab03713410dd1b50edc7fc1d71242ac3e74 (patch) | |
tree | ac1c468c3ba58298805eb9c39b4fd2ce62560274 /src/librbd | |
parent | Merge PR #25898 into master (diff) | |
download | ceph-b6f9aab03713410dd1b50edc7fc1d71242ac3e74.tar.xz ceph-b6f9aab03713410dd1b50edc7fc1d71242ac3e74.zip |
librbd: add trash purge api calls
Add trash purge api calls and fix the docs of some other rbd trash functions
Signed-off-by: Theofilos Mouratidis <mtheofilos@gmail.com>
Diffstat (limited to 'src/librbd')
-rw-r--r-- | src/librbd/api/Trash.cc | 168 | ||||
-rw-r--r-- | src/librbd/api/Trash.h | 2 | ||||
-rw-r--r-- | src/librbd/internal.cc | 8 | ||||
-rw-r--r-- | src/librbd/librbd.cc | 46 |
4 files changed, 219 insertions, 5 deletions
diff --git a/src/librbd/api/Trash.cc b/src/librbd/api/Trash.cc index 319be136b58..fdc2d03a643 100644 --- a/src/librbd/api/Trash.cc +++ b/src/librbd/api/Trash.cc @@ -18,6 +18,7 @@ #include "librbd/mirror/DisableRequest.h" #include "librbd/mirror/EnableRequest.h" #include "librbd/trash/MoveRequest.h" +#include <json_spirit/json_spirit.h> #define dout_subsys ceph_subsys_rbd #undef dout_prefix @@ -271,6 +272,173 @@ int Trash<I>::list(IoCtx &io_ctx, vector<trash_image_info_t> &entries) { } template <typename I> +int Trash<I>::purge(IoCtx& io_ctx, time_t expire_ts, + float threshold, ProgressContext& pctx) { + auto *cct((CephContext *) io_ctx.cct()); + + librbd::RBD rbd; + + std::vector<librbd::trash_image_info_t> trash_entries; + int r = librbd::api::Trash<>::list(io_ctx, trash_entries); + if (r < 0) { + return r; + } + + std::remove_if(trash_entries.begin(), trash_entries.end(), + [](librbd::trash_image_info_t info) { + return info.source != RBD_TRASH_IMAGE_SOURCE_USER; + } + ); + + std::vector<const char *> to_be_removed; + if (threshold != -1) { + if (threshold < 0 || threshold > 1) { + lderr(cct) << "argument 'threshold' is out of valid range" + << dendl; + return -EINVAL; + } + + librados::bufferlist inbl; + librados::bufferlist outbl; + std::string pool_name = io_ctx.get_pool_name(); + + librados::Rados rados(io_ctx); + rados.mon_command(R"({"prefix": "df", "format": "json"})", inbl, + &outbl, nullptr); + + json_spirit::mValue json; + if (!json_spirit::read(outbl.to_str(), json)) { + lderr(cct) << "ceph df json output could not be parsed" + << dendl; + return -EBADMSG; + } + + json_spirit::mArray arr = json.get_obj()["pools"].get_array(); + + double pool_percent_used = 0; + uint64_t pool_total_bytes = 0; + + std::map<std::string, std::vector<const char *>> datapools; + + std::sort(trash_entries.begin(), trash_entries.end(), + [](librbd::trash_image_info_t a, librbd::trash_image_info_t b) { + return a.deferment_end_time < b.deferment_end_time; + } + ); + + for (const auto &entry : trash_entries) { + librbd::Image image; + std::string data_pool; + r = rbd.open_by_id_read_only(io_ctx, image, entry.id.c_str(), NULL); + if (r < 0) continue; + + int64_t data_pool_id = image.get_data_pool_id(); + if (data_pool_id != io_ctx.get_id()) { + librados::IoCtx data_io_ctx; + r = util::create_ioctx(io_ctx, "image", data_pool_id, + {}, &data_io_ctx); + if (r < 0) { + lderr(cct) << "error accessing data pool" << dendl; + continue; + } + data_pool = data_io_ctx.get_pool_name(); + datapools[data_pool].push_back(entry.id.c_str()); + } else { + datapools[pool_name].push_back(entry.id.c_str()); + } + } + + uint64_t bytes_to_free = 0; + + for (uint8_t i = 0; i < arr.size(); ++i) { + json_spirit::mObject obj = arr[i].get_obj(); + std::string name = obj.find("name")->second.get_str(); + auto img = datapools.find(name); + if (img != datapools.end()) { + json_spirit::mObject stats = arr[i].get_obj()["stats"].get_obj(); + pool_percent_used = stats["percent_used"].get_real(); + if (pool_percent_used <= threshold) continue; + + bytes_to_free = 0; + + pool_total_bytes = stats["max_avail"].get_uint64() + + stats["bytes_used"].get_uint64(); + + auto bytes_threshold = (uint64_t) (pool_total_bytes * + (pool_percent_used - threshold)); + + librbd::Image curr_img; + for (const auto &it : img->second) { + r = rbd.open_by_id_read_only(io_ctx, curr_img, it, NULL); + if (r < 0) continue; + + uint64_t img_size; + curr_img.size(&img_size); + r = curr_img.diff_iterate2(nullptr, 0, img_size, false, true, + [](uint64_t offset, size_t len, int exists, void *arg) { + auto *to_free = reinterpret_cast<uint64_t *>(arg); + if (exists) + (*to_free) += len; + return 0; + }, &bytes_to_free + ); + if (r < 0) continue; + to_be_removed.push_back(it); + if (bytes_to_free >= bytes_threshold) break; + } + } + } + if (bytes_to_free == 0) { + ldout(cct, 10) << "pool usage is lower than or equal to " + << (threshold * 100) + << "%" << dendl; + return 0; + } + } + + if (expire_ts == 0) { + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + expire_ts = now.tv_sec; + } + + for (const auto &entry : trash_entries) { + if (expire_ts >= entry.deferment_end_time) { + to_be_removed.push_back(entry.id.c_str()); + } + } + + NoOpProgressContext remove_pctx; + uint64_t list_size = to_be_removed.size(), i = 0; + for (const auto &entry_id : to_be_removed) { + r = librbd::api::Trash<>::remove(io_ctx, entry_id, true, remove_pctx); + if (r < 0) { + if (r == -ENOTEMPTY) { + ldout(cct, 5) << "image has snapshots - these must be deleted " + << "with 'rbd snap purge' before the image can be removed." + << dendl; + } else if (r == -EBUSY) { + ldout(cct, 5) << "error: image still has watchers" + << std::endl + << "This means the image is still open or the client using " + << "it crashed. Try again after closing/unmapping it or " + << "waiting 30s for the crashed client to timeout." + << dendl; + } else if (r == -EMLINK) { + ldout(cct, 5) << "Remove the image from the group and try again." + << dendl; + } else { + lderr(cct) << "remove error: " << cpp_strerror(r) << dendl; + } + return r; + } + pctx.update_progress(++i, list_size); + } + + return 0; +} + +template <typename I> int Trash<I>::remove(IoCtx &io_ctx, const std::string &image_id, bool force, ProgressContext& prog_ctx) { CephContext *cct((CephContext *)io_ctx.cct()); diff --git a/src/librbd/api/Trash.h b/src/librbd/api/Trash.h index cf7217de809..f2e52f6cbeb 100644 --- a/src/librbd/api/Trash.h +++ b/src/librbd/api/Trash.h @@ -27,6 +27,8 @@ struct Trash { trash_image_info_t *info); static int list(librados::IoCtx &io_ctx, std::vector<trash_image_info_t> &entries); + static int purge(IoCtx& io_ctx, time_t expire_ts, + float threshold, ProgressContext& pctx); static int remove(librados::IoCtx &io_ctx, const std::string &image_id, bool force, ProgressContext& prog_ctx); static int restore(librados::IoCtx &io_ctx, const std::string &image_id, diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index ccb38aed5e4..8b499c283da 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -1135,8 +1135,7 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) { } int lock_break(ImageCtx *ictx, rbd_lock_mode_t lock_mode, - const std::string &lock_owner) - { + const std::string &lock_owner) { CephContext *cct = ictx->cct; ldout(cct, 20) << __func__ << ": ictx=" << ictx << ", " << "lock_mode=" << lock_mode << ", " @@ -1527,7 +1526,7 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) { if (throttle.pending_error()) { return throttle.wait_for_ret(); } - + { RWLock::RLocker snap_locker(src->snap_lock); if (src->object_map != nullptr) { @@ -1545,7 +1544,7 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) { } else { object_id += src->stripe_count; } - } + } uint64_t len = min(period, src_size - offset); bufferlist *bl = new bufferlist(); @@ -2006,4 +2005,3 @@ std::ostream &operator<<(std::ostream &os, const librbd::ImageOptions &opts) { return os; } - diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 30c608737c3..142cdec6ea0 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -648,6 +648,26 @@ namespace librbd { return r; } + int RBD::trash_purge(IoCtx &io_ctx, time_t expire_ts, float threshold) { + TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx)); + tracepoint(librbd, trash_purge_enter, io_ctx.get_pool_name().c_str(), + io_ctx.get_id(), expire_ts, threshold); + NoOpProgressContext nop_pctx; + int r = librbd::api::Trash<>::purge(io_ctx, expire_ts, threshold, nop_pctx); + tracepoint(librbd, trash_purge_exit, r); + return r; + } + + int RBD::trash_purge_with_progress(IoCtx &io_ctx, time_t expire_ts, + float threshold, ProgressContext &pctx) { + TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx)); + tracepoint(librbd, trash_purge_enter, io_ctx.get_pool_name().c_str(), + io_ctx.get_id(), expire_ts, threshold); + int r = librbd::api::Trash<>::purge(io_ctx, expire_ts, threshold, pctx); + tracepoint(librbd, trash_purge_exit, r); + return r; + } + int RBD::namespace_create(IoCtx& io_ctx, const char *namespace_name) { return librbd::api::Namespace<>::create(io_ctx, namespace_name); } @@ -3182,6 +3202,32 @@ extern "C" void rbd_trash_list_cleanup(rbd_trash_image_info_t *entries, } } +extern "C" int rbd_trash_purge(rados_ioctx_t io, time_t expire_ts, + float threshold) { + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(io, io_ctx); + TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx)); + tracepoint(librbd, trash_purge_enter, io_ctx.get_pool_name().c_str(), + io_ctx.get_id(), expire_ts, threshold); + librbd::NoOpProgressContext nop_pctx; + int r = librbd::api::Trash<>::purge(io_ctx, expire_ts, threshold, nop_pctx); + tracepoint(librbd, trash_purge_exit, r); + return r; +} + +extern "C" int rbd_trash_purge_with_progress(rados_ioctx_t io, time_t expire_ts, + float threshold, librbd_progress_fn_t cb, void* cbdata) { + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(io, io_ctx); + TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx)); + tracepoint(librbd, trash_purge_enter, io_ctx.get_pool_name().c_str(), + io_ctx.get_id(), expire_ts, threshold); + librbd::CProgressContext pctx(cb, cbdata); + int r = librbd::api::Trash<>::purge(io_ctx, expire_ts, threshold, pctx); + tracepoint(librbd, trash_purge_exit, r); + return r; +} + extern "C" int rbd_trash_remove(rados_ioctx_t p, const char *image_id, bool force) { librados::IoCtx io_ctx; |