Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mimic: librbd: deep copy optionally support flattening cloned image #22038

Merged
merged 6 commits into from
May 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions qa/workunits/rbd/cli_generic.sh
Original file line number Diff line number Diff line change
Expand Up @@ -496,13 +496,30 @@ test_deep_copy_clone() {
rbd snap create testimg2@snap2
rbd deep copy testimg2 testimg3
rbd info testimg3 | grep 'size 256MiB'
rbd info testimg3 | grep 'parent: rbd/testimg1@snap1'
rbd snap ls testimg3 | grep -v 'SNAPID' | wc -l | grep 1
rbd snap ls testimg3 | grep '.*snap2.*'
rbd info testimg2 | grep 'features:.*deep-flatten' || rbd snap rm testimg2@snap2
rbd info testimg3 | grep 'features:.*deep-flatten' || rbd snap rm testimg3@snap2
rbd flatten testimg2
rbd flatten testimg3
rbd snap unprotect testimg1@snap1
rbd snap purge testimg2
rbd snap purge testimg3
rbd rm testimg2
rbd rm testimg3

rbd snap protect testimg1@snap1
rbd clone testimg1@snap1 testimg2
rbd snap create testimg2@snap2
rbd deep copy --flatten testimg2 testimg3
rbd info testimg3 | grep 'size 256MiB'
rbd info testimg3 | grep -v 'parent:'
rbd snap ls testimg3 | grep -v 'SNAPID' | wc -l | grep 1
rbd snap ls testimg3 | grep '.*snap2.*'
rbd info testimg2 | grep 'features:.*deep-flatten' || rbd snap rm testimg2@snap2
rbd flatten testimg2
rbd snap unprotect testimg1@snap1

remove_images
}
Expand Down
3 changes: 2 additions & 1 deletion src/include/rbd/librbd.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ enum {
RBD_IMAGE_OPTION_JOURNAL_POOL = 7,
RBD_IMAGE_OPTION_FEATURES_SET = 8,
RBD_IMAGE_OPTION_FEATURES_CLEAR = 9,
RBD_IMAGE_OPTION_DATA_POOL = 10
RBD_IMAGE_OPTION_DATA_POOL = 10,
RBD_IMAGE_OPTION_FLATTEN = 11,
};

typedef enum {
Expand Down
15 changes: 8 additions & 7 deletions src/librbd/DeepCopyRequest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@ using librbd::util::unique_lock_name;
template <typename I>
DeepCopyRequest<I>::DeepCopyRequest(I *src_image_ctx, I *dst_image_ctx,
librados::snap_t snap_id_start,
librados::snap_t snap_id_end,
librados::snap_t snap_id_end, bool flatten,
const ObjectNumber &object_number,
ContextWQ *work_queue, SnapSeqs *snap_seqs,
ProgressContext *prog_ctx,
Context *on_finish)
: RefCountedObject(dst_image_ctx->cct, 1), m_src_image_ctx(src_image_ctx),
m_dst_image_ctx(dst_image_ctx), m_snap_id_start(snap_id_start),
m_snap_id_end(snap_id_end), m_object_number(object_number),
m_work_queue(work_queue), m_snap_seqs(snap_seqs), m_prog_ctx(prog_ctx),
m_on_finish(on_finish), m_cct(dst_image_ctx->cct),
m_snap_id_end(snap_id_end), m_flatten(flatten),
m_object_number(object_number), m_work_queue(work_queue),
m_snap_seqs(snap_seqs), m_prog_ctx(prog_ctx), m_on_finish(on_finish),
m_cct(dst_image_ctx->cct),
m_lock(unique_lock_name("DeepCopyRequest::m_lock", this)) {
}

Expand Down Expand Up @@ -90,8 +91,8 @@ void DeepCopyRequest<I>::send_copy_snapshots() {
Context *ctx = create_context_callback<
DeepCopyRequest<I>, &DeepCopyRequest<I>::handle_copy_snapshots>(this);
m_snapshot_copy_request = SnapshotCopyRequest<I>::create(
m_src_image_ctx, m_dst_image_ctx, m_snap_id_end, m_work_queue, m_snap_seqs,
ctx);
m_src_image_ctx, m_dst_image_ctx, m_snap_id_end, m_flatten, m_work_queue,
m_snap_seqs, ctx);
m_snapshot_copy_request->get();
m_lock.Unlock();

Expand Down Expand Up @@ -140,7 +141,7 @@ void DeepCopyRequest<I>::send_copy_image() {
DeepCopyRequest<I>, &DeepCopyRequest<I>::handle_copy_image>(this);
m_image_copy_request = ImageCopyRequest<I>::create(
m_src_image_ctx, m_dst_image_ctx, m_snap_id_start, m_snap_id_end,
m_object_number, *m_snap_seqs, m_prog_ctx, ctx);
m_flatten, m_object_number, *m_snap_seqs, m_prog_ctx, ctx);
m_image_copy_request->get();
m_lock.Unlock();

Expand Down
7 changes: 4 additions & 3 deletions src/librbd/DeepCopyRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ class DeepCopyRequest : public RefCountedObject {
static DeepCopyRequest* create(ImageCtxT *src_image_ctx,
ImageCtxT *dst_image_ctx,
librados::snap_t snap_id_start,
librados::snap_t snap_id_end,
librados::snap_t snap_id_end, bool flatten,
const deep_copy::ObjectNumber &object_number,
ContextWQ *work_queue,
SnapSeqs *snap_seqs,
ProgressContext *prog_ctx,
Context *on_finish) {
return new DeepCopyRequest(src_image_ctx, dst_image_ctx, snap_id_start,
snap_id_end, object_number, work_queue,
snap_id_end, flatten, object_number, work_queue,
snap_seqs, prog_ctx, on_finish);
}

DeepCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx,
librados::snap_t snap_id_start, librados::snap_t snap_id_end,
const deep_copy::ObjectNumber &object_number,
bool flatten, const deep_copy::ObjectNumber &object_number,
ContextWQ *work_queue, SnapSeqs *snap_seqs,
ProgressContext *prog_ctx, Context *on_finish);
~DeepCopyRequest();
Expand Down Expand Up @@ -88,6 +88,7 @@ class DeepCopyRequest : public RefCountedObject {
ImageCtxT *m_dst_image_ctx;
librados::snap_t m_snap_id_start;
librados::snap_t m_snap_id_end;
bool m_flatten;
deep_copy::ObjectNumber m_object_number;
ContextWQ *m_work_queue;
SnapSeqs *m_snap_seqs;
Expand Down
18 changes: 13 additions & 5 deletions src/librbd/api/Image.cc
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,15 @@ int Image<I>::deep_copy(I *src, librados::IoCtx& dest_md_ctx,
return -ENOSYS;
}

uint64_t flatten = 0;
if (opts.get(RBD_IMAGE_OPTION_FLATTEN, &flatten) == 0) {
opts.unset(RBD_IMAGE_OPTION_FLATTEN);
}

ParentSpec parent_spec;
{
if (flatten > 0) {
parent_spec.pool_id = -1;
} else {
RWLock::RLocker snap_locker(src->snap_lock);
RWLock::RLocker parent_locker(src->parent_lock);

Expand Down Expand Up @@ -297,7 +304,7 @@ int Image<I>::deep_copy(I *src, librados::IoCtx& dest_md_ctx,
return r;
}

r = deep_copy(src, dest, prog_ctx);
r = deep_copy(src, dest, flatten > 0, prog_ctx);

int close_r = dest->state->close();
if (r == 0 && close_r < 0) {
Expand All @@ -307,7 +314,8 @@ int Image<I>::deep_copy(I *src, librados::IoCtx& dest_md_ctx,
}

template <typename I>
int Image<I>::deep_copy(I *src, I *dest, ProgressContext &prog_ctx) {
int Image<I>::deep_copy(I *src, I *dest, bool flatten,
ProgressContext &prog_ctx) {
CephContext *cct = src->cct;
librados::snap_t snap_id_start = 0;
librados::snap_t snap_id_end;
Expand All @@ -323,8 +331,8 @@ int Image<I>::deep_copy(I *src, I *dest, ProgressContext &prog_ctx) {
C_SaferCond cond;
SnapSeqs snap_seqs;
auto req = DeepCopyRequest<>::create(src, dest, snap_id_start, snap_id_end,
boost::none, op_work_queue, &snap_seqs,
&prog_ctx, &cond);
flatten, boost::none, op_work_queue,
&snap_seqs, &prog_ctx, &cond);
req->send();
int r = cond.wait();
if (r < 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/librbd/api/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct Image {
static int deep_copy(ImageCtxT *ictx, librados::IoCtx& dest_md_ctx,
const char *destname, ImageOptions& opts,
ProgressContext &prog_ctx);
static int deep_copy(ImageCtxT *src, ImageCtxT *dest,
static int deep_copy(ImageCtxT *src, ImageCtxT *dest, bool flatten,
ProgressContext &prog_ctx);

static int snap_set(ImageCtxT *ictx,
Expand Down
134 changes: 128 additions & 6 deletions src/librbd/deep_copy/ImageCopyRequest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include "common/errno.h"
#include "librbd/Utils.h"
#include "librbd/deep_copy/Utils.h"
#include "librbd/image/CloseRequest.h"
#include "librbd/image/OpenRequest.h"
#include "librbd/image/SetSnapRequest.h"
#include "osdc/Striper.h"

#define dout_subsys ceph_subsys_rbd
Expand All @@ -16,21 +19,23 @@
namespace librbd {
namespace deep_copy {

using librbd::util::create_context_callback;
using librbd::util::unique_lock_name;

template <typename I>
ImageCopyRequest<I>::ImageCopyRequest(I *src_image_ctx, I *dst_image_ctx,
librados::snap_t snap_id_start,
librados::snap_t snap_id_end,
bool flatten,
const ObjectNumber &object_number,
const SnapSeqs &snap_seqs,
ProgressContext *prog_ctx,
Context *on_finish)
: RefCountedObject(dst_image_ctx->cct, 1), m_src_image_ctx(src_image_ctx),
m_dst_image_ctx(dst_image_ctx), m_snap_id_start(snap_id_start),
m_snap_id_end(snap_id_end), m_object_number(object_number),
m_snap_seqs(snap_seqs), m_prog_ctx(prog_ctx), m_on_finish(on_finish),
m_cct(dst_image_ctx->cct),
m_snap_id_end(snap_id_end), m_flatten(flatten),
m_object_number(object_number), m_snap_seqs(snap_seqs),
m_prog_ctx(prog_ctx), m_on_finish(on_finish), m_cct(dst_image_ctx->cct),
m_lock(unique_lock_name("ImageCopyRequest::m_lock", this)) {
}

Expand All @@ -44,7 +49,7 @@ void ImageCopyRequest<I>::send() {
return;
}

send_object_copies();
send_open_parent();
}

template <typename I>
Expand All @@ -55,6 +60,90 @@ void ImageCopyRequest<I>::cancel() {
m_canceled = true;
}

template <typename I>
void ImageCopyRequest<I>::send_open_parent() {
{
RWLock::RLocker snap_locker(m_src_image_ctx->snap_lock);
RWLock::RLocker parent_locker(m_src_image_ctx->parent_lock);

auto snap_id = m_snap_map.begin()->first;
auto parent_info = m_src_image_ctx->get_parent_info(snap_id);
if (parent_info == nullptr) {
ldout(m_cct, 20) << "could not find parent info for snap id " << snap_id
<< dendl;
} else {
m_parent_spec = parent_info->spec;
}
}

if (m_parent_spec.pool_id == -1) {
send_object_copies();
return;
}

ldout(m_cct, 20) << "pool_id=" << m_parent_spec.pool_id << ", image_id="
<< m_parent_spec.image_id << ", snap_id="
<< m_parent_spec.snap_id << dendl;

librados::Rados rados(m_src_image_ctx->md_ctx);
librados::IoCtx parent_io_ctx;
int r = rados.ioctx_create2(m_parent_spec.pool_id, parent_io_ctx);
if (r < 0) {
lderr(m_cct) << "failed to access parent pool (id=" << m_parent_spec.pool_id
<< "): " << cpp_strerror(r) << dendl;
finish(r);
return;
}

m_src_parent_image_ctx = I::create("", m_parent_spec.image_id, nullptr, parent_io_ctx, true);

auto ctx = create_context_callback<
ImageCopyRequest<I>, &ImageCopyRequest<I>::handle_open_parent>(this);

auto req = image::OpenRequest<I>::create(m_src_parent_image_ctx, false, ctx);
req->send();
}

template <typename I>
void ImageCopyRequest<I>::handle_open_parent(int r) {
ldout(m_cct, 20) << "r=" << r << dendl;

if (r < 0) {
lderr(m_cct) << "failed to open parent: " << cpp_strerror(r) << dendl;
m_src_parent_image_ctx->destroy();
m_src_parent_image_ctx = nullptr;
finish(r);
return;
}

send_set_parent_snap();
}

template <typename I>
void ImageCopyRequest<I>::send_set_parent_snap() {
ldout(m_cct, 20) << dendl;

auto ctx = create_context_callback<
ImageCopyRequest<I>, &ImageCopyRequest<I>::handle_set_parent_snap>(this);
auto req = image::SetSnapRequest<I>::create(*m_src_parent_image_ctx,
m_parent_spec.snap_id, ctx);
req->send();
}

template <typename I>
void ImageCopyRequest<I>::handle_set_parent_snap(int r) {
ldout(m_cct, 20) << "r=" << r << dendl;

if (r < 0) {
lderr(m_cct) << "failed to set parent snap: " << cpp_strerror(r) << dendl;
m_ret_val = r;
send_close_parent();
return;
}

send_object_copies();
}

template <typename I>
void ImageCopyRequest<I>::send_object_copies() {
m_object_no = 0;
Expand Down Expand Up @@ -90,7 +179,7 @@ void ImageCopyRequest<I>::send_object_copies() {
}

if (complete) {
finish(m_ret_val);
send_close_parent();
}
}

Expand Down Expand Up @@ -118,7 +207,8 @@ void ImageCopyRequest<I>::send_next_object_copy() {
handle_object_copy(ono, r);
});
ObjectCopyRequest<I> *req = ObjectCopyRequest<I>::create(
m_src_image_ctx, m_dst_image_ctx, m_snap_map, ono, ctx);
m_src_image_ctx, m_src_parent_image_ctx, m_dst_image_ctx, m_snap_map, ono,
m_flatten, ctx);
req->send();
}

Expand Down Expand Up @@ -158,8 +248,40 @@ void ImageCopyRequest<I>::handle_object_copy(uint64_t object_no, int r) {
}

if (complete) {
send_close_parent();
}
}

template <typename I>
void ImageCopyRequest<I>::send_close_parent() {
if (m_src_parent_image_ctx == nullptr) {
finish(m_ret_val);
return;
}

ldout(m_cct, 20) << dendl;

auto ctx = create_context_callback<
ImageCopyRequest<I>, &ImageCopyRequest<I>::handle_close_parent>(this);
auto req = image::CloseRequest<I>::create(m_src_parent_image_ctx, ctx);
req->send();
}

template <typename I>
void ImageCopyRequest<I>::handle_close_parent(int r) {
ldout(m_cct, 20) << "r=" << r << dendl;

if (r < 0) {
lderr(m_cct) << "failed to close parent: " << cpp_strerror(r) << dendl;
if (m_ret_val == 0) {
m_ret_val = r;
}
}

m_src_parent_image_ctx->destroy();
m_src_parent_image_ctx = nullptr;

finish(m_ret_val);
}

template <typename I>
Expand Down