1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
6 * This is an OSD class that implements methods for
9 * Most of these deal with the rbd header object. Methods prefixed
10 * with old_ deal with the original rbd design, in which clients read
11 * and interpreted the header object directly.
13 * The new format is meant to be opaque to clients - all their
14 * interactions with non-data objects should go through this
15 * class. The OSD class interface leaves the class to implement its
16 * own argument and payload serialization/deserialization, so for ease
17 * of implementation we use the existing ceph encoding/decoding
18 * methods. Something like json might be preferable, but the rbd
19 * kernel module has to be able to understand format as well. The
20 * datatypes exposed to the clients are strings, unsigned integers,
21 * and vectors of those types. The on-wire format can be found in
22 * src/include/encoding.h.
24 * The methods for interacting with the new format document their
25 * parameters as the client sees them - it would be silly to mention
26 * in each one that they take an input and an output bufferlist.
28 #include "include/types.h"
34 #include "include/uuid.h"
35 #include "common/bit_vector.hpp"
36 #include "common/errno.h"
37 #include "objclass/objclass.h"
38 #include "osd/osd_types.h"
39 #include "include/rbd_types.h"
40 #include "include/rbd/object_map_types.h"
42 #include "cls/rbd/cls_rbd.h"
43 #include "cls/rbd/cls_rbd_types.h"
51 * stripe_unit: size in bytes of the stripe unit. if not present,
52 * the stripe unit is assumed to match the object size (1 << order).
54 * stripe_count: number of objects to stripe over before looping back.
55 * if not present or 1, striping is disabled. this is the default.
62 #define RBD_MAX_KEYS_READ 64
63 #define RBD_SNAP_KEY_PREFIX "snapshot_"
64 #define RBD_SNAP_CHILDREN_KEY_PREFIX "snap_children_"
65 #define RBD_DIR_ID_KEY_PREFIX "id_"
66 #define RBD_DIR_NAME_KEY_PREFIX "name_"
67 #define RBD_METADATA_KEY_PREFIX "metadata_"
71 uint64_t get_encode_features(cls_method_context_t hctx
) {
72 uint64_t features
= 0;
73 int8_t require_osd_release
= cls_get_required_osd_release(hctx
);
74 if (require_osd_release
>= CEPH_RELEASE_NAUTILUS
) {
75 features
|= CEPH_FEATURE_SERVER_NAUTILUS
;
80 bool calc_sparse_extent(const bufferptr
&bp
, size_t sparse_size
,
81 uint64_t length
, size_t *write_offset
,
82 size_t *write_length
, size_t *offset
) {
84 if (*offset
+ sparse_size
> length
) {
85 extent_size
= length
- *offset
;
87 extent_size
= sparse_size
;
90 bufferptr
extent(bp
, *offset
, extent_size
);
91 *offset
+= extent_size
;
93 bool extent_is_zero
= extent
.is_zero();
94 if (!extent_is_zero
) {
95 *write_length
+= extent_size
;
97 if (extent_is_zero
&& *write_length
== 0) {
98 *write_offset
+= extent_size
;
101 if ((extent_is_zero
|| *offset
== length
) && *write_length
!= 0) {
107 } // anonymous namespace
109 static int snap_read_header(cls_method_context_t hctx
, bufferlist
& bl
)
111 unsigned snap_count
= 0;
112 uint64_t snap_names_len
= 0;
113 struct rbd_obj_header_ondisk
*header
;
115 CLS_LOG(20, "snapshots_list");
118 int len
= sizeof(*header
) +
119 snap_count
* sizeof(struct rbd_obj_snap_ondisk
) +
122 int rc
= cls_cxx_read(hctx
, 0, len
, &bl
);
126 if (bl
.length() < sizeof(*header
))
129 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
132 if ((snap_count
!= header
->snap_count
) ||
133 (snap_names_len
!= header
->snap_names_len
)) {
134 snap_count
= header
->snap_count
;
135 snap_names_len
= header
->snap_names_len
;
145 static void key_from_snap_id(snapid_t snap_id
, string
*out
)
148 oss
<< RBD_SNAP_KEY_PREFIX
149 << std::setw(16) << std::setfill('0') << std::hex
<< snap_id
;
153 static snapid_t
snap_id_from_key(const string
&key
) {
154 istringstream
iss(key
);
156 iss
.ignore(strlen(RBD_SNAP_KEY_PREFIX
)) >> std::hex
>> id
;
161 static int read_key(cls_method_context_t hctx
, const string
&key
, T
*out
)
164 int r
= cls_cxx_map_get_val(hctx
, key
, &bl
);
167 CLS_ERR("error reading omap key %s: %s", key
.c_str(), cpp_strerror(r
).c_str());
173 auto it
= bl
.cbegin();
175 } catch (const buffer::error
&err
) {
176 CLS_ERR("error decoding %s", key
.c_str());
183 template <typename T
>
184 static int write_key(cls_method_context_t hctx
, const string
&key
, const T
&t
) {
188 int r
= cls_cxx_map_set_val(hctx
, key
, &bl
);
190 CLS_ERR("failed to set omap key: %s", key
.c_str());
196 template <typename T
>
197 static int write_key(cls_method_context_t hctx
, const string
&key
, const T
&t
,
200 encode(t
, bl
, features
);
202 int r
= cls_cxx_map_set_val(hctx
, key
, &bl
);
204 CLS_ERR("failed to set omap key: %s", key
.c_str());
210 static int remove_key(cls_method_context_t hctx
, const string
&key
) {
211 int r
= cls_cxx_map_remove_key(hctx
, key
);
212 if (r
< 0 && r
!= -ENOENT
) {
213 CLS_ERR("failed to remove key: %s", key
.c_str());
219 static bool is_valid_id(const string
&id
) {
222 for (size_t i
= 0; i
< id
.size(); ++i
) {
223 if (!isalnum(id
[i
])) {
231 * verify that the header object exists
233 * @return 0 if the object exists, -ENOENT if it does not, or other error
235 static int check_exists(cls_method_context_t hctx
)
239 return cls_cxx_stat(hctx
, &size
, &mtime
);
245 * check that given feature(s) are set
247 * @param hctx context
248 * @param need features needed
249 * @return 0 if features are set, negative error (like ENOEXEC) otherwise
251 int require_feature(cls_method_context_t hctx
, uint64_t need
)
254 int r
= read_key(hctx
, "features", &features
);
255 if (r
== -ENOENT
) // this implies it's an old-style image with no features
259 if ((features
& need
) != need
) {
260 CLS_LOG(10, "require_feature missing feature %llx, have %llx",
261 (unsigned long long)need
, (unsigned long long)features
);
267 std::string
snap_children_key_from_snap_id(snapid_t snap_id
)
270 oss
<< RBD_SNAP_CHILDREN_KEY_PREFIX
271 << std::setw(16) << std::setfill('0') << std::hex
<< snap_id
;
275 int set_op_features(cls_method_context_t hctx
, uint64_t op_features
,
277 uint64_t orig_features
;
278 int r
= read_key(hctx
, "features", &orig_features
);
280 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
284 uint64_t orig_op_features
= 0;
285 r
= read_key(hctx
, "op_features", &orig_op_features
);
286 if (r
< 0 && r
!= -ENOENT
) {
287 CLS_ERR("Could not read op features off disk: %s", cpp_strerror(r
).c_str());
291 op_features
= (orig_op_features
& ~mask
) | (op_features
& mask
);
292 CLS_LOG(10, "op_features=%" PRIu64
" orig_op_features=%" PRIu64
,
293 op_features
, orig_op_features
);
294 if (op_features
== orig_op_features
) {
298 uint64_t features
= orig_features
;
299 if (op_features
== 0ULL) {
300 features
&= ~RBD_FEATURE_OPERATIONS
;
302 r
= cls_cxx_map_remove_key(hctx
, "op_features");
307 features
|= RBD_FEATURE_OPERATIONS
;
310 encode(op_features
, bl
);
311 r
= cls_cxx_map_set_val(hctx
, "op_features", &bl
);
315 CLS_ERR("error updating op features: %s", cpp_strerror(r
).c_str());
319 if (features
!= orig_features
) {
321 encode(features
, bl
);
322 r
= cls_cxx_map_set_val(hctx
, "features", &bl
);
324 CLS_ERR("error updating features: %s", cpp_strerror(r
).c_str());
332 int set_migration(cls_method_context_t hctx
,
333 const cls::rbd::MigrationSpec
&migration_spec
, bool init
) {
336 int r
= cls_cxx_map_get_val(hctx
, "migration", &bl
);
339 CLS_LOG(10, "migration already set");
342 CLS_ERR("failed to read migration off disk: %s", cpp_strerror(r
).c_str());
346 uint64_t features
= 0;
347 r
= read_key(hctx
, "features", &features
);
349 CLS_LOG(20, "no features, assuming v1 format");
351 r
= cls_cxx_read(hctx
, 0, sizeof(RBD_HEADER_TEXT
), &header
);
353 CLS_ERR("failed to read v1 header: %s", cpp_strerror(r
).c_str());
356 if (header
.length() != sizeof(RBD_HEADER_TEXT
)) {
357 CLS_ERR("unrecognized v1 header format");
360 if (memcmp(RBD_HEADER_TEXT
, header
.c_str(), header
.length()) != 0) {
361 if (memcmp(RBD_MIGRATE_HEADER_TEXT
, header
.c_str(),
362 header
.length()) == 0) {
363 CLS_LOG(10, "migration already set");
366 CLS_ERR("unrecognized v1 header format");
370 if (migration_spec
.header_type
!= cls::rbd::MIGRATION_HEADER_TYPE_SRC
) {
371 CLS_LOG(10, "v1 format image can only be migration source");
376 header
.append(RBD_MIGRATE_HEADER_TEXT
);
377 r
= cls_cxx_write(hctx
, 0, header
.length(), &header
);
379 CLS_ERR("error updating v1 header: %s", cpp_strerror(r
).c_str());
383 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
385 } else if ((features
& RBD_FEATURE_MIGRATING
) != 0ULL) {
386 if (migration_spec
.header_type
!= cls::rbd::MIGRATION_HEADER_TYPE_DST
) {
387 CLS_LOG(10, "migrating feature already set");
391 features
|= RBD_FEATURE_MIGRATING
;
393 encode(features
, bl
);
394 r
= cls_cxx_map_set_val(hctx
, "features", &bl
);
396 CLS_ERR("error updating features: %s", cpp_strerror(r
).c_str());
403 encode(migration_spec
, bl
);
404 int r
= cls_cxx_map_set_val(hctx
, "migration", &bl
);
406 CLS_ERR("error setting migration: %s", cpp_strerror(r
).c_str());
413 int read_migration(cls_method_context_t hctx
,
414 cls::rbd::MigrationSpec
*migration_spec
) {
415 uint64_t features
= 0;
416 int r
= read_key(hctx
, "features", &features
);
418 CLS_LOG(20, "no features, assuming v1 format");
420 r
= cls_cxx_read(hctx
, 0, sizeof(RBD_HEADER_TEXT
), &header
);
422 CLS_ERR("failed to read v1 header: %s", cpp_strerror(r
).c_str());
425 if (header
.length() != sizeof(RBD_HEADER_TEXT
)) {
426 CLS_ERR("unrecognized v1 header format");
429 if (memcmp(RBD_MIGRATE_HEADER_TEXT
, header
.c_str(), header
.length()) != 0) {
430 if (memcmp(RBD_HEADER_TEXT
, header
.c_str(), header
.length()) == 0) {
431 CLS_LOG(10, "migration feature not set");
434 CLS_ERR("unrecognized v1 header format");
438 if (migration_spec
->header_type
!= cls::rbd::MIGRATION_HEADER_TYPE_SRC
) {
439 CLS_LOG(10, "v1 format image can only be migration source");
443 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
445 } else if ((features
& RBD_FEATURE_MIGRATING
) == 0ULL) {
446 CLS_LOG(10, "migration feature not set");
450 r
= read_key(hctx
, "migration", migration_spec
);
452 CLS_ERR("failed to read migration off disk: %s", cpp_strerror(r
).c_str());
459 int remove_migration(cls_method_context_t hctx
) {
460 int r
= remove_key(hctx
, "migration");
465 uint64_t features
= 0;
466 r
= read_key(hctx
, "features", &features
);
468 CLS_LOG(20, "no features, assuming v1 format");
470 r
= cls_cxx_read(hctx
, 0, sizeof(RBD_MIGRATE_HEADER_TEXT
), &header
);
471 if (header
.length() != sizeof(RBD_MIGRATE_HEADER_TEXT
)) {
472 CLS_ERR("unrecognized v1 header format");
475 if (memcmp(RBD_MIGRATE_HEADER_TEXT
, header
.c_str(), header
.length()) != 0) {
476 if (memcmp(RBD_HEADER_TEXT
, header
.c_str(), header
.length()) == 0) {
477 CLS_LOG(10, "migration feature not set");
480 CLS_ERR("unrecognized v1 header format");
485 header
.append(RBD_HEADER_TEXT
);
486 r
= cls_cxx_write(hctx
, 0, header
.length(), &header
);
488 CLS_ERR("error updating v1 header: %s", cpp_strerror(r
).c_str());
492 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
494 } else if ((features
& RBD_FEATURE_MIGRATING
) == 0ULL) {
495 CLS_LOG(10, "migrating feature not set");
497 features
&= ~RBD_FEATURE_MIGRATING
;
499 encode(features
, bl
);
500 r
= cls_cxx_map_set_val(hctx
, "features", &bl
);
502 CLS_ERR("error updating features: %s", cpp_strerror(r
).c_str());
513 int iterate(cls_method_context_t hctx
, L
& lambda
) {
514 int max_read
= RBD_MAX_KEYS_READ
;
515 string last_read
= RBD_SNAP_KEY_PREFIX
;
518 map
<string
, bufferlist
> vals
;
519 int r
= cls_cxx_map_get_vals(hctx
, last_read
, RBD_SNAP_KEY_PREFIX
,
520 max_read
, &vals
, &more
);
525 cls_rbd_snap snap_meta
;
526 for (auto& val
: vals
) {
527 auto iter
= val
.second
.cbegin();
529 decode(snap_meta
, iter
);
530 } catch (const buffer::error
&err
) {
531 CLS_ERR("error decoding snapshot metadata for snap : %s",
536 r
= lambda(snap_meta
);
543 last_read
= vals
.rbegin()->first
;
550 int write(cls_method_context_t hctx
, const std::string
& snap_key
,
551 cls_rbd_snap
&& snap
) {
553 uint64_t encode_features
= get_encode_features(hctx
);
554 if (snap
.migrate_parent_format(encode_features
)) {
555 // ensure the normalized parent link exists before removing it from the
557 cls_rbd_parent on_disk_parent
;
558 r
= read_key(hctx
, "parent", &on_disk_parent
);
559 if (r
< 0 && r
!= -ENOENT
) {
563 if (!on_disk_parent
.exists()) {
564 on_disk_parent
= snap
.parent
;
565 on_disk_parent
.head_overlap
= std::nullopt
;
567 r
= write_key(hctx
, "parent", on_disk_parent
, encode_features
);
573 // only store the parent overlap in the snapshot
574 snap
.parent_overlap
= snap
.parent
.head_overlap
;
578 r
= write_key(hctx
, snap_key
, snap
, encode_features
);
585 } // namespace snapshot
589 int attach(cls_method_context_t hctx
, cls_rbd_parent parent
,
591 int r
= check_exists(hctx
);
593 CLS_LOG(20, "cls_rbd::image::parent::attach: child doesn't exist");
597 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
599 CLS_LOG(20, "cls_rbd::image::parent::attach: child does not support "
604 CLS_LOG(20, "cls_rbd::image::parent::attach: pool=%" PRIi64
", ns=%s, id=%s, "
605 "snapid=%" PRIu64
", size=%" PRIu64
,
606 parent
.pool_id
, parent
.pool_namespace
.c_str(),
607 parent
.image_id
.c_str(), parent
.snap_id
.val
,
608 parent
.head_overlap
.value_or(0ULL));
609 if (!parent
.exists() || parent
.head_overlap
.value_or(0ULL) == 0ULL) {
613 // make sure there isn't already a parent
614 cls_rbd_parent on_disk_parent
;
615 r
= read_key(hctx
, "parent", &on_disk_parent
);
616 if (r
< 0 && r
!= -ENOENT
) {
620 auto on_disk_parent_without_overlap
{on_disk_parent
};
621 on_disk_parent_without_overlap
.head_overlap
= parent
.head_overlap
;
624 (on_disk_parent
.head_overlap
||
625 on_disk_parent_without_overlap
!= parent
) &&
627 CLS_LOG(20, "cls_rbd::parent::attach: existing legacy parent "
628 "pool=%" PRIi64
", ns=%s, id=%s, snapid=%" PRIu64
", "
630 on_disk_parent
.pool_id
, on_disk_parent
.pool_namespace
.c_str(),
631 on_disk_parent
.image_id
.c_str(), on_disk_parent
.snap_id
.val
,
632 on_disk_parent
.head_overlap
.value_or(0ULL));
636 // our overlap is the min of our size and the parent's size.
638 r
= read_key(hctx
, "size", &our_size
);
643 parent
.head_overlap
= std::min(*parent
.head_overlap
, our_size
);
645 r
= write_key(hctx
, "parent", parent
, get_encode_features(hctx
));
653 int detach(cls_method_context_t hctx
, bool legacy_api
) {
654 int r
= check_exists(hctx
);
656 CLS_LOG(20, "cls_rbd::parent::detach: child doesn't exist");
661 r
= read_key(hctx
, "features", &features
);
662 if (r
== -ENOENT
|| ((features
& RBD_FEATURE_LAYERING
) == 0)) {
663 CLS_LOG(20, "cls_rbd::image::parent::detach: child does not support "
670 cls_rbd_parent on_disk_parent
;
671 r
= read_key(hctx
, "parent", &on_disk_parent
);
674 } else if (legacy_api
&& !on_disk_parent
.pool_namespace
.empty()) {
676 } else if (!on_disk_parent
.head_overlap
) {
680 auto detach_lambda
= [hctx
, features
](const cls_rbd_snap
& snap_meta
) {
681 if (snap_meta
.parent
.pool_id
!= -1 || snap_meta
.parent_overlap
) {
682 if ((features
& RBD_FEATURE_DEEP_FLATTEN
) != 0ULL) {
683 // remove parent reference from snapshot
684 cls_rbd_snap snap_meta_copy
= snap_meta
;
685 snap_meta_copy
.parent
= {};
686 snap_meta_copy
.parent_overlap
= std::nullopt
;
688 std::string snap_key
;
689 key_from_snap_id(snap_meta_copy
.id
, &snap_key
);
690 int r
= snapshot::write(hctx
, snap_key
, std::move(snap_meta_copy
));
701 r
= snapshot::iterate(hctx
, detach_lambda
);
702 bool has_child_snaps
= (r
== -EEXIST
);
703 if (r
< 0 && r
!= -EEXIST
) {
707 int8_t require_osd_release
= cls_get_required_osd_release(hctx
);
708 if (has_child_snaps
&& require_osd_release
>= CEPH_RELEASE_NAUTILUS
) {
709 // remove overlap from HEAD revision but keep spec for snapshots
710 on_disk_parent
.head_overlap
= std::nullopt
;
711 r
= write_key(hctx
, "parent", on_disk_parent
, get_encode_features(hctx
));
716 r
= remove_key(hctx
, "parent");
717 if (r
< 0 && r
!= -ENOENT
) {
722 if (!has_child_snaps
) {
723 // disable clone child op feature if no longer associated
724 r
= set_op_features(hctx
, 0, RBD_OPERATION_FEATURE_CLONE_CHILD
);
732 } // namespace parent
736 * Initialize the header with basic metadata.
737 * Extra features may initialize more fields in the future.
738 * Everything is stored as key/value pairs as omaps in the header object.
740 * If features the OSD does not understand are requested, -ENOSYS is
744 * @param size number of bytes in the image (uint64_t)
745 * @param order bits to shift to determine the size of data objects (uint8_t)
746 * @param features what optional things this image will use (uint64_t)
747 * @param object_prefix a prefix for all the data objects
748 * @param data_pool_id pool id where data objects is stored (int64_t)
751 * @return 0 on success, negative error code on failure
753 int create(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
755 string object_prefix
;
756 uint64_t features
, size
;
758 int64_t data_pool_id
= -1;
761 auto iter
= in
->cbegin();
764 decode(features
, iter
);
765 decode(object_prefix
, iter
);
767 decode(data_pool_id
, iter
);
769 } catch (const buffer::error
&err
) {
773 CLS_LOG(20, "create object_prefix=%s size=%llu order=%u features=%llu",
774 object_prefix
.c_str(), (unsigned long long)size
, order
,
775 (unsigned long long)features
);
777 if (features
& ~RBD_FEATURES_ALL
) {
781 if (!object_prefix
.size()) {
785 bufferlist stored_prefixbl
;
786 int r
= cls_cxx_map_get_val(hctx
, "object_prefix", &stored_prefixbl
);
788 CLS_ERR("reading object_prefix returned %d", r
);
794 bufferlist featuresbl
;
795 bufferlist object_prefixbl
;
796 bufferlist snap_seqbl
;
797 bufferlist timestampbl
;
798 uint64_t snap_seq
= 0;
799 utime_t timestamp
= ceph_clock_now();
800 encode(size
, sizebl
);
801 encode(order
, orderbl
);
802 encode(features
, featuresbl
);
803 encode(object_prefix
, object_prefixbl
);
804 encode(snap_seq
, snap_seqbl
);
805 encode(timestamp
, timestampbl
);
807 map
<string
, bufferlist
> omap_vals
;
808 omap_vals
["size"] = sizebl
;
809 omap_vals
["order"] = orderbl
;
810 omap_vals
["features"] = featuresbl
;
811 omap_vals
["object_prefix"] = object_prefixbl
;
812 omap_vals
["snap_seq"] = snap_seqbl
;
813 omap_vals
["create_timestamp"] = timestampbl
;
814 omap_vals
["access_timestamp"] = timestampbl
;
815 omap_vals
["modify_timestamp"] = timestampbl
;
817 if ((features
& RBD_FEATURE_OPERATIONS
) != 0ULL) {
818 CLS_ERR("Attempting to set internal feature: operations");
822 if (features
& RBD_FEATURE_DATA_POOL
) {
823 if (data_pool_id
== -1) {
824 CLS_ERR("data pool not provided with feature enabled");
828 bufferlist data_pool_id_bl
;
829 encode(data_pool_id
, data_pool_id_bl
);
830 omap_vals
["data_pool_id"] = data_pool_id_bl
;
831 } else if (data_pool_id
!= -1) {
832 CLS_ERR("data pool provided with feature disabled");
836 r
= cls_cxx_map_set_vals(hctx
, &omap_vals
);
845 * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t) (deprecated)
846 * @param read_only true if the image will be used read-only (bool)
849 * @param features list of enabled features for the given snapshot (uint64_t)
850 * @param incompatible incompatible feature bits
851 * @returns 0 on success, negative error code on failure
853 int get_features(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
855 bool read_only
= false;
857 auto iter
= in
->cbegin();
860 decode(snap_id
, iter
);
862 decode(read_only
, iter
);
864 } catch (const buffer::error
&err
) {
868 CLS_LOG(20, "get_features read_only=%d", read_only
);
871 int r
= read_key(hctx
, "features", &features
);
873 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
877 uint64_t incompatible
= (read_only
? features
& RBD_FEATURES_INCOMPATIBLE
:
878 features
& RBD_FEATURES_RW_INCOMPATIBLE
);
879 encode(features
, *out
);
880 encode(incompatible
, *out
);
885 * set the image features
888 * @param features image features
889 * @param mask image feature mask
894 * @returns 0 on success, negative error code upon failure
896 int set_features(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
900 auto iter
= in
->cbegin();
902 decode(features
, iter
);
904 } catch (const buffer::error
&err
) {
908 // check that features exists to make sure this is a header object
909 // that was created correctly
910 uint64_t orig_features
= 0;
911 int r
= read_key(hctx
, "features", &orig_features
);
912 if (r
< 0 && r
!= -ENOENT
) {
913 CLS_ERR("Could not read image's features off disk: %s",
914 cpp_strerror(r
).c_str());
918 if ((mask
& RBD_FEATURES_INTERNAL
) != 0ULL) {
919 CLS_ERR("Attempting to set internal feature: %" PRIu64
,
920 static_cast<uint64_t>(mask
& RBD_FEATURES_INTERNAL
));
924 // newer clients might attempt to mask off features we don't support
925 mask
&= RBD_FEATURES_ALL
;
927 uint64_t enabled_features
= features
& mask
;
928 if ((enabled_features
& RBD_FEATURES_MUTABLE
) != enabled_features
) {
929 CLS_ERR("Attempting to enable immutable feature: %" PRIu64
,
930 static_cast<uint64_t>(enabled_features
& ~RBD_FEATURES_MUTABLE
));
934 uint64_t disabled_features
= ~features
& mask
;
935 uint64_t disable_mask
= (RBD_FEATURES_MUTABLE
| RBD_FEATURES_DISABLE_ONLY
);
936 if ((disabled_features
& disable_mask
) != disabled_features
) {
937 CLS_ERR("Attempting to disable immutable feature: %" PRIu64
,
938 enabled_features
& ~disable_mask
);
942 features
= (orig_features
& ~mask
) | (features
& mask
);
943 CLS_LOG(10, "set_features features=%" PRIu64
" orig_features=%" PRIu64
,
944 features
, orig_features
);
947 encode(features
, bl
);
948 r
= cls_cxx_map_set_val(hctx
, "features", &bl
);
950 CLS_ERR("error updating features: %s", cpp_strerror(r
).c_str());
958 * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t)
961 * @param order bits to shift to get the size of data objects (uint8_t)
962 * @param size size of the image in bytes for the given snapshot (uint64_t)
963 * @returns 0 on success, negative error code on failure
965 int get_size(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
967 uint64_t snap_id
, size
;
970 auto iter
= in
->cbegin();
972 decode(snap_id
, iter
);
973 } catch (const buffer::error
&err
) {
977 CLS_LOG(20, "get_size snap_id=%llu", (unsigned long long)snap_id
);
979 int r
= read_key(hctx
, "order", &order
);
981 CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r
).c_str());
985 if (snap_id
== CEPH_NOSNAP
) {
986 r
= read_key(hctx
, "size", &size
);
988 CLS_ERR("failed to read the image's size off of disk: %s", cpp_strerror(r
).c_str());
994 key_from_snap_id(snap_id
, &snapshot_key
);
995 int r
= read_key(hctx
, snapshot_key
, &snap
);
999 size
= snap
.image_size
;
1002 encode(order
, *out
);
1010 * @param size new capacity of the image in bytes (uint64_t)
1013 * @returns 0 on success, negative error code on failure
1015 int set_size(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1019 auto iter
= in
->cbegin();
1022 } catch (const buffer::error
&err
) {
1026 // check that size exists to make sure this is a header object
1027 // that was created correctly
1029 int r
= read_key(hctx
, "size", &orig_size
);
1031 CLS_ERR("Could not read image's size off disk: %s", cpp_strerror(r
).c_str());
1035 CLS_LOG(20, "set_size size=%llu orig_size=%llu", (unsigned long long)size
,
1036 (unsigned long long)orig_size
);
1039 encode(size
, sizebl
);
1040 r
= cls_cxx_map_set_val(hctx
, "size", &sizebl
);
1042 CLS_ERR("error writing snapshot metadata: %s", cpp_strerror(r
).c_str());
1046 // if we are shrinking, and have a parent, shrink our overlap with
1048 if (size
< orig_size
) {
1049 cls_rbd_parent parent
;
1050 r
= read_key(hctx
, "parent", &parent
);
1055 if (parent
.exists() && parent
.head_overlap
.value_or(0ULL) > size
) {
1056 parent
.head_overlap
= size
;
1057 r
= write_key(hctx
, "parent", parent
, get_encode_features(hctx
));
1068 * get the current protection status of the specified snapshot
1071 * @param snap_id (uint64_t) which snapshot to get the status of
1074 * @param status (uint8_t) one of:
1075 * RBD_PROTECTION_STATUS_{PROTECTED, UNPROTECTED, UNPROTECTING}
1077 * @returns 0 on success, negative error code on failure
1078 * @returns -EINVAL if snapid is CEPH_NOSNAP
1080 int get_protection_status(cls_method_context_t hctx
, bufferlist
*in
,
1085 auto iter
= in
->cbegin();
1087 decode(snap_id
, iter
);
1088 } catch (const buffer::error
&err
) {
1089 CLS_LOG(20, "get_protection_status: invalid decode");
1093 int r
= check_exists(hctx
);
1097 CLS_LOG(20, "get_protection_status snap_id=%llu",
1098 (unsigned long long)snap_id
.val
);
1100 if (snap_id
== CEPH_NOSNAP
)
1104 string snapshot_key
;
1105 key_from_snap_id(snap_id
.val
, &snapshot_key
);
1106 r
= read_key(hctx
, snapshot_key
, &snap
);
1108 CLS_ERR("could not read key for snapshot id %" PRIu64
, snap_id
.val
);
1112 if (snap
.protection_status
>= RBD_PROTECTION_STATUS_LAST
) {
1113 CLS_ERR("invalid protection status for snap id %llu: %u",
1114 (unsigned long long)snap_id
.val
, snap
.protection_status
);
1118 encode(snap
.protection_status
, *out
);
1123 * set the proctection status of a snapshot
1126 * @param snapid (uint64_t) which snapshot to set the status of
1127 * @param status (uint8_t) one of:
1128 * RBD_PROTECTION_STATUS_{PROTECTED, UNPROTECTED, UNPROTECTING}
1130 * @returns 0 on success, negative error code on failure
1131 * @returns -EINVAL if snapid is CEPH_NOSNAP
1133 int set_protection_status(cls_method_context_t hctx
, bufferlist
*in
,
1139 auto iter
= in
->cbegin();
1141 decode(snap_id
, iter
);
1142 decode(status
, iter
);
1143 } catch (const buffer::error
&err
) {
1144 CLS_LOG(20, "set_protection_status: invalid decode");
1148 int r
= check_exists(hctx
);
1152 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
1154 CLS_LOG(20, "image does not support layering");
1158 CLS_LOG(20, "set_protection_status snapid=%llu status=%u",
1159 (unsigned long long)snap_id
.val
, status
);
1161 if (snap_id
== CEPH_NOSNAP
)
1164 if (status
>= RBD_PROTECTION_STATUS_LAST
) {
1165 CLS_LOG(10, "invalid protection status for snap id %llu: %u",
1166 (unsigned long long)snap_id
.val
, status
);
1171 string snapshot_key
;
1172 key_from_snap_id(snap_id
.val
, &snapshot_key
);
1173 r
= read_key(hctx
, snapshot_key
, &snap
);
1175 CLS_ERR("could not read key for snapshot id %" PRIu64
, snap_id
.val
);
1179 snap
.protection_status
= status
;
1180 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap
));
1189 * get striping parameters
1195 * @param stripe unit (bytes)
1196 * @param stripe count (num objects)
1198 * @returns 0 on success
1200 int get_stripe_unit_count(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1202 int r
= check_exists(hctx
);
1206 CLS_LOG(20, "get_stripe_unit_count");
1208 r
= image::require_feature(hctx
, RBD_FEATURE_STRIPINGV2
);
1212 uint64_t stripe_unit
= 0, stripe_count
= 0;
1213 r
= read_key(hctx
, "stripe_unit", &stripe_unit
);
1215 // default to object size
1217 r
= read_key(hctx
, "order", &order
);
1219 CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r
).c_str());
1222 stripe_unit
= 1ull << order
;
1226 r
= read_key(hctx
, "stripe_count", &stripe_count
);
1235 encode(stripe_unit
, *out
);
1236 encode(stripe_count
, *out
);
1241 * set striping parameters
1244 * @param stripe unit (bytes)
1245 * @param stripe count (num objects)
1247 * @returns 0 on success
1249 int set_stripe_unit_count(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1251 uint64_t stripe_unit
, stripe_count
;
1253 auto iter
= in
->cbegin();
1255 decode(stripe_unit
, iter
);
1256 decode(stripe_count
, iter
);
1257 } catch (const buffer::error
&err
) {
1258 CLS_LOG(20, "set_stripe_unit_count: invalid decode");
1262 if (!stripe_count
|| !stripe_unit
)
1265 int r
= check_exists(hctx
);
1269 CLS_LOG(20, "set_stripe_unit_count");
1271 r
= image::require_feature(hctx
, RBD_FEATURE_STRIPINGV2
);
1276 r
= read_key(hctx
, "order", &order
);
1278 CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r
).c_str());
1281 if ((1ull << order
) % stripe_unit
|| stripe_unit
> (1ull << order
)) {
1282 CLS_ERR("stripe unit %llu is not a factor of the object size %llu",
1283 (unsigned long long)stripe_unit
, 1ull << order
);
1288 encode(stripe_unit
, bl
);
1289 r
= cls_cxx_map_set_val(hctx
, "stripe_unit", &bl
);
1291 CLS_ERR("error writing stripe_unit metadata: %s", cpp_strerror(r
).c_str());
1295 encode(stripe_count
, bl2
);
1296 r
= cls_cxx_map_set_val(hctx
, "stripe_count", &bl2
);
1298 CLS_ERR("error writing stripe_count metadata: %s", cpp_strerror(r
).c_str());
1305 int get_create_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1307 CLS_LOG(20, "get_create_timestamp");
1311 int r
= cls_cxx_map_get_val(hctx
, "create_timestamp", &bl
);
1314 CLS_ERR("error reading create_timestamp: %s", cpp_strerror(r
).c_str());
1319 auto it
= bl
.cbegin();
1320 decode(timestamp
, it
);
1321 } catch (const buffer::error
&err
) {
1322 CLS_ERR("could not decode create_timestamp");
1327 encode(timestamp
, *out
);
1332 * get the image access timestamp
1338 * @param timestamp the image access timestamp
1340 * @returns 0 on success, negative error code upon failure
1342 int get_access_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1344 CLS_LOG(20, "get_access_timestamp");
1348 int r
= cls_cxx_map_get_val(hctx
, "access_timestamp", &bl
);
1351 CLS_ERR("error reading access_timestamp: %s", cpp_strerror(r
).c_str());
1356 auto it
= bl
.cbegin();
1357 decode(timestamp
, it
);
1358 } catch (const buffer::error
&err
) {
1359 CLS_ERR("could not decode access_timestamp");
1364 encode(timestamp
, *out
);
1369 * get the image modify timestamp
1375 * @param timestamp the image modify timestamp
1377 * @returns 0 on success, negative error code upon failure
1379 int get_modify_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1381 CLS_LOG(20, "get_modify_timestamp");
1385 int r
= cls_cxx_map_get_val(hctx
, "modify_timestamp", &bl
);
1388 CLS_ERR("error reading modify_timestamp: %s", cpp_strerror(r
).c_str());
1393 auto it
= bl
.cbegin();
1394 decode(timestamp
, it
);
1395 } catch (const buffer::error
&err
) {
1396 CLS_ERR("could not decode modify_timestamp");
1401 encode(timestamp
, *out
);
1407 * get the image flags
1410 * @param snap_id which snapshot to query, to CEPH_NOSNAP (uint64_t)
1413 * @param flags image flags
1415 * @returns 0 on success, negative error code upon failure
1417 int get_flags(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1420 auto iter
= in
->cbegin();
1422 decode(snap_id
, iter
);
1423 } catch (const buffer::error
&err
) {
1427 CLS_LOG(20, "get_flags snap_id=%llu", (unsigned long long)snap_id
);
1430 if (snap_id
== CEPH_NOSNAP
) {
1431 int r
= read_key(hctx
, "flags", &flags
);
1432 if (r
< 0 && r
!= -ENOENT
) {
1433 CLS_ERR("failed to read flags off disk: %s", cpp_strerror(r
).c_str());
1438 string snapshot_key
;
1439 key_from_snap_id(snap_id
, &snapshot_key
);
1440 int r
= read_key(hctx
, snapshot_key
, &snap
);
1447 encode(flags
, *out
);
1452 * set the image flags
1455 * @param flags image flags
1456 * @param mask image flag mask
1457 * @param snap_id which snapshot to update, or CEPH_NOSNAP (uint64_t)
1462 * @returns 0 on success, negative error code upon failure
1464 int set_flags(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1468 uint64_t snap_id
= CEPH_NOSNAP
;
1469 auto iter
= in
->cbegin();
1471 decode(flags
, iter
);
1474 decode(snap_id
, iter
);
1476 } catch (const buffer::error
&err
) {
1480 // check that size exists to make sure this is a header object
1481 // that was created correctly
1483 uint64_t orig_flags
= 0;
1484 cls_rbd_snap snap_meta
;
1485 string snap_meta_key
;
1486 if (snap_id
== CEPH_NOSNAP
) {
1487 r
= read_key(hctx
, "flags", &orig_flags
);
1488 if (r
< 0 && r
!= -ENOENT
) {
1489 CLS_ERR("Could not read image's flags off disk: %s",
1490 cpp_strerror(r
).c_str());
1494 key_from_snap_id(snap_id
, &snap_meta_key
);
1495 r
= read_key(hctx
, snap_meta_key
, &snap_meta
);
1497 CLS_ERR("Could not read snapshot: snap_id=%" PRIu64
": %s",
1498 snap_id
, cpp_strerror(r
).c_str());
1501 orig_flags
= snap_meta
.flags
;
1504 flags
= (orig_flags
& ~mask
) | (flags
& mask
);
1505 CLS_LOG(20, "set_flags snap_id=%" PRIu64
", orig_flags=%" PRIu64
", "
1506 "new_flags=%" PRIu64
", mask=%" PRIu64
, snap_id
, orig_flags
,
1509 if (snap_id
== CEPH_NOSNAP
) {
1510 r
= write_key(hctx
, "flags", flags
);
1512 snap_meta
.flags
= flags
;
1513 r
= image::snapshot::write(hctx
, snap_meta_key
, std::move(snap_meta
));
1523 * Get the operation-based image features
1528 * @param bitmask of enabled op features (uint64_t)
1529 * @returns 0 on success, negative error code on failure
1531 int op_features_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1533 CLS_LOG(20, "op_features_get");
1535 uint64_t op_features
= 0;
1536 int r
= read_key(hctx
, "op_features", &op_features
);
1537 if (r
< 0 && r
!= -ENOENT
) {
1538 CLS_ERR("failed to read op features off disk: %s", cpp_strerror(r
).c_str());
1542 encode(op_features
, *out
);
1547 * Set the operation-based image features
1550 * @param op_features image op features
1551 * @param mask image op feature mask
1556 * @returns 0 on success, negative error code upon failure
1558 int op_features_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1560 uint64_t op_features
;
1562 auto iter
= in
->cbegin();
1564 decode(op_features
, iter
);
1566 } catch (const buffer::error
&err
) {
1570 uint64_t unsupported_op_features
= (mask
& ~RBD_OPERATION_FEATURES_ALL
);
1571 if (unsupported_op_features
!= 0ULL) {
1572 CLS_ERR("unsupported op features: %" PRIu64
, unsupported_op_features
);
1576 return image::set_op_features(hctx
, op_features
, mask
);
1580 * get the current parent, if any
1583 * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t)
1586 * @param pool parent pool id (-1 if parent does not exist)
1587 * @param image parent image id
1588 * @param snapid parent snapid
1589 * @param size portion of parent mapped under the child
1591 * @returns 0 on success or parent does not exist, negative error code on failure
1593 int get_parent(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1597 auto iter
= in
->cbegin();
1599 decode(snap_id
, iter
);
1600 } catch (const buffer::error
&err
) {
1604 int r
= check_exists(hctx
);
1609 CLS_LOG(20, "get_parent snap_id=%" PRIu64
, snap_id
);
1611 cls_rbd_parent parent
;
1612 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
1614 r
= read_key(hctx
, "parent", &parent
);
1615 if (r
< 0 && r
!= -ENOENT
) {
1617 } else if (!parent
.pool_namespace
.empty()) {
1621 if (snap_id
!= CEPH_NOSNAP
) {
1623 std::string snapshot_key
;
1624 key_from_snap_id(snap_id
, &snapshot_key
);
1625 r
= read_key(hctx
, snapshot_key
, &snap
);
1626 if (r
< 0 && r
!= -ENOENT
) {
1630 if (snap
.parent
.exists()) {
1631 // legacy format where full parent spec is written within
1632 // each snapshot record
1633 parent
= snap
.parent
;
1634 } else if (snap
.parent_overlap
) {
1635 // normalized parent reference
1636 if (!parent
.exists()) {
1637 CLS_ERR("get_parent: snap_id=%" PRIu64
": invalid parent spec",
1641 parent
.head_overlap
= *snap
.parent_overlap
;
1643 // snapshot doesn't have associated parent
1649 encode(parent
.pool_id
, *out
);
1650 encode(parent
.image_id
, *out
);
1651 encode(parent
.snap_id
, *out
);
1652 encode(parent
.head_overlap
.value_or(0ULL), *out
);
1657 * set the image parent
1660 * @param pool parent pool
1661 * @param id parent image id
1662 * @param snapid parent snapid
1663 * @param size parent size
1665 * @returns 0 on success, or negative error code
1667 int set_parent(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1669 cls_rbd_parent parent
;
1670 auto iter
= in
->cbegin();
1672 decode(parent
.pool_id
, iter
);
1673 decode(parent
.image_id
, iter
);
1674 decode(parent
.snap_id
, iter
);
1677 decode(overlap
, iter
);
1678 parent
.head_overlap
= overlap
;
1679 } catch (const buffer::error
&err
) {
1680 CLS_LOG(20, "cls_rbd::set_parent: invalid decode");
1684 int r
= image::parent::attach(hctx
, parent
, false);
1694 * remove the parent pointer
1696 * This can only happen on the head, not on a snapshot. No arguments.
1698 * @returns 0 on success, negative error code on failure.
1700 int remove_parent(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1702 int r
= image::parent::detach(hctx
, true);
1715 * @param parent spec (cls::rbd::ParentImageSpec)
1716 * @returns 0 on success, negative error code on failure
1718 int parent_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
1719 int r
= check_exists(hctx
);
1724 CLS_LOG(20, "parent_get");
1726 cls_rbd_parent parent
;
1727 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
1729 r
= read_key(hctx
, "parent", &parent
);
1730 if (r
< 0 && r
!= -ENOENT
) {
1732 } else if (r
== -ENOENT
) {
1733 // examine oldest snapshot to see if it has a denormalized parent
1734 auto parent_lambda
= [hctx
, &parent
](const cls_rbd_snap
& snap_meta
) {
1735 if (snap_meta
.parent
.exists()) {
1736 parent
= snap_meta
.parent
;
1741 r
= image::snapshot::iterate(hctx
, parent_lambda
);
1748 cls::rbd::ParentImageSpec parent_image_spec
{
1749 parent
.pool_id
, parent
.pool_namespace
, parent
.image_id
,
1751 encode(parent_image_spec
, *out
);
1757 * @param snap id (uint64_t) parent snapshot id
1760 * @param byte overlap of parent image (std::optional<uint64_t>)
1761 * @returns 0 on success, negative error code on failure
1763 int parent_overlap_get(cls_method_context_t hctx
, bufferlist
*in
,
1766 auto iter
= in
->cbegin();
1768 decode(snap_id
, iter
);
1769 } catch (const buffer::error
&err
) {
1773 int r
= check_exists(hctx
);
1774 CLS_LOG(20, "parent_overlap_get");
1776 std::optional
<uint64_t> parent_overlap
= std::nullopt
;
1777 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
1779 if (snap_id
== CEPH_NOSNAP
) {
1780 cls_rbd_parent parent
;
1781 r
= read_key(hctx
, "parent", &parent
);
1782 if (r
< 0 && r
!= -ENOENT
) {
1784 } else if (r
== 0) {
1785 parent_overlap
= parent
.head_overlap
;
1789 std::string snapshot_key
;
1790 key_from_snap_id(snap_id
, &snapshot_key
);
1791 r
= read_key(hctx
, snapshot_key
, &snap
);
1796 if (snap
.parent_overlap
) {
1797 parent_overlap
= snap
.parent_overlap
;
1798 } else if (snap
.parent
.exists()) {
1799 // legacy format where full parent spec is written within
1800 // each snapshot record
1801 parent_overlap
= snap
.parent
.head_overlap
;
1806 encode(parent_overlap
, *out
);
1812 * @param parent spec (cls::rbd::ParentImageSpec)
1813 * @param size parent size (uint64_t)
1816 * @returns 0 on success, negative error code on failure
1818 int parent_attach(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
1819 cls::rbd::ParentImageSpec parent_image_spec
;
1820 uint64_t parent_overlap
;
1821 bool reattach
= false;
1823 auto iter
= in
->cbegin();
1825 decode(parent_image_spec
, iter
);
1826 decode(parent_overlap
, iter
);
1828 decode(reattach
, iter
);
1830 } catch (const buffer::error
&err
) {
1831 CLS_LOG(20, "cls_rbd::parent_attach: invalid decode");
1835 int r
= image::parent::attach(hctx
, {parent_image_spec
, parent_overlap
},
1849 * @returns 0 on success, negative error code on failure
1851 int parent_detach(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
1852 int r
= image::parent::detach(hctx
, false);
1862 * methods for dealing with rbd_children object
1865 static int decode_parent_common(bufferlist::const_iterator
& it
, uint64_t *pool_id
,
1866 string
*image_id
, snapid_t
*snap_id
)
1869 decode(*pool_id
, it
);
1870 decode(*image_id
, it
);
1871 decode(*snap_id
, it
);
1872 } catch (const buffer::error
&err
) {
1873 CLS_ERR("error decoding parent spec");
1879 static int decode_parent(bufferlist
*in
, uint64_t *pool_id
,
1880 string
*image_id
, snapid_t
*snap_id
)
1882 auto it
= in
->cbegin();
1883 return decode_parent_common(it
, pool_id
, image_id
, snap_id
);
1886 static int decode_parent_and_child(bufferlist
*in
, uint64_t *pool_id
,
1887 string
*image_id
, snapid_t
*snap_id
,
1890 auto it
= in
->cbegin();
1891 int r
= decode_parent_common(it
, pool_id
, image_id
, snap_id
);
1895 decode(*c_image_id
, it
);
1896 } catch (const buffer::error
&err
) {
1897 CLS_ERR("error decoding child image id");
1903 static string
parent_key(uint64_t pool_id
, string image_id
, snapid_t snap_id
)
1906 encode(pool_id
, key_bl
);
1907 encode(image_id
, key_bl
);
1908 encode(snap_id
, key_bl
);
1909 return string(key_bl
.c_str(), key_bl
.length());
1913 * add child to rbd_children directory object
1915 * rbd_children is a map of (p_pool_id, p_image_id, p_snap_id) to
1916 * [c_image_id, [c_image_id ... ]]
1919 * @param p_pool_id parent pool id
1920 * @param p_image_id parent image oid
1921 * @param p_snap_id parent snapshot id
1922 * @param c_image_id new child image oid to add
1924 * @returns 0 on success, negative error on failure
1927 int add_child(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1933 string p_image_id
, c_image_id
;
1934 // Use set for ease of erase() for remove_child()
1935 std::set
<string
> children
;
1937 r
= decode_parent_and_child(in
, &p_pool_id
, &p_image_id
, &p_snap_id
,
1942 CLS_LOG(20, "add_child %s to (%" PRIu64
", %s, %" PRIu64
")", c_image_id
.c_str(),
1943 p_pool_id
, p_image_id
.c_str(), p_snap_id
.val
);
1945 string key
= parent_key(p_pool_id
, p_image_id
, p_snap_id
);
1947 // get current child list for parent, if any
1948 r
= read_key(hctx
, key
, &children
);
1949 if ((r
< 0) && (r
!= -ENOENT
)) {
1950 CLS_LOG(20, "add_child: omap read failed: %s", cpp_strerror(r
).c_str());
1954 if (children
.find(c_image_id
) != children
.end()) {
1955 CLS_LOG(20, "add_child: child already exists: %s", c_image_id
.c_str());
1959 children
.insert(c_image_id
);
1963 encode(children
, childbl
);
1964 r
= cls_cxx_map_set_val(hctx
, key
, &childbl
);
1966 CLS_LOG(20, "add_child: omap write failed: %s", cpp_strerror(r
).c_str());
1971 * remove child from rbd_children directory object
1974 * @param p_pool_id parent pool id
1975 * @param p_image_id parent image oid
1976 * @param p_snap_id parent snapshot id
1977 * @param c_image_id new child image oid to add
1979 * @returns 0 on success, negative error on failure
1982 int remove_child(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1988 string p_image_id
, c_image_id
;
1989 std::set
<string
> children
;
1991 r
= decode_parent_and_child(in
, &p_pool_id
, &p_image_id
, &p_snap_id
,
1996 CLS_LOG(20, "remove_child %s from (%" PRIu64
", %s, %" PRIu64
")",
1997 c_image_id
.c_str(), p_pool_id
, p_image_id
.c_str(),
2000 string key
= parent_key(p_pool_id
, p_image_id
, p_snap_id
);
2002 // get current child list for parent. Unlike add_child(), an empty list
2003 // is an error (how can we remove something that doesn't exist?)
2004 r
= read_key(hctx
, key
, &children
);
2006 CLS_LOG(20, "remove_child: read omap failed: %s", cpp_strerror(r
).c_str());
2010 if (children
.find(c_image_id
) == children
.end()) {
2011 CLS_LOG(20, "remove_child: child not found: %s", c_image_id
.c_str());
2014 // find and remove child
2015 children
.erase(c_image_id
);
2017 // now empty? remove key altogether
2018 if (children
.empty()) {
2019 r
= cls_cxx_map_remove_key(hctx
, key
);
2021 CLS_LOG(20, "remove_child: remove key failed: %s", cpp_strerror(r
).c_str());
2023 // write back shortened children list
2025 encode(children
, childbl
);
2026 r
= cls_cxx_map_set_val(hctx
, key
, &childbl
);
2028 CLS_LOG(20, "remove_child: write omap failed: %s", cpp_strerror(r
).c_str());
2035 * @param p_pool_id parent pool id
2036 * @param p_image_id parent image oid
2037 * @param p_snap_id parent snapshot id
2038 * @param c_image_id new child image oid to add
2041 * @param children set<string> of children
2043 * @returns 0 on success, negative error on failure
2045 int get_children(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2051 std::set
<string
> children
;
2053 r
= decode_parent(in
, &p_pool_id
, &p_image_id
, &p_snap_id
);
2057 CLS_LOG(20, "get_children of (%" PRIu64
", %s, %" PRIu64
")",
2058 p_pool_id
, p_image_id
.c_str(), p_snap_id
.val
);
2060 string key
= parent_key(p_pool_id
, p_image_id
, p_snap_id
);
2062 r
= read_key(hctx
, key
, &children
);
2065 CLS_LOG(20, "get_children: read omap failed: %s", cpp_strerror(r
).c_str());
2068 encode(children
, *out
);
2074 * Get the information needed to create a rados snap context for doing
2075 * I/O to the data objects. This must include all snapshots.
2078 * @param snap_seq the highest snapshot id ever associated with the image (uint64_t)
2079 * @param snap_ids existing snapshot ids in descending order (vector<uint64_t>)
2080 * @returns 0 on success, negative error code on failure
2082 int get_snapcontext(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2084 CLS_LOG(20, "get_snapcontext");
2087 int max_read
= RBD_MAX_KEYS_READ
;
2088 vector
<snapid_t
> snap_ids
;
2089 string last_read
= RBD_SNAP_KEY_PREFIX
;
2094 r
= cls_cxx_map_get_keys(hctx
, last_read
, max_read
, &keys
, &more
);
2098 for (set
<string
>::const_iterator it
= keys
.begin();
2099 it
!= keys
.end(); ++it
) {
2100 if ((*it
).find(RBD_SNAP_KEY_PREFIX
) != 0)
2102 snapid_t snap_id
= snap_id_from_key(*it
);
2103 snap_ids
.push_back(snap_id
);
2106 last_read
= *(keys
.rbegin());
2110 r
= read_key(hctx
, "snap_seq", &snap_seq
);
2112 CLS_ERR("could not read the image's snap_seq off disk: %s", cpp_strerror(r
).c_str());
2116 // snap_ids must be descending in a snap context
2117 std::reverse(snap_ids
.begin(), snap_ids
.end());
2119 encode(snap_seq
, *out
);
2120 encode(snap_ids
, *out
);
2127 * @param object_prefix prefix for data object names (string)
2128 * @returns 0 on success, negative error code on failure
2130 int get_object_prefix(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2132 CLS_LOG(20, "get_object_prefix");
2134 string object_prefix
;
2135 int r
= read_key(hctx
, "object_prefix", &object_prefix
);
2137 CLS_ERR("failed to read the image's object prefix off of disk: %s",
2138 cpp_strerror(r
).c_str());
2142 encode(object_prefix
, *out
);
2152 * @param pool_id (int64_t) of data pool or -1 if none
2153 * @returns 0 on success, negative error code on failure
2155 int get_data_pool(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2157 CLS_LOG(20, "get_data_pool");
2159 int64_t data_pool_id
= -1;
2160 int r
= read_key(hctx
, "data_pool_id", &data_pool_id
);
2164 CLS_ERR("error reading image data pool id: %s", cpp_strerror(r
).c_str());
2168 encode(data_pool_id
, *out
);
2174 * @param snap_id which snapshot to query
2177 * @param name (string) of the snapshot
2178 * @returns 0 on success, negative error code on failure
2180 int get_snapshot_name(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2184 auto iter
= in
->cbegin();
2186 decode(snap_id
, iter
);
2187 } catch (const buffer::error
&err
) {
2191 CLS_LOG(20, "get_snapshot_name snap_id=%llu", (unsigned long long)snap_id
);
2193 if (snap_id
== CEPH_NOSNAP
)
2197 string snapshot_key
;
2198 key_from_snap_id(snap_id
, &snapshot_key
);
2199 int r
= read_key(hctx
, snapshot_key
, &snap
);
2203 encode(snap
.name
, *out
);
2210 * @param snap_id which snapshot to query
2213 * @param timestamp (utime_t) of the snapshot
2214 * @returns 0 on success, negative error code on failure
2216 * NOTE: deprecated - remove this method after Luminous is unsupported
2218 int get_snapshot_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2222 auto iter
= in
->cbegin();
2224 decode(snap_id
, iter
);
2225 } catch (const buffer::error
&err
) {
2229 CLS_LOG(20, "get_snapshot_timestamp snap_id=%llu", (unsigned long long)snap_id
);
2231 if (snap_id
== CEPH_NOSNAP
) {
2236 string snapshot_key
;
2237 key_from_snap_id(snap_id
, &snapshot_key
);
2238 int r
= read_key(hctx
, snapshot_key
, &snap
);
2243 encode(snap
.timestamp
, *out
);
2249 * @param snap_id which snapshot to query
2252 * @param snapshot (cls::rbd::SnapshotInfo)
2253 * @returns 0 on success, negative error code on failure
2255 int snapshot_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2259 auto iter
= in
->cbegin();
2261 decode(snap_id
, iter
);
2262 } catch (const buffer::error
&err
) {
2266 CLS_LOG(20, "snapshot_get snap_id=%llu", (unsigned long long)snap_id
);
2267 if (snap_id
== CEPH_NOSNAP
) {
2272 string snapshot_key
;
2273 key_from_snap_id(snap_id
, &snapshot_key
);
2274 int r
= read_key(hctx
, snapshot_key
, &snap
);
2279 cls::rbd::SnapshotInfo snapshot_info
{snap
.id
, snap
.snapshot_namespace
,
2280 snap
.name
, snap
.image_size
,
2281 snap
.timestamp
, snap
.child_count
};
2282 encode(snapshot_info
, *out
);
2287 * Adds a snapshot to an rbd header. Ensures the id and name are unique.
2290 * @param snap_name name of the snapshot (string)
2291 * @param snap_id id of the snapshot (uint64_t)
2292 * @param snap_namespace namespace of the snapshot (cls::rbd::SnapshotNamespace)
2295 * @returns 0 on success, negative error code on failure.
2296 * @returns -ESTALE if the input snap_id is less than the image's snap_seq
2297 * @returns -EEXIST if the id or name are already used by another snapshot
2299 int snapshot_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2301 bufferlist snap_namebl
, snap_idbl
;
2302 cls_rbd_snap snap_meta
;
2303 uint64_t snap_limit
;
2306 auto iter
= in
->cbegin();
2307 decode(snap_meta
.name
, iter
);
2308 decode(snap_meta
.id
, iter
);
2310 decode(snap_meta
.snapshot_namespace
, iter
);
2312 } catch (const buffer::error
&err
) {
2316 if (boost::get
<cls::rbd::UnknownSnapshotNamespace
>(
2317 &snap_meta
.snapshot_namespace
) != nullptr) {
2318 CLS_ERR("Unknown snapshot namespace provided");
2322 CLS_LOG(20, "snapshot_add name=%s id=%llu", snap_meta
.name
.c_str(),
2323 (unsigned long long)snap_meta
.id
.val
);
2325 if (snap_meta
.id
> CEPH_MAXSNAP
)
2328 uint64_t cur_snap_seq
;
2329 int r
= read_key(hctx
, "snap_seq", &cur_snap_seq
);
2331 CLS_ERR("Could not read image's snap_seq off disk: %s", cpp_strerror(r
).c_str());
2335 // client lost a race with another snapshot creation.
2336 // snap_seq must be monotonically increasing.
2337 if (snap_meta
.id
< cur_snap_seq
)
2340 r
= read_key(hctx
, "size", &snap_meta
.image_size
);
2342 CLS_ERR("Could not read image's size off disk: %s", cpp_strerror(r
).c_str());
2345 r
= read_key(hctx
, "flags", &snap_meta
.flags
);
2346 if (r
< 0 && r
!= -ENOENT
) {
2347 CLS_ERR("Could not read image's flags off disk: %s", cpp_strerror(r
).c_str());
2351 r
= read_key(hctx
, "snap_limit", &snap_limit
);
2353 snap_limit
= UINT64_MAX
;
2355 CLS_ERR("Could not read snapshot limit off disk: %s", cpp_strerror(r
).c_str());
2359 snap_meta
.timestamp
= ceph_clock_now();
2361 uint64_t total_read
= 0;
2362 auto pre_check_lambda
=
2363 [&snap_meta
, &total_read
, snap_limit
](const cls_rbd_snap
& old_meta
) {
2365 if (total_read
>= snap_limit
) {
2366 CLS_ERR("Attempt to create snapshot over limit of %" PRIu64
,
2371 if ((snap_meta
.name
== old_meta
.name
&&
2372 snap_meta
.snapshot_namespace
== old_meta
.snapshot_namespace
) ||
2373 snap_meta
.id
== old_meta
.id
) {
2374 CLS_LOG(20, "snap_name %s or snap_id %" PRIu64
" matches existing snap "
2375 "%s %" PRIu64
, snap_meta
.name
.c_str(), snap_meta
.id
.val
,
2376 old_meta
.name
.c_str(), old_meta
.id
.val
);
2382 r
= image::snapshot::iterate(hctx
, pre_check_lambda
);
2387 // snapshot inherits parent, if any
2388 cls_rbd_parent parent
;
2389 r
= read_key(hctx
, "parent", &parent
);
2390 if (r
< 0 && r
!= -ENOENT
) {
2394 // write helper method will convert to normalized format if required
2395 snap_meta
.parent
= parent
;
2398 if (cls::rbd::get_snap_namespace_type(snap_meta
.snapshot_namespace
) ==
2399 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
) {
2400 // add snap_trash feature bit if not already enabled
2401 r
= image::set_op_features(hctx
, RBD_OPERATION_FEATURE_SNAP_TRASH
,
2402 RBD_OPERATION_FEATURE_SNAP_TRASH
);
2408 r
= write_key(hctx
, "snap_seq", snap_meta
.id
);
2413 std::string snapshot_key
;
2414 key_from_snap_id(snap_meta
.id
, &snapshot_key
);
2415 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap_meta
));
2427 * @param src_snap_id old snap id of the snapshot (snapid_t)
2428 * @param dst_snap_name new name of the snapshot (string)
2431 * @returns 0 on success, negative error code on failure.
2433 int snapshot_rename(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2435 bufferlist snap_namebl
, snap_idbl
;
2436 snapid_t src_snap_id
;
2437 string dst_snap_name
;
2438 cls_rbd_snap snap_meta
;
2442 auto iter
= in
->cbegin();
2443 decode(src_snap_id
, iter
);
2444 decode(dst_snap_name
, iter
);
2445 } catch (const buffer::error
&err
) {
2449 CLS_LOG(20, "snapshot_rename id=%" PRIu64
", dst_name=%s",
2450 src_snap_id
.val
, dst_snap_name
.c_str());
2452 auto duplicate_name_lambda
= [&dst_snap_name
](const cls_rbd_snap
& snap_meta
) {
2453 if (cls::rbd::get_snap_namespace_type(snap_meta
.snapshot_namespace
) ==
2454 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER
&&
2455 snap_meta
.name
== dst_snap_name
) {
2456 CLS_LOG(20, "snap_name %s matches existing snap with snap id %" PRIu64
,
2457 dst_snap_name
.c_str(), snap_meta
.id
.val
);
2462 r
= image::snapshot::iterate(hctx
, duplicate_name_lambda
);
2467 std::string src_snap_key
;
2468 key_from_snap_id(src_snap_id
, &src_snap_key
);
2469 r
= read_key(hctx
, src_snap_key
, &snap_meta
);
2471 CLS_LOG(20, "cannot find existing snap with snap id = %" PRIu64
,
2476 if (cls::rbd::get_snap_namespace_type(snap_meta
.snapshot_namespace
) !=
2477 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER
) {
2478 // can only rename user snapshots
2482 snap_meta
.name
= dst_snap_name
;
2483 r
= image::snapshot::write(hctx
, src_snap_key
, std::move(snap_meta
));
2492 * Removes a snapshot from an rbd header.
2495 * @param snap_id the id of the snapshot to remove (uint64_t)
2498 * @returns 0 on success, negative error code on failure
2500 int snapshot_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2505 auto iter
= in
->cbegin();
2506 decode(snap_id
, iter
);
2507 } catch (const buffer::error
&err
) {
2511 CLS_LOG(20, "snapshot_remove id=%llu", (unsigned long long)snap_id
.val
);
2513 // check if the key exists. we can't rely on remove_key doing this for
2514 // us, since OMAPRMKEYS returns success if the key is not there.
2515 // bug or feature? sounds like a bug, since tmap did not have this
2516 // behavior, but cls_rgw may rely on it...
2518 string snapshot_key
;
2519 key_from_snap_id(snap_id
, &snapshot_key
);
2520 int r
= read_key(hctx
, snapshot_key
, &snap
);
2525 if (snap
.protection_status
!= RBD_PROTECTION_STATUS_UNPROTECTED
) {
2529 // snapshot is in-use by clone v2 child
2530 if (snap
.child_count
> 0) {
2534 r
= remove_key(hctx
, snapshot_key
);
2539 bool has_child_snaps
= false;
2540 bool has_trash_snaps
= false;
2541 auto remove_lambda
= [snap_id
, &has_child_snaps
, &has_trash_snaps
](
2542 const cls_rbd_snap
& snap_meta
) {
2543 if (snap_meta
.id
!= snap_id
) {
2544 if (snap_meta
.parent
.pool_id
!= -1 || snap_meta
.parent_overlap
) {
2545 has_child_snaps
= true;
2548 if (cls::rbd::get_snap_namespace_type(snap_meta
.snapshot_namespace
) ==
2549 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
) {
2550 has_trash_snaps
= true;
2556 r
= image::snapshot::iterate(hctx
, remove_lambda
);
2561 cls_rbd_parent parent
;
2562 r
= read_key(hctx
, "parent", &parent
);
2563 if (r
< 0 && r
!= -ENOENT
) {
2567 bool has_parent
= (r
>= 0 && parent
.exists());
2568 bool is_head_child
= (has_parent
&& parent
.head_overlap
);
2569 int8_t require_osd_release
= cls_get_required_osd_release(hctx
);
2570 if (has_parent
&& !is_head_child
&& !has_child_snaps
&&
2571 require_osd_release
>= CEPH_RELEASE_NAUTILUS
) {
2572 // remove the unused parent image spec
2573 r
= remove_key(hctx
, "parent");
2574 if (r
< 0 && r
!= -ENOENT
) {
2579 uint64_t op_features_mask
= 0ULL;
2580 if (!has_child_snaps
&& !is_head_child
) {
2581 // disable clone child op feature if no longer associated
2582 op_features_mask
|= RBD_OPERATION_FEATURE_CLONE_CHILD
;
2584 if (!has_trash_snaps
) {
2585 // remove the snap_trash op feature if not in-use by any other snapshots
2586 op_features_mask
|= RBD_OPERATION_FEATURE_SNAP_TRASH
;
2589 if (op_features_mask
!= 0ULL) {
2590 r
= image::set_op_features(hctx
, 0, op_features_mask
);
2600 * Moves a snapshot to the trash namespace.
2603 * @param snap_id the id of the snapshot to move to the trash (uint64_t)
2606 * @returns 0 on success, negative error code on failure
2608 int snapshot_trash_add(cls_method_context_t hctx
, bufferlist
*in
,
2614 auto iter
= in
->cbegin();
2615 decode(snap_id
, iter
);
2616 } catch (const buffer::error
&err
) {
2620 CLS_LOG(20, "snapshot_trash_add id=%" PRIu64
, snap_id
.val
);
2623 std::string snapshot_key
;
2624 key_from_snap_id(snap_id
, &snapshot_key
);
2625 int r
= read_key(hctx
, snapshot_key
, &snap
);
2630 if (snap
.protection_status
!= RBD_PROTECTION_STATUS_UNPROTECTED
) {
2634 auto snap_type
= cls::rbd::get_snap_namespace_type(snap
.snapshot_namespace
);
2635 if (snap_type
== cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
) {
2639 // add snap_trash feature bit if not already enabled
2640 r
= image::set_op_features(hctx
, RBD_OPERATION_FEATURE_SNAP_TRASH
,
2641 RBD_OPERATION_FEATURE_SNAP_TRASH
);
2646 snap
.snapshot_namespace
= cls::rbd::TrashSnapshotNamespace
{snap_type
,
2649 uuid_gen
.generate_random();
2650 snap
.name
= uuid_gen
.to_string();
2652 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap
));
2661 * Returns a uint64_t of all the features supported by this class.
2663 int get_all_features(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2665 uint64_t all_features
= RBD_FEATURES_ALL
;
2666 encode(all_features
, *out
);
2671 * "Copy up" data from the parent of a clone to the clone's object(s).
2672 * Used for implementing copy-on-write for a clone image. Client
2673 * will pass down a chunk of data that fits completely within one
2674 * clone block (one object), and is aligned (starts at beginning of block),
2675 * but may be shorter (for non-full parent blocks). The class method
2676 * can't know the object size to validate the requested length,
2677 * so it just writes the data as given if the child object doesn't
2678 * already exist, and returns success if it does.
2681 * @param in bufferlist of data to write
2684 * @returns 0 on success, or if block already exists in child
2685 * negative error code on other error
2688 int copyup(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2690 // check for existence; if child object exists, just return success
2691 if (cls_cxx_stat(hctx
, NULL
, NULL
) == 0)
2693 CLS_LOG(20, "copyup: writing length %d\n", in
->length());
2694 return cls_cxx_write(hctx
, 0, in
->length(), in
);
2698 /************************ rbd_id object methods **************************/
2705 * @param id the id stored in the object
2706 * @returns 0 on success, negative error code on failure
2708 int get_id(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2711 int r
= cls_cxx_stat(hctx
, &size
, NULL
);
2719 r
= cls_cxx_read(hctx
, 0, size
, &read_bl
);
2721 CLS_ERR("get_id: could not read id: %s", cpp_strerror(r
).c_str());
2727 auto iter
= read_bl
.cbegin();
2729 } catch (const buffer::error
&err
) {
2738 * Set the id of an image. The object must already exist.
2741 * @param id the id of the image, as an alpha-numeric string
2744 * @returns 0 on success, -EEXIST if the atomic create fails,
2745 * negative error code on other error
2747 int set_id(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2749 int r
= check_exists(hctx
);
2755 auto iter
= in
->cbegin();
2757 } catch (const buffer::error
&err
) {
2761 if (!is_valid_id(id
)) {
2762 CLS_ERR("set_id: invalid id '%s'", id
.c_str());
2767 r
= cls_cxx_stat(hctx
, &size
, NULL
);
2773 CLS_LOG(20, "set_id: id=%s", id
.c_str());
2775 bufferlist write_bl
;
2776 encode(id
, write_bl
);
2777 return cls_cxx_write(hctx
, 0, write_bl
.length(), &write_bl
);
2781 * Update the access timestamp of an image
2787 * @returns 0 on success, negative error code on other error
2789 int set_access_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2791 int r
= check_exists(hctx
);
2795 utime_t timestamp
= ceph_clock_now();
2796 r
= write_key(hctx
, "access_timestamp", timestamp
);
2798 CLS_ERR("error setting access_timestamp");
2806 * Update the modify timestamp of an image
2812 * @returns 0 on success, negative error code on other error
2815 int set_modify_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2817 int r
= check_exists(hctx
);
2821 utime_t timestamp
= ceph_clock_now();
2822 r
= write_key(hctx
, "modify_timestamp", timestamp
);
2824 CLS_ERR("error setting modify_timestamp");
2833 /*********************** methods for rbd_directory ***********************/
2835 static const string
dir_key_for_id(const string
&id
)
2837 return RBD_DIR_ID_KEY_PREFIX
+ id
;
2840 static const string
dir_key_for_name(const string
&name
)
2842 return RBD_DIR_NAME_KEY_PREFIX
+ name
;
2845 static const string
dir_name_from_key(const string
&key
)
2847 return key
.substr(strlen(RBD_DIR_NAME_KEY_PREFIX
));
2850 static int dir_add_image_helper(cls_method_context_t hctx
,
2851 const string
&name
, const string
&id
,
2852 bool check_for_unique_id
)
2854 if (!name
.size() || !is_valid_id(id
)) {
2855 CLS_ERR("dir_add_image_helper: invalid name '%s' or id '%s'",
2856 name
.c_str(), id
.c_str());
2860 CLS_LOG(20, "dir_add_image_helper name=%s id=%s", name
.c_str(), id
.c_str());
2863 string name_key
= dir_key_for_name(name
);
2864 string id_key
= dir_key_for_id(id
);
2865 int r
= read_key(hctx
, name_key
, &tmp
);
2867 CLS_LOG(10, "name already exists");
2870 r
= read_key(hctx
, id_key
, &tmp
);
2871 if (r
!= -ENOENT
&& check_for_unique_id
) {
2872 CLS_LOG(10, "id already exists");
2875 bufferlist id_bl
, name_bl
;
2877 encode(name
, name_bl
);
2878 map
<string
, bufferlist
> omap_vals
;
2879 omap_vals
[name_key
] = id_bl
;
2880 omap_vals
[id_key
] = name_bl
;
2881 return cls_cxx_map_set_vals(hctx
, &omap_vals
);
2884 static int dir_remove_image_helper(cls_method_context_t hctx
,
2885 const string
&name
, const string
&id
)
2887 CLS_LOG(20, "dir_remove_image_helper name=%s id=%s",
2888 name
.c_str(), id
.c_str());
2890 string stored_name
, stored_id
;
2891 string name_key
= dir_key_for_name(name
);
2892 string id_key
= dir_key_for_id(id
);
2893 int r
= read_key(hctx
, name_key
, &stored_id
);
2896 CLS_ERR("error reading name to id mapping: %s", cpp_strerror(r
).c_str());
2899 r
= read_key(hctx
, id_key
, &stored_name
);
2901 CLS_ERR("error reading id to name mapping: %s", cpp_strerror(r
).c_str());
2905 // check if this op raced with a rename
2906 if (stored_name
!= name
|| stored_id
!= id
) {
2907 CLS_ERR("stored name '%s' and id '%s' do not match args '%s' and '%s'",
2908 stored_name
.c_str(), stored_id
.c_str(), name
.c_str(), id
.c_str());
2912 r
= cls_cxx_map_remove_key(hctx
, name_key
);
2914 CLS_ERR("error removing name: %s", cpp_strerror(r
).c_str());
2918 r
= cls_cxx_map_remove_key(hctx
, id_key
);
2920 CLS_ERR("error removing id: %s", cpp_strerror(r
).c_str());
2928 * Rename an image in the directory, updating both indexes
2929 * atomically. This can't be done from the client calling
2930 * dir_add_image and dir_remove_image in one transaction because the
2931 * results of the first method are not visibale to later steps.
2934 * @param src original name of the image
2935 * @param dest new name of the image
2936 * @param id the id of the image
2939 * @returns -ESTALE if src and id do not map to each other
2940 * @returns -ENOENT if src or id are not in the directory
2941 * @returns -EEXIST if dest already exists
2942 * @returns 0 on success, negative error code on failure
2944 int dir_rename_image(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2946 string src
, dest
, id
;
2948 auto iter
= in
->cbegin();
2952 } catch (const buffer::error
&err
) {
2956 int r
= dir_remove_image_helper(hctx
, src
, id
);
2959 // ignore duplicate id because the result of
2960 // remove_image_helper is not visible yet
2961 return dir_add_image_helper(hctx
, dest
, id
, false);
2965 * Get the id of an image given its name.
2968 * @param name the name of the image
2971 * @param id the id of the image
2972 * @returns 0 on success, negative error code on failure
2974 int dir_get_id(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2979 auto iter
= in
->cbegin();
2981 } catch (const buffer::error
&err
) {
2985 CLS_LOG(20, "dir_get_id: name=%s", name
.c_str());
2988 int r
= read_key(hctx
, dir_key_for_name(name
), &id
);
2991 CLS_ERR("error reading id for name '%s': %s", name
.c_str(), cpp_strerror(r
).c_str());
2999 * Get the name of an image given its id.
3002 * @param id the id of the image
3005 * @param name the name of the image
3006 * @returns 0 on success, negative error code on failure
3008 int dir_get_name(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3013 auto iter
= in
->cbegin();
3015 } catch (const buffer::error
&err
) {
3019 CLS_LOG(20, "dir_get_name: id=%s", id
.c_str());
3022 int r
= read_key(hctx
, dir_key_for_id(id
), &name
);
3025 CLS_ERR("error reading name for id '%s': %s", id
.c_str(),
3026 cpp_strerror(r
).c_str());
3035 * List the names and ids of the images in the directory, sorted by
3039 * @param start_after which name to begin listing after
3040 * (use the empty string to start at the beginning)
3041 * @param max_return the maximum number of names to list
3044 * @param images map from name to id of up to max_return images
3045 * @returns 0 on success, negative error code on failure
3047 int dir_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3050 uint64_t max_return
;
3053 auto iter
= in
->cbegin();
3054 decode(start_after
, iter
);
3055 decode(max_return
, iter
);
3056 } catch (const buffer::error
&err
) {
3060 int max_read
= RBD_MAX_KEYS_READ
;
3061 map
<string
, string
> images
;
3062 string last_read
= dir_key_for_name(start_after
);
3065 while (more
&& images
.size() < max_return
) {
3066 map
<string
, bufferlist
> vals
;
3067 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
3068 int r
= cls_cxx_map_get_vals(hctx
, last_read
, RBD_DIR_NAME_KEY_PREFIX
,
3069 max_read
, &vals
, &more
);
3072 CLS_ERR("error reading directory by name: %s", cpp_strerror(r
).c_str());
3077 for (map
<string
, bufferlist
>::iterator it
= vals
.begin();
3078 it
!= vals
.end(); ++it
) {
3080 auto iter
= it
->second
.cbegin();
3083 } catch (const buffer::error
&err
) {
3084 CLS_ERR("could not decode id of image '%s'", it
->first
.c_str());
3087 CLS_LOG(20, "adding '%s' -> '%s'", dir_name_from_key(it
->first
).c_str(), id
.c_str());
3088 images
[dir_name_from_key(it
->first
)] = id
;
3089 if (images
.size() >= max_return
)
3092 if (!vals
.empty()) {
3093 last_read
= dir_key_for_name(images
.rbegin()->first
);
3097 encode(images
, *out
);
3103 * Add an image to the rbd directory. Creates the directory object if
3104 * needed, and updates the index from id to name and name to id.
3107 * @param name the name of the image
3108 * @param id the id of the image
3111 * @returns -EEXIST if the image name is already in the directory
3112 * @returns -EBADF if the image id is already in the directory
3113 * @returns 0 on success, negative error code on failure
3115 int dir_add_image(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3117 int r
= cls_cxx_create(hctx
, false);
3119 CLS_ERR("could not create directory: %s", cpp_strerror(r
).c_str());
3125 auto iter
= in
->cbegin();
3128 } catch (const buffer::error
&err
) {
3132 return dir_add_image_helper(hctx
, name
, id
, true);
3136 * Remove an image from the rbd directory.
3139 * @param name the name of the image
3140 * @param id the id of the image
3143 * @returns -ESTALE if the name and id do not map to each other
3144 * @returns 0 on success, negative error code on failure
3146 int dir_remove_image(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3150 auto iter
= in
->cbegin();
3153 } catch (const buffer::error
&err
) {
3157 return dir_remove_image_helper(hctx
, name
, id
);
3161 * Verify the current state of the directory
3164 * @param state the DirectoryState of the directory
3167 * @returns -ENOENT if the state does not match
3168 * @returns 0 on success, negative error code on failure
3170 int dir_state_assert(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3172 cls::rbd::DirectoryState directory_state
= cls::rbd::DIRECTORY_STATE_READY
;
3174 auto iter
= in
->cbegin();
3175 decode(directory_state
, iter
);
3176 } catch (const buffer::error
&err
) {
3180 cls::rbd::DirectoryState on_disk_directory_state
= directory_state
;
3181 int r
= read_key(hctx
, "state", &on_disk_directory_state
);
3186 if (directory_state
!= on_disk_directory_state
) {
3193 * Set the current state of the directory
3196 * @param state the DirectoryState of the directory
3199 * @returns -ENOENT if the state does not match
3200 * @returns 0 on success, negative error code on failure
3202 int dir_state_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3204 cls::rbd::DirectoryState directory_state
;
3206 auto iter
= in
->cbegin();
3207 decode(directory_state
, iter
);
3208 } catch (const buffer::error
&err
) {
3212 int r
= check_exists(hctx
);
3213 if (r
< 0 && r
!= -ENOENT
) {
3217 switch (directory_state
) {
3218 case cls::rbd::DIRECTORY_STATE_READY
:
3220 case cls::rbd::DIRECTORY_STATE_ADD_DISABLED
:
3226 // verify that the directory is empty
3227 std::map
<std::string
, bufferlist
> vals
;
3229 r
= cls_cxx_map_get_vals(hctx
, RBD_DIR_NAME_KEY_PREFIX
,
3230 RBD_DIR_NAME_KEY_PREFIX
, 1, &vals
, &more
);
3233 } else if (!vals
.empty()) {
3242 r
= write_key(hctx
, "state", directory_state
);
3250 int object_map_read(cls_method_context_t hctx
, BitVector
<2> &object_map
)
3253 int r
= cls_cxx_stat(hctx
, &size
, NULL
);
3262 r
= cls_cxx_read(hctx
, 0, size
, &bl
);
3268 auto iter
= bl
.cbegin();
3269 decode(object_map
, iter
);
3270 } catch (const buffer::error
&err
) {
3271 CLS_ERR("failed to decode object map: %s", err
.what());
3278 * Load an rbd image's object map
3284 * @param object map bit vector
3285 * @returns 0 on success, negative error code on failure
3287 int object_map_load(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3289 BitVector
<2> object_map
;
3290 int r
= object_map_read(hctx
, object_map
);
3295 object_map
.set_crc_enabled(false);
3296 encode(object_map
, *out
);
3301 * Save an rbd image's object map
3304 * @param object map bit vector
3307 * @returns 0 on success, negative error code on failure
3309 int object_map_save(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3311 BitVector
<2> object_map
;
3313 auto iter
= in
->cbegin();
3314 decode(object_map
, iter
);
3315 } catch (const buffer::error
&err
) {
3319 object_map
.set_crc_enabled(true);
3322 encode(object_map
, bl
);
3323 CLS_LOG(20, "object_map_save: object size=%" PRIu64
", byte size=%u",
3324 object_map
.size(), bl
.length());
3325 return cls_cxx_write_full(hctx
, &bl
);
3329 * Resize an rbd image's object map
3332 * @param object_count the max number of objects in the image
3333 * @param default_state the default state of newly created objects
3336 * @returns 0 on success, negative error code on failure
3338 int object_map_resize(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3340 uint64_t object_count
;
3341 uint8_t default_state
;
3343 auto iter
= in
->cbegin();
3344 decode(object_count
, iter
);
3345 decode(default_state
, iter
);
3346 } catch (const buffer::error
&err
) {
3350 // protect against excessive memory requirements
3351 if (object_count
> cls::rbd::MAX_OBJECT_MAP_OBJECT_COUNT
) {
3352 CLS_ERR("object map too large: %" PRIu64
, object_count
);
3356 BitVector
<2> object_map
;
3357 int r
= object_map_read(hctx
, object_map
);
3358 if ((r
< 0) && (r
!= -ENOENT
)) {
3362 size_t orig_object_map_size
= object_map
.size();
3363 if (object_count
< orig_object_map_size
) {
3364 auto it
= object_map
.begin() + object_count
;
3365 auto end_it
= object_map
.end() ;
3366 uint64_t i
= object_count
;
3367 for (; it
!= end_it
; ++it
, ++i
) {
3368 if (*it
!= default_state
) {
3369 CLS_ERR("object map indicates object still exists: %" PRIu64
, i
);
3373 object_map
.resize(object_count
);
3374 } else if (object_count
> orig_object_map_size
) {
3375 object_map
.resize(object_count
);
3376 auto it
= object_map
.begin() + orig_object_map_size
;
3377 auto end_it
= object_map
.end();
3378 for (; it
!= end_it
; ++it
) {
3379 *it
= default_state
;
3384 encode(object_map
, map
);
3385 CLS_LOG(20, "object_map_resize: object size=%" PRIu64
", byte size=%u",
3386 object_count
, map
.length());
3387 return cls_cxx_write_full(hctx
, &map
);
3391 * Update an rbd image's object map
3394 * @param start_object_no the start object iterator
3395 * @param end_object_no the end object iterator
3396 * @param new_object_state the new object state
3397 * @param current_object_state optional current object state filter
3400 * @returns 0 on success, negative error code on failure
3402 int object_map_update(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3404 uint64_t start_object_no
;
3405 uint64_t end_object_no
;
3406 uint8_t new_object_state
;
3407 boost::optional
<uint8_t> current_object_state
;
3409 auto iter
= in
->cbegin();
3410 decode(start_object_no
, iter
);
3411 decode(end_object_no
, iter
);
3412 decode(new_object_state
, iter
);
3413 decode(current_object_state
, iter
);
3414 } catch (const buffer::error
&err
) {
3415 CLS_ERR("failed to decode message");
3420 int r
= cls_cxx_stat(hctx
, &size
, NULL
);
3425 BitVector
<2> object_map
;
3426 bufferlist header_bl
;
3427 r
= cls_cxx_read2(hctx
, 0, object_map
.get_header_length(), &header_bl
,
3428 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3430 CLS_ERR("object map header read failed");
3435 auto it
= header_bl
.cbegin();
3436 object_map
.decode_header(it
);
3437 } catch (const buffer::error
&err
) {
3438 CLS_ERR("failed to decode object map header: %s", err
.what());
3442 uint64_t object_byte_offset
;
3443 uint64_t byte_length
;
3444 object_map
.get_header_crc_extents(&object_byte_offset
, &byte_length
);
3446 bufferlist footer_bl
;
3447 r
= cls_cxx_read2(hctx
, object_byte_offset
, byte_length
, &footer_bl
,
3448 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3450 CLS_ERR("object map footer read header CRC failed");
3455 auto it
= footer_bl
.cbegin();
3456 object_map
.decode_header_crc(it
);
3457 } catch (const buffer::error
&err
) {
3458 CLS_ERR("failed to decode object map header CRC: %s", err
.what());
3461 if (start_object_no
>= end_object_no
|| end_object_no
> object_map
.size()) {
3465 uint64_t object_count
= end_object_no
- start_object_no
;
3466 object_map
.get_data_crcs_extents(start_object_no
, object_count
,
3467 &object_byte_offset
, &byte_length
);
3468 const auto footer_object_offset
= object_byte_offset
;
3471 r
= cls_cxx_read2(hctx
, object_byte_offset
, byte_length
, &footer_bl
,
3472 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3474 CLS_ERR("object map footer read data CRCs failed");
3479 auto it
= footer_bl
.cbegin();
3480 object_map
.decode_data_crcs(it
, start_object_no
);
3481 } catch (const buffer::error
&err
) {
3482 CLS_ERR("failed to decode object map data CRCs: %s", err
.what());
3485 uint64_t data_byte_offset
;
3486 object_map
.get_data_extents(start_object_no
, object_count
,
3487 &data_byte_offset
, &object_byte_offset
,
3491 r
= cls_cxx_read2(hctx
, object_byte_offset
, byte_length
, &data_bl
,
3492 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3494 CLS_ERR("object map data read failed");
3499 auto it
= data_bl
.cbegin();
3500 object_map
.decode_data(it
, data_byte_offset
);
3501 } catch (const buffer::error
&err
) {
3502 CLS_ERR("failed to decode data chunk [%" PRIu64
"]: %s",
3503 data_byte_offset
, err
.what());
3507 bool updated
= false;
3508 auto it
= object_map
.begin() + start_object_no
;
3509 auto end_it
= object_map
.begin() + end_object_no
;
3510 for (; it
!= end_it
; ++it
) {
3511 uint8_t state
= *it
;
3512 if ((!current_object_state
|| state
== *current_object_state
||
3513 (*current_object_state
== OBJECT_EXISTS
&&
3514 state
== OBJECT_EXISTS_CLEAN
)) && state
!= new_object_state
) {
3515 *it
= new_object_state
;
3521 CLS_LOG(20, "object_map_update: %" PRIu64
"~%" PRIu64
" -> %" PRIu64
,
3522 data_byte_offset
, byte_length
, object_byte_offset
);
3525 object_map
.encode_data(data_bl
, data_byte_offset
, byte_length
);
3526 r
= cls_cxx_write2(hctx
, object_byte_offset
, data_bl
.length(), &data_bl
,
3527 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3529 CLS_ERR("failed to write object map header: %s", cpp_strerror(r
).c_str());
3534 object_map
.encode_data_crcs(footer_bl
, start_object_no
, object_count
);
3535 r
= cls_cxx_write2(hctx
, footer_object_offset
, footer_bl
.length(),
3536 &footer_bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3538 CLS_ERR("failed to write object map footer: %s", cpp_strerror(r
).c_str());
3542 CLS_LOG(20, "object_map_update: no update necessary");
3549 * Mark all _EXISTS objects as _EXISTS_CLEAN so future writes to the
3550 * image HEAD can be tracked.
3556 * @returns 0 on success, negative error code on failure
3558 int object_map_snap_add(cls_method_context_t hctx
, bufferlist
*in
,
3561 BitVector
<2> object_map
;
3562 int r
= object_map_read(hctx
, object_map
);
3567 bool updated
= false;
3568 auto it
= object_map
.begin();
3569 auto end_it
= object_map
.end();
3570 for (; it
!= end_it
; ++it
) {
3571 if (*it
== OBJECT_EXISTS
) {
3572 *it
= OBJECT_EXISTS_CLEAN
;
3579 encode(object_map
, bl
);
3580 r
= cls_cxx_write_full(hctx
, &bl
);
3586 * Mark all _EXISTS_CLEAN objects as _EXISTS in the current object map
3587 * if the provided snapshot object map object is marked as _EXISTS.
3590 * @param snapshot object map bit vector
3593 * @returns 0 on success, negative error code on failure
3595 int object_map_snap_remove(cls_method_context_t hctx
, bufferlist
*in
,
3598 BitVector
<2> src_object_map
;
3600 auto iter
= in
->cbegin();
3601 decode(src_object_map
, iter
);
3602 } catch (const buffer::error
&err
) {
3606 BitVector
<2> dst_object_map
;
3607 int r
= object_map_read(hctx
, dst_object_map
);
3612 bool updated
= false;
3613 auto src_it
= src_object_map
.begin();
3614 auto dst_it
= dst_object_map
.begin();
3615 auto dst_it_end
= dst_object_map
.end();
3617 for (; dst_it
!= dst_it_end
; ++dst_it
) {
3618 if (*dst_it
== OBJECT_EXISTS_CLEAN
&&
3619 (i
>= src_object_map
.size() || *src_it
== OBJECT_EXISTS
)) {
3620 *dst_it
= OBJECT_EXISTS
;
3623 if (i
< src_object_map
.size())
3630 encode(dst_object_map
, bl
);
3631 r
= cls_cxx_write_full(hctx
, &bl
);
3636 static const string
metadata_key_for_name(const string
&name
)
3638 return RBD_METADATA_KEY_PREFIX
+ name
;
3641 static const string
metadata_name_from_key(const string
&key
)
3643 return key
.substr(strlen(RBD_METADATA_KEY_PREFIX
));
3648 * @param start_after which name to begin listing after
3649 * (use the empty string to start at the beginning)
3650 * @param max_return the maximum number of names to list
3654 * @returns 0 on success, negative error code on failure
3656 int metadata_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3659 uint64_t max_return
;
3662 auto iter
= in
->cbegin();
3663 decode(start_after
, iter
);
3664 decode(max_return
, iter
);
3665 } catch (const buffer::error
&err
) {
3669 // TODO remove implicit support for zero during the N-release
3670 if (max_return
== 0) {
3671 max_return
= RBD_MAX_KEYS_READ
;
3674 map
<string
, bufferlist
> data
;
3675 string last_read
= metadata_key_for_name(start_after
);
3678 while (more
&& data
.size() < max_return
) {
3679 map
<string
, bufferlist
> raw_data
;
3680 int max_read
= std::min
<uint64_t>(RBD_MAX_KEYS_READ
, max_return
- data
.size());
3681 int r
= cls_cxx_map_get_vals(hctx
, last_read
, RBD_METADATA_KEY_PREFIX
,
3682 max_read
, &raw_data
, &more
);
3685 CLS_ERR("failed to read the vals off of disk: %s",
3686 cpp_strerror(r
).c_str());
3691 for (auto& kv
: raw_data
) {
3692 data
[metadata_name_from_key(kv
.first
)].swap(kv
.second
);
3695 if (!raw_data
.empty()) {
3696 last_read
= raw_data
.rbegin()->first
;
3706 * @param data <map(key, value)>
3709 * @returns 0 on success, negative error code on failure
3711 int metadata_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3713 map
<string
, bufferlist
> data
, raw_data
;
3715 auto iter
= in
->cbegin();
3718 } catch (const buffer::error
&err
) {
3722 for (map
<string
, bufferlist
>::iterator it
= data
.begin();
3723 it
!= data
.end(); ++it
) {
3724 CLS_LOG(20, "metadata_set key=%s value=%.*s", it
->first
.c_str(),
3725 it
->second
.length(), it
->second
.c_str());
3726 raw_data
[metadata_key_for_name(it
->first
)].swap(it
->second
);
3728 int r
= cls_cxx_map_set_vals(hctx
, &raw_data
);
3730 CLS_ERR("error writing metadata: %s", cpp_strerror(r
).c_str());
3742 * @returns 0 on success, negative error code on failure
3744 int metadata_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3748 auto iter
= in
->cbegin();
3751 } catch (const buffer::error
&err
) {
3755 CLS_LOG(20, "metadata_remove key=%s", key
.c_str());
3757 int r
= cls_cxx_map_remove_key(hctx
, metadata_key_for_name(key
));
3759 CLS_ERR("error removing metadata: %s", cpp_strerror(r
).c_str());
3771 * @param metadata value associated with the key
3772 * @returns 0 on success, negative error code on failure
3774 int metadata_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3779 auto iter
= in
->cbegin();
3782 } catch (const buffer::error
&err
) {
3786 CLS_LOG(20, "metadata_get key=%s", key
.c_str());
3788 int r
= cls_cxx_map_get_val(hctx
, metadata_key_for_name(key
), &value
);
3791 CLS_ERR("error getting metadata: %s", cpp_strerror(r
).c_str());
3795 encode(value
, *out
);
3799 int snapshot_get_limit(cls_method_context_t hctx
, bufferlist
*in
,
3802 uint64_t snap_limit
;
3803 int r
= read_key(hctx
, "snap_limit", &snap_limit
);
3805 snap_limit
= UINT64_MAX
;
3807 CLS_ERR("error retrieving snapshot limit: %s", cpp_strerror(r
).c_str());
3811 CLS_LOG(20, "read snapshot limit %" PRIu64
, snap_limit
);
3812 encode(snap_limit
, *out
);
3817 int snapshot_set_limit(cls_method_context_t hctx
, bufferlist
*in
,
3823 size_t snap_count
= 0;
3826 auto iter
= in
->cbegin();
3827 decode(new_limit
, iter
);
3828 } catch (const buffer::error
&err
) {
3832 if (new_limit
== UINT64_MAX
) {
3833 CLS_LOG(20, "remove snapshot limit\n");
3834 rc
= cls_cxx_map_remove_key(hctx
, "snap_limit");
3838 //try to read header as v1 format
3839 rc
= snap_read_header(hctx
, bl
);
3841 // error when reading header
3842 if (rc
< 0 && rc
!= -EINVAL
) {
3844 } else if (rc
>= 0) {
3845 // success, the image is v1 format
3846 struct rbd_obj_header_ondisk
*header
;
3847 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
3848 snap_count
= header
->snap_count
;
3850 // else, the image is v2 format
3851 int max_read
= RBD_MAX_KEYS_READ
;
3852 string last_read
= RBD_SNAP_KEY_PREFIX
;
3857 rc
= cls_cxx_map_get_keys(hctx
, last_read
, max_read
, &keys
, &more
);
3859 CLS_ERR("error retrieving snapshots: %s", cpp_strerror(rc
).c_str());
3862 for (auto& key
: keys
) {
3863 if (key
.find(RBD_SNAP_KEY_PREFIX
) != 0)
3868 last_read
= *(keys
.rbegin());
3872 if (new_limit
< snap_count
) {
3874 CLS_LOG(10, "snapshot limit is less than the number of snapshots.\n");
3876 CLS_LOG(20, "set snapshot limit to %" PRIu64
"\n", new_limit
);
3878 encode(new_limit
, bl
);
3879 rc
= cls_cxx_map_set_val(hctx
, "snap_limit", &bl
);
3888 * @param snap id (uint64_t) parent snapshot id
3889 * @param child spec (cls::rbd::ChildImageSpec) child image
3892 * @returns 0 on success, negative error code on failure
3894 int child_attach(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3897 cls::rbd::ChildImageSpec child_image
;
3899 auto it
= in
->cbegin();
3900 decode(snap_id
, it
);
3901 decode(child_image
, it
);
3902 } catch (const buffer::error
&err
) {
3906 CLS_LOG(20, "child_attach snap_id=%" PRIu64
", child_pool_id=%" PRIi64
", "
3907 "child_image_id=%s", snap_id
, child_image
.pool_id
,
3908 child_image
.image_id
.c_str());
3911 std::string snapshot_key
;
3912 key_from_snap_id(snap_id
, &snapshot_key
);
3913 int r
= read_key(hctx
, snapshot_key
, &snap
);
3918 if (cls::rbd::get_snap_namespace_type(snap
.snapshot_namespace
) ==
3919 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
) {
3920 // cannot attach to a deleted snapshot
3924 auto children_key
= image::snap_children_key_from_snap_id(snap_id
);
3925 cls::rbd::ChildImageSpecs child_images
;
3926 r
= read_key(hctx
, children_key
, &child_images
);
3927 if (r
< 0 && r
!= -ENOENT
) {
3928 CLS_ERR("error reading snapshot children: %s", cpp_strerror(r
).c_str());
3932 auto it
= child_images
.insert(child_image
);
3934 // child already attached to the snapshot
3938 r
= write_key(hctx
, children_key
, child_images
);
3940 CLS_ERR("error writing snapshot children: %s", cpp_strerror(r
).c_str());
3945 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap
));
3950 r
= image::set_op_features(hctx
, RBD_OPERATION_FEATURE_CLONE_PARENT
,
3951 RBD_OPERATION_FEATURE_CLONE_PARENT
);
3961 * @param snap id (uint64_t) parent snapshot id
3962 * @param child spec (cls::rbd::ChildImageSpec) child image
3965 * @returns 0 on success, negative error code on failure
3967 int child_detach(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3970 cls::rbd::ChildImageSpec child_image
;
3972 auto it
= in
->cbegin();
3973 decode(snap_id
, it
);
3974 decode(child_image
, it
);
3975 } catch (const buffer::error
&err
) {
3979 CLS_LOG(20, "child_detach snap_id=%" PRIu64
", child_pool_id=%" PRIi64
", "
3980 "child_image_id=%s", snap_id
, child_image
.pool_id
,
3981 child_image
.image_id
.c_str());
3984 std::string snapshot_key
;
3985 key_from_snap_id(snap_id
, &snapshot_key
);
3986 int r
= read_key(hctx
, snapshot_key
, &snap
);
3991 auto children_key
= image::snap_children_key_from_snap_id(snap_id
);
3992 cls::rbd::ChildImageSpecs child_images
;
3993 r
= read_key(hctx
, children_key
, &child_images
);
3994 if (r
< 0 && r
!= -ENOENT
) {
3995 CLS_ERR("error reading snapshot children: %s", cpp_strerror(r
).c_str());
3999 if (snap
.child_count
!= child_images
.size()) {
4000 // children and reference count don't match
4001 CLS_ERR("children reference count mismatch: %" PRIu64
, snap_id
);
4005 if (child_images
.erase(child_image
) == 0) {
4006 // child not attached to the snapshot
4010 if (child_images
.empty()) {
4011 r
= remove_key(hctx
, children_key
);
4013 r
= write_key(hctx
, children_key
, child_images
);
4015 CLS_ERR("error writing snapshot children: %s", cpp_strerror(r
).c_str());
4021 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap
));
4026 if (snap
.child_count
== 0) {
4027 auto clone_in_use_lambda
= [snap_id
](const cls_rbd_snap
& snap_meta
) {
4028 if (snap_meta
.id
!= snap_id
&& snap_meta
.child_count
> 0) {
4034 r
= image::snapshot::iterate(hctx
, clone_in_use_lambda
);
4035 if (r
< 0 && r
!= -EEXIST
) {
4040 // remove the clone_v2 op feature if not in-use by any other snapshots
4041 r
= image::set_op_features(hctx
, 0, RBD_OPERATION_FEATURE_CLONE_PARENT
);
4053 * @param snap id (uint64_t) parent snapshot id
4056 * @param (cls::rbd::ChildImageSpecs) child images
4057 * @returns 0 on success, negative error code on failure
4059 int children_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4063 auto it
= in
->cbegin();
4064 decode(snap_id
, it
);
4065 } catch (const buffer::error
&err
) {
4069 CLS_LOG(20, "child_detach snap_id=%" PRIu64
, snap_id
);
4072 std::string snapshot_key
;
4073 key_from_snap_id(snap_id
, &snapshot_key
);
4074 int r
= read_key(hctx
, snapshot_key
, &snap
);
4079 auto children_key
= image::snap_children_key_from_snap_id(snap_id
);
4080 cls::rbd::ChildImageSpecs child_images
;
4081 r
= read_key(hctx
, children_key
, &child_images
);
4085 CLS_ERR("error reading snapshot children: %s", cpp_strerror(r
).c_str());
4089 encode(child_images
, *out
);
4094 * Set image migration.
4097 * @param migration_spec (cls::rbd::MigrationSpec) image migration spec
4101 * @returns 0 on success, negative error code on failure
4103 int migration_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
4104 cls::rbd::MigrationSpec migration_spec
;
4106 auto it
= in
->cbegin();
4107 decode(migration_spec
, it
);
4108 } catch (const buffer::error
&err
) {
4112 int r
= image::set_migration(hctx
, migration_spec
, true);
4121 * Set image migration state.
4124 * @param state (cls::rbd::MigrationState) migration state
4125 * @param description (std::string) migration state description
4129 * @returns 0 on success, negative error code on failure
4131 int migration_set_state(cls_method_context_t hctx
, bufferlist
*in
,
4133 cls::rbd::MigrationState state
;
4134 std::string description
;
4136 auto it
= in
->cbegin();
4138 decode(description
, it
);
4139 } catch (const buffer::error
&err
) {
4143 cls::rbd::MigrationSpec migration_spec
;
4144 int r
= image::read_migration(hctx
, &migration_spec
);
4149 migration_spec
.state
= state
;
4150 migration_spec
.state_description
= description
;
4152 r
= image::set_migration(hctx
, migration_spec
, false);
4161 * Get image migration spec.
4166 * @param migration_spec (cls::rbd::MigrationSpec) image migration spec
4168 * @returns 0 on success, negative error code on failure
4170 int migration_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
4171 cls::rbd::MigrationSpec migration_spec
;
4172 int r
= image::read_migration(hctx
, &migration_spec
);
4177 encode(migration_spec
, *out
);
4183 * Remove image migration spec.
4189 * @returns 0 on success, negative error code on failure
4191 int migration_remove(cls_method_context_t hctx
, bufferlist
*in
,
4193 int r
= image::remove_migration(hctx
);
4202 * Ensure writer snapc state
4205 * @param snap id (uint64_t) snap context sequence id
4206 * @param state (cls::rbd::AssertSnapcSeqState) snap context state
4209 * @returns -ERANGE if assertion fails
4210 * @returns 0 on success, negative error code on failure
4212 int assert_snapc_seq(cls_method_context_t hctx
, bufferlist
*in
,
4216 cls::rbd::AssertSnapcSeqState state
;
4218 auto it
= in
->cbegin();
4219 decode(snapc_seq
, it
);
4221 } catch (const buffer::error
&err
) {
4225 uint64_t snapset_seq
;
4226 int r
= cls_get_snapset_seq(hctx
, &snapset_seq
);
4227 if (r
< 0 && r
!= -ENOENT
) {
4232 case cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ
:
4233 return (r
== -ENOENT
|| snapc_seq
> snapset_seq
) ? 0 : -ERANGE
;
4234 case cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ
:
4235 return (r
== -ENOENT
|| snapc_seq
> snapset_seq
) ? -ERANGE
: 0;
4241 /****************************** Old format *******************************/
4243 int old_snapshots_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4246 struct rbd_obj_header_ondisk
*header
;
4247 int rc
= snap_read_header(hctx
, bl
);
4251 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
4252 bufferptr
p(header
->snap_names_len
);
4253 char *buf
= (char *)header
;
4254 char *name
= buf
+ sizeof(*header
) + header
->snap_count
* sizeof(struct rbd_obj_snap_ondisk
);
4255 char *end
= name
+ header
->snap_names_len
;
4257 buf
+ sizeof(*header
) + header
->snap_count
* sizeof(struct rbd_obj_snap_ondisk
),
4258 header
->snap_names_len
);
4260 encode(header
->snap_seq
, *out
);
4261 encode(header
->snap_count
, *out
);
4263 for (unsigned i
= 0; i
< header
->snap_count
; i
++) {
4265 encode(header
->snaps
[i
].id
, *out
);
4266 encode(header
->snaps
[i
].image_size
, *out
);
4269 name
+= strlen(name
) + 1;
4277 int old_snapshot_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4280 struct rbd_obj_header_ondisk
*header
;
4282 bufferptr
header_bp(sizeof(*header
));
4283 struct rbd_obj_snap_ondisk
*new_snaps
;
4285 int rc
= snap_read_header(hctx
, bl
);
4289 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
4291 int snaps_id_ofs
= sizeof(*header
);
4292 int names_ofs
= snaps_id_ofs
+ sizeof(*new_snaps
) * header
->snap_count
;
4293 const char *snap_name
;
4294 const char *snap_names
= ((char *)header
) + names_ofs
;
4295 const char *end
= snap_names
+ header
->snap_names_len
;
4296 auto iter
= in
->cbegin();
4302 decode(snap_id
, iter
);
4303 } catch (const buffer::error
&err
) {
4306 snap_name
= s
.c_str();
4308 if (header
->snap_seq
> snap_id
)
4311 uint64_t snap_limit
;
4312 rc
= read_key(hctx
, "snap_limit", &snap_limit
);
4313 if (rc
== -ENOENT
) {
4314 snap_limit
= UINT64_MAX
;
4315 } else if (rc
< 0) {
4319 if (header
->snap_count
>= snap_limit
)
4322 const char *cur_snap_name
;
4323 for (cur_snap_name
= snap_names
; cur_snap_name
< end
; cur_snap_name
+= strlen(cur_snap_name
) + 1) {
4324 if (strncmp(cur_snap_name
, snap_name
, end
- cur_snap_name
) == 0)
4327 if (cur_snap_name
> end
)
4330 int snap_name_len
= strlen(snap_name
);
4332 bufferptr
new_names_bp(header
->snap_names_len
+ snap_name_len
+ 1);
4333 bufferptr
new_snaps_bp(sizeof(*new_snaps
) * (header
->snap_count
+ 1));
4335 /* copy snap names and append to new snap name */
4336 char *new_snap_names
= new_names_bp
.c_str();
4337 strcpy(new_snap_names
, snap_name
);
4338 memcpy(new_snap_names
+ snap_name_len
+ 1, snap_names
, header
->snap_names_len
);
4340 /* append new snap id */
4341 new_snaps
= (struct rbd_obj_snap_ondisk
*)new_snaps_bp
.c_str();
4342 memcpy(new_snaps
+ 1, header
->snaps
, sizeof(*new_snaps
) * header
->snap_count
);
4344 header
->snap_count
= header
->snap_count
+ 1;
4345 header
->snap_names_len
= header
->snap_names_len
+ snap_name_len
+ 1;
4346 header
->snap_seq
= snap_id
;
4348 new_snaps
[0].id
= snap_id
;
4349 new_snaps
[0].image_size
= header
->image_size
;
4351 memcpy(header_bp
.c_str(), header
, sizeof(*header
));
4353 newbl
.push_back(header_bp
);
4354 newbl
.push_back(new_snaps_bp
);
4355 newbl
.push_back(new_names_bp
);
4357 rc
= cls_cxx_write_full(hctx
, &newbl
);
4364 int old_snapshot_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4367 struct rbd_obj_header_ondisk
*header
;
4369 bufferptr
header_bp(sizeof(*header
));
4371 int rc
= snap_read_header(hctx
, bl
);
4375 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
4377 int snaps_id_ofs
= sizeof(*header
);
4378 int names_ofs
= snaps_id_ofs
+ sizeof(struct rbd_obj_snap_ondisk
) * header
->snap_count
;
4379 const char *snap_name
;
4380 const char *snap_names
= ((char *)header
) + names_ofs
;
4381 const char *orig_names
= snap_names
;
4382 const char *end
= snap_names
+ header
->snap_names_len
;
4383 auto iter
= in
->cbegin();
4387 struct rbd_obj_snap_ondisk snap
;
4391 } catch (const buffer::error
&err
) {
4394 snap_name
= s
.c_str();
4396 for (i
= 0; snap_names
< end
; i
++) {
4397 if (strcmp(snap_names
, snap_name
) == 0) {
4398 snap
= header
->snaps
[i
];
4402 snap_names
+= strlen(snap_names
) + 1;
4405 CLS_ERR("couldn't find snap %s\n", snap_name
);
4409 header
->snap_names_len
= header
->snap_names_len
- (s
.length() + 1);
4410 header
->snap_count
= header
->snap_count
- 1;
4412 bufferptr
new_names_bp(header
->snap_names_len
);
4413 bufferptr
new_snaps_bp(sizeof(header
->snaps
[0]) * header
->snap_count
);
4415 memcpy(header_bp
.c_str(), header
, sizeof(*header
));
4416 newbl
.push_back(header_bp
);
4418 if (header
->snap_count
) {
4421 CLS_LOG(20, "i=%u\n", i
);
4423 snaps_len
= sizeof(header
->snaps
[0]) * i
;
4424 names_len
= snap_names
- orig_names
;
4425 memcpy(new_snaps_bp
.c_str(), header
->snaps
, snaps_len
);
4426 memcpy(new_names_bp
.c_str(), orig_names
, names_len
);
4428 snap_names
+= s
.length() + 1;
4430 if (i
< header
->snap_count
) {
4431 memcpy(new_snaps_bp
.c_str() + snaps_len
,
4432 header
->snaps
+ i
+ 1,
4433 sizeof(header
->snaps
[0]) * (header
->snap_count
- i
));
4434 memcpy(new_names_bp
.c_str() + names_len
, snap_names
, end
- snap_names
);
4436 newbl
.push_back(new_snaps_bp
);
4437 newbl
.push_back(new_names_bp
);
4440 rc
= cls_cxx_write_full(hctx
, &newbl
);
4448 * rename snapshot of old format.
4451 * @param src_snap_id old snap id of the snapshot (snapid_t)
4452 * @param dst_snap_name new name of the snapshot (string)
4455 * @returns 0 on success, negative error code on failure.
4457 int old_snapshot_rename(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4460 struct rbd_obj_header_ondisk
*header
;
4462 bufferptr
header_bp(sizeof(*header
));
4463 snapid_t src_snap_id
;
4464 const char *dst_snap_name
;
4467 int rc
= snap_read_header(hctx
, bl
);
4471 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
4473 int snaps_id_ofs
= sizeof(*header
);
4474 int names_ofs
= snaps_id_ofs
+ sizeof(rbd_obj_snap_ondisk
) * header
->snap_count
;
4475 const char *snap_names
= ((char *)header
) + names_ofs
;
4476 const char *orig_names
= snap_names
;
4477 const char *end
= snap_names
+ header
->snap_names_len
;
4478 auto iter
= in
->cbegin();
4483 decode(src_snap_id
, iter
);
4485 } catch (const buffer::error
&err
) {
4488 dst_snap_name
= dst
.c_str();
4490 const char *cur_snap_name
;
4491 for (cur_snap_name
= snap_names
; cur_snap_name
< end
;
4492 cur_snap_name
+= strlen(cur_snap_name
) + 1) {
4493 if (strcmp(cur_snap_name
, dst_snap_name
) == 0)
4496 if (cur_snap_name
> end
)
4498 for (i
= 0; i
< header
->snap_count
; i
++) {
4499 if (src_snap_id
== header
->snaps
[i
].id
) {
4503 snap_names
+= strlen(snap_names
) + 1;
4506 CLS_ERR("couldn't find snap %llu\n", (unsigned long long)src_snap_id
.val
);
4510 CLS_LOG(20, "rename snap with snap id %llu to dest name %s", (unsigned long long)src_snap_id
.val
, dst_snap_name
);
4511 header
->snap_names_len
= header
->snap_names_len
- strlen(snap_names
) + dst
.length();
4513 bufferptr
new_names_bp(header
->snap_names_len
);
4514 bufferptr
new_snaps_bp(sizeof(header
->snaps
[0]) * header
->snap_count
);
4516 if (header
->snap_count
) {
4518 CLS_LOG(20, "i=%u\n", i
);
4520 names_len
= snap_names
- orig_names
;
4521 memcpy(new_names_bp
.c_str(), orig_names
, names_len
);
4523 strcpy(new_names_bp
.c_str() + names_len
, dst_snap_name
);
4524 names_len
+= strlen(dst_snap_name
) + 1;
4525 snap_names
+= strlen(snap_names
) + 1;
4526 if (i
< header
->snap_count
) {
4527 memcpy(new_names_bp
.c_str() + names_len
, snap_names
, end
- snap_names
);
4529 memcpy(new_snaps_bp
.c_str(), header
->snaps
, sizeof(header
->snaps
[0]) * header
->snap_count
);
4532 memcpy(header_bp
.c_str(), header
, sizeof(*header
));
4533 newbl
.push_back(header_bp
);
4534 newbl
.push_back(new_snaps_bp
);
4535 newbl
.push_back(new_names_bp
);
4537 rc
= cls_cxx_write_full(hctx
, &newbl
);
4546 static const std::string
UUID("mirror_uuid");
4547 static const std::string
MODE("mirror_mode");
4548 static const std::string
PEER_KEY_PREFIX("mirror_peer_");
4549 static const std::string
IMAGE_KEY_PREFIX("image_");
4550 static const std::string
GLOBAL_KEY_PREFIX("global_");
4551 static const std::string
STATUS_GLOBAL_KEY_PREFIX("status_global_");
4552 static const std::string
INSTANCE_KEY_PREFIX("instance_");
4553 static const std::string
MIRROR_IMAGE_MAP_KEY_PREFIX("image_map_");
4555 std::string
peer_key(const std::string
&uuid
) {
4556 return PEER_KEY_PREFIX
+ uuid
;
4559 std::string
image_key(const string
&image_id
) {
4560 return IMAGE_KEY_PREFIX
+ image_id
;
4563 std::string
global_key(const string
&global_id
) {
4564 return GLOBAL_KEY_PREFIX
+ global_id
;
4567 std::string
status_global_key(const string
&global_id
) {
4568 return STATUS_GLOBAL_KEY_PREFIX
+ global_id
;
4571 std::string
instance_key(const string
&instance_id
) {
4572 return INSTANCE_KEY_PREFIX
+ instance_id
;
4575 std::string
mirror_image_map_key(const string
& global_image_id
) {
4576 return MIRROR_IMAGE_MAP_KEY_PREFIX
+ global_image_id
;
4579 int uuid_get(cls_method_context_t hctx
, std::string
*mirror_uuid
) {
4580 bufferlist mirror_uuid_bl
;
4581 int r
= cls_cxx_map_get_val(hctx
, mirror::UUID
, &mirror_uuid_bl
);
4584 CLS_ERR("error reading mirror uuid: %s", cpp_strerror(r
).c_str());
4589 *mirror_uuid
= std::string(mirror_uuid_bl
.c_str(), mirror_uuid_bl
.length());
4593 int list_watchers(cls_method_context_t hctx
,
4594 std::set
<entity_inst_t
> *entities
) {
4595 obj_list_watch_response_t watchers
;
4596 int r
= cls_cxx_list_watchers(hctx
, &watchers
);
4597 if (r
< 0 && r
!= -ENOENT
) {
4598 CLS_ERR("error listing watchers: '%s'", cpp_strerror(r
).c_str());
4603 for (auto &w
: watchers
.entries
) {
4604 entities
->emplace(w
.name
, w
.addr
);
4609 int read_peers(cls_method_context_t hctx
,
4610 std::vector
<cls::rbd::MirrorPeer
> *peers
) {
4611 std::string last_read
= PEER_KEY_PREFIX
;
4612 int max_read
= RBD_MAX_KEYS_READ
;
4615 std::map
<std::string
, bufferlist
> vals
;
4616 int r
= cls_cxx_map_get_vals(hctx
, last_read
, PEER_KEY_PREFIX
.c_str(),
4617 max_read
, &vals
, &more
);
4620 CLS_ERR("error reading peers: %s", cpp_strerror(r
).c_str());
4625 for (auto &it
: vals
) {
4627 auto bl_it
= it
.second
.cbegin();
4628 cls::rbd::MirrorPeer peer
;
4629 decode(peer
, bl_it
);
4630 peers
->push_back(peer
);
4631 } catch (const buffer::error
&err
) {
4632 CLS_ERR("could not decode peer '%s'", it
.first
.c_str());
4637 if (!vals
.empty()) {
4638 last_read
= vals
.rbegin()->first
;
4644 int read_peer(cls_method_context_t hctx
, const std::string
&id
,
4645 cls::rbd::MirrorPeer
*peer
) {
4647 int r
= cls_cxx_map_get_val(hctx
, peer_key(id
), &bl
);
4649 CLS_ERR("error reading peer '%s': %s", id
.c_str(),
4650 cpp_strerror(r
).c_str());
4655 auto bl_it
= bl
.cbegin();
4656 decode(*peer
, bl_it
);
4657 } catch (const buffer::error
&err
) {
4658 CLS_ERR("could not decode peer '%s'", id
.c_str());
4664 int write_peer(cls_method_context_t hctx
, const std::string
&id
,
4665 const cls::rbd::MirrorPeer
&peer
) {
4669 int r
= cls_cxx_map_set_val(hctx
, peer_key(id
), &bl
);
4671 CLS_ERR("error writing peer '%s': %s", id
.c_str(),
4672 cpp_strerror(r
).c_str());
4678 int image_get(cls_method_context_t hctx
, const string
&image_id
,
4679 cls::rbd::MirrorImage
*mirror_image
) {
4681 int r
= cls_cxx_map_get_val(hctx
, image_key(image_id
), &bl
);
4684 CLS_ERR("error reading mirrored image '%s': '%s'", image_id
.c_str(),
4685 cpp_strerror(r
).c_str());
4691 auto it
= bl
.cbegin();
4692 decode(*mirror_image
, it
);
4693 } catch (const buffer::error
&err
) {
4694 CLS_ERR("could not decode mirrored image '%s'", image_id
.c_str());
4701 int image_set(cls_method_context_t hctx
, const string
&image_id
,
4702 const cls::rbd::MirrorImage
&mirror_image
) {
4704 encode(mirror_image
, bl
);
4706 cls::rbd::MirrorImage existing_mirror_image
;
4707 int r
= image_get(hctx
, image_id
, &existing_mirror_image
);
4709 // make sure global id doesn't already exist
4710 std::string global_id_key
= global_key(mirror_image
.global_image_id
);
4711 std::string image_id
;
4712 r
= read_key(hctx
, global_id_key
, &image_id
);
4715 } else if (r
!= -ENOENT
) {
4716 CLS_ERR("error reading global image id: '%s': '%s'", image_id
.c_str(),
4717 cpp_strerror(r
).c_str());
4721 // make sure this was not a race for disabling
4722 if (mirror_image
.state
== cls::rbd::MIRROR_IMAGE_STATE_DISABLING
) {
4723 CLS_ERR("image '%s' is already disabled", image_id
.c_str());
4727 CLS_ERR("error reading mirrored image '%s': '%s'", image_id
.c_str(),
4728 cpp_strerror(r
).c_str());
4730 } else if (existing_mirror_image
.global_image_id
!=
4731 mirror_image
.global_image_id
) {
4732 // cannot change the global id
4736 r
= cls_cxx_map_set_val(hctx
, image_key(image_id
), &bl
);
4738 CLS_ERR("error adding mirrored image '%s': %s", image_id
.c_str(),
4739 cpp_strerror(r
).c_str());
4743 bufferlist image_id_bl
;
4744 encode(image_id
, image_id_bl
);
4745 r
= cls_cxx_map_set_val(hctx
, global_key(mirror_image
.global_image_id
),
4748 CLS_ERR("error adding global id for image '%s': %s", image_id
.c_str(),
4749 cpp_strerror(r
).c_str());
4755 int image_remove(cls_method_context_t hctx
, const string
&image_id
) {
4757 cls::rbd::MirrorImage mirror_image
;
4758 int r
= image_get(hctx
, image_id
, &mirror_image
);
4761 CLS_ERR("error reading mirrored image '%s': '%s'", image_id
.c_str(),
4762 cpp_strerror(r
).c_str());
4767 if (mirror_image
.state
!= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
) {
4771 r
= cls_cxx_map_remove_key(hctx
, image_key(image_id
));
4773 CLS_ERR("error removing mirrored image '%s': %s", image_id
.c_str(),
4774 cpp_strerror(r
).c_str());
4778 r
= cls_cxx_map_remove_key(hctx
, global_key(mirror_image
.global_image_id
));
4779 if (r
< 0 && r
!= -ENOENT
) {
4780 CLS_ERR("error removing global id for image '%s': %s", image_id
.c_str(),
4781 cpp_strerror(r
).c_str());
4785 r
= cls_cxx_map_remove_key(hctx
,
4786 status_global_key(mirror_image
.global_image_id
));
4787 if (r
< 0 && r
!= -ENOENT
) {
4788 CLS_ERR("error removing global status for image '%s': %s", image_id
.c_str(),
4789 cpp_strerror(r
).c_str());
4796 struct MirrorImageStatusOnDisk
: cls::rbd::MirrorImageStatus
{
4797 entity_inst_t origin
;
4799 MirrorImageStatusOnDisk() {
4801 MirrorImageStatusOnDisk(const cls::rbd::MirrorImageStatus
&status
) :
4802 cls::rbd::MirrorImageStatus(status
) {
4805 void encode_meta(bufferlist
&bl
, uint64_t features
) const {
4806 ENCODE_START(1, 1, bl
);
4807 encode(origin
, bl
, features
);
4811 void encode(bufferlist
&bl
, uint64_t features
) const {
4812 encode_meta(bl
, features
);
4813 cls::rbd::MirrorImageStatus::encode(bl
);
4816 void decode_meta(bufferlist::const_iterator
&it
) {
4817 DECODE_START(1, it
);
4822 void decode(bufferlist::const_iterator
&it
) {
4824 cls::rbd::MirrorImageStatus::decode(it
);
4827 WRITE_CLASS_ENCODER_FEATURES(MirrorImageStatusOnDisk
)
4829 int image_status_set(cls_method_context_t hctx
, const string
&global_image_id
,
4830 const cls::rbd::MirrorImageStatus
&status
) {
4831 MirrorImageStatusOnDisk
ondisk_status(status
);
4832 ondisk_status
.up
= false;
4833 ondisk_status
.last_update
= ceph_clock_now();
4835 int r
= cls_get_request_origin(hctx
, &ondisk_status
.origin
);
4836 ceph_assert(r
== 0);
4839 encode(ondisk_status
, bl
, cls_get_features(hctx
));
4841 r
= cls_cxx_map_set_val(hctx
, status_global_key(global_image_id
), &bl
);
4843 CLS_ERR("error setting status for mirrored image, global id '%s': %s",
4844 global_image_id
.c_str(), cpp_strerror(r
).c_str());
4850 int image_status_remove(cls_method_context_t hctx
,
4851 const string
&global_image_id
) {
4853 int r
= cls_cxx_map_remove_key(hctx
, status_global_key(global_image_id
));
4855 CLS_ERR("error removing status for mirrored image, global id '%s': %s",
4856 global_image_id
.c_str(), cpp_strerror(r
).c_str());
4862 int image_status_get(cls_method_context_t hctx
, const string
&global_image_id
,
4863 const std::set
<entity_inst_t
> &watchers
,
4864 cls::rbd::MirrorImageStatus
*status
) {
4867 int r
= cls_cxx_map_get_val(hctx
, status_global_key(global_image_id
), &bl
);
4870 CLS_ERR("error reading status for mirrored image, global id '%s': '%s'",
4871 global_image_id
.c_str(), cpp_strerror(r
).c_str());
4876 MirrorImageStatusOnDisk ondisk_status
;
4878 auto it
= bl
.cbegin();
4879 decode(ondisk_status
, it
);
4880 } catch (const buffer::error
&err
) {
4881 CLS_ERR("could not decode status for mirrored image, global id '%s'",
4882 global_image_id
.c_str());
4887 *status
= static_cast<cls::rbd::MirrorImageStatus
>(ondisk_status
);
4888 status
->up
= (watchers
.find(ondisk_status
.origin
) != watchers
.end());
4892 int image_status_list(cls_method_context_t hctx
,
4893 const std::string
&start_after
, uint64_t max_return
,
4894 map
<std::string
, cls::rbd::MirrorImage
> *mirror_images
,
4895 map
<std::string
, cls::rbd::MirrorImageStatus
> *mirror_statuses
) {
4896 std::string last_read
= image_key(start_after
);
4897 int max_read
= RBD_MAX_KEYS_READ
;
4900 std::set
<entity_inst_t
> watchers
;
4901 int r
= list_watchers(hctx
, &watchers
);
4906 while (more
&& mirror_images
->size() < max_return
) {
4907 std::map
<std::string
, bufferlist
> vals
;
4908 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
4909 r
= cls_cxx_map_get_vals(hctx
, last_read
, IMAGE_KEY_PREFIX
, max_read
, &vals
,
4913 CLS_ERR("error reading mirror image directory by name: %s",
4914 cpp_strerror(r
).c_str());
4919 for (auto it
= vals
.begin(); it
!= vals
.end() &&
4920 mirror_images
->size() < max_return
; ++it
) {
4921 const std::string
&image_id
= it
->first
.substr(IMAGE_KEY_PREFIX
.size());
4922 cls::rbd::MirrorImage mirror_image
;
4923 auto iter
= it
->second
.cbegin();
4925 decode(mirror_image
, iter
);
4926 } catch (const buffer::error
&err
) {
4927 CLS_ERR("could not decode mirror image payload of image '%s'",
4932 (*mirror_images
)[image_id
] = mirror_image
;
4934 cls::rbd::MirrorImageStatus status
;
4935 int r1
= image_status_get(hctx
, mirror_image
.global_image_id
, watchers
,
4941 (*mirror_statuses
)[image_id
] = status
;
4943 if (!vals
.empty()) {
4944 last_read
= image_key(mirror_images
->rbegin()->first
);
4951 int image_status_get_summary(
4952 cls_method_context_t hctx
,
4953 std::map
<cls::rbd::MirrorImageStatusState
, int> *states
) {
4954 std::set
<entity_inst_t
> watchers
;
4955 int r
= list_watchers(hctx
, &watchers
);
4962 string last_read
= IMAGE_KEY_PREFIX
;
4963 int max_read
= RBD_MAX_KEYS_READ
;
4966 map
<string
, bufferlist
> vals
;
4967 r
= cls_cxx_map_get_vals(hctx
, last_read
, IMAGE_KEY_PREFIX
,
4968 max_read
, &vals
, &more
);
4971 CLS_ERR("error reading mirrored images: %s", cpp_strerror(r
).c_str());
4976 for (auto &list_it
: vals
) {
4977 const string
&key
= list_it
.first
;
4979 if (0 != key
.compare(0, IMAGE_KEY_PREFIX
.size(), IMAGE_KEY_PREFIX
)) {
4983 cls::rbd::MirrorImage mirror_image
;
4984 auto iter
= list_it
.second
.cbegin();
4986 decode(mirror_image
, iter
);
4987 } catch (const buffer::error
&err
) {
4988 CLS_ERR("could not decode mirror image payload for key '%s'",
4993 cls::rbd::MirrorImageStatus status
;
4994 image_status_get(hctx
, mirror_image
.global_image_id
, watchers
, &status
);
4996 cls::rbd::MirrorImageStatusState state
= status
.up
? status
.state
:
4997 cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
;
5001 if (!vals
.empty()) {
5002 last_read
= vals
.rbegin()->first
;
5009 int image_status_remove_down(cls_method_context_t hctx
) {
5010 std::set
<entity_inst_t
> watchers
;
5011 int r
= list_watchers(hctx
, &watchers
);
5016 string last_read
= STATUS_GLOBAL_KEY_PREFIX
;
5017 int max_read
= RBD_MAX_KEYS_READ
;
5020 map
<string
, bufferlist
> vals
;
5021 r
= cls_cxx_map_get_vals(hctx
, last_read
, STATUS_GLOBAL_KEY_PREFIX
,
5022 max_read
, &vals
, &more
);
5025 CLS_ERR("error reading mirrored images: %s", cpp_strerror(r
).c_str());
5030 for (auto &list_it
: vals
) {
5031 const string
&key
= list_it
.first
;
5033 if (0 != key
.compare(0, STATUS_GLOBAL_KEY_PREFIX
.size(),
5034 STATUS_GLOBAL_KEY_PREFIX
)) {
5038 MirrorImageStatusOnDisk status
;
5040 auto it
= list_it
.second
.cbegin();
5041 status
.decode_meta(it
);
5042 } catch (const buffer::error
&err
) {
5043 CLS_ERR("could not decode status metadata for mirrored image '%s'",
5048 if (watchers
.find(status
.origin
) == watchers
.end()) {
5049 CLS_LOG(20, "removing stale status object for key %s",
5051 int r1
= cls_cxx_map_remove_key(hctx
, key
);
5053 CLS_ERR("error removing stale status for key '%s': %s",
5054 key
.c_str(), cpp_strerror(r1
).c_str());
5060 if (!vals
.empty()) {
5061 last_read
= vals
.rbegin()->first
;
5068 int image_instance_get(cls_method_context_t hctx
,
5069 const string
&global_image_id
,
5070 const std::set
<entity_inst_t
> &watchers
,
5071 entity_inst_t
*instance
) {
5073 int r
= cls_cxx_map_get_val(hctx
, status_global_key(global_image_id
), &bl
);
5076 CLS_ERR("error reading status for mirrored image, global id '%s': '%s'",
5077 global_image_id
.c_str(), cpp_strerror(r
).c_str());
5082 MirrorImageStatusOnDisk ondisk_status
;
5084 auto it
= bl
.cbegin();
5085 decode(ondisk_status
, it
);
5086 } catch (const buffer::error
&err
) {
5087 CLS_ERR("could not decode status for mirrored image, global id '%s'",
5088 global_image_id
.c_str());
5092 if (watchers
.find(ondisk_status
.origin
) == watchers
.end()) {
5096 *instance
= ondisk_status
.origin
;
5100 int image_instance_list(cls_method_context_t hctx
,
5101 const std::string
&start_after
,
5102 uint64_t max_return
,
5103 map
<std::string
, entity_inst_t
> *instances
) {
5104 std::string last_read
= image_key(start_after
);
5105 int max_read
= RBD_MAX_KEYS_READ
;
5108 std::set
<entity_inst_t
> watchers
;
5109 int r
= list_watchers(hctx
, &watchers
);
5114 while (more
&& instances
->size() < max_return
) {
5115 std::map
<std::string
, bufferlist
> vals
;
5116 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
5117 r
= cls_cxx_map_get_vals(hctx
, last_read
, IMAGE_KEY_PREFIX
, max_read
, &vals
,
5121 CLS_ERR("error reading mirror image directory by name: %s",
5122 cpp_strerror(r
).c_str());
5127 for (auto it
= vals
.begin(); it
!= vals
.end() &&
5128 instances
->size() < max_return
; ++it
) {
5129 const std::string
&image_id
= it
->first
.substr(IMAGE_KEY_PREFIX
.size());
5130 cls::rbd::MirrorImage mirror_image
;
5131 auto iter
= it
->second
.cbegin();
5133 decode(mirror_image
, iter
);
5134 } catch (const buffer::error
&err
) {
5135 CLS_ERR("could not decode mirror image payload of image '%s'",
5140 entity_inst_t instance
;
5141 r
= image_instance_get(hctx
, mirror_image
.global_image_id
, watchers
,
5147 (*instances
)[image_id
] = instance
;
5149 if (!vals
.empty()) {
5150 last_read
= vals
.rbegin()->first
;
5157 int instances_list(cls_method_context_t hctx
,
5158 std::vector
<std::string
> *instance_ids
) {
5159 std::string last_read
= INSTANCE_KEY_PREFIX
;
5160 int max_read
= RBD_MAX_KEYS_READ
;
5163 std::map
<std::string
, bufferlist
> vals
;
5164 int r
= cls_cxx_map_get_vals(hctx
, last_read
, INSTANCE_KEY_PREFIX
.c_str(),
5165 max_read
, &vals
, &more
);
5168 CLS_ERR("error reading mirror instances: %s", cpp_strerror(r
).c_str());
5173 for (auto &it
: vals
) {
5174 instance_ids
->push_back(it
.first
.substr(INSTANCE_KEY_PREFIX
.size()));
5177 if (!vals
.empty()) {
5178 last_read
= vals
.rbegin()->first
;
5184 int instances_add(cls_method_context_t hctx
, const string
&instance_id
) {
5187 int r
= cls_cxx_map_set_val(hctx
, instance_key(instance_id
), &bl
);
5189 CLS_ERR("error setting mirror instance %s: %s", instance_id
.c_str(),
5190 cpp_strerror(r
).c_str());
5196 int instances_remove(cls_method_context_t hctx
, const string
&instance_id
) {
5198 int r
= cls_cxx_map_remove_key(hctx
, instance_key(instance_id
));
5200 CLS_ERR("error removing mirror instance %s: %s", instance_id
.c_str(),
5201 cpp_strerror(r
).c_str());
5207 int mirror_image_map_list(cls_method_context_t hctx
,
5208 const std::string
&start_after
,
5209 uint64_t max_return
,
5210 std::map
<std::string
, cls::rbd::MirrorImageMap
> *image_mapping
) {
5212 std::string last_read
= mirror_image_map_key(start_after
);
5214 while (more
&& image_mapping
->size() < max_return
) {
5215 std::map
<std::string
, bufferlist
> vals
;
5216 CLS_LOG(20, "last read: '%s'", last_read
.c_str());
5218 int max_read
= std::min
<uint64_t>(RBD_MAX_KEYS_READ
, max_return
- image_mapping
->size());
5219 int r
= cls_cxx_map_get_vals(hctx
, last_read
, MIRROR_IMAGE_MAP_KEY_PREFIX
,
5220 max_read
, &vals
, &more
);
5222 CLS_ERR("error reading image map: %s", cpp_strerror(r
).c_str());
5230 for (auto it
= vals
.begin(); it
!= vals
.end(); ++it
) {
5231 const std::string
&global_image_id
=
5232 it
->first
.substr(MIRROR_IMAGE_MAP_KEY_PREFIX
.size());
5234 cls::rbd::MirrorImageMap mirror_image_map
;
5235 auto iter
= it
->second
.cbegin();
5237 decode(mirror_image_map
, iter
);
5238 } catch (const buffer::error
&err
) {
5239 CLS_ERR("could not decode image map payload: %s",
5240 cpp_strerror(r
).c_str());
5244 image_mapping
->insert(std::make_pair(global_image_id
, mirror_image_map
));
5247 if (!vals
.empty()) {
5248 last_read
= vals
.rbegin()->first
;
5255 } // namespace mirror
5262 * @param uuid (std::string)
5263 * @returns 0 on success, negative error code on failure
5265 int mirror_uuid_get(cls_method_context_t hctx
, bufferlist
*in
,
5267 std::string mirror_uuid
;
5268 int r
= mirror::uuid_get(hctx
, &mirror_uuid
);
5273 encode(mirror_uuid
, *out
);
5279 * @param mirror_uuid (std::string)
5282 * @returns 0 on success, negative error code on failure
5284 int mirror_uuid_set(cls_method_context_t hctx
, bufferlist
*in
,
5286 std::string mirror_uuid
;
5288 auto bl_it
= in
->cbegin();
5289 decode(mirror_uuid
, bl_it
);
5290 } catch (const buffer::error
&err
) {
5294 if (mirror_uuid
.empty()) {
5295 CLS_ERR("cannot set empty mirror uuid");
5299 uint32_t mirror_mode
;
5300 int r
= read_key(hctx
, mirror::MODE
, &mirror_mode
);
5301 if (r
< 0 && r
!= -ENOENT
) {
5303 } else if (r
== 0 && mirror_mode
!= cls::rbd::MIRROR_MODE_DISABLED
) {
5304 CLS_ERR("cannot set mirror uuid while mirroring enabled");
5308 bufferlist mirror_uuid_bl
;
5309 mirror_uuid_bl
.append(mirror_uuid
);
5310 r
= cls_cxx_map_set_val(hctx
, mirror::UUID
, &mirror_uuid_bl
);
5312 CLS_ERR("failed to set mirror uuid");
5323 * @param cls::rbd::MirrorMode (uint32_t)
5324 * @returns 0 on success, negative error code on failure
5326 int mirror_mode_get(cls_method_context_t hctx
, bufferlist
*in
,
5328 uint32_t mirror_mode_decode
;
5329 int r
= read_key(hctx
, mirror::MODE
, &mirror_mode_decode
);
5334 encode(mirror_mode_decode
, *out
);
5340 * @param mirror_mode (cls::rbd::MirrorMode) (uint32_t)
5343 * @returns 0 on success, negative error code on failure
5345 int mirror_mode_set(cls_method_context_t hctx
, bufferlist
*in
,
5347 uint32_t mirror_mode_decode
;
5349 auto bl_it
= in
->cbegin();
5350 decode(mirror_mode_decode
, bl_it
);
5351 } catch (const buffer::error
&err
) {
5356 switch (static_cast<cls::rbd::MirrorMode
>(mirror_mode_decode
)) {
5357 case cls::rbd::MIRROR_MODE_DISABLED
:
5360 case cls::rbd::MIRROR_MODE_IMAGE
:
5361 case cls::rbd::MIRROR_MODE_POOL
:
5365 CLS_ERR("invalid mirror mode: %d", mirror_mode_decode
);
5371 std::string mirror_uuid
;
5372 r
= mirror::uuid_get(hctx
, &mirror_uuid
);
5380 encode(mirror_mode_decode
, bl
);
5382 r
= cls_cxx_map_set_val(hctx
, mirror::MODE
, &bl
);
5384 CLS_ERR("error enabling mirroring: %s", cpp_strerror(r
).c_str());
5388 std::vector
<cls::rbd::MirrorPeer
> peers
;
5389 r
= mirror::read_peers(hctx
, &peers
);
5390 if (r
< 0 && r
!= -ENOENT
) {
5394 if (!peers
.empty()) {
5395 CLS_ERR("mirroring peers still registered");
5399 r
= remove_key(hctx
, mirror::MODE
);
5404 r
= remove_key(hctx
, mirror::UUID
);
5417 * @param std::vector<cls::rbd::MirrorPeer>: collection of peers
5418 * @returns 0 on success, negative error code on failure
5420 int mirror_peer_list(cls_method_context_t hctx
, bufferlist
*in
,
5422 std::vector
<cls::rbd::MirrorPeer
> peers
;
5423 int r
= mirror::read_peers(hctx
, &peers
);
5424 if (r
< 0 && r
!= -ENOENT
) {
5428 encode(peers
, *out
);
5434 * @param mirror_peer (cls::rbd::MirrorPeer)
5437 * @returns 0 on success, negative error code on failure
5439 int mirror_peer_add(cls_method_context_t hctx
, bufferlist
*in
,
5441 cls::rbd::MirrorPeer mirror_peer
;
5443 auto it
= in
->cbegin();
5444 decode(mirror_peer
, it
);
5445 } catch (const buffer::error
&err
) {
5449 uint32_t mirror_mode_decode
;
5450 int r
= read_key(hctx
, mirror::MODE
, &mirror_mode_decode
);
5451 if (r
< 0 && r
!= -ENOENT
) {
5453 } else if (r
== -ENOENT
||
5454 mirror_mode_decode
== cls::rbd::MIRROR_MODE_DISABLED
) {
5455 CLS_ERR("mirroring must be enabled on the pool");
5457 } else if (!mirror_peer
.is_valid()) {
5458 CLS_ERR("mirror peer is not valid");
5462 std::string mirror_uuid
;
5463 r
= mirror::uuid_get(hctx
, &mirror_uuid
);
5465 CLS_ERR("error retrieving mirroring uuid: %s", cpp_strerror(r
).c_str());
5467 } else if (mirror_peer
.uuid
== mirror_uuid
) {
5468 CLS_ERR("peer uuid '%s' matches pool mirroring uuid",
5469 mirror_uuid
.c_str());
5473 std::vector
<cls::rbd::MirrorPeer
> peers
;
5474 r
= mirror::read_peers(hctx
, &peers
);
5475 if (r
< 0 && r
!= -ENOENT
) {
5479 for (auto const &peer
: peers
) {
5480 if (peer
.uuid
== mirror_peer
.uuid
) {
5481 CLS_ERR("peer uuid '%s' already exists",
5484 } else if (peer
.cluster_name
== mirror_peer
.cluster_name
&&
5485 (peer
.pool_id
== -1 || mirror_peer
.pool_id
== -1 ||
5486 peer
.pool_id
== mirror_peer
.pool_id
)) {
5487 CLS_ERR("peer cluster name '%s' already exists",
5488 peer
.cluster_name
.c_str());
5494 encode(mirror_peer
, bl
);
5495 r
= cls_cxx_map_set_val(hctx
, mirror::peer_key(mirror_peer
.uuid
),
5498 CLS_ERR("error adding peer: %s", cpp_strerror(r
).c_str());
5506 * @param uuid (std::string)
5509 * @returns 0 on success, negative error code on failure
5511 int mirror_peer_remove(cls_method_context_t hctx
, bufferlist
*in
,
5515 auto it
= in
->cbegin();
5517 } catch (const buffer::error
&err
) {
5521 int r
= cls_cxx_map_remove_key(hctx
, mirror::peer_key(uuid
));
5522 if (r
< 0 && r
!= -ENOENT
) {
5523 CLS_ERR("error removing peer: %s", cpp_strerror(r
).c_str());
5531 * @param uuid (std::string)
5532 * @param client_name (std::string)
5535 * @returns 0 on success, negative error code on failure
5537 int mirror_peer_set_client(cls_method_context_t hctx
, bufferlist
*in
,
5540 std::string client_name
;
5542 auto it
= in
->cbegin();
5544 decode(client_name
, it
);
5545 } catch (const buffer::error
&err
) {
5549 cls::rbd::MirrorPeer peer
;
5550 int r
= mirror::read_peer(hctx
, uuid
, &peer
);
5555 peer
.client_name
= client_name
;
5556 r
= mirror::write_peer(hctx
, uuid
, peer
);
5565 * @param uuid (std::string)
5566 * @param cluster_name (std::string)
5569 * @returns 0 on success, negative error code on failure
5571 int mirror_peer_set_cluster(cls_method_context_t hctx
, bufferlist
*in
,
5574 std::string cluster_name
;
5576 auto it
= in
->cbegin();
5578 decode(cluster_name
, it
);
5579 } catch (const buffer::error
&err
) {
5583 cls::rbd::MirrorPeer peer
;
5584 int r
= mirror::read_peer(hctx
, uuid
, &peer
);
5589 peer
.cluster_name
= cluster_name
;
5590 r
= mirror::write_peer(hctx
, uuid
, peer
);
5599 * @param start_after which name to begin listing after
5600 * (use the empty string to start at the beginning)
5601 * @param max_return the maximum number of names to list
5604 * @param std::map<std::string, std::string>: local id to global id map
5605 * @returns 0 on success, negative error code on failure
5607 int mirror_image_list(cls_method_context_t hctx
, bufferlist
*in
,
5609 std::string start_after
;
5610 uint64_t max_return
;
5612 auto iter
= in
->cbegin();
5613 decode(start_after
, iter
);
5614 decode(max_return
, iter
);
5615 } catch (const buffer::error
&err
) {
5619 int max_read
= RBD_MAX_KEYS_READ
;
5621 std::map
<std::string
, std::string
> mirror_images
;
5622 std::string last_read
= mirror::image_key(start_after
);
5624 while (more
&& mirror_images
.size() < max_return
) {
5625 std::map
<std::string
, bufferlist
> vals
;
5626 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
5627 int r
= cls_cxx_map_get_vals(hctx
, last_read
, mirror::IMAGE_KEY_PREFIX
,
5628 max_read
, &vals
, &more
);
5631 CLS_ERR("error reading mirror image directory by name: %s",
5632 cpp_strerror(r
).c_str());
5637 for (auto it
= vals
.begin(); it
!= vals
.end(); ++it
) {
5638 const std::string
&image_id
=
5639 it
->first
.substr(mirror::IMAGE_KEY_PREFIX
.size());
5640 cls::rbd::MirrorImage mirror_image
;
5641 auto iter
= it
->second
.cbegin();
5643 decode(mirror_image
, iter
);
5644 } catch (const buffer::error
&err
) {
5645 CLS_ERR("could not decode mirror image payload of image '%s'",
5650 mirror_images
[image_id
] = mirror_image
.global_image_id
;
5651 if (mirror_images
.size() >= max_return
) {
5655 if (!vals
.empty()) {
5656 last_read
= mirror::image_key(mirror_images
.rbegin()->first
);
5660 encode(mirror_images
, *out
);
5666 * @param global_id (std::string)
5669 * @param std::string - image id
5670 * @returns 0 on success, negative error code on failure
5672 int mirror_image_get_image_id(cls_method_context_t hctx
, bufferlist
*in
,
5674 std::string global_id
;
5676 auto it
= in
->cbegin();
5677 decode(global_id
, it
);
5678 } catch (const buffer::error
&err
) {
5682 std::string image_id
;
5683 int r
= read_key(hctx
, mirror::global_key(global_id
), &image_id
);
5686 CLS_ERR("error retrieving image id for global id '%s': %s",
5687 global_id
.c_str(), cpp_strerror(r
).c_str());
5692 encode(image_id
, *out
);
5698 * @param image_id (std::string)
5701 * @param cls::rbd::MirrorImage - metadata associated with the image_id
5702 * @returns 0 on success, negative error code on failure
5704 int mirror_image_get(cls_method_context_t hctx
, bufferlist
*in
,
5708 auto it
= in
->cbegin();
5709 decode(image_id
, it
);
5710 } catch (const buffer::error
&err
) {
5714 cls::rbd::MirrorImage mirror_image
;
5715 int r
= mirror::image_get(hctx
, image_id
, &mirror_image
);
5720 encode(mirror_image
, *out
);
5726 * @param image_id (std::string)
5727 * @param mirror_image (cls::rbd::MirrorImage)
5730 * @returns 0 on success, negative error code on failure
5731 * @returns -EEXIST if there's an existing image_id with a different global_image_id
5733 int mirror_image_set(cls_method_context_t hctx
, bufferlist
*in
,
5736 cls::rbd::MirrorImage mirror_image
;
5738 auto it
= in
->cbegin();
5739 decode(image_id
, it
);
5740 decode(mirror_image
, it
);
5741 } catch (const buffer::error
&err
) {
5745 int r
= mirror::image_set(hctx
, image_id
, mirror_image
);
5754 * @param image_id (std::string)
5757 * @returns 0 on success, negative error code on failure
5759 int mirror_image_remove(cls_method_context_t hctx
, bufferlist
*in
,
5763 auto it
= in
->cbegin();
5764 decode(image_id
, it
);
5765 } catch (const buffer::error
&err
) {
5769 int r
= mirror::image_remove(hctx
, image_id
);
5778 * @param global_image_id (std::string)
5779 * @param status (cls::rbd::MirrorImageStatus)
5782 * @returns 0 on success, negative error code on failure
5784 int mirror_image_status_set(cls_method_context_t hctx
, bufferlist
*in
,
5786 string global_image_id
;
5787 cls::rbd::MirrorImageStatus status
;
5789 auto it
= in
->cbegin();
5790 decode(global_image_id
, it
);
5792 } catch (const buffer::error
&err
) {
5796 int r
= mirror::image_status_set(hctx
, global_image_id
, status
);
5805 * @param global_image_id (std::string)
5808 * @returns 0 on success, negative error code on failure
5810 int mirror_image_status_remove(cls_method_context_t hctx
, bufferlist
*in
,
5812 string global_image_id
;
5814 auto it
= in
->cbegin();
5815 decode(global_image_id
, it
);
5816 } catch (const buffer::error
&err
) {
5820 int r
= mirror::image_status_remove(hctx
, global_image_id
);
5829 * @param global_image_id (std::string)
5832 * @param cls::rbd::MirrorImageStatus - metadata associated with the global_image_id
5833 * @returns 0 on success, negative error code on failure
5835 int mirror_image_status_get(cls_method_context_t hctx
, bufferlist
*in
,
5837 string global_image_id
;
5839 auto it
= in
->cbegin();
5840 decode(global_image_id
, it
);
5841 } catch (const buffer::error
&err
) {
5845 std::set
<entity_inst_t
> watchers
;
5846 int r
= mirror::list_watchers(hctx
, &watchers
);
5851 cls::rbd::MirrorImageStatus status
;
5852 r
= mirror::image_status_get(hctx
, global_image_id
, watchers
, &status
);
5857 encode(status
, *out
);
5863 * @param start_after which name to begin listing after
5864 * (use the empty string to start at the beginning)
5865 * @param max_return the maximum number of names to list
5868 * @param std::map<std::string, cls::rbd::MirrorImage>: image id to image map
5869 * @param std::map<std::string, cls::rbd::MirrorImageStatus>: image it to status map
5870 * @returns 0 on success, negative error code on failure
5872 int mirror_image_status_list(cls_method_context_t hctx
, bufferlist
*in
,
5874 std::string start_after
;
5875 uint64_t max_return
;
5877 auto iter
= in
->cbegin();
5878 decode(start_after
, iter
);
5879 decode(max_return
, iter
);
5880 } catch (const buffer::error
&err
) {
5884 map
<std::string
, cls::rbd::MirrorImage
> images
;
5885 map
<std::string
, cls::rbd::MirrorImageStatus
> statuses
;
5886 int r
= mirror::image_status_list(hctx
, start_after
, max_return
, &images
,
5892 encode(images
, *out
);
5893 encode(statuses
, *out
);
5902 * @param std::map<cls::rbd::MirrorImageStatusState, int>: states counts
5903 * @returns 0 on success, negative error code on failure
5905 int mirror_image_status_get_summary(cls_method_context_t hctx
, bufferlist
*in
,
5907 std::map
<cls::rbd::MirrorImageStatusState
, int> states
;
5909 int r
= mirror::image_status_get_summary(hctx
, &states
);
5914 encode(states
, *out
);
5923 * @returns 0 on success, negative error code on failure
5925 int mirror_image_status_remove_down(cls_method_context_t hctx
, bufferlist
*in
,
5927 int r
= mirror::image_status_remove_down(hctx
);
5936 * @param global_image_id (std::string)
5939 * @param entity_inst_t - instance
5940 * @returns 0 on success, negative error code on failure
5942 int mirror_image_instance_get(cls_method_context_t hctx
, bufferlist
*in
,
5944 string global_image_id
;
5946 auto it
= in
->cbegin();
5947 decode(global_image_id
, it
);
5948 } catch (const buffer::error
&err
) {
5952 std::set
<entity_inst_t
> watchers
;
5953 int r
= mirror::list_watchers(hctx
, &watchers
);
5958 entity_inst_t instance
;
5959 r
= mirror::image_instance_get(hctx
, global_image_id
, watchers
, &instance
);
5964 encode(instance
, *out
, cls_get_features(hctx
));
5970 * @param start_after which name to begin listing after
5971 * (use the empty string to start at the beginning)
5972 * @param max_return the maximum number of names to list
5975 * @param std::map<std::string, entity_inst_t>: image id to instance map
5976 * @returns 0 on success, negative error code on failure
5978 int mirror_image_instance_list(cls_method_context_t hctx
, bufferlist
*in
,
5980 std::string start_after
;
5981 uint64_t max_return
;
5983 auto iter
= in
->cbegin();
5984 decode(start_after
, iter
);
5985 decode(max_return
, iter
);
5986 } catch (const buffer::error
&err
) {
5990 map
<std::string
, entity_inst_t
> instances
;
5991 int r
= mirror::image_instance_list(hctx
, start_after
, max_return
,
5997 encode(instances
, *out
, cls_get_features(hctx
));
6006 * @param std::vector<std::string>: instance ids
6007 * @returns 0 on success, negative error code on failure
6009 int mirror_instances_list(cls_method_context_t hctx
, bufferlist
*in
,
6011 std::vector
<std::string
> instance_ids
;
6013 int r
= mirror::instances_list(hctx
, &instance_ids
);
6018 encode(instance_ids
, *out
);
6024 * @param instance_id (std::string)
6027 * @returns 0 on success, negative error code on failure
6029 int mirror_instances_add(cls_method_context_t hctx
, bufferlist
*in
,
6031 std::string instance_id
;
6033 auto iter
= in
->cbegin();
6034 decode(instance_id
, iter
);
6035 } catch (const buffer::error
&err
) {
6039 int r
= mirror::instances_add(hctx
, instance_id
);
6048 * @param instance_id (std::string)
6051 * @returns 0 on success, negative error code on failure
6053 int mirror_instances_remove(cls_method_context_t hctx
, bufferlist
*in
,
6055 std::string instance_id
;
6057 auto iter
= in
->cbegin();
6058 decode(instance_id
, iter
);
6059 } catch (const buffer::error
&err
) {
6063 int r
= mirror::instances_remove(hctx
, instance_id
);
6072 * @param start_after: key to start after
6073 * @param max_return: max return items
6076 * @param std::map<std::string, cls::rbd::MirrorImageMap>: image mapping
6077 * @returns 0 on success, negative error code on failure
6079 int mirror_image_map_list(cls_method_context_t hctx
, bufferlist
*in
,
6081 std::string start_after
;
6082 uint64_t max_return
;
6084 auto it
= in
->cbegin();
6085 decode(start_after
, it
);
6086 decode(max_return
, it
);
6087 } catch (const buffer::error
&err
) {
6091 std::map
<std::string
, cls::rbd::MirrorImageMap
> image_mapping
;
6092 int r
= mirror::mirror_image_map_list(hctx
, start_after
, max_return
, &image_mapping
);
6097 encode(image_mapping
, *out
);
6103 * @param global_image_id: global image id
6104 * @param image_map: image map
6107 * @returns 0 on success, negative error code on failure
6109 int mirror_image_map_update(cls_method_context_t hctx
, bufferlist
*in
,
6111 std::string global_image_id
;
6112 cls::rbd::MirrorImageMap image_map
;
6115 auto it
= in
->cbegin();
6116 decode(global_image_id
, it
);
6117 decode(image_map
, it
);
6118 } catch (const buffer::error
&err
) {
6123 encode(image_map
, bl
);
6125 const std::string key
= mirror::mirror_image_map_key(global_image_id
);
6126 int r
= cls_cxx_map_set_val(hctx
, key
, &bl
);
6128 CLS_ERR("error updating image map %s: %s", key
.c_str(),
6129 cpp_strerror(r
).c_str());
6138 * @param global_image_id: global image id
6141 * @returns 0 on success, negative error code on failure
6143 int mirror_image_map_remove(cls_method_context_t hctx
, bufferlist
*in
,
6145 std::string global_image_id
;
6148 auto it
= in
->cbegin();
6149 decode(global_image_id
, it
);
6150 } catch (const buffer::error
&err
) {
6154 const std::string key
= mirror::mirror_image_map_key(global_image_id
);
6155 int r
= cls_cxx_map_remove_key(hctx
, key
);
6156 if (r
< 0 && r
!= -ENOENT
) {
6157 CLS_ERR("error removing image map %s: %s", key
.c_str(),
6158 cpp_strerror(r
).c_str());
6167 /********************** methods for rbd_group_directory ***********************/
6169 int dir_add(cls_method_context_t hctx
,
6170 const string
&name
, const string
&id
,
6171 bool check_for_unique_id
)
6173 if (!name
.size() || !is_valid_id(id
)) {
6174 CLS_ERR("invalid group name '%s' or id '%s'",
6175 name
.c_str(), id
.c_str());
6179 CLS_LOG(20, "dir_add name=%s id=%s", name
.c_str(), id
.c_str());
6181 string name_key
= dir_key_for_name(name
);
6182 string id_key
= dir_key_for_id(id
);
6184 int r
= read_key(hctx
, name_key
, &tmp
);
6186 CLS_LOG(10, "name already exists");
6189 r
= read_key(hctx
, id_key
, &tmp
);
6190 if (r
!= -ENOENT
&& check_for_unique_id
) {
6191 CLS_LOG(10, "id already exists");
6194 bufferlist id_bl
, name_bl
;
6196 encode(name
, name_bl
);
6197 map
<string
, bufferlist
> omap_vals
;
6198 omap_vals
[name_key
] = id_bl
;
6199 omap_vals
[id_key
] = name_bl
;
6200 return cls_cxx_map_set_vals(hctx
, &omap_vals
);
6203 int dir_remove(cls_method_context_t hctx
,
6204 const string
&name
, const string
&id
)
6206 CLS_LOG(20, "dir_remove name=%s id=%s", name
.c_str(), id
.c_str());
6208 string name_key
= dir_key_for_name(name
);
6209 string id_key
= dir_key_for_id(id
);
6210 string stored_name
, stored_id
;
6212 int r
= read_key(hctx
, name_key
, &stored_id
);
6215 CLS_ERR("error reading name to id mapping: %s", cpp_strerror(r
).c_str());
6218 r
= read_key(hctx
, id_key
, &stored_name
);
6221 CLS_ERR("error reading id to name mapping: %s", cpp_strerror(r
).c_str());
6225 // check if this op raced with a rename
6226 if (stored_name
!= name
|| stored_id
!= id
) {
6227 CLS_ERR("stored name '%s' and id '%s' do not match args '%s' and '%s'",
6228 stored_name
.c_str(), stored_id
.c_str(), name
.c_str(), id
.c_str());
6232 r
= cls_cxx_map_remove_key(hctx
, name_key
);
6234 CLS_ERR("error removing name: %s", cpp_strerror(r
).c_str());
6238 r
= cls_cxx_map_remove_key(hctx
, id_key
);
6240 CLS_ERR("error removing id: %s", cpp_strerror(r
).c_str());
6247 static const string RBD_GROUP_SNAP_KEY_PREFIX
= "snapshot_";
6249 std::string
snap_key(const std::string
&snap_id
) {
6251 oss
<< RBD_GROUP_SNAP_KEY_PREFIX
<< snap_id
;
6255 int snap_list(cls_method_context_t hctx
, cls::rbd::GroupSnapshot start_after
,
6256 uint64_t max_return
,
6257 std::vector
<cls::rbd::GroupSnapshot
> *group_snaps
)
6259 int max_read
= RBD_MAX_KEYS_READ
;
6260 std::map
<string
, bufferlist
> vals
;
6261 string last_read
= snap_key(start_after
.id
);
6263 group_snaps
->clear();
6267 int r
= cls_cxx_map_get_vals(hctx
, last_read
,
6268 RBD_GROUP_SNAP_KEY_PREFIX
,
6269 max_read
, &vals
, &more
);
6273 for (map
<string
, bufferlist
>::iterator it
= vals
.begin();
6274 it
!= vals
.end() && group_snaps
->size() < max_return
; ++it
) {
6276 auto iter
= it
->second
.cbegin();
6277 cls::rbd::GroupSnapshot snap
;
6280 } catch (const buffer::error
&err
) {
6281 CLS_ERR("error decoding snapshot: %s", it
->first
.c_str());
6284 CLS_LOG(20, "Discovered snapshot %s %s",
6287 group_snaps
->push_back(snap
);
6290 } while (more
&& (group_snaps
->size() < max_return
));
6295 static int check_duplicate_snap_name(cls_method_context_t hctx
,
6296 const std::string
&snap_name
,
6297 const std::string
&snap_id
)
6299 const int max_read
= 1024;
6300 cls::rbd::GroupSnapshot snap_last
;
6301 std::vector
<cls::rbd::GroupSnapshot
> page
;
6304 int r
= snap_list(hctx
, snap_last
, max_read
, &page
);
6308 for (auto& snap
: page
) {
6309 if (snap
.name
== snap_name
&& snap
.id
!= snap_id
) {
6314 if (page
.size() < max_read
) {
6318 snap_last
= *page
.rbegin();
6324 } // namespace group
6327 * List groups from the directory.
6330 * @param start_after (std::string)
6331 * @param max_return (int64_t)
6334 * @param map of groups (name, id)
6335 * @return 0 on success, negative error code on failure
6337 int group_dir_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
6340 uint64_t max_return
;
6343 auto iter
= in
->cbegin();
6344 decode(start_after
, iter
);
6345 decode(max_return
, iter
);
6346 } catch (const buffer::error
&err
) {
6350 int max_read
= RBD_MAX_KEYS_READ
;
6352 map
<string
, string
> groups
;
6353 string last_read
= dir_key_for_name(start_after
);
6355 while (more
&& groups
.size() < max_return
) {
6356 map
<string
, bufferlist
> vals
;
6357 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
6358 int r
= cls_cxx_map_get_vals(hctx
, last_read
, RBD_DIR_NAME_KEY_PREFIX
,
6359 max_read
, &vals
, &more
);
6362 CLS_ERR("error reading directory by name: %s", cpp_strerror(r
).c_str());
6367 for (pair
<string
, bufferlist
> val
: vals
) {
6369 auto iter
= val
.second
.cbegin();
6372 } catch (const buffer::error
&err
) {
6373 CLS_ERR("could not decode id of group '%s'", val
.first
.c_str());
6376 CLS_LOG(20, "adding '%s' -> '%s'", dir_name_from_key(val
.first
).c_str(), id
.c_str());
6377 groups
[dir_name_from_key(val
.first
)] = id
;
6378 if (groups
.size() >= max_return
)
6381 if (!vals
.empty()) {
6382 last_read
= dir_key_for_name(groups
.rbegin()->first
);
6386 encode(groups
, *out
);
6392 * Add a group to the directory.
6395 * @param name (std::string)
6396 * @param id (std::string)
6399 * @return 0 on success, negative error code on failure
6401 int group_dir_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
6403 int r
= cls_cxx_create(hctx
, false);
6406 CLS_ERR("could not create group directory: %s",
6407 cpp_strerror(r
).c_str());
6413 auto iter
= in
->cbegin();
6416 } catch (const buffer::error
&err
) {
6420 return group::dir_add(hctx
, name
, id
, true);
6424 * Rename a group to the directory.
6427 * @param src original name of the group (std::string)
6428 * @param dest new name of the group (std::string)
6429 * @param id the id of the group (std::string)
6432 * @return 0 on success, negative error code on failure
6434 int group_dir_rename(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
6436 string src
, dest
, id
;
6438 auto iter
= in
->cbegin();
6442 } catch (const buffer::error
&err
) {
6446 int r
= group::dir_remove(hctx
, src
, id
);
6450 return group::dir_add(hctx
, dest
, id
, false);
6454 * Remove a group from the directory.
6457 * @param name (std::string)
6458 * @param id (std::string)
6461 * @return 0 on success, negative error code on failure
6463 int group_dir_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
6467 auto iter
= in
->cbegin();
6470 } catch (const buffer::error
&err
) {
6474 return group::dir_remove(hctx
, name
, id
);
6478 * Set state of an image in the group.
6481 * @param image_status (cls::rbd::GroupImageStatus)
6484 * @return 0 on success, negative error code on failure
6486 int group_image_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
6488 CLS_LOG(20, "group_image_set");
6490 cls::rbd::GroupImageStatus st
;
6492 auto iter
= in
->cbegin();
6494 } catch (const buffer::error
&err
) {
6498 string image_key
= st
.spec
.image_key();
6500 bufferlist image_val_bl
;
6501 encode(st
.state
, image_val_bl
);
6502 int r
= cls_cxx_map_set_val(hctx
, image_key
, &image_val_bl
);
6511 * Remove reference to an image from the group.
6514 * @param spec (cls::rbd::GroupImageSpec)
6517 * @return 0 on success, negative error code on failure
6519 int group_image_remove(cls_method_context_t hctx
,
6520 bufferlist
*in
, bufferlist
*out
)
6522 CLS_LOG(20, "group_image_remove");
6523 cls::rbd::GroupImageSpec spec
;
6525 auto iter
= in
->cbegin();
6527 } catch (const buffer::error
&err
) {
6531 string image_key
= spec
.image_key();
6533 int r
= cls_cxx_map_remove_key(hctx
, image_key
);
6535 CLS_ERR("error removing image from group: %s", cpp_strerror(r
).c_str());
6543 * List images in the group.
6546 * @param start_after which name to begin listing after
6547 * (use the empty string to start at the beginning)
6548 * @param max_return the maximum number of names to list
6551 * @param tuples of descriptions of the images: image_id, pool_id, image reference state.
6552 * @return 0 on success, negative error code on failure
6554 int group_image_list(cls_method_context_t hctx
,
6555 bufferlist
*in
, bufferlist
*out
)
6557 CLS_LOG(20, "group_image_list");
6558 cls::rbd::GroupImageSpec start_after
;
6559 uint64_t max_return
;
6561 auto iter
= in
->cbegin();
6562 decode(start_after
, iter
);
6563 decode(max_return
, iter
);
6564 } catch (const buffer::error
&err
) {
6568 int max_read
= RBD_MAX_KEYS_READ
;
6569 std::map
<string
, bufferlist
> vals
;
6570 string last_read
= start_after
.image_key();
6571 std::vector
<cls::rbd::GroupImageStatus
> res
;
6574 int r
= cls_cxx_map_get_vals(hctx
, last_read
,
6575 cls::rbd::RBD_GROUP_IMAGE_KEY_PREFIX
,
6576 max_read
, &vals
, &more
);
6580 for (map
<string
, bufferlist
>::iterator it
= vals
.begin();
6581 it
!= vals
.end() && res
.size() < max_return
; ++it
) {
6583 auto iter
= it
->second
.cbegin();
6584 cls::rbd::GroupImageLinkState state
;
6586 decode(state
, iter
);
6587 } catch (const buffer::error
&err
) {
6588 CLS_ERR("error decoding state for image: %s", it
->first
.c_str());
6591 cls::rbd::GroupImageSpec spec
;
6592 int r
= cls::rbd::GroupImageSpec::from_key(it
->first
, &spec
);
6596 CLS_LOG(20, "Discovered image %s %" PRId64
" %d", spec
.image_id
.c_str(),
6599 res
.push_back(cls::rbd::GroupImageStatus(spec
, state
));
6601 if (res
.size() > 0) {
6602 last_read
= res
.rbegin()->spec
.image_key();
6605 } while (more
&& (res
.size() < max_return
));
6612 * Reference the group this image belongs to.
6615 * @param group_id (std::string)
6616 * @param pool_id (int64_t)
6619 * @return 0 on success, negative error code on failure
6621 int image_group_add(cls_method_context_t hctx
,
6622 bufferlist
*in
, bufferlist
*out
)
6624 CLS_LOG(20, "image_group_add");
6625 cls::rbd::GroupSpec new_group
;
6627 auto iter
= in
->cbegin();
6628 decode(new_group
, iter
);
6629 } catch (const buffer::error
&err
) {
6633 bufferlist existing_refbl
;
6635 int r
= cls_cxx_map_get_val(hctx
, RBD_GROUP_REF
, &existing_refbl
);
6637 // If we are trying to link this image to the same group then return
6638 // success. If this image already belongs to another group then abort.
6639 cls::rbd::GroupSpec old_group
;
6641 auto iter
= existing_refbl
.cbegin();
6642 decode(old_group
, iter
);
6643 } catch (const buffer::error
&err
) {
6647 if ((old_group
.group_id
!= new_group
.group_id
) ||
6648 (old_group
.pool_id
!= new_group
.pool_id
)) {
6651 return 0; // In this case the values are already correct
6653 } else if (r
< 0 && r
!= -ENOENT
) {
6654 // No entry means this image is not a member of any group.
6658 r
= image::set_op_features(hctx
, RBD_OPERATION_FEATURE_GROUP
,
6659 RBD_OPERATION_FEATURE_GROUP
);
6665 encode(new_group
, refbl
);
6666 r
= cls_cxx_map_set_val(hctx
, RBD_GROUP_REF
, &refbl
);
6675 * Remove image's pointer to the group.
6678 * @param cg_id (std::string)
6679 * @param pool_id (int64_t)
6682 * @return 0 on success, negative error code on failure
6684 int image_group_remove(cls_method_context_t hctx
,
6688 CLS_LOG(20, "image_group_remove");
6689 cls::rbd::GroupSpec spec
;
6691 auto iter
= in
->cbegin();
6693 } catch (const buffer::error
&err
) {
6698 int r
= cls_cxx_map_get_val(hctx
, RBD_GROUP_REF
, &refbl
);
6703 cls::rbd::GroupSpec ref_spec
;
6704 auto iter
= refbl
.cbegin();
6706 decode(ref_spec
, iter
);
6707 } catch (const buffer::error
&err
) {
6711 if (ref_spec
.pool_id
!= spec
.pool_id
|| ref_spec
.group_id
!= spec
.group_id
) {
6715 r
= cls_cxx_map_remove_key(hctx
, RBD_GROUP_REF
);
6720 r
= image::set_op_features(hctx
, 0, RBD_OPERATION_FEATURE_GROUP
);
6729 * Retrieve the id and pool of the group this image belongs to.
6736 * @return 0 on success, negative error code on failure
6738 int image_group_get(cls_method_context_t hctx
,
6739 bufferlist
*in
, bufferlist
*out
)
6741 CLS_LOG(20, "image_group_get");
6743 int r
= cls_cxx_map_get_val(hctx
, RBD_GROUP_REF
, &refbl
);
6744 if (r
< 0 && r
!= -ENOENT
) {
6748 cls::rbd::GroupSpec spec
;
6751 auto iter
= refbl
.cbegin();
6754 } catch (const buffer::error
&err
) {
6764 * Save initial snapshot record.
6767 * @param GroupSnapshot
6770 * @return 0 on success, negative error code on failure
6772 int group_snap_set(cls_method_context_t hctx
,
6773 bufferlist
*in
, bufferlist
*out
)
6775 CLS_LOG(20, "group_snap_set");
6776 cls::rbd::GroupSnapshot group_snap
;
6778 auto iter
= in
->cbegin();
6779 decode(group_snap
, iter
);
6780 } catch (const buffer::error
&err
) {
6784 if (group_snap
.name
.empty()) {
6785 CLS_ERR("group snapshot name is empty");
6788 if (group_snap
.id
.empty()) {
6789 CLS_ERR("group snapshot id is empty");
6793 int r
= group::check_duplicate_snap_name(hctx
, group_snap
.name
,
6799 std::string key
= group::snap_key(group_snap
.id
);
6800 if (group_snap
.state
== cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
) {
6802 r
= cls_cxx_map_get_val(hctx
, key
, &snap_bl
);
6803 if (r
< 0 && r
!= -ENOENT
) {
6805 } else if (r
>= 0) {
6811 encode(group_snap
, obl
);
6812 r
= cls_cxx_map_set_val(hctx
, key
, &obl
);
6817 * Remove snapshot record.
6820 * @param id Snapshot id
6823 * @return 0 on success, negative error code on failure
6825 int group_snap_remove(cls_method_context_t hctx
,
6826 bufferlist
*in
, bufferlist
*out
)
6828 CLS_LOG(20, "group_snap_remove");
6829 std::string snap_id
;
6831 auto iter
= in
->cbegin();
6832 decode(snap_id
, iter
);
6833 } catch (const buffer::error
&err
) {
6837 std::string snap_key
= group::snap_key(snap_id
);
6839 CLS_LOG(20, "removing snapshot with key %s", snap_key
.c_str());
6840 int r
= cls_cxx_map_remove_key(hctx
, snap_key
);
6845 * Get group's snapshot by id.
6848 * @param snapshot_id the id of the snapshot to look for.
6851 * @param GroupSnapshot the requested snapshot
6852 * @return 0 on success, negative error code on failure
6854 int group_snap_get_by_id(cls_method_context_t hctx
,
6855 bufferlist
*in
, bufferlist
*out
)
6857 CLS_LOG(20, "group_snap_get_by_id");
6859 std::string snap_id
;
6861 auto iter
= in
->cbegin();
6862 decode(snap_id
, iter
);
6863 } catch (const buffer::error
&err
) {
6869 int r
= cls_cxx_map_get_val(hctx
, group::snap_key(snap_id
), &snapbl
);
6874 cls::rbd::GroupSnapshot group_snap
;
6875 auto iter
= snapbl
.cbegin();
6877 decode(group_snap
, iter
);
6878 } catch (const buffer::error
&err
) {
6879 CLS_ERR("error decoding snapshot: %s", snap_id
.c_str());
6883 encode(group_snap
, *out
);
6889 * List group's snapshots.
6892 * @param start_after which name to begin listing after
6893 * (use the empty string to start at the beginning)
6894 * @param max_return the maximum number of snapshots to list
6897 * @param list of snapshots
6898 * @return 0 on success, negative error code on failure
6900 int group_snap_list(cls_method_context_t hctx
,
6901 bufferlist
*in
, bufferlist
*out
)
6903 CLS_LOG(20, "group_snap_list");
6905 cls::rbd::GroupSnapshot start_after
;
6906 uint64_t max_return
;
6908 auto iter
= in
->cbegin();
6909 decode(start_after
, iter
);
6910 decode(max_return
, iter
);
6911 } catch (const buffer::error
&err
) {
6914 std::vector
<cls::rbd::GroupSnapshot
> group_snaps
;
6915 group::snap_list(hctx
, start_after
, max_return
, &group_snaps
);
6917 encode(group_snaps
, *out
);
6924 static const std::string
IMAGE_KEY_PREFIX("id_");
6926 std::string
image_key(const std::string
&image_id
) {
6927 return IMAGE_KEY_PREFIX
+ image_id
;
6930 std::string
image_id_from_key(const std::string
&key
) {
6931 return key
.substr(IMAGE_KEY_PREFIX
.size());
6934 } // namespace trash
6937 * Add an image entry to the rbd trash. Creates the trash object if
6938 * needed, and stores the trash spec information of the deleted image.
6941 * @param id the id of the image
6942 * @param trash_spec the spec info of the deleted image
6945 * @returns -EEXIST if the image id is already in the trash
6946 * @returns 0 on success, negative error code on failure
6948 int trash_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
6950 int r
= cls_cxx_create(hctx
, false);
6952 CLS_ERR("could not create trash: %s", cpp_strerror(r
).c_str());
6957 cls::rbd::TrashImageSpec trash_spec
;
6959 auto iter
= in
->cbegin();
6961 decode(trash_spec
, iter
);
6962 } catch (const buffer::error
&err
) {
6966 if (!is_valid_id(id
)) {
6967 CLS_ERR("trash_add: invalid id '%s'", id
.c_str());
6971 CLS_LOG(20, "trash_add id=%s", id
.c_str());
6973 string key
= trash::image_key(id
);
6974 cls::rbd::TrashImageSpec tmp
;
6975 r
= read_key(hctx
, key
, &tmp
);
6976 if (r
< 0 && r
!= -ENOENT
) {
6977 CLS_ERR("could not read key %s entry from trash: %s", key
.c_str(),
6978 cpp_strerror(r
).c_str());
6980 } else if (r
== 0) {
6981 CLS_LOG(10, "id already exists");
6985 map
<string
, bufferlist
> omap_vals
;
6986 encode(trash_spec
, omap_vals
[key
]);
6987 return cls_cxx_map_set_vals(hctx
, &omap_vals
);
6991 * Removes an image entry from the rbd trash object.
6995 * @param id the id of the image
6998 * @returns -ENOENT if the image id does not exist in the trash
6999 * @returns 0 on success, negative error code on failure
7001 int trash_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7005 auto iter
= in
->cbegin();
7007 } catch (const buffer::error
&err
) {
7011 CLS_LOG(20, "trash_remove id=%s", id
.c_str());
7013 string key
= trash::image_key(id
);
7015 int r
= cls_cxx_map_get_val(hctx
, key
, &tmp
);
7018 CLS_ERR("error reading entry key %s: %s", key
.c_str(), cpp_strerror(r
).c_str());
7023 r
= cls_cxx_map_remove_key(hctx
, key
);
7025 CLS_ERR("error removing entry: %s", cpp_strerror(r
).c_str());
7033 * Returns the list of trash spec entries registered in the rbd_trash
7037 * @param start_after which name to begin listing after
7038 * (use the empty string to start at the beginning)
7039 * @param max_return the maximum number of names to list
7042 * @param data the map between image id and trash spec info
7044 * @returns 0 on success, negative error code on failure
7046 int trash_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7049 uint64_t max_return
;
7052 auto iter
= in
->cbegin();
7053 decode(start_after
, iter
);
7054 decode(max_return
, iter
);
7055 } catch (const buffer::error
&err
) {
7059 map
<string
, cls::rbd::TrashImageSpec
> data
;
7060 string last_read
= trash::image_key(start_after
);
7063 CLS_LOG(20, "trash_get_images");
7064 while (data
.size() < max_return
) {
7065 map
<string
, bufferlist
> raw_data
;
7066 int max_read
= std::min
<int32_t>(RBD_MAX_KEYS_READ
,
7067 max_return
- data
.size());
7068 int r
= cls_cxx_map_get_vals(hctx
, last_read
, trash::IMAGE_KEY_PREFIX
,
7069 max_read
, &raw_data
, &more
);
7072 CLS_ERR("failed to read the vals off of disk: %s",
7073 cpp_strerror(r
).c_str());
7077 if (raw_data
.empty()) {
7081 map
<string
, bufferlist
>::iterator it
= raw_data
.begin();
7082 for (; it
!= raw_data
.end(); ++it
) {
7083 decode(data
[trash::image_id_from_key(it
->first
)], it
->second
);
7090 last_read
= raw_data
.rbegin()->first
;
7098 * Returns the trash spec entry of an image registered in the rbd_trash
7102 * @param id the id of the image
7105 * @param out the trash spec entry
7107 * @returns 0 on success, negative error code on failure
7109 int trash_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7113 auto iter
= in
->cbegin();
7115 } catch (const buffer::error
&err
) {
7119 CLS_LOG(20, "trash_get_image id=%s", id
.c_str());
7122 string key
= trash::image_key(id
);
7124 int r
= cls_cxx_map_get_val(hctx
, key
, out
);
7125 if (r
< 0 && r
!= -ENOENT
) {
7126 CLS_ERR("error reading image from trash '%s': '%s'", id
.c_str(),
7127 cpp_strerror(r
).c_str());
7133 * Set state of an image in the rbd_trash object.
7136 * @param id the id of the image
7137 * @param trash_state the state of the image to be set
7138 * @param expect_state the expected state of the image
7141 * @returns 0 on success, negative error code on failure
7143 int trash_state_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7146 cls::rbd::TrashImageState trash_state
;
7147 cls::rbd::TrashImageState expect_state
;
7149 bufferlist::const_iterator iter
= in
->begin();
7151 decode(trash_state
, iter
);
7152 decode(expect_state
, iter
);
7153 } catch (const buffer::error
&err
) {
7157 CLS_LOG(20, "trash_state_set id=%s", id
.c_str());
7159 string key
= trash::image_key(id
);
7160 cls::rbd::TrashImageSpec trash_spec
;
7161 int r
= read_key(hctx
, key
, &trash_spec
);
7164 CLS_ERR("Could not read trash image spec off disk: %s",
7165 cpp_strerror(r
).c_str());
7170 if (trash_spec
.state
== expect_state
) {
7171 trash_spec
.state
= trash_state
;
7172 r
= write_key(hctx
, key
, trash_spec
);
7174 CLS_ERR("error setting trash image state: %s", cpp_strerror(r
).c_str());
7179 } else if (trash_spec
.state
== trash_state
) {
7182 CLS_ERR("Current trash state: %d do not match expected: %d or set: %d",
7183 trash_spec
.state
, expect_state
, trash_state
);
7190 const std::string
NAME_KEY_PREFIX("name_");
7192 std::string
key_for_name(const std::string
& name
) {
7193 return NAME_KEY_PREFIX
+ name
;
7196 std::string
name_from_key(const std::string
&key
) {
7197 return key
.substr(NAME_KEY_PREFIX
.size());
7200 } // namespace nspace
7203 * Add a namespace to the namespace directory.
7206 * @param name the name of the namespace
7209 * @returns -EEXIST if the namespace is already exists
7210 * @returns 0 on success, negative error code on failure
7212 int namespace_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7216 auto iter
= in
->cbegin();
7218 } catch (const buffer::error
&err
) {
7222 std::string
key(nspace::key_for_name(name
));
7224 int r
= cls_cxx_map_get_val(hctx
, key
, &value
);
7225 if (r
< 0 && r
!= -ENOENT
) {
7227 } else if (r
== 0) {
7231 r
= cls_cxx_map_set_val(hctx
, key
, &value
);
7233 CLS_ERR("failed to set omap key: %s", key
.c_str());
7241 * Remove a namespace from the namespace directory.
7244 * @param name the name of the namespace
7247 * @returns 0 on success, negative error code on failure
7249 int namespace_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7253 auto iter
= in
->cbegin();
7255 } catch (const buffer::error
&err
) {
7259 std::string
key(nspace::key_for_name(name
));
7261 int r
= cls_cxx_map_get_val(hctx
, key
, &bl
);
7266 r
= cls_cxx_map_remove_key(hctx
, key
);
7275 * Returns the list of namespaces in the rbd_namespace object
7278 * @param start_after which name to begin listing after
7279 * (use the empty string to start at the beginning)
7280 * @param max_return the maximum number of names to list
7283 * @param data list of namespace names
7284 * @returns 0 on success, negative error code on failure
7286 int namespace_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7289 uint64_t max_return
;
7291 auto iter
= in
->cbegin();
7292 decode(start_after
, iter
);
7293 decode(max_return
, iter
);
7294 } catch (const buffer::error
&err
) {
7298 std::list
<std::string
> data
;
7299 std::string last_read
= nspace::key_for_name(start_after
);
7302 CLS_LOG(20, "namespace_list");
7303 while (data
.size() < max_return
) {
7304 std::map
<std::string
, bufferlist
> raw_data
;
7305 int max_read
= std::min
<int32_t>(RBD_MAX_KEYS_READ
,
7306 max_return
- data
.size());
7307 int r
= cls_cxx_map_get_vals(hctx
, last_read
, nspace::NAME_KEY_PREFIX
,
7308 max_read
, &raw_data
, &more
);
7311 CLS_ERR("failed to read the vals off of disk: %s",
7312 cpp_strerror(r
).c_str());
7317 for (auto& it
: raw_data
) {
7318 data
.push_back(nspace::name_from_key(it
.first
));
7321 if (raw_data
.empty() || !more
) {
7325 last_read
= raw_data
.rbegin()->first
;
7333 * Reclaim space for zeroed extents
7336 * @param sparse_size minimal zeroed block to sparse
7337 * @param remove_empty boolean, true if the object should be removed if empty
7340 * @returns -ENOENT if the object does not exist or has been removed
7341 * @returns 0 on success, negative error code on failure
7343 int sparsify(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7348 auto iter
= in
->cbegin();
7349 decode(sparse_size
, iter
);
7350 decode(remove_empty
, iter
);
7351 } catch (const buffer::error
&err
) {
7355 int r
= check_exists(hctx
);
7361 r
= cls_cxx_read(hctx
, 0, 0, &bl
);
7363 CLS_ERR("failed to read data off of disk: %s", cpp_strerror(r
).c_str());
7369 CLS_LOG(20, "remove");
7370 r
= cls_cxx_remove(hctx
);
7372 CLS_ERR("remove failed: %s", cpp_strerror(r
).c_str());
7375 } else if (bl
.length() > 0) {
7376 CLS_LOG(20, "truncate");
7377 bufferlist write_bl
;
7378 r
= cls_cxx_replace(hctx
, 0, 0, &write_bl
);
7380 CLS_ERR("truncate failed: %s", cpp_strerror(r
).c_str());
7384 CLS_LOG(20, "skip empty");
7389 bl
.rebuild(buffer::ptr_node::create(bl
.length()));
7390 size_t write_offset
= 0;
7391 size_t write_length
= 0;
7393 size_t length
= bl
.length();
7394 const auto& ptr
= bl
.front();
7395 bool replace
= true;
7396 while (offset
< length
) {
7397 if (calc_sparse_extent(ptr
, sparse_size
, length
, &write_offset
,
7398 &write_length
, &offset
)) {
7399 if (write_offset
== 0 && write_length
== length
) {
7400 CLS_LOG(20, "nothing to do");
7403 CLS_LOG(20, "write%s %" PRIu64
"~%" PRIu64
, (replace
? "(replace)" : ""),
7404 write_offset
, write_length
);
7405 bufferlist write_bl
;
7406 write_bl
.push_back(buffer::ptr_node::create(ptr
, write_offset
,
7409 r
= cls_cxx_replace(hctx
, write_offset
, write_length
, &write_bl
);
7412 r
= cls_cxx_write(hctx
, write_offset
, write_length
, &write_bl
);
7415 CLS_ERR("write failed: %s", cpp_strerror(r
).c_str());
7418 write_offset
= offset
;
7428 CLS_LOG(20, "Loaded rbd class!");
7430 cls_handle_t h_class
;
7431 cls_method_handle_t h_create
;
7432 cls_method_handle_t h_get_features
;
7433 cls_method_handle_t h_set_features
;
7434 cls_method_handle_t h_get_size
;
7435 cls_method_handle_t h_set_size
;
7436 cls_method_handle_t h_get_parent
;
7437 cls_method_handle_t h_set_parent
;
7438 cls_method_handle_t h_remove_parent
;
7439 cls_method_handle_t h_parent_get
;
7440 cls_method_handle_t h_parent_overlap_get
;
7441 cls_method_handle_t h_parent_attach
;
7442 cls_method_handle_t h_parent_detach
;
7443 cls_method_handle_t h_get_protection_status
;
7444 cls_method_handle_t h_set_protection_status
;
7445 cls_method_handle_t h_get_stripe_unit_count
;
7446 cls_method_handle_t h_set_stripe_unit_count
;
7447 cls_method_handle_t h_get_create_timestamp
;
7448 cls_method_handle_t h_get_access_timestamp
;
7449 cls_method_handle_t h_get_modify_timestamp
;
7450 cls_method_handle_t h_get_flags
;
7451 cls_method_handle_t h_set_flags
;
7452 cls_method_handle_t h_op_features_get
;
7453 cls_method_handle_t h_op_features_set
;
7454 cls_method_handle_t h_add_child
;
7455 cls_method_handle_t h_remove_child
;
7456 cls_method_handle_t h_get_children
;
7457 cls_method_handle_t h_get_snapcontext
;
7458 cls_method_handle_t h_get_object_prefix
;
7459 cls_method_handle_t h_get_data_pool
;
7460 cls_method_handle_t h_get_snapshot_name
;
7461 cls_method_handle_t h_get_snapshot_timestamp
;
7462 cls_method_handle_t h_snapshot_get
;
7463 cls_method_handle_t h_snapshot_add
;
7464 cls_method_handle_t h_snapshot_remove
;
7465 cls_method_handle_t h_snapshot_rename
;
7466 cls_method_handle_t h_snapshot_trash_add
;
7467 cls_method_handle_t h_get_all_features
;
7468 cls_method_handle_t h_get_id
;
7469 cls_method_handle_t h_set_id
;
7470 cls_method_handle_t h_set_modify_timestamp
;
7471 cls_method_handle_t h_set_access_timestamp
;
7472 cls_method_handle_t h_dir_get_id
;
7473 cls_method_handle_t h_dir_get_name
;
7474 cls_method_handle_t h_dir_list
;
7475 cls_method_handle_t h_dir_add_image
;
7476 cls_method_handle_t h_dir_remove_image
;
7477 cls_method_handle_t h_dir_rename_image
;
7478 cls_method_handle_t h_dir_state_assert
;
7479 cls_method_handle_t h_dir_state_set
;
7480 cls_method_handle_t h_object_map_load
;
7481 cls_method_handle_t h_object_map_save
;
7482 cls_method_handle_t h_object_map_resize
;
7483 cls_method_handle_t h_object_map_update
;
7484 cls_method_handle_t h_object_map_snap_add
;
7485 cls_method_handle_t h_object_map_snap_remove
;
7486 cls_method_handle_t h_metadata_set
;
7487 cls_method_handle_t h_metadata_remove
;
7488 cls_method_handle_t h_metadata_list
;
7489 cls_method_handle_t h_metadata_get
;
7490 cls_method_handle_t h_snapshot_get_limit
;
7491 cls_method_handle_t h_snapshot_set_limit
;
7492 cls_method_handle_t h_child_attach
;
7493 cls_method_handle_t h_child_detach
;
7494 cls_method_handle_t h_children_list
;
7495 cls_method_handle_t h_migration_set
;
7496 cls_method_handle_t h_migration_set_state
;
7497 cls_method_handle_t h_migration_get
;
7498 cls_method_handle_t h_migration_remove
;
7499 cls_method_handle_t h_old_snapshots_list
;
7500 cls_method_handle_t h_old_snapshot_add
;
7501 cls_method_handle_t h_old_snapshot_remove
;
7502 cls_method_handle_t h_old_snapshot_rename
;
7503 cls_method_handle_t h_mirror_uuid_get
;
7504 cls_method_handle_t h_mirror_uuid_set
;
7505 cls_method_handle_t h_mirror_mode_get
;
7506 cls_method_handle_t h_mirror_mode_set
;
7507 cls_method_handle_t h_mirror_peer_list
;
7508 cls_method_handle_t h_mirror_peer_add
;
7509 cls_method_handle_t h_mirror_peer_remove
;
7510 cls_method_handle_t h_mirror_peer_set_client
;
7511 cls_method_handle_t h_mirror_peer_set_cluster
;
7512 cls_method_handle_t h_mirror_image_list
;
7513 cls_method_handle_t h_mirror_image_get_image_id
;
7514 cls_method_handle_t h_mirror_image_get
;
7515 cls_method_handle_t h_mirror_image_set
;
7516 cls_method_handle_t h_mirror_image_remove
;
7517 cls_method_handle_t h_mirror_image_status_set
;
7518 cls_method_handle_t h_mirror_image_status_remove
;
7519 cls_method_handle_t h_mirror_image_status_get
;
7520 cls_method_handle_t h_mirror_image_status_list
;
7521 cls_method_handle_t h_mirror_image_status_get_summary
;
7522 cls_method_handle_t h_mirror_image_status_remove_down
;
7523 cls_method_handle_t h_mirror_image_instance_get
;
7524 cls_method_handle_t h_mirror_image_instance_list
;
7525 cls_method_handle_t h_mirror_instances_list
;
7526 cls_method_handle_t h_mirror_instances_add
;
7527 cls_method_handle_t h_mirror_instances_remove
;
7528 cls_method_handle_t h_mirror_image_map_list
;
7529 cls_method_handle_t h_mirror_image_map_update
;
7530 cls_method_handle_t h_mirror_image_map_remove
;
7531 cls_method_handle_t h_group_dir_list
;
7532 cls_method_handle_t h_group_dir_add
;
7533 cls_method_handle_t h_group_dir_remove
;
7534 cls_method_handle_t h_group_dir_rename
;
7535 cls_method_handle_t h_group_image_remove
;
7536 cls_method_handle_t h_group_image_list
;
7537 cls_method_handle_t h_group_image_set
;
7538 cls_method_handle_t h_image_group_add
;
7539 cls_method_handle_t h_image_group_remove
;
7540 cls_method_handle_t h_image_group_get
;
7541 cls_method_handle_t h_group_snap_set
;
7542 cls_method_handle_t h_group_snap_remove
;
7543 cls_method_handle_t h_group_snap_get_by_id
;
7544 cls_method_handle_t h_group_snap_list
;
7545 cls_method_handle_t h_trash_add
;
7546 cls_method_handle_t h_trash_remove
;
7547 cls_method_handle_t h_trash_list
;
7548 cls_method_handle_t h_trash_get
;
7549 cls_method_handle_t h_trash_state_set
;
7550 cls_method_handle_t h_namespace_add
;
7551 cls_method_handle_t h_namespace_remove
;
7552 cls_method_handle_t h_namespace_list
;
7553 cls_method_handle_t h_copyup
;
7554 cls_method_handle_t h_assert_snapc_seq
;
7555 cls_method_handle_t h_sparsify
;
7557 cls_register("rbd", &h_class
);
7558 cls_register_cxx_method(h_class
, "create",
7559 CLS_METHOD_RD
| CLS_METHOD_WR
,
7561 cls_register_cxx_method(h_class
, "get_features",
7563 get_features
, &h_get_features
);
7564 cls_register_cxx_method(h_class
, "set_features",
7565 CLS_METHOD_RD
| CLS_METHOD_WR
,
7566 set_features
, &h_set_features
);
7567 cls_register_cxx_method(h_class
, "get_size",
7569 get_size
, &h_get_size
);
7570 cls_register_cxx_method(h_class
, "set_size",
7571 CLS_METHOD_RD
| CLS_METHOD_WR
,
7572 set_size
, &h_set_size
);
7573 cls_register_cxx_method(h_class
, "get_snapcontext",
7575 get_snapcontext
, &h_get_snapcontext
);
7576 cls_register_cxx_method(h_class
, "get_object_prefix",
7578 get_object_prefix
, &h_get_object_prefix
);
7579 cls_register_cxx_method(h_class
, "get_data_pool", CLS_METHOD_RD
,
7580 get_data_pool
, &h_get_data_pool
);
7581 cls_register_cxx_method(h_class
, "get_snapshot_name",
7583 get_snapshot_name
, &h_get_snapshot_name
);
7584 cls_register_cxx_method(h_class
, "get_snapshot_timestamp",
7586 get_snapshot_timestamp
, &h_get_snapshot_timestamp
);
7587 cls_register_cxx_method(h_class
, "snapshot_get",
7589 snapshot_get
, &h_snapshot_get
);
7590 cls_register_cxx_method(h_class
, "snapshot_add",
7591 CLS_METHOD_RD
| CLS_METHOD_WR
,
7592 snapshot_add
, &h_snapshot_add
);
7593 cls_register_cxx_method(h_class
, "snapshot_remove",
7594 CLS_METHOD_RD
| CLS_METHOD_WR
,
7595 snapshot_remove
, &h_snapshot_remove
);
7596 cls_register_cxx_method(h_class
, "snapshot_rename",
7597 CLS_METHOD_RD
| CLS_METHOD_WR
,
7598 snapshot_rename
, &h_snapshot_rename
);
7599 cls_register_cxx_method(h_class
, "snapshot_trash_add",
7600 CLS_METHOD_RD
| CLS_METHOD_WR
,
7601 snapshot_trash_add
, &h_snapshot_trash_add
);
7602 cls_register_cxx_method(h_class
, "get_all_features",
7604 get_all_features
, &h_get_all_features
);
7606 // NOTE: deprecate v1 parent APIs after mimic EOLed
7607 cls_register_cxx_method(h_class
, "get_parent",
7609 get_parent
, &h_get_parent
);
7610 cls_register_cxx_method(h_class
, "set_parent",
7611 CLS_METHOD_RD
| CLS_METHOD_WR
,
7612 set_parent
, &h_set_parent
);
7613 cls_register_cxx_method(h_class
, "remove_parent",
7614 CLS_METHOD_RD
| CLS_METHOD_WR
,
7615 remove_parent
, &h_remove_parent
);
7617 cls_register_cxx_method(h_class
, "parent_get",
7618 CLS_METHOD_RD
, parent_get
, &h_parent_get
);
7619 cls_register_cxx_method(h_class
, "parent_overlap_get",
7620 CLS_METHOD_RD
, parent_overlap_get
,
7621 &h_parent_overlap_get
);
7622 cls_register_cxx_method(h_class
, "parent_attach",
7623 CLS_METHOD_RD
| CLS_METHOD_WR
,
7624 parent_attach
, &h_parent_attach
);
7625 cls_register_cxx_method(h_class
, "parent_detach",
7626 CLS_METHOD_RD
| CLS_METHOD_WR
,
7627 parent_detach
, &h_parent_detach
);
7629 cls_register_cxx_method(h_class
, "set_protection_status",
7630 CLS_METHOD_RD
| CLS_METHOD_WR
,
7631 set_protection_status
, &h_set_protection_status
);
7632 cls_register_cxx_method(h_class
, "get_protection_status",
7634 get_protection_status
, &h_get_protection_status
);
7635 cls_register_cxx_method(h_class
, "get_stripe_unit_count",
7637 get_stripe_unit_count
, &h_get_stripe_unit_count
);
7638 cls_register_cxx_method(h_class
, "set_stripe_unit_count",
7639 CLS_METHOD_RD
| CLS_METHOD_WR
,
7640 set_stripe_unit_count
, &h_set_stripe_unit_count
);
7641 cls_register_cxx_method(h_class
, "get_create_timestamp",
7643 get_create_timestamp
, &h_get_create_timestamp
);
7644 cls_register_cxx_method(h_class
, "get_access_timestamp",
7646 get_access_timestamp
, &h_get_access_timestamp
);
7647 cls_register_cxx_method(h_class
, "get_modify_timestamp",
7649 get_modify_timestamp
, &h_get_modify_timestamp
);
7650 cls_register_cxx_method(h_class
, "get_flags",
7652 get_flags
, &h_get_flags
);
7653 cls_register_cxx_method(h_class
, "set_flags",
7654 CLS_METHOD_RD
| CLS_METHOD_WR
,
7655 set_flags
, &h_set_flags
);
7656 cls_register_cxx_method(h_class
, "op_features_get", CLS_METHOD_RD
,
7657 op_features_get
, &h_op_features_get
);
7658 cls_register_cxx_method(h_class
, "op_features_set",
7659 CLS_METHOD_RD
| CLS_METHOD_WR
,
7660 op_features_set
, &h_op_features_set
);
7661 cls_register_cxx_method(h_class
, "metadata_list",
7663 metadata_list
, &h_metadata_list
);
7664 cls_register_cxx_method(h_class
, "metadata_set",
7665 CLS_METHOD_RD
| CLS_METHOD_WR
,
7666 metadata_set
, &h_metadata_set
);
7667 cls_register_cxx_method(h_class
, "metadata_remove",
7668 CLS_METHOD_RD
| CLS_METHOD_WR
,
7669 metadata_remove
, &h_metadata_remove
);
7670 cls_register_cxx_method(h_class
, "metadata_get",
7672 metadata_get
, &h_metadata_get
);
7673 cls_register_cxx_method(h_class
, "snapshot_get_limit",
7675 snapshot_get_limit
, &h_snapshot_get_limit
);
7676 cls_register_cxx_method(h_class
, "snapshot_set_limit",
7677 CLS_METHOD_RD
| CLS_METHOD_WR
,
7678 snapshot_set_limit
, &h_snapshot_set_limit
);
7679 cls_register_cxx_method(h_class
, "child_attach",
7680 CLS_METHOD_RD
| CLS_METHOD_WR
,
7681 child_attach
, &h_child_attach
);
7682 cls_register_cxx_method(h_class
, "child_detach",
7683 CLS_METHOD_RD
| CLS_METHOD_WR
,
7684 child_detach
, &h_child_detach
);
7685 cls_register_cxx_method(h_class
, "children_list",
7687 children_list
, &h_children_list
);
7688 cls_register_cxx_method(h_class
, "migration_set",
7689 CLS_METHOD_RD
| CLS_METHOD_WR
,
7690 migration_set
, &h_migration_set
);
7691 cls_register_cxx_method(h_class
, "migration_set_state",
7692 CLS_METHOD_RD
| CLS_METHOD_WR
,
7693 migration_set_state
, &h_migration_set_state
);
7694 cls_register_cxx_method(h_class
, "migration_get",
7696 migration_get
, &h_migration_get
);
7697 cls_register_cxx_method(h_class
, "migration_remove",
7698 CLS_METHOD_RD
| CLS_METHOD_WR
,
7699 migration_remove
, &h_migration_remove
);
7701 cls_register_cxx_method(h_class
, "set_modify_timestamp",
7702 CLS_METHOD_RD
| CLS_METHOD_WR
,
7703 set_modify_timestamp
, &h_set_modify_timestamp
);
7705 cls_register_cxx_method(h_class
, "set_access_timestamp",
7706 CLS_METHOD_RD
| CLS_METHOD_WR
,
7707 set_access_timestamp
, &h_set_access_timestamp
);
7709 /* methods for the rbd_children object */
7710 cls_register_cxx_method(h_class
, "add_child",
7711 CLS_METHOD_RD
| CLS_METHOD_WR
,
7712 add_child
, &h_add_child
);
7713 cls_register_cxx_method(h_class
, "remove_child",
7714 CLS_METHOD_RD
| CLS_METHOD_WR
,
7715 remove_child
, &h_remove_child
);
7716 cls_register_cxx_method(h_class
, "get_children",
7718 get_children
, &h_get_children
);
7720 /* methods for the rbd_id.$image_name objects */
7721 cls_register_cxx_method(h_class
, "get_id",
7724 cls_register_cxx_method(h_class
, "set_id",
7725 CLS_METHOD_RD
| CLS_METHOD_WR
,
7728 /* methods for the rbd_directory object */
7729 cls_register_cxx_method(h_class
, "dir_get_id",
7731 dir_get_id
, &h_dir_get_id
);
7732 cls_register_cxx_method(h_class
, "dir_get_name",
7734 dir_get_name
, &h_dir_get_name
);
7735 cls_register_cxx_method(h_class
, "dir_list",
7737 dir_list
, &h_dir_list
);
7738 cls_register_cxx_method(h_class
, "dir_add_image",
7739 CLS_METHOD_RD
| CLS_METHOD_WR
,
7740 dir_add_image
, &h_dir_add_image
);
7741 cls_register_cxx_method(h_class
, "dir_remove_image",
7742 CLS_METHOD_RD
| CLS_METHOD_WR
,
7743 dir_remove_image
, &h_dir_remove_image
);
7744 cls_register_cxx_method(h_class
, "dir_rename_image",
7745 CLS_METHOD_RD
| CLS_METHOD_WR
,
7746 dir_rename_image
, &h_dir_rename_image
);
7747 cls_register_cxx_method(h_class
, "dir_state_assert", CLS_METHOD_RD
,
7748 dir_state_assert
, &h_dir_state_assert
);
7749 cls_register_cxx_method(h_class
, "dir_state_set",
7750 CLS_METHOD_RD
| CLS_METHOD_WR
,
7751 dir_state_set
, &h_dir_state_set
);
7753 /* methods for the rbd_object_map.$image_id object */
7754 cls_register_cxx_method(h_class
, "object_map_load",
7756 object_map_load
, &h_object_map_load
);
7757 cls_register_cxx_method(h_class
, "object_map_save",
7758 CLS_METHOD_RD
| CLS_METHOD_WR
,
7759 object_map_save
, &h_object_map_save
);
7760 cls_register_cxx_method(h_class
, "object_map_resize",
7761 CLS_METHOD_RD
| CLS_METHOD_WR
,
7762 object_map_resize
, &h_object_map_resize
);
7763 cls_register_cxx_method(h_class
, "object_map_update",
7764 CLS_METHOD_RD
| CLS_METHOD_WR
,
7765 object_map_update
, &h_object_map_update
);
7766 cls_register_cxx_method(h_class
, "object_map_snap_add",
7767 CLS_METHOD_RD
| CLS_METHOD_WR
,
7768 object_map_snap_add
, &h_object_map_snap_add
);
7769 cls_register_cxx_method(h_class
, "object_map_snap_remove",
7770 CLS_METHOD_RD
| CLS_METHOD_WR
,
7771 object_map_snap_remove
, &h_object_map_snap_remove
);
7773 /* methods for the old format */
7774 cls_register_cxx_method(h_class
, "snap_list",
7776 old_snapshots_list
, &h_old_snapshots_list
);
7777 cls_register_cxx_method(h_class
, "snap_add",
7778 CLS_METHOD_RD
| CLS_METHOD_WR
,
7779 old_snapshot_add
, &h_old_snapshot_add
);
7780 cls_register_cxx_method(h_class
, "snap_remove",
7781 CLS_METHOD_RD
| CLS_METHOD_WR
,
7782 old_snapshot_remove
, &h_old_snapshot_remove
);
7783 cls_register_cxx_method(h_class
, "snap_rename",
7784 CLS_METHOD_RD
| CLS_METHOD_WR
,
7785 old_snapshot_rename
, &h_old_snapshot_rename
);
7787 /* methods for the rbd_mirroring object */
7788 cls_register_cxx_method(h_class
, "mirror_uuid_get", CLS_METHOD_RD
,
7789 mirror_uuid_get
, &h_mirror_uuid_get
);
7790 cls_register_cxx_method(h_class
, "mirror_uuid_set",
7791 CLS_METHOD_RD
| CLS_METHOD_WR
,
7792 mirror_uuid_set
, &h_mirror_uuid_set
);
7793 cls_register_cxx_method(h_class
, "mirror_mode_get", CLS_METHOD_RD
,
7794 mirror_mode_get
, &h_mirror_mode_get
);
7795 cls_register_cxx_method(h_class
, "mirror_mode_set",
7796 CLS_METHOD_RD
| CLS_METHOD_WR
,
7797 mirror_mode_set
, &h_mirror_mode_set
);
7798 cls_register_cxx_method(h_class
, "mirror_peer_list", CLS_METHOD_RD
,
7799 mirror_peer_list
, &h_mirror_peer_list
);
7800 cls_register_cxx_method(h_class
, "mirror_peer_add",
7801 CLS_METHOD_RD
| CLS_METHOD_WR
,
7802 mirror_peer_add
, &h_mirror_peer_add
);
7803 cls_register_cxx_method(h_class
, "mirror_peer_remove",
7804 CLS_METHOD_RD
| CLS_METHOD_WR
,
7805 mirror_peer_remove
, &h_mirror_peer_remove
);
7806 cls_register_cxx_method(h_class
, "mirror_peer_set_client",
7807 CLS_METHOD_RD
| CLS_METHOD_WR
,
7808 mirror_peer_set_client
, &h_mirror_peer_set_client
);
7809 cls_register_cxx_method(h_class
, "mirror_peer_set_cluster",
7810 CLS_METHOD_RD
| CLS_METHOD_WR
,
7811 mirror_peer_set_cluster
, &h_mirror_peer_set_cluster
);
7812 cls_register_cxx_method(h_class
, "mirror_image_list", CLS_METHOD_RD
,
7813 mirror_image_list
, &h_mirror_image_list
);
7814 cls_register_cxx_method(h_class
, "mirror_image_get_image_id", CLS_METHOD_RD
,
7815 mirror_image_get_image_id
,
7816 &h_mirror_image_get_image_id
);
7817 cls_register_cxx_method(h_class
, "mirror_image_get", CLS_METHOD_RD
,
7818 mirror_image_get
, &h_mirror_image_get
);
7819 cls_register_cxx_method(h_class
, "mirror_image_set",
7820 CLS_METHOD_RD
| CLS_METHOD_WR
,
7821 mirror_image_set
, &h_mirror_image_set
);
7822 cls_register_cxx_method(h_class
, "mirror_image_remove",
7823 CLS_METHOD_RD
| CLS_METHOD_WR
,
7824 mirror_image_remove
, &h_mirror_image_remove
);
7825 cls_register_cxx_method(h_class
, "mirror_image_status_set",
7826 CLS_METHOD_RD
| CLS_METHOD_WR
| CLS_METHOD_PROMOTE
,
7827 mirror_image_status_set
, &h_mirror_image_status_set
);
7828 cls_register_cxx_method(h_class
, "mirror_image_status_remove",
7829 CLS_METHOD_RD
| CLS_METHOD_WR
,
7830 mirror_image_status_remove
,
7831 &h_mirror_image_status_remove
);
7832 cls_register_cxx_method(h_class
, "mirror_image_status_get", CLS_METHOD_RD
,
7833 mirror_image_status_get
, &h_mirror_image_status_get
);
7834 cls_register_cxx_method(h_class
, "mirror_image_status_list", CLS_METHOD_RD
,
7835 mirror_image_status_list
,
7836 &h_mirror_image_status_list
);
7837 cls_register_cxx_method(h_class
, "mirror_image_status_get_summary",
7838 CLS_METHOD_RD
, mirror_image_status_get_summary
,
7839 &h_mirror_image_status_get_summary
);
7840 cls_register_cxx_method(h_class
, "mirror_image_status_remove_down",
7841 CLS_METHOD_RD
| CLS_METHOD_WR
,
7842 mirror_image_status_remove_down
,
7843 &h_mirror_image_status_remove_down
);
7844 cls_register_cxx_method(h_class
, "mirror_image_instance_get", CLS_METHOD_RD
,
7845 mirror_image_instance_get
,
7846 &h_mirror_image_instance_get
);
7847 cls_register_cxx_method(h_class
, "mirror_image_instance_list", CLS_METHOD_RD
,
7848 mirror_image_instance_list
,
7849 &h_mirror_image_instance_list
);
7850 cls_register_cxx_method(h_class
, "mirror_instances_list", CLS_METHOD_RD
,
7851 mirror_instances_list
, &h_mirror_instances_list
);
7852 cls_register_cxx_method(h_class
, "mirror_instances_add",
7853 CLS_METHOD_RD
| CLS_METHOD_WR
| CLS_METHOD_PROMOTE
,
7854 mirror_instances_add
, &h_mirror_instances_add
);
7855 cls_register_cxx_method(h_class
, "mirror_instances_remove",
7856 CLS_METHOD_RD
| CLS_METHOD_WR
,
7857 mirror_instances_remove
,
7858 &h_mirror_instances_remove
);
7859 cls_register_cxx_method(h_class
, "mirror_image_map_list",
7860 CLS_METHOD_RD
, mirror_image_map_list
,
7861 &h_mirror_image_map_list
);
7862 cls_register_cxx_method(h_class
, "mirror_image_map_update",
7863 CLS_METHOD_WR
, mirror_image_map_update
,
7864 &h_mirror_image_map_update
);
7865 cls_register_cxx_method(h_class
, "mirror_image_map_remove",
7866 CLS_METHOD_WR
, mirror_image_map_remove
,
7867 &h_mirror_image_map_remove
);
7869 /* methods for the groups feature */
7870 cls_register_cxx_method(h_class
, "group_dir_list",
7872 group_dir_list
, &h_group_dir_list
);
7873 cls_register_cxx_method(h_class
, "group_dir_add",
7874 CLS_METHOD_RD
| CLS_METHOD_WR
,
7875 group_dir_add
, &h_group_dir_add
);
7876 cls_register_cxx_method(h_class
, "group_dir_remove",
7877 CLS_METHOD_RD
| CLS_METHOD_WR
,
7878 group_dir_remove
, &h_group_dir_remove
);
7879 cls_register_cxx_method(h_class
, "group_dir_rename",
7880 CLS_METHOD_RD
| CLS_METHOD_WR
,
7881 group_dir_rename
, &h_group_dir_rename
);
7882 cls_register_cxx_method(h_class
, "group_image_remove",
7883 CLS_METHOD_RD
| CLS_METHOD_WR
,
7884 group_image_remove
, &h_group_image_remove
);
7885 cls_register_cxx_method(h_class
, "group_image_list",
7887 group_image_list
, &h_group_image_list
);
7888 cls_register_cxx_method(h_class
, "group_image_set",
7889 CLS_METHOD_RD
| CLS_METHOD_WR
,
7890 group_image_set
, &h_group_image_set
);
7891 cls_register_cxx_method(h_class
, "image_group_add",
7892 CLS_METHOD_RD
| CLS_METHOD_WR
,
7893 image_group_add
, &h_image_group_add
);
7894 cls_register_cxx_method(h_class
, "image_group_remove",
7895 CLS_METHOD_RD
| CLS_METHOD_WR
,
7896 image_group_remove
, &h_image_group_remove
);
7897 cls_register_cxx_method(h_class
, "image_group_get",
7899 image_group_get
, &h_image_group_get
);
7900 cls_register_cxx_method(h_class
, "group_snap_set",
7901 CLS_METHOD_RD
| CLS_METHOD_WR
,
7902 group_snap_set
, &h_group_snap_set
);
7903 cls_register_cxx_method(h_class
, "group_snap_remove",
7904 CLS_METHOD_RD
| CLS_METHOD_WR
,
7905 group_snap_remove
, &h_group_snap_remove
);
7906 cls_register_cxx_method(h_class
, "group_snap_get_by_id",
7908 group_snap_get_by_id
, &h_group_snap_get_by_id
);
7909 cls_register_cxx_method(h_class
, "group_snap_list",
7911 group_snap_list
, &h_group_snap_list
);
7913 /* rbd_trash object methods */
7914 cls_register_cxx_method(h_class
, "trash_add",
7915 CLS_METHOD_RD
| CLS_METHOD_WR
,
7916 trash_add
, &h_trash_add
);
7917 cls_register_cxx_method(h_class
, "trash_remove",
7918 CLS_METHOD_RD
| CLS_METHOD_WR
,
7919 trash_remove
, &h_trash_remove
);
7920 cls_register_cxx_method(h_class
, "trash_list",
7922 trash_list
, &h_trash_list
);
7923 cls_register_cxx_method(h_class
, "trash_get",
7925 trash_get
, &h_trash_get
);
7926 cls_register_cxx_method(h_class
, "trash_state_set",
7927 CLS_METHOD_RD
| CLS_METHOD_WR
,
7928 trash_state_set
, &h_trash_state_set
);
7930 /* rbd_namespace object methods */
7931 cls_register_cxx_method(h_class
, "namespace_add",
7932 CLS_METHOD_RD
| CLS_METHOD_WR
,
7933 namespace_add
, &h_namespace_add
);
7934 cls_register_cxx_method(h_class
, "namespace_remove",
7935 CLS_METHOD_RD
| CLS_METHOD_WR
,
7936 namespace_remove
, &h_namespace_remove
);
7937 cls_register_cxx_method(h_class
, "namespace_list", CLS_METHOD_RD
,
7938 namespace_list
, &h_namespace_list
);
7940 /* data object methods */
7941 cls_register_cxx_method(h_class
, "copyup",
7942 CLS_METHOD_RD
| CLS_METHOD_WR
,
7944 cls_register_cxx_method(h_class
, "assert_snapc_seq",
7945 CLS_METHOD_RD
| CLS_METHOD_WR
,
7947 &h_assert_snapc_seq
);
7948 cls_register_cxx_method(h_class
, "sparsify",
7949 CLS_METHOD_RD
| CLS_METHOD_WR
,
7950 sparsify
, &h_sparsify
);