Skip to content

Commit 2b6ed5b

Browse files
authored
Merge pull request ceph#57954 from idryomov/wip-64662
librbd: allow cloning from non-user snapshots Reviewed-by: Ramana Raja <[email protected]> Reviewed-by: Afreen Misbah <[email protected]>
2 parents 3139c54 + e5c3dd3 commit 2b6ed5b

File tree

25 files changed

+575
-130
lines changed

25 files changed

+575
-130
lines changed

PendingReleaseNotes

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,12 @@ CephFS: Disallow delegating preallocated inode ranges to clients. Config
226226
Copies, and list metrics.
227227
* RBD: `Image::access_timestamp` and `Image::modify_timestamp` Python APIs now
228228
return timestamps in UTC.
229+
* RBD: Support for cloning from non-user type snapshots is added. This is
230+
intended primarily as a building block for cloning new groups from group
231+
snapshots created with `rbd group snap create` command, but has also been
232+
exposed via the new `--snap-id` option for `rbd clone` command.
233+
* RBD: The output of `rbd snap ls --all` command now includes the original
234+
type for trashed snapshots.
229235

230236
>=18.0.0
231237

qa/tasks/mgr/dashboard/test_rbd.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,14 @@ def _validate_image(self, img, **kwargs):
236236
'features_name': JList(JLeaf(str)),
237237
'stripe_count': JLeaf(int, none=True),
238238
'stripe_unit': JLeaf(int, none=True),
239-
'parent': JObj(sub_elems={'pool_name': JLeaf(str),
239+
'parent': JObj(sub_elems={'pool_id': JLeaf(int),
240+
'pool_name': JLeaf(str),
240241
'pool_namespace': JLeaf(str, none=True),
242+
'image_id': JLeaf(str),
241243
'image_name': JLeaf(str),
244+
'trash': JLeaf(bool),
245+
'snap_id': JLeaf(int),
246+
'snap_namespace_type': JLeaf(int),
242247
'snap_name': JLeaf(str)}, none=True),
243248
'data_pool': JLeaf(str, none=True),
244249
'snapshots': JList(JLeaf(dict)),
@@ -256,7 +261,12 @@ def _validate_image(self, img, **kwargs):
256261
self.assertSchema(img, schema)
257262

258263
for k, v in kwargs.items():
259-
if isinstance(v, list):
264+
if k == 'parent' and v is not None:
265+
# check that img['parent'] contains (is a superset of) v
266+
actual = {pk: img['parent'][pk]
267+
for pk in v.keys() if pk in img['parent']}
268+
self.assertEqual(actual, v)
269+
elif isinstance(v, list):
260270
self.assertSetEqual(set(img[k]), set(v))
261271
else:
262272
self.assertEqual(img[k], v)

qa/workunits/rbd/cli_generic.sh

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -385,19 +385,35 @@ test_clone() {
385385
rbd clone test1@s1 rbd2/clone
386386
rbd -p rbd2 ls | grep clone
387387
rbd -p rbd2 ls -l | grep clone | grep test1@s1
388-
rbd ls | grep -v clone
388+
test "$(rbd ls)" = 'test1'
389389
rbd flatten rbd2/clone
390390
rbd snap create rbd2/clone@s1
391391
rbd snap protect rbd2/clone@s1
392392
rbd clone rbd2/clone@s1 clone2
393393
rbd ls | grep clone2
394394
rbd ls -l | grep clone2 | grep rbd2/clone@s1
395-
rbd -p rbd2 ls | grep -v clone2
395+
test "$(rbd -p rbd2 ls)" = 'clone'
396+
397+
rbd clone rbd2/clone clone3 |& grep 'snapshot name was not specified'
398+
rbd clone rbd2/clone@invalid clone3 |& grep 'failed to open parent image'
399+
rbd clone rbd2/clone --snap-id 0 clone3 |& grep 'failed to open parent image'
400+
rbd clone rbd2/clone@invalid --snap-id 0 clone3 |&
401+
grep 'trying to access snapshot using both name and id'
402+
SNAP_ID=$(rbd snap ls rbd2/clone --format json |
403+
jq '.[] | select(.name == "s1") | .id')
404+
rbd clone --snap-id $SNAP_ID rbd2/clone clone3
405+
rbd ls | grep clone3
406+
rbd ls -l | grep clone3 | grep rbd2/clone@s1
407+
test "$(rbd -p rbd2 ls)" = 'clone'
408+
test "$(rbd ls -l | grep -c rbd2/clone@s1)" = '2'
409+
rbd flatten clone3
410+
test "$(rbd ls -l | grep -c rbd2/clone@s1)" = '1'
396411

397412
rbd rm clone2
398413
rbd snap unprotect rbd2/clone@s1
399414
rbd snap rm rbd2/clone@s1
400415
rbd rm rbd2/clone
416+
rbd rm clone3
401417
rbd snap unprotect test1@s1
402418
rbd snap rm test1@s1
403419
rbd rm test1
@@ -752,7 +768,9 @@ test_clone_v2() {
752768
rbd snap create test1@1
753769
rbd clone --rbd-default-clone-format=1 test1@1 test2 && exit 1 || true
754770
rbd clone --rbd-default-clone-format=2 test1@1 test2
755-
rbd clone --rbd-default-clone-format=2 test1@1 test3
771+
SNAP_ID=$(rbd snap ls test1 --format json |
772+
jq '.[] | select(.name == "1") | .id')
773+
rbd clone --rbd-default-clone-format=2 --snap-id $SNAP_ID test1 test3
756774

757775
rbd snap protect test1@1
758776
rbd clone --rbd-default-clone-format=1 test1@1 test4
@@ -764,7 +782,7 @@ test_clone_v2() {
764782
rbd snap unprotect test1@1
765783

766784
rbd snap remove test1@1
767-
rbd snap list --all test1 | grep -E "trash \(1\) *$"
785+
rbd snap list --all test1 | grep -E "trash \(user 1\) *$"
768786

769787
rbd snap create test1@2
770788
rbd rm test1 2>&1 | grep 'image has snapshots'

qa/workunits/rbd/rbd_mirror_helpers.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1215,7 +1215,7 @@ test_snap_moved_to_trash()
12151215
local snap_name=$4
12161216

12171217
rbd --cluster ${cluster} snap ls ${pool}/${image} --all |
1218-
grep -F " trash (${snap_name})"
1218+
grep -F " trash (user ${snap_name})"
12191219
}
12201220

12211221
wait_for_snap_moved_to_trash()

src/include/rbd/librbd.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,11 @@ typedef struct {
260260
char *group_snap_name;
261261
} rbd_snap_group_namespace_t;
262262

263+
typedef struct {
264+
rbd_snap_namespace_type_t original_namespace_type;
265+
char *original_name;
266+
} rbd_snap_trash_namespace_t;
267+
263268
typedef enum {
264269
RBD_SNAP_MIRROR_STATE_PRIMARY,
265270
RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED,
@@ -479,6 +484,9 @@ CEPH_RBD_API int rbd_clone2(rados_ioctx_t p_ioctx, const char *p_name,
479484
CEPH_RBD_API int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
480485
const char *p_snapname, rados_ioctx_t c_ioctx,
481486
const char *c_name, rbd_image_options_t c_opts);
487+
CEPH_RBD_API int rbd_clone4(rados_ioctx_t p_ioctx, const char *p_name,
488+
uint64_t p_snap_id, rados_ioctx_t c_ioctx,
489+
const char *c_name, rbd_image_options_t c_opts);
482490
CEPH_RBD_API int rbd_remove(rados_ioctx_t io, const char *name);
483491
CEPH_RBD_API int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
484492
librbd_progress_fn_t cb,
@@ -965,6 +973,11 @@ CEPH_RBD_API int rbd_snap_get_trash_namespace(rbd_image_t image,
965973
uint64_t snap_id,
966974
char* original_name,
967975
size_t max_length);
976+
CEPH_RBD_API int rbd_snap_get_trash_namespace2(
977+
rbd_image_t image, uint64_t snap_id,
978+
rbd_snap_trash_namespace_t *trash_snap, size_t trash_snap_size);
979+
CEPH_RBD_API int rbd_snap_trash_namespace_cleanup(
980+
rbd_snap_trash_namespace_t *trash_snap, size_t trash_snap_size);
968981
CEPH_RBD_API int rbd_snap_get_mirror_namespace(
969982
rbd_image_t image, uint64_t snap_id,
970983
rbd_snap_mirror_namespace_t *mirror_snap, size_t mirror_snap_size);

src/include/rbd/librbd.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ namespace librbd {
7373
std::string group_snap_name;
7474
} snap_group_namespace_t;
7575

76+
typedef struct {
77+
snap_namespace_type_t original_namespace_type;
78+
std::string original_name;
79+
} snap_trash_namespace_t;
80+
7681
typedef rbd_snap_mirror_state_t snap_mirror_state_t;
7782

7883
typedef struct {
@@ -294,6 +299,8 @@ class CEPH_RBD_API RBD
294299
int *c_order, uint64_t stripe_unit, int stripe_count);
295300
int clone3(IoCtx& p_ioctx, const char *p_name, const char *p_snapname,
296301
IoCtx& c_ioctx, const char *c_name, ImageOptions& opts);
302+
int clone4(IoCtx& p_ioctx, const char *p_name, uint64_t p_snap_id,
303+
IoCtx& c_ioctx, const char *c_name, ImageOptions& opts);
297304
int remove(IoCtx& io_ctx, const char *name);
298305
int remove_with_progress(IoCtx& io_ctx, const char *name, ProgressContext& pctx);
299306
int rename(IoCtx& src_io_ctx, const char *srcname, const char *destname);
@@ -677,6 +684,9 @@ class CEPH_RBD_API Image
677684
snap_group_namespace_t *group_namespace,
678685
size_t snap_group_namespace_size);
679686
int snap_get_trash_namespace(uint64_t snap_id, std::string* original_name);
687+
int snap_get_trash_namespace2(uint64_t snap_id,
688+
snap_trash_namespace_t *trash_namespace,
689+
size_t snap_trash_namespace_size);
680690
int snap_get_mirror_namespace(
681691
uint64_t snap_id, snap_mirror_namespace_t *mirror_namespace,
682692
size_t snap_mirror_namespace_size);

src/librbd/api/Snapshot.cc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ class GetGroupVisitor {
8282

8383
class GetTrashVisitor {
8484
public:
85-
std::string* original_name;
85+
snap_trash_namespace_t *trash_snap;
8686

87-
explicit GetTrashVisitor(std::string* original_name)
88-
: original_name(original_name) {
87+
explicit GetTrashVisitor(snap_trash_namespace_t *trash_snap)
88+
: trash_snap(trash_snap) {
8989
}
9090

9191
template <typename T>
@@ -95,7 +95,9 @@ class GetTrashVisitor {
9595

9696
inline int operator()(
9797
const cls::rbd::TrashSnapshotNamespace& snap_namespace) {
98-
*original_name = snap_namespace.original_name;
98+
trash_snap->original_namespace_type = static_cast<snap_namespace_type_t>(
99+
snap_namespace.original_snapshot_namespace_type);
100+
trash_snap->original_name = snap_namespace.original_name;
99101
return 0;
100102
}
101103
};
@@ -153,7 +155,7 @@ int Snapshot<I>::get_group_namespace(I *ictx, uint64_t snap_id,
153155

154156
template <typename I>
155157
int Snapshot<I>::get_trash_namespace(I *ictx, uint64_t snap_id,
156-
std::string* original_name) {
158+
snap_trash_namespace_t *trash_snap) {
157159
int r = ictx->state->refresh_if_required();
158160
if (r < 0) {
159161
return r;
@@ -165,7 +167,7 @@ int Snapshot<I>::get_trash_namespace(I *ictx, uint64_t snap_id,
165167
return -ENOENT;
166168
}
167169

168-
auto visitor = GetTrashVisitor(original_name);
170+
auto visitor = GetTrashVisitor(trash_snap);
169171
r = snap_info->snap_namespace.visit(visitor);
170172
if (r < 0) {
171173
return r;

src/librbd/api/Snapshot.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct Snapshot {
2121
snap_group_namespace_t *group_snap);
2222

2323
static int get_trash_namespace(ImageCtxT *ictx, uint64_t snap_id,
24-
std::string *original_name);
24+
snap_trash_namespace_t *trash_snap);
2525

2626
static int get_mirror_namespace(
2727
ImageCtxT *ictx, uint64_t snap_id,

src/librbd/image/CloneRequest.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ void CloneRequest<I>::handle_attach_child(int r) {
397397
ldout(m_cct, 15) << "r=" << r << dendl;
398398

399399
if (r < 0) {
400-
lderr(m_cct) << "failed to attach parent: " << cpp_strerror(r) << dendl;
400+
lderr(m_cct) << "failed to attach child: " << cpp_strerror(r) << dendl;
401401
m_r_saved = r;
402402
close_child();
403403
return;

src/librbd/internal.cc

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -716,24 +716,40 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
716716
opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit);
717717
opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count);
718718

719-
int r = clone(p_ioctx, nullptr, p_name, p_snap_name, c_ioctx, nullptr,
720-
c_name, opts, "", "");
719+
int r = clone(p_ioctx, nullptr, p_name, CEPH_NOSNAP, p_snap_name,
720+
c_ioctx, nullptr, c_name, opts, "", "");
721721
opts.get(RBD_IMAGE_OPTION_ORDER, &order);
722722
*c_order = order;
723723
return r;
724724
}
725725

726726
int clone(IoCtx& p_ioctx, const char *p_id, const char *p_name,
727-
const char *p_snap_name, IoCtx& c_ioctx, const char *c_id,
728-
const char *c_name, ImageOptions& c_opts,
727+
uint64_t p_snap_id, const char *p_snap_name, IoCtx& c_ioctx,
728+
const char *c_id, const char *c_name, ImageOptions& c_opts,
729729
const std::string &non_primary_global_image_id,
730730
const std::string &primary_mirror_uuid)
731731
{
732-
ceph_assert((p_id == nullptr) ^ (p_name == nullptr));
733-
734732
CephContext *cct = (CephContext *)p_ioctx.cct();
735-
if (p_snap_name == nullptr) {
736-
lderr(cct) << "image to be cloned must be a snapshot" << dendl;
733+
ldout(cct, 10) << __func__
734+
<< " p_id=" << (p_id ?: "")
735+
<< ", p_name=" << (p_name ?: "")
736+
<< ", p_snap_id=" << p_snap_id
737+
<< ", p_snap_name=" << (p_snap_name ?: "")
738+
<< ", c_id=" << (c_id ?: "")
739+
<< ", c_name=" << c_name
740+
<< ", c_opts=" << c_opts
741+
<< ", non_primary_global_image_id=" << non_primary_global_image_id
742+
<< ", primary_mirror_uuid=" << primary_mirror_uuid
743+
<< dendl;
744+
745+
if (((p_id == nullptr) ^ (p_name == nullptr)) == 0) {
746+
lderr(cct) << "must specify either parent image id or parent image name"
747+
<< dendl;
748+
return -EINVAL;
749+
}
750+
if (((p_snap_id == CEPH_NOSNAP) ^ (p_snap_name == nullptr)) == 0) {
751+
lderr(cct) << "must specify either parent snap id or parent snap name"
752+
<< dendl;
737753
return -EINVAL;
738754
}
739755

@@ -766,10 +782,8 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
766782
clone_id = c_id;
767783
}
768784

769-
ldout(cct, 10) << __func__ << " "
770-
<< "c_name=" << c_name << ", "
771-
<< "c_id= " << clone_id << ", "
772-
<< "c_opts=" << c_opts << dendl;
785+
ldout(cct, 10) << __func__ << " parent_id=" << parent_id
786+
<< ", clone_id=" << clone_id << dendl;
773787

774788
ConfigProxy config{reinterpret_cast<CephContext *>(c_ioctx.cct())->_conf};
775789
api::Config<>::apply_pool_overrides(c_ioctx, &config);
@@ -778,8 +792,8 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
778792

779793
C_SaferCond cond;
780794
auto *req = image::CloneRequest<>::create(
781-
config, p_ioctx, parent_id, p_snap_name,
782-
{cls::rbd::UserSnapshotNamespace{}}, CEPH_NOSNAP, c_ioctx, c_name,
795+
config, p_ioctx, parent_id, (p_snap_name ?: ""),
796+
{cls::rbd::UserSnapshotNamespace{}}, p_snap_id, c_ioctx, c_name,
783797
clone_id, c_opts, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
784798
non_primary_global_image_id, primary_mirror_uuid,
785799
asio_engine.get_work_queue(), &cond);

0 commit comments

Comments
 (0)