X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Flibrbd%2Foperation%2FFlattenRequest.cc;fp=src%2Fceph%2Fsrc%2Flibrbd%2Foperation%2FFlattenRequest.cc;h=e01dc2bc67b749658ab7b015169ff02286d06939;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/librbd/operation/FlattenRequest.cc b/src/ceph/src/librbd/operation/FlattenRequest.cc new file mode 100644 index 0000000..e01dc2b --- /dev/null +++ b/src/ceph/src/librbd/operation/FlattenRequest.cc @@ -0,0 +1,189 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "librbd/operation/FlattenRequest.h" +#include "librbd/AsyncObjectThrottle.h" +#include "librbd/ExclusiveLock.h" +#include "librbd/ImageCtx.h" +#include "librbd/io/ObjectRequest.h" +#include "common/dout.h" +#include "common/errno.h" +#include +#include + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::FlattenRequest: " + +namespace librbd { +namespace operation { + +template +class C_FlattenObject : public C_AsyncObjectThrottle { +public: + C_FlattenObject(AsyncObjectThrottle &throttle, I *image_ctx, + uint64_t object_size, ::SnapContext snapc, uint64_t object_no) + : C_AsyncObjectThrottle(throttle, *image_ctx), m_object_size(object_size), + m_snapc(snapc), m_object_no(object_no) + { + } + + int send() override { + I &image_ctx = this->m_image_ctx; + assert(image_ctx.owner_lock.is_locked()); + CephContext *cct = image_ctx.cct; + + if (image_ctx.exclusive_lock != nullptr && + !image_ctx.exclusive_lock->is_lock_owner()) { + ldout(cct, 1) << "lost exclusive lock during flatten" << dendl; + return -ERESTART; + } + + bufferlist bl; + string oid = image_ctx.get_object_name(m_object_no); + auto req = new io::ObjectWriteRequest(&image_ctx, oid, m_object_no, 0, + bl, m_snapc, 0, {}, this); + if (!req->has_parent()) { + // stop early if the parent went away - it just means + // another flatten finished first or the image was resized + delete req; + return 1; + } + + req->send(); + return 0; + } + +private: + uint64_t m_object_size; + ::SnapContext m_snapc; + uint64_t m_object_no; +}; + +template +bool FlattenRequest::should_complete(int r) { + I &image_ctx = this->m_image_ctx; + CephContext *cct = image_ctx.cct; + ldout(cct, 5) << this << " should_complete: " << " r=" << r << dendl; + if (r == -ERESTART) { + ldout(cct, 5) << "flatten operation interrupted" << dendl; + return true; + } else if (r < 0 && !(r == -ENOENT && m_ignore_enoent) ) { + lderr(cct) << "flatten encountered an error: " << cpp_strerror(r) << dendl; + return true; + } + + RWLock::RLocker owner_locker(image_ctx.owner_lock); + switch (m_state) { + case STATE_FLATTEN_OBJECTS: + ldout(cct, 5) << "FLATTEN_OBJECTS" << dendl; + return send_update_header(); + + case STATE_UPDATE_HEADER: + ldout(cct, 5) << "UPDATE_HEADER" << dendl; + return send_update_children(); + + case STATE_UPDATE_CHILDREN: + ldout(cct, 5) << "UPDATE_CHILDREN" << dendl; + return true; + + default: + lderr(cct) << "invalid state: " << m_state << dendl; + assert(false); + break; + } + return false; +} + +template +void FlattenRequest::send_op() { + I &image_ctx = this->m_image_ctx; + assert(image_ctx.owner_lock.is_locked()); + CephContext *cct = image_ctx.cct; + ldout(cct, 5) << this << " send" << dendl; + + m_state = STATE_FLATTEN_OBJECTS; + typename AsyncObjectThrottle::ContextFactory context_factory( + boost::lambda::bind(boost::lambda::new_ptr >(), + boost::lambda::_1, &image_ctx, m_object_size, m_snapc, + boost::lambda::_2)); + AsyncObjectThrottle *throttle = new AsyncObjectThrottle( + this, image_ctx, context_factory, this->create_callback_context(), &m_prog_ctx, + 0, m_overlap_objects); + throttle->start_ops(image_ctx.concurrent_management_ops); +} + +template +bool FlattenRequest::send_update_header() { + I &image_ctx = this->m_image_ctx; + assert(image_ctx.owner_lock.is_locked()); + CephContext *cct = image_ctx.cct; + + ldout(cct, 5) << this << " send_update_header" << dendl; + m_state = STATE_UPDATE_HEADER; + + // should have been canceled prior to releasing lock + assert(image_ctx.exclusive_lock == nullptr || + image_ctx.exclusive_lock->is_lock_owner()); + + { + RWLock::RLocker parent_locker(image_ctx.parent_lock); + // stop early if the parent went away - it just means + // another flatten finished first, so this one is useless. + if (!image_ctx.parent) { + ldout(cct, 5) << "image already flattened" << dendl; + return true; + } + m_parent_spec = image_ctx.parent_md.spec; + } + m_ignore_enoent = true; + + // remove parent from this (base) image + librados::ObjectWriteOperation op; + cls_client::remove_parent(&op); + + librados::AioCompletion *rados_completion = this->create_callback_completion(); + int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, + rados_completion, &op); + assert(r == 0); + rados_completion->release(); + return false; +} + +template +bool FlattenRequest::send_update_children() { + I &image_ctx = this->m_image_ctx; + assert(image_ctx.owner_lock.is_locked()); + CephContext *cct = image_ctx.cct; + + // should have been canceled prior to releasing lock + assert(image_ctx.exclusive_lock == nullptr || + image_ctx.exclusive_lock->is_lock_owner()); + + // if there are no snaps, remove from the children object as well + // (if snapshots remain, they have their own parent info, and the child + // will be removed when the last snap goes away) + RWLock::RLocker snap_locker(image_ctx.snap_lock); + if ((image_ctx.features & RBD_FEATURE_DEEP_FLATTEN) == 0 && + !image_ctx.snaps.empty()) { + return true; + } + + ldout(cct, 2) << "removing child from children list..." << dendl; + m_state = STATE_UPDATE_CHILDREN; + + librados::ObjectWriteOperation op; + cls_client::remove_child(&op, m_parent_spec, image_ctx.id); + + librados::AioCompletion *rados_completion = this->create_callback_completion(); + int r = image_ctx.md_ctx.aio_operate(RBD_CHILDREN, rados_completion, + &op); + assert(r == 0); + rados_completion->release(); + return false; +} + +} // namespace operation +} // namespace librbd + +template class librbd::operation::FlattenRequest;