X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Ftools%2Frbd_mirror%2FImageDeleter.cc;fp=src%2Fceph%2Fsrc%2Ftools%2Frbd_mirror%2FImageDeleter.cc;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=333d11e06e494c8e5bfd0953b62ed548ecaa13d0;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/tools/rbd_mirror/ImageDeleter.cc b/src/ceph/src/tools/rbd_mirror/ImageDeleter.cc deleted file mode 100644 index 333d11e..0000000 --- a/src/ceph/src/tools/rbd_mirror/ImageDeleter.cc +++ /dev/null @@ -1,675 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2016 SUSE LINUX GmbH - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include -#include -#include -#include - -#include "include/rados/librados.hpp" -#include "common/Formatter.h" -#include "common/admin_socket.h" -#include "common/debug.h" -#include "common/errno.h" -#include "common/WorkQueue.h" -#include "global/global_context.h" -#include "librbd/internal.h" -#include "librbd/ImageCtx.h" -#include "librbd/ImageState.h" -#include "librbd/Journal.h" -#include "librbd/Operations.h" -#include "librbd/journal/Policy.h" -#include "cls/rbd/cls_rbd_client.h" -#include "cls/rbd/cls_rbd_types.h" -#include "librbd/Utils.h" -#include "ImageDeleter.h" - -#define dout_context g_ceph_context -#define dout_subsys ceph_subsys_rbd_mirror -#undef dout_prefix -#define dout_prefix *_dout << "rbd::mirror::ImageDeleter: " << this << " " \ - << __func__ << ": " - -using std::string; -using std::map; -using std::stringstream; -using std::vector; -using std::pair; -using std::make_pair; - -using librados::IoCtx; -using namespace librbd; - -namespace rbd { -namespace mirror { - -namespace { - -class ImageDeleterAdminSocketCommand { -public: - virtual ~ImageDeleterAdminSocketCommand() {} - virtual bool call(Formatter *f, stringstream *ss) = 0; -}; - -template -class StatusCommand : public ImageDeleterAdminSocketCommand { -public: - explicit StatusCommand(ImageDeleter *image_del) : image_del(image_del) {} - - bool call(Formatter *f, stringstream *ss) override { - image_del->print_status(f, ss); - return true; - } - -private: - ImageDeleter *image_del; -}; - -struct DeleteJournalPolicy : public librbd::journal::Policy { - bool append_disabled() const override { - return true; - } - bool journal_disabled() const override { - return false; - } - - void allocate_tag_on_lock(Context *on_finish) override { - on_finish->complete(0); - } -}; - -} // anonymous namespace - -template -class ImageDeleterAdminSocketHook : public AdminSocketHook { -public: - ImageDeleterAdminSocketHook(CephContext *cct, ImageDeleter *image_del) : - admin_socket(cct->get_admin_socket()) { - - std::string command; - int r; - - command = "rbd mirror deletion status"; - r = admin_socket->register_command(command, command, this, - "get status for image deleter"); - if (r == 0) { - commands[command] = new StatusCommand(image_del); - } - - } - - ~ImageDeleterAdminSocketHook() override { - for (Commands::const_iterator i = commands.begin(); i != commands.end(); - ++i) { - (void)admin_socket->unregister_command(i->first); - delete i->second; - } - } - - bool call(std::string command, cmdmap_t& cmdmap, std::string format, - bufferlist& out) override { - Commands::const_iterator i = commands.find(command); - assert(i != commands.end()); - Formatter *f = Formatter::create(format); - stringstream ss; - bool r = i->second->call(f, &ss); - delete f; - out.append(ss); - return r; - } - -private: - typedef std::map Commands; - AdminSocket *admin_socket; - Commands commands; -}; - -template -ImageDeleter::ImageDeleter(ContextWQ *work_queue, SafeTimer *timer, - Mutex *timer_lock, - ServiceDaemon* service_daemon) - : m_work_queue(work_queue), - m_service_daemon(service_daemon), - m_delete_lock("rbd::mirror::ImageDeleter::Delete"), - m_image_deleter_thread(this), - m_failed_timer(timer), - m_failed_timer_lock(timer_lock), - m_asok_hook(new ImageDeleterAdminSocketHook(g_ceph_context, this)) -{ - set_failed_timer_interval(g_ceph_context->_conf->get_val( - "rbd_mirror_delete_retry_interval")); - m_image_deleter_thread.create("image_deleter"); -} - -template -ImageDeleter::~ImageDeleter() { - dout(20) << "enter" << dendl; - - m_running = false; - { - Mutex::Locker l (m_delete_lock); - m_delete_queue_cond.Signal(); - } - if (m_image_deleter_thread.is_started()) { - m_image_deleter_thread.join(); - } - - delete m_asok_hook; - dout(20) << "return" << dendl; -} - -template -void ImageDeleter::run() { - dout(20) << "enter" << dendl; - while(m_running) { - m_delete_lock.Lock(); - while (m_delete_queue.empty()) { - dout(20) << "waiting for delete requests" << dendl; - m_delete_queue_cond.Wait(m_delete_lock); - - if (!m_running) { - m_delete_lock.Unlock(); - dout(20) << "return" << dendl; - return; - } - } - - m_active_delete = std::move(m_delete_queue.back()); - m_delete_queue.pop_back(); - m_delete_lock.Unlock(); - - bool move_to_next = process_image_delete(); - if (!move_to_next) { - if (!m_running) { - dout(20) << "return" << dendl; - return; - } - - Mutex::Locker l(m_delete_lock); - if (m_delete_queue.size() == 1) { - m_delete_queue_cond.Wait(m_delete_lock); - } - } - } -} - -template -void ImageDeleter::schedule_image_delete(RadosRef local_rados, - int64_t local_pool_id, - const std::string& global_image_id, - bool ignore_orphaned) { - dout(20) << "enter" << dendl; - - Mutex::Locker locker(m_delete_lock); - - auto del_info = find_delete_info(local_pool_id, global_image_id); - if (del_info != nullptr) { - dout(20) << "image " << global_image_id << " " - << "was already scheduled for deletion" << dendl; - if (ignore_orphaned) { - (*del_info)->ignore_orphaned = true; - } - return; - } - - m_delete_queue.push_front( - unique_ptr(new DeleteInfo(local_rados, local_pool_id, - global_image_id, ignore_orphaned))); - m_delete_queue_cond.Signal(); -} - -template -void ImageDeleter::wait_for_scheduled_deletion(int64_t local_pool_id, - const std::string &global_image_id, - Context *ctx, - bool notify_on_failed_retry) { - - ctx = new FunctionContext([this, ctx](int r) { - m_work_queue->queue(ctx, r); - }); - - Mutex::Locker locker(m_delete_lock); - auto del_info = find_delete_info(local_pool_id, global_image_id); - if (!del_info) { - // image not scheduled for deletion - ctx->complete(0); - return; - } - - dout(20) << "local_pool_id=" << local_pool_id << ", " - << "global_image_id=" << global_image_id << dendl; - - if ((*del_info)->on_delete != nullptr) { - (*del_info)->on_delete->complete(-ESTALE); - } - (*del_info)->on_delete = ctx; - (*del_info)->notify_on_failed_retry = notify_on_failed_retry; -} - -template -void ImageDeleter::cancel_waiter(int64_t local_pool_id, - const std::string &global_image_id) { - Mutex::Locker locker(m_delete_lock); - auto del_info = find_delete_info(local_pool_id, global_image_id); - if (!del_info) { - return; - } - - if ((*del_info)->on_delete != nullptr) { - (*del_info)->on_delete->complete(-ECANCELED); - (*del_info)->on_delete = nullptr; - } -} - -template -bool ImageDeleter::process_image_delete() { - stringstream ss; - m_active_delete->to_string(ss); - std::string del_info_str = ss.str(); - dout(10) << "start processing delete request: " << del_info_str << dendl; - int r; - cls::rbd::MirrorImage mirror_image; - - // remote image was disabled, now we need to delete local image - IoCtx ioctx; - r = m_active_delete->local_rados->ioctx_create2( - m_active_delete->local_pool_id, ioctx); - if (r < 0) { - derr << "error accessing local pool " << m_active_delete->local_pool_id - << ": " << cpp_strerror(r) << dendl; - enqueue_failed_delete(r); - return true; - } - - dout(20) << "connected to local pool: " << ioctx.get_pool_name() << dendl; - - auto &global_image_id = m_active_delete->global_image_id; - std::string local_image_id; - r = librbd::cls_client::mirror_image_get_image_id( - &ioctx, global_image_id, &local_image_id); - if (r == -ENOENT) { - dout(10) << "image " << global_image_id << " is not mirrored" << dendl; - complete_active_delete(r); - return true; - } else if (r < 0) { - derr << "error retrieving local id for image " << global_image_id - << ": " << cpp_strerror(r) << dendl; - enqueue_failed_delete(r); - return true; - } - - std::string mirror_uuid; - C_SaferCond tag_owner_ctx; - Journal<>::get_tag_owner(ioctx, local_image_id, &mirror_uuid, m_work_queue, - &tag_owner_ctx); - r = tag_owner_ctx.wait(); - if (r < 0 && r != -ENOENT) { - derr << "error retrieving image primary info for image " << global_image_id - << ": " << cpp_strerror(r) << dendl; - enqueue_failed_delete(r); - return true; - } else if (r != -ENOENT) { - if (mirror_uuid == Journal<>::LOCAL_MIRROR_UUID) { - dout(10) << "image " << global_image_id << " is local primary" << dendl; - complete_active_delete(-EISPRM); - return true; - } else if (mirror_uuid == Journal<>::ORPHAN_MIRROR_UUID && - !m_active_delete->ignore_orphaned) { - dout(10) << "image " << global_image_id << " is orphaned" << dendl; - complete_active_delete(-EISPRM); - return true; - } - } - - dout(20) << "local image is not the primary" << dendl; - bool has_snapshots; - r = image_has_snapshots_and_children(&ioctx, local_image_id, &has_snapshots); - if (r < 0) { - enqueue_failed_delete(r); - return true; - } - - mirror_image.global_image_id = global_image_id; - mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING; - r = cls_client::mirror_image_set(&ioctx, local_image_id, mirror_image); - if (r == -ENOENT) { - dout(10) << "local image is not mirrored, aborting deletion..." << dendl; - complete_active_delete(r); - return true; - } else if (r == -EEXIST || r == -EINVAL) { - derr << "cannot disable mirroring for image " << global_image_id - << ": global_image_id has changed/reused: " - << cpp_strerror(r) << dendl; - complete_active_delete(r); - return true; - } else if (r < 0) { - derr << "cannot disable mirroring for image " << global_image_id - << ": " << cpp_strerror(r) << dendl; - enqueue_failed_delete(r); - return true; - } - - dout(20) << "set local image mirroring to disable" << dendl; - - if (has_snapshots) { - dout(20) << "local image has snapshots" << dendl; - - ImageCtx *imgctx = new ImageCtx("", local_image_id, nullptr, ioctx, false); - r = imgctx->state->open(false); - if (r < 0) { - derr << "error opening image " << global_image_id << " (" - << local_image_id << "): " << cpp_strerror(r) << dendl; - enqueue_failed_delete(r); - return true; - } - - { - RWLock::WLocker snap_locker(imgctx->snap_lock); - imgctx->set_journal_policy(new DeleteJournalPolicy()); - } - - std::vector snaps; - r = librbd::snap_list(imgctx, snaps); - if (r < 0) { - derr << "error listing snapshot of image " << imgctx->name - << cpp_strerror(r) << dendl; - imgctx->state->close(); - enqueue_failed_delete(r); - return true; - } - - for (const auto& snap : snaps) { - dout(20) << "processing deletion of snapshot " << imgctx->name << "@" - << snap.name << dendl; - - bool is_protected; - r = librbd::snap_is_protected(imgctx, snap.name.c_str(), &is_protected); - if (r < 0) { - derr << "error checking snapshot protection of snapshot " - << imgctx->name << "@" << snap.name << ": " << cpp_strerror(r) - << dendl; - imgctx->state->close(); - enqueue_failed_delete(r); - return true; - } - if (is_protected) { - dout(20) << "snapshot " << imgctx->name << "@" << snap.name - << " is protected, issuing unprotect command" << dendl; - - r = imgctx->operations->snap_unprotect( - cls::rbd::UserSnapshotNamespace(), snap.name.c_str()); - if (r == -EBUSY) { - // there are still clones of snapshots of this image, therefore send - // the delete request to the end of the queue - dout(10) << "local image id " << local_image_id << " has " - << "snapshots with cloned children, postponing deletion..." - << dendl; - imgctx->state->close(); - Mutex::Locker l(m_delete_lock); - m_active_delete->notify(r); - m_delete_queue.push_front(std::move(m_active_delete)); - return false; - } else if (r < 0) { - derr << "error unprotecting snapshot " << imgctx->name << "@" - << snap.name << ": " << cpp_strerror(r) << dendl; - imgctx->state->close(); - enqueue_failed_delete(r); - return true; - } - } - - r = imgctx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(), - snap.name.c_str()); - if (r < 0) { - derr << "error removing snapshot " << imgctx->name << "@" - << snap.name << ": " << cpp_strerror(r) << dendl; - imgctx->state->close(); - enqueue_failed_delete(r); - return true; - } - - dout(10) << "snapshot " << imgctx->name << "@" << snap.name - << " was deleted" << dendl; - } - - imgctx->state->close(); - } - - librbd::NoOpProgressContext ctx; - r = librbd::remove(ioctx, "", local_image_id, ctx, true); - if (r < 0 && r != -ENOENT) { - derr << "error removing image " << global_image_id << " " - << "(" << local_image_id << ") from local pool: " - << cpp_strerror(r) << dendl; - enqueue_failed_delete(r); - return true; - } - - // image was already deleted from rbd_directory, now we will make sure - // that will be also removed from rbd_mirroring - if (r == -ENOENT) { - dout(20) << "local image does not exist, removing image from rbd_mirroring" - << dendl; - } - - r = cls_client::mirror_image_remove(&ioctx, local_image_id); - if (r < 0 && r != -ENOENT) { - derr << "error removing image from mirroring directory: " - << cpp_strerror(r) << dendl; - enqueue_failed_delete(r); - return true; - } - - dout(10) << "Successfully deleted image " - << global_image_id << " " << "(" << local_image_id << ")" << dendl; - - complete_active_delete(0); - return true; -} - -template -int ImageDeleter::image_has_snapshots_and_children(IoCtx *ioctx, - string& image_id, - bool *has_snapshots) { - string header_oid = librbd::util::header_name(image_id); - ::SnapContext snapc; - int r = cls_client::get_snapcontext(ioctx, header_oid, &snapc); - if (r < 0 && r != -ENOENT) { - derr << "error retrieving snapshot context for image id " << image_id - << ": " << cpp_strerror(r) << dendl; - return r; - } - - *has_snapshots = !snapc.snaps.empty(); - - return 0; -} - -template -void ImageDeleter::complete_active_delete(int r) { - dout(20) << dendl; - - Mutex::Locker delete_locker(m_delete_lock); - m_active_delete->notify(r); - m_active_delete.reset(); -} - -template -void ImageDeleter::enqueue_failed_delete(int error_code) { - dout(20) << "enter" << dendl; - - if (error_code == -EBLACKLISTED) { - derr << "blacklisted while deleting local image" << dendl; - complete_active_delete(error_code); - return; - } - - m_delete_lock.Lock(); - if (m_active_delete->notify_on_failed_retry) { - m_active_delete->notify(error_code); - } - m_active_delete->error_code = error_code; - bool was_empty = m_failed_queue.empty(); - m_failed_queue.push_front(std::move(m_active_delete)); - m_delete_lock.Unlock(); - if (was_empty) { - FunctionContext *ctx = new FunctionContext( - boost::bind(&ImageDeleter::retry_failed_deletions, this)); - Mutex::Locker l(*m_failed_timer_lock); - m_failed_timer->add_event_after(m_failed_interval, ctx); - } -} - -template -void ImageDeleter::retry_failed_deletions() { - dout(20) << "enter" << dendl; - - Mutex::Locker l(m_delete_lock); - - bool empty = m_failed_queue.empty(); - while (!m_failed_queue.empty()) { - m_delete_queue.push_back(std::move(m_failed_queue.back())); - m_delete_queue.back()->retries++; - m_failed_queue.pop_back(); - } - if (!empty) { - m_delete_queue_cond.Signal(); - } -} - -template -unique_ptr::DeleteInfo> const* -ImageDeleter::find_delete_info(int64_t local_pool_id, - const std::string &global_image_id) { - assert(m_delete_lock.is_locked()); - - if (m_active_delete && m_active_delete->match(local_pool_id, - global_image_id)) { - return &m_active_delete; - } - - for (const auto& del_info : m_delete_queue) { - if (del_info->match(local_pool_id, global_image_id)) { - return &del_info; - } - } - - for (const auto& del_info : m_failed_queue) { - if (del_info->match(local_pool_id, global_image_id)) { - return &del_info; - } - } - - return nullptr; -} - -template -void ImageDeleter::print_status(Formatter *f, stringstream *ss) { - dout(20) << "enter" << dendl; - - if (f) { - f->open_object_section("image_deleter_status"); - f->open_array_section("delete_images_queue"); - } - - Mutex::Locker l(m_delete_lock); - for (const auto& image : m_delete_queue) { - image->print_status(f, ss); - } - - if (f) { - f->close_section(); - f->open_array_section("failed_deletes_queue"); - } - - for (const auto& image : m_failed_queue) { - image->print_status(f, ss, true); - } - - if (f) { - f->close_section(); - f->close_section(); - f->flush(*ss); - } -} - -template -void ImageDeleter::DeleteInfo::notify(int r) { - if (on_delete) { - dout(20) << "executing image deletion handler r=" << r << dendl; - - Context *ctx = on_delete; - on_delete = nullptr; - ctx->complete(r); - } -} - -template -void ImageDeleter::DeleteInfo::to_string(stringstream& ss) { - ss << "[" << "local_pool_id=" << local_pool_id << ", "; - ss << "global_image_id=" << global_image_id << "]"; -} - -template -void ImageDeleter::DeleteInfo::print_status(Formatter *f, stringstream *ss, - bool print_failure_info) { - if (f) { - f->open_object_section("delete_info"); - f->dump_int("local_pool_id", local_pool_id); - f->dump_string("global_image_id", global_image_id); - if (print_failure_info) { - f->dump_string("error_code", cpp_strerror(error_code)); - f->dump_int("retries", retries); - } - f->close_section(); - f->flush(*ss); - } else { - this->to_string(*ss); - } -} - -template -vector ImageDeleter::get_delete_queue_items() { - vector items; - - Mutex::Locker l(m_delete_lock); - for (const auto& del_info : m_delete_queue) { - items.push_back(del_info->global_image_id); - } - - return items; -} - -template -vector > ImageDeleter::get_failed_queue_items() { - vector > items; - - Mutex::Locker l(m_delete_lock); - for (const auto& del_info : m_failed_queue) { - items.push_back(make_pair(del_info->global_image_id, - del_info->error_code)); - } - - return items; -} - -template -void ImageDeleter::set_failed_timer_interval(double interval) { - this->m_failed_interval = interval; -} - -} // namespace mirror -} // namespace rbd - -template class rbd::mirror::ImageDeleter;