X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Ftools%2Frbd_mirror%2Fimage_sync%2FSnapshotCreateRequest.cc;fp=src%2Fceph%2Fsrc%2Ftools%2Frbd_mirror%2Fimage_sync%2FSnapshotCreateRequest.cc;h=2384179343549c8ad4446c8c3b71630ee1ade2fa;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc b/src/ceph/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc new file mode 100644 index 0000000..2384179 --- /dev/null +++ b/src/ceph/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc @@ -0,0 +1,334 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "SnapshotCreateRequest.h" +#include "common/errno.h" +#include "cls/rbd/cls_rbd_client.h" +#include "cls/rbd/cls_rbd_types.h" +#include "librbd/ExclusiveLock.h" +#include "librbd/ObjectMap.h" +#include "librbd/Operations.h" +#include "librbd/Utils.h" +#include "osdc/Striper.h" + +#define dout_context g_ceph_context +#define dout_subsys ceph_subsys_rbd_mirror +#undef dout_prefix +#define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCreateRequest: " \ + << this << " " << __func__ + +namespace rbd { +namespace mirror { +namespace image_sync { + +using librbd::util::create_context_callback; +using librbd::util::create_rados_callback; + +template +SnapshotCreateRequest::SnapshotCreateRequest(I *local_image_ctx, + const std::string &snap_name, + const cls::rbd::SnapshotNamespace &snap_namespace, + uint64_t size, + const librbd::ParentSpec &spec, + uint64_t parent_overlap, + Context *on_finish) + : m_local_image_ctx(local_image_ctx), m_snap_name(snap_name), + m_snap_namespace(snap_namespace), m_size(size), + m_parent_spec(spec), m_parent_overlap(parent_overlap), + m_on_finish(on_finish) { +} + +template +void SnapshotCreateRequest::send() { + send_set_size(); +} + +template +void SnapshotCreateRequest::send_set_size() { + m_local_image_ctx->snap_lock.get_read(); + if (m_local_image_ctx->size == m_size) { + m_local_image_ctx->snap_lock.put_read(); + send_remove_parent(); + return; + } + m_local_image_ctx->snap_lock.put_read(); + + dout(20) << dendl; + + // Change the image size on disk so that the snapshot picks up + // the expected size. We can do this because the last snapshot + // we process is the sync snapshot which was created to match the + // image size. We also don't need to worry about trimming because + // we track the highest possible object number within the sync record + librados::ObjectWriteOperation op; + librbd::cls_client::set_size(&op, m_size); + + auto finish_op_ctx = start_local_op(); + if (finish_op_ctx == nullptr) { + derr << ": lost exclusive lock" << dendl; + finish(-EROFS); + return; + } + + auto ctx = new FunctionContext([this, finish_op_ctx](int r) { + handle_set_size(r); + finish_op_ctx->complete(0); + }); + librados::AioCompletion *comp = create_rados_callback(ctx); + int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid, + comp, &op); + assert(r == 0); + comp->release(); +} + +template +void SnapshotCreateRequest::handle_set_size(int r) { + dout(20) << ": r=" << r << dendl; + + if (r < 0) { + derr << ": failed to update image size '" << m_snap_name << "': " + << cpp_strerror(r) << dendl; + finish(r); + return; + } + + { + // adjust in-memory image size now that it's updated on disk + RWLock::WLocker snap_locker(m_local_image_ctx->snap_lock); + m_local_image_ctx->size = m_size; + } + + send_remove_parent(); +} + +template +void SnapshotCreateRequest::send_remove_parent() { + m_local_image_ctx->parent_lock.get_read(); + if (m_local_image_ctx->parent_md.spec.pool_id == -1 || + m_local_image_ctx->parent_md.spec == m_parent_spec) { + m_local_image_ctx->parent_lock.put_read(); + send_set_parent(); + return; + } + m_local_image_ctx->parent_lock.put_read(); + + dout(20) << dendl; + + librados::ObjectWriteOperation op; + librbd::cls_client::remove_parent(&op); + + auto finish_op_ctx = start_local_op(); + if (finish_op_ctx == nullptr) { + derr << ": lost exclusive lock" << dendl; + finish(-EROFS); + return; + } + + auto ctx = new FunctionContext([this, finish_op_ctx](int r) { + handle_remove_parent(r); + finish_op_ctx->complete(0); + }); + librados::AioCompletion *comp = create_rados_callback(ctx); + int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid, + comp, &op); + assert(r == 0); + comp->release(); +} + +template +void SnapshotCreateRequest::handle_remove_parent(int r) { + dout(20) << ": r=" << r << dendl; + + if (r < 0) { + derr << ": failed to remove parent '" << m_snap_name << "': " + << cpp_strerror(r) << dendl; + finish(r); + return; + } + + { + // adjust in-memory parent now that it's updated on disk + RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock); + m_local_image_ctx->parent_md.spec = {}; + m_local_image_ctx->parent_md.overlap = 0; + } + + send_set_parent(); +} + +template +void SnapshotCreateRequest::send_set_parent() { + m_local_image_ctx->parent_lock.get_read(); + if (m_local_image_ctx->parent_md.spec == m_parent_spec && + m_local_image_ctx->parent_md.overlap == m_parent_overlap) { + m_local_image_ctx->parent_lock.put_read(); + send_snap_create(); + return; + } + m_local_image_ctx->parent_lock.put_read(); + + dout(20) << dendl; + + librados::ObjectWriteOperation op; + librbd::cls_client::set_parent(&op, m_parent_spec, m_parent_overlap); + + auto finish_op_ctx = start_local_op(); + if (finish_op_ctx == nullptr) { + derr << ": lost exclusive lock" << dendl; + finish(-EROFS); + return; + } + + auto ctx = new FunctionContext([this, finish_op_ctx](int r) { + handle_set_parent(r); + finish_op_ctx->complete(0); + }); + librados::AioCompletion *comp = create_rados_callback(ctx); + int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid, + comp, &op); + assert(r == 0); + comp->release(); +} + +template +void SnapshotCreateRequest::handle_set_parent(int r) { + dout(20) << ": r=" << r << dendl; + + if (r < 0) { + derr << ": failed to set parent '" << m_snap_name << "': " + << cpp_strerror(r) << dendl; + finish(r); + return; + } + + { + // adjust in-memory parent now that it's updated on disk + RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock); + m_local_image_ctx->parent_md.spec = m_parent_spec; + m_local_image_ctx->parent_md.overlap = m_parent_overlap; + } + + send_snap_create(); +} + +template +void SnapshotCreateRequest::send_snap_create() { + dout(20) << ": snap_name=" << m_snap_name << dendl; + + auto finish_op_ctx = start_local_op(); + if (finish_op_ctx == nullptr) { + derr << ": lost exclusive lock" << dendl; + finish(-EROFS); + return; + } + + auto ctx = new FunctionContext([this, finish_op_ctx](int r) { + handle_snap_create(r); + finish_op_ctx->complete(0); + }); + RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock); + m_local_image_ctx->operations->execute_snap_create(m_snap_namespace, + m_snap_name.c_str(), + ctx, + 0U, true); +} + +template +void SnapshotCreateRequest::handle_snap_create(int r) { + dout(20) << ": r=" << r << dendl; + + if (r < 0) { + derr << ": failed to create snapshot '" << m_snap_name << "': " + << cpp_strerror(r) << dendl; + finish(r); + return; + } + + send_create_object_map(); +} +template +void SnapshotCreateRequest::send_create_object_map() { + + if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP)) { + finish(0); + return; + } + + m_local_image_ctx->snap_lock.get_read(); + auto snap_it = m_local_image_ctx->snap_ids.find( + {cls::rbd::UserSnapshotNamespace(), m_snap_name}); + if (snap_it == m_local_image_ctx->snap_ids.end()) { + derr << ": failed to locate snap: " << m_snap_name << dendl; + m_local_image_ctx->snap_lock.put_read(); + finish(-ENOENT); + return; + } + librados::snap_t local_snap_id = snap_it->second; + m_local_image_ctx->snap_lock.put_read(); + + std::string object_map_oid(librbd::ObjectMap<>::object_map_name( + m_local_image_ctx->id, local_snap_id)); + uint64_t object_count = Striper::get_num_objects(m_local_image_ctx->layout, + m_size); + dout(20) << ": " + << "object_map_oid=" << object_map_oid << ", " + << "object_count=" << object_count << dendl; + + // initialize an empty object map of the correct size (object sync + // will populate the object map) + librados::ObjectWriteOperation op; + librbd::cls_client::object_map_resize(&op, object_count, OBJECT_NONEXISTENT); + + auto finish_op_ctx = start_local_op(); + if (finish_op_ctx == nullptr) { + derr << ": lost exclusive lock" << dendl; + finish(-EROFS); + return; + } + + auto ctx = new FunctionContext([this, finish_op_ctx](int r) { + handle_create_object_map(r); + finish_op_ctx->complete(0); + }); + librados::AioCompletion *comp = create_rados_callback(ctx); + int r = m_local_image_ctx->md_ctx.aio_operate(object_map_oid, comp, &op); + assert(r == 0); + comp->release(); +} + +template +void SnapshotCreateRequest::handle_create_object_map(int r) { + dout(20) << ": r=" << r << dendl; + + if (r < 0) { + derr << ": failed to create object map: " << cpp_strerror(r) + << dendl; + finish(r); + return; + } + + finish(0); +} + +template +Context *SnapshotCreateRequest::start_local_op() { + RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock); + if (m_local_image_ctx->exclusive_lock == nullptr) { + return nullptr; + } + return m_local_image_ctx->exclusive_lock->start_op(); +} + +template +void SnapshotCreateRequest::finish(int r) { + dout(20) << ": r=" << r << dendl; + + m_on_finish->complete(r); + delete this; +} + +} // namespace image_sync +} // namespace mirror +} // namespace rbd + +template class rbd::mirror::image_sync::SnapshotCreateRequest;