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"
45 #include <boost/algorithm/string/predicate.hpp>
47 using std::istringstream
;
48 using std::ostringstream
;
54 using ceph::BitVector
;
55 using ceph::bufferlist
;
56 using ceph::bufferptr
;
65 * stripe_unit: size in bytes of the stripe unit. if not present,
66 * the stripe unit is assumed to match the object size (1 << order).
68 * stripe_count: number of objects to stripe over before looping back.
69 * if not present or 1, striping is disabled. this is the default.
76 #define RBD_MAX_KEYS_READ 64
77 #define RBD_SNAP_KEY_PREFIX "snapshot_"
78 #define RBD_SNAP_CHILDREN_KEY_PREFIX "snap_children_"
79 #define RBD_DIR_ID_KEY_PREFIX "id_"
80 #define RBD_DIR_NAME_KEY_PREFIX "name_"
81 #define RBD_METADATA_KEY_PREFIX "metadata_"
85 uint64_t get_encode_features(cls_method_context_t hctx
) {
86 uint64_t features
= 0;
87 ceph_release_t require_osd_release
= cls_get_required_osd_release(hctx
);
88 if (require_osd_release
>= ceph_release_t::nautilus
) {
89 features
|= CEPH_FEATURE_SERVER_NAUTILUS
;
94 bool calc_sparse_extent(const bufferptr
&bp
, size_t sparse_size
,
95 uint64_t length
, size_t *write_offset
,
96 size_t *write_length
, size_t *offset
) {
98 if (*offset
+ sparse_size
> length
) {
99 extent_size
= length
- *offset
;
101 extent_size
= sparse_size
;
104 bufferptr
extent(bp
, *offset
, extent_size
);
105 *offset
+= extent_size
;
107 bool extent_is_zero
= extent
.is_zero();
108 if (!extent_is_zero
) {
109 *write_length
+= extent_size
;
111 if (extent_is_zero
&& *write_length
== 0) {
112 *write_offset
+= extent_size
;
115 if ((extent_is_zero
|| *offset
== length
) && *write_length
!= 0) {
121 } // anonymous namespace
123 static int snap_read_header(cls_method_context_t hctx
, bufferlist
& bl
)
125 unsigned snap_count
= 0;
126 uint64_t snap_names_len
= 0;
127 struct rbd_obj_header_ondisk
*header
;
129 CLS_LOG(20, "snapshots_list");
132 int len
= sizeof(*header
) +
133 snap_count
* sizeof(struct rbd_obj_snap_ondisk
) +
136 int rc
= cls_cxx_read(hctx
, 0, len
, &bl
);
140 if (bl
.length() < sizeof(*header
))
143 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
146 if ((snap_count
!= header
->snap_count
) ||
147 (snap_names_len
!= header
->snap_names_len
)) {
148 snap_count
= header
->snap_count
;
149 snap_names_len
= header
->snap_names_len
;
159 static void key_from_snap_id(snapid_t snap_id
, string
*out
)
162 oss
<< RBD_SNAP_KEY_PREFIX
163 << std::setw(16) << std::setfill('0') << std::hex
<< snap_id
;
167 static snapid_t
snap_id_from_key(const string
&key
) {
168 istringstream
iss(key
);
170 iss
.ignore(strlen(RBD_SNAP_KEY_PREFIX
)) >> std::hex
>> id
;
175 static int read_key(cls_method_context_t hctx
, const string
&key
, T
*out
)
178 int r
= cls_cxx_map_get_val(hctx
, key
, &bl
);
181 CLS_ERR("error reading omap key %s: %s", key
.c_str(), cpp_strerror(r
).c_str());
187 auto it
= bl
.cbegin();
189 } catch (const ceph::buffer::error
&err
) {
190 CLS_ERR("error decoding %s", key
.c_str());
197 template <typename T
>
198 static int write_key(cls_method_context_t hctx
, const string
&key
, const T
&t
) {
202 int r
= cls_cxx_map_set_val(hctx
, key
, &bl
);
204 CLS_ERR("failed to set omap key: %s", key
.c_str());
210 template <typename T
>
211 static int write_key(cls_method_context_t hctx
, const string
&key
, const T
&t
,
214 encode(t
, bl
, features
);
216 int r
= cls_cxx_map_set_val(hctx
, key
, &bl
);
218 CLS_ERR("failed to set omap key: %s", key
.c_str());
224 static int remove_key(cls_method_context_t hctx
, const string
&key
) {
225 int r
= cls_cxx_map_remove_key(hctx
, key
);
226 if (r
< 0 && r
!= -ENOENT
) {
227 CLS_ERR("failed to remove key: %s", key
.c_str());
233 static bool is_valid_id(const string
&id
) {
236 for (size_t i
= 0; i
< id
.size(); ++i
) {
237 if (!isalnum(id
[i
])) {
245 * verify that the header object exists
247 * @return 0 if the object exists, -ENOENT if it does not, or other error
249 static int check_exists(cls_method_context_t hctx
)
253 return cls_cxx_stat(hctx
, &size
, &mtime
);
259 * check that given feature(s) are set
261 * @param hctx context
262 * @param need features needed
263 * @return 0 if features are set, negative error (like ENOEXEC) otherwise
265 int require_feature(cls_method_context_t hctx
, uint64_t need
)
268 int r
= read_key(hctx
, "features", &features
);
269 if (r
== -ENOENT
) // this implies it's an old-style image with no features
273 if ((features
& need
) != need
) {
274 CLS_LOG(10, "require_feature missing feature %llx, have %llx",
275 (unsigned long long)need
, (unsigned long long)features
);
281 std::string
snap_children_key_from_snap_id(snapid_t snap_id
)
284 oss
<< RBD_SNAP_CHILDREN_KEY_PREFIX
285 << std::setw(16) << std::setfill('0') << std::hex
<< snap_id
;
289 int set_op_features(cls_method_context_t hctx
, uint64_t op_features
,
291 uint64_t orig_features
;
292 int r
= read_key(hctx
, "features", &orig_features
);
294 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
298 uint64_t orig_op_features
= 0;
299 r
= read_key(hctx
, "op_features", &orig_op_features
);
300 if (r
< 0 && r
!= -ENOENT
) {
301 CLS_ERR("Could not read op features off disk: %s", cpp_strerror(r
).c_str());
305 op_features
= (orig_op_features
& ~mask
) | (op_features
& mask
);
306 CLS_LOG(10, "op_features=%" PRIu64
" orig_op_features=%" PRIu64
,
307 op_features
, orig_op_features
);
308 if (op_features
== orig_op_features
) {
312 uint64_t features
= orig_features
;
313 if (op_features
== 0ULL) {
314 features
&= ~RBD_FEATURE_OPERATIONS
;
316 r
= cls_cxx_map_remove_key(hctx
, "op_features");
321 features
|= RBD_FEATURE_OPERATIONS
;
324 encode(op_features
, bl
);
325 r
= cls_cxx_map_set_val(hctx
, "op_features", &bl
);
329 CLS_ERR("error updating op features: %s", cpp_strerror(r
).c_str());
333 if (features
!= orig_features
) {
335 encode(features
, bl
);
336 r
= cls_cxx_map_set_val(hctx
, "features", &bl
);
338 CLS_ERR("error updating features: %s", cpp_strerror(r
).c_str());
346 int set_migration(cls_method_context_t hctx
,
347 const cls::rbd::MigrationSpec
&migration_spec
, bool init
) {
350 int r
= cls_cxx_map_get_val(hctx
, "migration", &bl
);
353 CLS_LOG(10, "migration already set");
356 CLS_ERR("failed to read migration off disk: %s", cpp_strerror(r
).c_str());
360 uint64_t features
= 0;
361 r
= read_key(hctx
, "features", &features
);
363 CLS_LOG(20, "no features, assuming v1 format");
365 r
= cls_cxx_read(hctx
, 0, sizeof(RBD_HEADER_TEXT
), &header
);
367 CLS_ERR("failed to read v1 header: %s", cpp_strerror(r
).c_str());
370 if (header
.length() != sizeof(RBD_HEADER_TEXT
)) {
371 CLS_ERR("unrecognized v1 header format");
374 if (memcmp(RBD_HEADER_TEXT
, header
.c_str(), header
.length()) != 0) {
375 if (memcmp(RBD_MIGRATE_HEADER_TEXT
, header
.c_str(),
376 header
.length()) == 0) {
377 CLS_LOG(10, "migration already set");
380 CLS_ERR("unrecognized v1 header format");
384 if (migration_spec
.header_type
!= cls::rbd::MIGRATION_HEADER_TYPE_SRC
) {
385 CLS_LOG(10, "v1 format image can only be migration source");
390 header
.append(RBD_MIGRATE_HEADER_TEXT
);
391 r
= cls_cxx_write(hctx
, 0, header
.length(), &header
);
393 CLS_ERR("error updating v1 header: %s", cpp_strerror(r
).c_str());
397 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
399 } else if ((features
& RBD_FEATURE_MIGRATING
) != 0ULL) {
400 if (migration_spec
.header_type
!= cls::rbd::MIGRATION_HEADER_TYPE_DST
) {
401 CLS_LOG(10, "migrating feature already set");
405 features
|= RBD_FEATURE_MIGRATING
;
407 encode(features
, bl
);
408 r
= cls_cxx_map_set_val(hctx
, "features", &bl
);
410 CLS_ERR("error updating features: %s", cpp_strerror(r
).c_str());
417 encode(migration_spec
, bl
);
418 int r
= cls_cxx_map_set_val(hctx
, "migration", &bl
);
420 CLS_ERR("error setting migration: %s", cpp_strerror(r
).c_str());
427 int read_migration(cls_method_context_t hctx
,
428 cls::rbd::MigrationSpec
*migration_spec
) {
429 uint64_t features
= 0;
430 int r
= read_key(hctx
, "features", &features
);
432 CLS_LOG(20, "no features, assuming v1 format");
434 r
= cls_cxx_read(hctx
, 0, sizeof(RBD_HEADER_TEXT
), &header
);
436 CLS_ERR("failed to read v1 header: %s", cpp_strerror(r
).c_str());
439 if (header
.length() != sizeof(RBD_HEADER_TEXT
)) {
440 CLS_ERR("unrecognized v1 header format");
443 if (memcmp(RBD_MIGRATE_HEADER_TEXT
, header
.c_str(), header
.length()) != 0) {
444 if (memcmp(RBD_HEADER_TEXT
, header
.c_str(), header
.length()) == 0) {
445 CLS_LOG(10, "migration feature not set");
448 CLS_ERR("unrecognized v1 header format");
452 if (migration_spec
->header_type
!= cls::rbd::MIGRATION_HEADER_TYPE_SRC
) {
453 CLS_LOG(10, "v1 format image can only be migration source");
457 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
459 } else if ((features
& RBD_FEATURE_MIGRATING
) == 0ULL) {
460 CLS_LOG(10, "migration feature not set");
464 r
= read_key(hctx
, "migration", migration_spec
);
466 CLS_ERR("failed to read migration off disk: %s", cpp_strerror(r
).c_str());
473 int remove_migration(cls_method_context_t hctx
) {
474 int r
= remove_key(hctx
, "migration");
479 uint64_t features
= 0;
480 r
= read_key(hctx
, "features", &features
);
482 CLS_LOG(20, "no features, assuming v1 format");
484 r
= cls_cxx_read(hctx
, 0, sizeof(RBD_MIGRATE_HEADER_TEXT
), &header
);
485 if (header
.length() != sizeof(RBD_MIGRATE_HEADER_TEXT
)) {
486 CLS_ERR("unrecognized v1 header format");
489 if (memcmp(RBD_MIGRATE_HEADER_TEXT
, header
.c_str(), header
.length()) != 0) {
490 if (memcmp(RBD_HEADER_TEXT
, header
.c_str(), header
.length()) == 0) {
491 CLS_LOG(10, "migration feature not set");
494 CLS_ERR("unrecognized v1 header format");
499 header
.append(RBD_HEADER_TEXT
);
500 r
= cls_cxx_write(hctx
, 0, header
.length(), &header
);
502 CLS_ERR("error updating v1 header: %s", cpp_strerror(r
).c_str());
506 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
508 } else if ((features
& RBD_FEATURE_MIGRATING
) == 0ULL) {
509 CLS_LOG(10, "migrating feature not set");
511 features
&= ~RBD_FEATURE_MIGRATING
;
513 encode(features
, bl
);
514 r
= cls_cxx_map_set_val(hctx
, "features", &bl
);
516 CLS_ERR("error updating features: %s", cpp_strerror(r
).c_str());
527 int iterate(cls_method_context_t hctx
, L
& lambda
) {
528 int max_read
= RBD_MAX_KEYS_READ
;
529 string last_read
= RBD_SNAP_KEY_PREFIX
;
532 map
<string
, bufferlist
> vals
;
533 int r
= cls_cxx_map_get_vals(hctx
, last_read
, RBD_SNAP_KEY_PREFIX
,
534 max_read
, &vals
, &more
);
539 cls_rbd_snap snap_meta
;
540 for (auto& val
: vals
) {
541 auto iter
= val
.second
.cbegin();
543 decode(snap_meta
, iter
);
544 } catch (const ceph::buffer::error
&err
) {
545 CLS_ERR("error decoding snapshot metadata for snap : %s",
550 r
= lambda(snap_meta
);
557 last_read
= vals
.rbegin()->first
;
564 int write(cls_method_context_t hctx
, const std::string
& snap_key
,
565 cls_rbd_snap
&& snap
) {
567 uint64_t encode_features
= get_encode_features(hctx
);
568 if (snap
.migrate_parent_format(encode_features
)) {
569 // ensure the normalized parent link exists before removing it from the
571 cls_rbd_parent on_disk_parent
;
572 r
= read_key(hctx
, "parent", &on_disk_parent
);
573 if (r
< 0 && r
!= -ENOENT
) {
577 if (!on_disk_parent
.exists()) {
578 on_disk_parent
= snap
.parent
;
579 on_disk_parent
.head_overlap
= std::nullopt
;
581 r
= write_key(hctx
, "parent", on_disk_parent
, encode_features
);
587 // only store the parent overlap in the snapshot
588 snap
.parent_overlap
= snap
.parent
.head_overlap
;
592 r
= write_key(hctx
, snap_key
, snap
, encode_features
);
599 } // namespace snapshot
603 int attach(cls_method_context_t hctx
, cls_rbd_parent parent
,
605 int r
= check_exists(hctx
);
607 CLS_LOG(20, "cls_rbd::image::parent::attach: child doesn't exist");
611 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
613 CLS_LOG(20, "cls_rbd::image::parent::attach: child does not support "
618 CLS_LOG(20, "cls_rbd::image::parent::attach: pool=%" PRIi64
", ns=%s, id=%s, "
619 "snapid=%" PRIu64
", size=%" PRIu64
,
620 parent
.pool_id
, parent
.pool_namespace
.c_str(),
621 parent
.image_id
.c_str(), parent
.snap_id
.val
,
622 parent
.head_overlap
.value_or(0ULL));
623 if (!parent
.exists() || parent
.head_overlap
.value_or(0ULL) == 0ULL) {
627 // make sure there isn't already a parent
628 cls_rbd_parent on_disk_parent
;
629 r
= read_key(hctx
, "parent", &on_disk_parent
);
630 if (r
< 0 && r
!= -ENOENT
) {
634 auto on_disk_parent_without_overlap
{on_disk_parent
};
635 on_disk_parent_without_overlap
.head_overlap
= parent
.head_overlap
;
638 (on_disk_parent
.head_overlap
||
639 on_disk_parent_without_overlap
!= parent
) &&
641 CLS_LOG(20, "cls_rbd::parent::attach: existing legacy parent "
642 "pool=%" PRIi64
", ns=%s, id=%s, snapid=%" PRIu64
", "
644 on_disk_parent
.pool_id
, on_disk_parent
.pool_namespace
.c_str(),
645 on_disk_parent
.image_id
.c_str(), on_disk_parent
.snap_id
.val
,
646 on_disk_parent
.head_overlap
.value_or(0ULL));
650 // our overlap is the min of our size and the parent's size.
652 r
= read_key(hctx
, "size", &our_size
);
657 parent
.head_overlap
= std::min(*parent
.head_overlap
, our_size
);
659 r
= write_key(hctx
, "parent", parent
, get_encode_features(hctx
));
667 int detach(cls_method_context_t hctx
, bool legacy_api
) {
668 int r
= check_exists(hctx
);
670 CLS_LOG(20, "cls_rbd::parent::detach: child doesn't exist");
675 r
= read_key(hctx
, "features", &features
);
676 if (r
== -ENOENT
|| ((features
& RBD_FEATURE_LAYERING
) == 0)) {
677 CLS_LOG(20, "cls_rbd::image::parent::detach: child does not support "
684 cls_rbd_parent on_disk_parent
;
685 r
= read_key(hctx
, "parent", &on_disk_parent
);
688 } else if (legacy_api
&& !on_disk_parent
.pool_namespace
.empty()) {
690 } else if (!on_disk_parent
.head_overlap
) {
694 auto detach_lambda
= [hctx
, features
](const cls_rbd_snap
& snap_meta
) {
695 if (snap_meta
.parent
.pool_id
!= -1 || snap_meta
.parent_overlap
) {
696 if ((features
& RBD_FEATURE_DEEP_FLATTEN
) != 0ULL) {
697 // remove parent reference from snapshot
698 cls_rbd_snap snap_meta_copy
= snap_meta
;
699 snap_meta_copy
.parent
= {};
700 snap_meta_copy
.parent_overlap
= std::nullopt
;
702 std::string snap_key
;
703 key_from_snap_id(snap_meta_copy
.id
, &snap_key
);
704 int r
= snapshot::write(hctx
, snap_key
, std::move(snap_meta_copy
));
715 r
= snapshot::iterate(hctx
, detach_lambda
);
716 bool has_child_snaps
= (r
== -EEXIST
);
717 if (r
< 0 && r
!= -EEXIST
) {
721 ceph_release_t require_osd_release
= cls_get_required_osd_release(hctx
);
722 if (has_child_snaps
&& require_osd_release
>= ceph_release_t::nautilus
) {
723 // remove overlap from HEAD revision but keep spec for snapshots
724 on_disk_parent
.head_overlap
= std::nullopt
;
725 r
= write_key(hctx
, "parent", on_disk_parent
, get_encode_features(hctx
));
730 r
= remove_key(hctx
, "parent");
731 if (r
< 0 && r
!= -ENOENT
) {
736 if (!has_child_snaps
) {
737 // disable clone child op feature if no longer associated
738 r
= set_op_features(hctx
, 0, RBD_OPERATION_FEATURE_CLONE_CHILD
);
746 } // namespace parent
750 * Initialize the header with basic metadata.
751 * Extra features may initialize more fields in the future.
752 * Everything is stored as key/value pairs as omaps in the header object.
754 * If features the OSD does not understand are requested, -ENOSYS is
758 * @param size number of bytes in the image (uint64_t)
759 * @param order bits to shift to determine the size of data objects (uint8_t)
760 * @param features what optional things this image will use (uint64_t)
761 * @param object_prefix a prefix for all the data objects
762 * @param data_pool_id pool id where data objects is stored (int64_t)
765 * @return 0 on success, negative error code on failure
767 int create(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
769 string object_prefix
;
770 uint64_t features
, size
;
772 int64_t data_pool_id
= -1;
775 auto iter
= in
->cbegin();
778 decode(features
, iter
);
779 decode(object_prefix
, iter
);
781 decode(data_pool_id
, iter
);
783 } catch (const ceph::buffer::error
&err
) {
787 CLS_LOG(20, "create object_prefix=%s size=%llu order=%u features=%llu",
788 object_prefix
.c_str(), (unsigned long long)size
, order
,
789 (unsigned long long)features
);
791 if (features
& ~RBD_FEATURES_ALL
) {
795 if (!object_prefix
.size()) {
799 bufferlist stored_prefixbl
;
800 int r
= cls_cxx_map_get_val(hctx
, "object_prefix", &stored_prefixbl
);
802 CLS_ERR("reading object_prefix returned %d", r
);
808 bufferlist featuresbl
;
809 bufferlist object_prefixbl
;
810 bufferlist snap_seqbl
;
811 bufferlist timestampbl
;
812 uint64_t snap_seq
= 0;
813 utime_t timestamp
= ceph_clock_now();
814 encode(size
, sizebl
);
815 encode(order
, orderbl
);
816 encode(features
, featuresbl
);
817 encode(object_prefix
, object_prefixbl
);
818 encode(snap_seq
, snap_seqbl
);
819 encode(timestamp
, timestampbl
);
821 map
<string
, bufferlist
> omap_vals
;
822 omap_vals
["size"] = sizebl
;
823 omap_vals
["order"] = orderbl
;
824 omap_vals
["features"] = featuresbl
;
825 omap_vals
["object_prefix"] = object_prefixbl
;
826 omap_vals
["snap_seq"] = snap_seqbl
;
827 omap_vals
["create_timestamp"] = timestampbl
;
828 omap_vals
["access_timestamp"] = timestampbl
;
829 omap_vals
["modify_timestamp"] = timestampbl
;
831 if ((features
& RBD_FEATURE_OPERATIONS
) != 0ULL) {
832 CLS_ERR("Attempting to set internal feature: operations");
836 if (features
& RBD_FEATURE_DATA_POOL
) {
837 if (data_pool_id
== -1) {
838 CLS_ERR("data pool not provided with feature enabled");
842 bufferlist data_pool_id_bl
;
843 encode(data_pool_id
, data_pool_id_bl
);
844 omap_vals
["data_pool_id"] = data_pool_id_bl
;
845 } else if (data_pool_id
!= -1) {
846 CLS_ERR("data pool provided with feature disabled");
850 r
= cls_cxx_map_set_vals(hctx
, &omap_vals
);
859 * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t) (deprecated)
860 * @param read_only true if the image will be used read-only (bool)
863 * @param features list of enabled features for the given snapshot (uint64_t)
864 * @param incompatible incompatible feature bits
865 * @returns 0 on success, negative error code on failure
867 int get_features(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
869 bool read_only
= false;
871 auto iter
= in
->cbegin();
874 decode(snap_id
, iter
);
876 decode(read_only
, iter
);
878 } catch (const ceph::buffer::error
&err
) {
882 CLS_LOG(20, "get_features read_only=%d", read_only
);
885 int r
= read_key(hctx
, "features", &features
);
887 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r
).c_str());
891 uint64_t incompatible
= (read_only
? features
& RBD_FEATURES_INCOMPATIBLE
:
892 features
& RBD_FEATURES_RW_INCOMPATIBLE
);
893 encode(features
, *out
);
894 encode(incompatible
, *out
);
899 * set the image features
902 * @param features image features
903 * @param mask image feature mask
908 * @returns 0 on success, negative error code upon failure
910 int set_features(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
914 auto iter
= in
->cbegin();
916 decode(features
, iter
);
918 } catch (const ceph::buffer::error
&err
) {
922 // check that features exists to make sure this is a header object
923 // that was created correctly
924 uint64_t orig_features
= 0;
925 int r
= read_key(hctx
, "features", &orig_features
);
926 if (r
< 0 && r
!= -ENOENT
) {
927 CLS_ERR("Could not read image's features off disk: %s",
928 cpp_strerror(r
).c_str());
932 if ((mask
& RBD_FEATURES_INTERNAL
) != 0ULL) {
933 CLS_ERR("Attempting to set internal feature: %" PRIu64
,
934 static_cast<uint64_t>(mask
& RBD_FEATURES_INTERNAL
));
938 // newer clients might attempt to mask off features we don't support
939 mask
&= RBD_FEATURES_ALL
;
941 uint64_t enabled_features
= features
& mask
;
942 if ((enabled_features
& RBD_FEATURES_MUTABLE
) != enabled_features
) {
943 CLS_ERR("Attempting to enable immutable feature: %" PRIu64
,
944 static_cast<uint64_t>(enabled_features
& ~RBD_FEATURES_MUTABLE
));
948 uint64_t disabled_features
= ~features
& mask
;
949 uint64_t disable_mask
= (RBD_FEATURES_MUTABLE
| RBD_FEATURES_DISABLE_ONLY
);
950 if ((disabled_features
& disable_mask
) != disabled_features
) {
951 CLS_ERR("Attempting to disable immutable feature: %" PRIu64
,
952 enabled_features
& ~disable_mask
);
956 features
= (orig_features
& ~mask
) | (features
& mask
);
957 CLS_LOG(10, "set_features features=%" PRIu64
" orig_features=%" PRIu64
,
958 features
, orig_features
);
961 encode(features
, bl
);
962 r
= cls_cxx_map_set_val(hctx
, "features", &bl
);
964 CLS_ERR("error updating features: %s", cpp_strerror(r
).c_str());
972 * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t)
975 * @param order bits to shift to get the size of data objects (uint8_t)
976 * @param size size of the image in bytes for the given snapshot (uint64_t)
977 * @returns 0 on success, negative error code on failure
979 int get_size(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
981 uint64_t snap_id
, size
;
984 auto iter
= in
->cbegin();
986 decode(snap_id
, iter
);
987 } catch (const ceph::buffer::error
&err
) {
991 CLS_LOG(20, "get_size snap_id=%llu", (unsigned long long)snap_id
);
993 int r
= read_key(hctx
, "order", &order
);
995 CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r
).c_str());
999 if (snap_id
== CEPH_NOSNAP
) {
1000 r
= read_key(hctx
, "size", &size
);
1002 CLS_ERR("failed to read the image's size off of disk: %s", cpp_strerror(r
).c_str());
1007 string snapshot_key
;
1008 key_from_snap_id(snap_id
, &snapshot_key
);
1009 int r
= read_key(hctx
, snapshot_key
, &snap
);
1013 size
= snap
.image_size
;
1016 encode(order
, *out
);
1024 * @param size new capacity of the image in bytes (uint64_t)
1027 * @returns 0 on success, negative error code on failure
1029 int set_size(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1033 auto iter
= in
->cbegin();
1036 } catch (const ceph::buffer::error
&err
) {
1040 // check that size exists to make sure this is a header object
1041 // that was created correctly
1043 int r
= read_key(hctx
, "size", &orig_size
);
1045 CLS_ERR("Could not read image's size off disk: %s", cpp_strerror(r
).c_str());
1049 CLS_LOG(20, "set_size size=%llu orig_size=%llu", (unsigned long long)size
,
1050 (unsigned long long)orig_size
);
1053 encode(size
, sizebl
);
1054 r
= cls_cxx_map_set_val(hctx
, "size", &sizebl
);
1056 CLS_ERR("error writing snapshot metadata: %s", cpp_strerror(r
).c_str());
1060 // if we are shrinking, and have a parent, shrink our overlap with
1062 if (size
< orig_size
) {
1063 cls_rbd_parent parent
;
1064 r
= read_key(hctx
, "parent", &parent
);
1069 if (parent
.exists() && parent
.head_overlap
.value_or(0ULL) > size
) {
1070 parent
.head_overlap
= size
;
1071 r
= write_key(hctx
, "parent", parent
, get_encode_features(hctx
));
1082 * get the current protection status of the specified snapshot
1085 * @param snap_id (uint64_t) which snapshot to get the status of
1088 * @param status (uint8_t) one of:
1089 * RBD_PROTECTION_STATUS_{PROTECTED, UNPROTECTED, UNPROTECTING}
1091 * @returns 0 on success, negative error code on failure
1092 * @returns -EINVAL if snapid is CEPH_NOSNAP
1094 int get_protection_status(cls_method_context_t hctx
, bufferlist
*in
,
1099 auto iter
= in
->cbegin();
1101 decode(snap_id
, iter
);
1102 } catch (const ceph::buffer::error
&err
) {
1103 CLS_LOG(20, "get_protection_status: invalid decode");
1107 int r
= check_exists(hctx
);
1111 CLS_LOG(20, "get_protection_status snap_id=%llu",
1112 (unsigned long long)snap_id
.val
);
1114 if (snap_id
== CEPH_NOSNAP
)
1118 string snapshot_key
;
1119 key_from_snap_id(snap_id
.val
, &snapshot_key
);
1120 r
= read_key(hctx
, snapshot_key
, &snap
);
1122 CLS_ERR("could not read key for snapshot id %" PRIu64
, snap_id
.val
);
1126 if (snap
.protection_status
>= RBD_PROTECTION_STATUS_LAST
) {
1127 CLS_ERR("invalid protection status for snap id %llu: %u",
1128 (unsigned long long)snap_id
.val
, snap
.protection_status
);
1132 encode(snap
.protection_status
, *out
);
1137 * set the proctection status of a snapshot
1140 * @param snapid (uint64_t) which snapshot to set the status of
1141 * @param status (uint8_t) one of:
1142 * RBD_PROTECTION_STATUS_{PROTECTED, UNPROTECTED, UNPROTECTING}
1144 * @returns 0 on success, negative error code on failure
1145 * @returns -EINVAL if snapid is CEPH_NOSNAP
1147 int set_protection_status(cls_method_context_t hctx
, bufferlist
*in
,
1153 auto iter
= in
->cbegin();
1155 decode(snap_id
, iter
);
1156 decode(status
, iter
);
1157 } catch (const ceph::buffer::error
&err
) {
1158 CLS_LOG(20, "set_protection_status: invalid decode");
1162 int r
= check_exists(hctx
);
1166 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
1168 CLS_LOG(20, "image does not support layering");
1172 CLS_LOG(20, "set_protection_status snapid=%llu status=%u",
1173 (unsigned long long)snap_id
.val
, status
);
1175 if (snap_id
== CEPH_NOSNAP
)
1178 if (status
>= RBD_PROTECTION_STATUS_LAST
) {
1179 CLS_LOG(10, "invalid protection status for snap id %llu: %u",
1180 (unsigned long long)snap_id
.val
, status
);
1185 string snapshot_key
;
1186 key_from_snap_id(snap_id
.val
, &snapshot_key
);
1187 r
= read_key(hctx
, snapshot_key
, &snap
);
1189 CLS_ERR("could not read key for snapshot id %" PRIu64
, snap_id
.val
);
1193 snap
.protection_status
= status
;
1194 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap
));
1203 * get striping parameters
1209 * @param stripe unit (bytes)
1210 * @param stripe count (num objects)
1212 * @returns 0 on success
1214 int get_stripe_unit_count(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1216 int r
= check_exists(hctx
);
1220 CLS_LOG(20, "get_stripe_unit_count");
1222 r
= image::require_feature(hctx
, RBD_FEATURE_STRIPINGV2
);
1226 uint64_t stripe_unit
= 0, stripe_count
= 0;
1227 r
= read_key(hctx
, "stripe_unit", &stripe_unit
);
1229 // default to object size
1231 r
= read_key(hctx
, "order", &order
);
1233 CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r
).c_str());
1236 stripe_unit
= 1ull << order
;
1240 r
= read_key(hctx
, "stripe_count", &stripe_count
);
1249 encode(stripe_unit
, *out
);
1250 encode(stripe_count
, *out
);
1255 * set striping parameters
1258 * @param stripe unit (bytes)
1259 * @param stripe count (num objects)
1261 * @returns 0 on success
1263 int set_stripe_unit_count(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1265 uint64_t stripe_unit
, stripe_count
;
1267 auto iter
= in
->cbegin();
1269 decode(stripe_unit
, iter
);
1270 decode(stripe_count
, iter
);
1271 } catch (const ceph::buffer::error
&err
) {
1272 CLS_LOG(20, "set_stripe_unit_count: invalid decode");
1276 if (!stripe_count
|| !stripe_unit
)
1279 int r
= check_exists(hctx
);
1283 CLS_LOG(20, "set_stripe_unit_count");
1285 r
= image::require_feature(hctx
, RBD_FEATURE_STRIPINGV2
);
1290 r
= read_key(hctx
, "order", &order
);
1292 CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r
).c_str());
1295 if ((1ull << order
) % stripe_unit
|| stripe_unit
> (1ull << order
)) {
1296 CLS_ERR("stripe unit %llu is not a factor of the object size %llu",
1297 (unsigned long long)stripe_unit
, 1ull << order
);
1302 encode(stripe_unit
, bl
);
1303 r
= cls_cxx_map_set_val(hctx
, "stripe_unit", &bl
);
1305 CLS_ERR("error writing stripe_unit metadata: %s", cpp_strerror(r
).c_str());
1309 encode(stripe_count
, bl2
);
1310 r
= cls_cxx_map_set_val(hctx
, "stripe_count", &bl2
);
1312 CLS_ERR("error writing stripe_count metadata: %s", cpp_strerror(r
).c_str());
1319 int get_create_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1321 CLS_LOG(20, "get_create_timestamp");
1325 int r
= cls_cxx_map_get_val(hctx
, "create_timestamp", &bl
);
1328 CLS_ERR("error reading create_timestamp: %s", cpp_strerror(r
).c_str());
1333 auto it
= bl
.cbegin();
1334 decode(timestamp
, it
);
1335 } catch (const ceph::buffer::error
&err
) {
1336 CLS_ERR("could not decode create_timestamp");
1341 encode(timestamp
, *out
);
1346 * get the image access timestamp
1352 * @param timestamp the image access timestamp
1354 * @returns 0 on success, negative error code upon failure
1356 int get_access_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1358 CLS_LOG(20, "get_access_timestamp");
1362 int r
= cls_cxx_map_get_val(hctx
, "access_timestamp", &bl
);
1365 CLS_ERR("error reading access_timestamp: %s", cpp_strerror(r
).c_str());
1370 auto it
= bl
.cbegin();
1371 decode(timestamp
, it
);
1372 } catch (const ceph::buffer::error
&err
) {
1373 CLS_ERR("could not decode access_timestamp");
1378 encode(timestamp
, *out
);
1383 * get the image modify timestamp
1389 * @param timestamp the image modify timestamp
1391 * @returns 0 on success, negative error code upon failure
1393 int get_modify_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1395 CLS_LOG(20, "get_modify_timestamp");
1399 int r
= cls_cxx_map_get_val(hctx
, "modify_timestamp", &bl
);
1402 CLS_ERR("error reading modify_timestamp: %s", cpp_strerror(r
).c_str());
1407 auto it
= bl
.cbegin();
1408 decode(timestamp
, it
);
1409 } catch (const ceph::buffer::error
&err
) {
1410 CLS_ERR("could not decode modify_timestamp");
1415 encode(timestamp
, *out
);
1421 * get the image flags
1424 * @param snap_id which snapshot to query, to CEPH_NOSNAP (uint64_t)
1427 * @param flags image flags
1429 * @returns 0 on success, negative error code upon failure
1431 int get_flags(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1434 auto iter
= in
->cbegin();
1436 decode(snap_id
, iter
);
1437 } catch (const ceph::buffer::error
&err
) {
1441 CLS_LOG(20, "get_flags snap_id=%llu", (unsigned long long)snap_id
);
1444 if (snap_id
== CEPH_NOSNAP
) {
1445 int r
= read_key(hctx
, "flags", &flags
);
1446 if (r
< 0 && r
!= -ENOENT
) {
1447 CLS_ERR("failed to read flags off disk: %s", cpp_strerror(r
).c_str());
1452 string snapshot_key
;
1453 key_from_snap_id(snap_id
, &snapshot_key
);
1454 int r
= read_key(hctx
, snapshot_key
, &snap
);
1461 encode(flags
, *out
);
1466 * set the image flags
1469 * @param flags image flags
1470 * @param mask image flag mask
1471 * @param snap_id which snapshot to update, or CEPH_NOSNAP (uint64_t)
1476 * @returns 0 on success, negative error code upon failure
1478 int set_flags(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1482 uint64_t snap_id
= CEPH_NOSNAP
;
1483 auto iter
= in
->cbegin();
1485 decode(flags
, iter
);
1488 decode(snap_id
, iter
);
1490 } catch (const ceph::buffer::error
&err
) {
1494 // check that size exists to make sure this is a header object
1495 // that was created correctly
1497 uint64_t orig_flags
= 0;
1498 cls_rbd_snap snap_meta
;
1499 string snap_meta_key
;
1500 if (snap_id
== CEPH_NOSNAP
) {
1501 r
= read_key(hctx
, "flags", &orig_flags
);
1502 if (r
< 0 && r
!= -ENOENT
) {
1503 CLS_ERR("Could not read image's flags off disk: %s",
1504 cpp_strerror(r
).c_str());
1508 key_from_snap_id(snap_id
, &snap_meta_key
);
1509 r
= read_key(hctx
, snap_meta_key
, &snap_meta
);
1511 CLS_ERR("Could not read snapshot: snap_id=%" PRIu64
": %s",
1512 snap_id
, cpp_strerror(r
).c_str());
1515 orig_flags
= snap_meta
.flags
;
1518 flags
= (orig_flags
& ~mask
) | (flags
& mask
);
1519 CLS_LOG(20, "set_flags snap_id=%" PRIu64
", orig_flags=%" PRIu64
", "
1520 "new_flags=%" PRIu64
", mask=%" PRIu64
, snap_id
, orig_flags
,
1523 if (snap_id
== CEPH_NOSNAP
) {
1524 r
= write_key(hctx
, "flags", flags
);
1526 snap_meta
.flags
= flags
;
1527 r
= image::snapshot::write(hctx
, snap_meta_key
, std::move(snap_meta
));
1537 * Get the operation-based image features
1542 * @param bitmask of enabled op features (uint64_t)
1543 * @returns 0 on success, negative error code on failure
1545 int op_features_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1547 CLS_LOG(20, "op_features_get");
1549 uint64_t op_features
= 0;
1550 int r
= read_key(hctx
, "op_features", &op_features
);
1551 if (r
< 0 && r
!= -ENOENT
) {
1552 CLS_ERR("failed to read op features off disk: %s", cpp_strerror(r
).c_str());
1556 encode(op_features
, *out
);
1561 * Set the operation-based image features
1564 * @param op_features image op features
1565 * @param mask image op feature mask
1570 * @returns 0 on success, negative error code upon failure
1572 int op_features_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1574 uint64_t op_features
;
1576 auto iter
= in
->cbegin();
1578 decode(op_features
, iter
);
1580 } catch (const ceph::buffer::error
&err
) {
1584 uint64_t unsupported_op_features
= (mask
& ~RBD_OPERATION_FEATURES_ALL
);
1585 if (unsupported_op_features
!= 0ULL) {
1586 CLS_ERR("unsupported op features: %" PRIu64
, unsupported_op_features
);
1590 return image::set_op_features(hctx
, op_features
, mask
);
1594 * get the current parent, if any
1597 * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t)
1600 * @param pool parent pool id (-1 if parent does not exist)
1601 * @param image parent image id
1602 * @param snapid parent snapid
1603 * @param size portion of parent mapped under the child
1605 * @returns 0 on success or parent does not exist, negative error code on failure
1607 int get_parent(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1611 auto iter
= in
->cbegin();
1613 decode(snap_id
, iter
);
1614 } catch (const ceph::buffer::error
&err
) {
1618 int r
= check_exists(hctx
);
1623 CLS_LOG(20, "get_parent snap_id=%" PRIu64
, snap_id
);
1625 cls_rbd_parent parent
;
1626 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
1628 r
= read_key(hctx
, "parent", &parent
);
1629 if (r
< 0 && r
!= -ENOENT
) {
1631 } else if (!parent
.pool_namespace
.empty()) {
1635 if (snap_id
!= CEPH_NOSNAP
) {
1637 std::string snapshot_key
;
1638 key_from_snap_id(snap_id
, &snapshot_key
);
1639 r
= read_key(hctx
, snapshot_key
, &snap
);
1640 if (r
< 0 && r
!= -ENOENT
) {
1644 if (snap
.parent
.exists()) {
1645 // legacy format where full parent spec is written within
1646 // each snapshot record
1647 parent
= snap
.parent
;
1648 } else if (snap
.parent_overlap
) {
1649 // normalized parent reference
1650 if (!parent
.exists()) {
1651 CLS_ERR("get_parent: snap_id=%" PRIu64
": invalid parent spec",
1655 parent
.head_overlap
= *snap
.parent_overlap
;
1657 // snapshot doesn't have associated parent
1663 encode(parent
.pool_id
, *out
);
1664 encode(parent
.image_id
, *out
);
1665 encode(parent
.snap_id
, *out
);
1666 encode(parent
.head_overlap
.value_or(0ULL), *out
);
1671 * set the image parent
1674 * @param pool parent pool
1675 * @param id parent image id
1676 * @param snapid parent snapid
1677 * @param size parent size
1679 * @returns 0 on success, or negative error code
1681 int set_parent(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1683 cls_rbd_parent parent
;
1684 auto iter
= in
->cbegin();
1686 decode(parent
.pool_id
, iter
);
1687 decode(parent
.image_id
, iter
);
1688 decode(parent
.snap_id
, iter
);
1691 decode(overlap
, iter
);
1692 parent
.head_overlap
= overlap
;
1693 } catch (const ceph::buffer::error
&err
) {
1694 CLS_LOG(20, "cls_rbd::set_parent: invalid decode");
1698 int r
= image::parent::attach(hctx
, parent
, false);
1708 * remove the parent pointer
1710 * This can only happen on the head, not on a snapshot. No arguments.
1712 * @returns 0 on success, negative error code on failure.
1714 int remove_parent(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1716 int r
= image::parent::detach(hctx
, true);
1729 * @param parent spec (cls::rbd::ParentImageSpec)
1730 * @returns 0 on success, negative error code on failure
1732 int parent_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
1733 int r
= check_exists(hctx
);
1738 CLS_LOG(20, "parent_get");
1740 cls_rbd_parent parent
;
1741 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
1743 r
= read_key(hctx
, "parent", &parent
);
1744 if (r
< 0 && r
!= -ENOENT
) {
1746 } else if (r
== -ENOENT
) {
1747 // examine oldest snapshot to see if it has a denormalized parent
1748 auto parent_lambda
= [&parent
](const cls_rbd_snap
& snap_meta
) {
1749 if (snap_meta
.parent
.exists()) {
1750 parent
= snap_meta
.parent
;
1755 r
= image::snapshot::iterate(hctx
, parent_lambda
);
1762 cls::rbd::ParentImageSpec parent_image_spec
{
1763 parent
.pool_id
, parent
.pool_namespace
, parent
.image_id
,
1765 encode(parent_image_spec
, *out
);
1771 * @param snap id (uint64_t) parent snapshot id
1774 * @param byte overlap of parent image (std::optional<uint64_t>)
1775 * @returns 0 on success, negative error code on failure
1777 int parent_overlap_get(cls_method_context_t hctx
, bufferlist
*in
,
1780 auto iter
= in
->cbegin();
1782 decode(snap_id
, iter
);
1783 } catch (const ceph::buffer::error
&err
) {
1787 int r
= check_exists(hctx
);
1788 CLS_LOG(20, "parent_overlap_get");
1790 std::optional
<uint64_t> parent_overlap
= std::nullopt
;
1791 r
= image::require_feature(hctx
, RBD_FEATURE_LAYERING
);
1793 if (snap_id
== CEPH_NOSNAP
) {
1794 cls_rbd_parent parent
;
1795 r
= read_key(hctx
, "parent", &parent
);
1796 if (r
< 0 && r
!= -ENOENT
) {
1798 } else if (r
== 0) {
1799 parent_overlap
= parent
.head_overlap
;
1803 std::string snapshot_key
;
1804 key_from_snap_id(snap_id
, &snapshot_key
);
1805 r
= read_key(hctx
, snapshot_key
, &snap
);
1810 if (snap
.parent_overlap
) {
1811 parent_overlap
= snap
.parent_overlap
;
1812 } else if (snap
.parent
.exists()) {
1813 // legacy format where full parent spec is written within
1814 // each snapshot record
1815 parent_overlap
= snap
.parent
.head_overlap
;
1820 encode(parent_overlap
, *out
);
1826 * @param parent spec (cls::rbd::ParentImageSpec)
1827 * @param size parent size (uint64_t)
1830 * @returns 0 on success, negative error code on failure
1832 int parent_attach(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
1833 cls::rbd::ParentImageSpec parent_image_spec
;
1834 uint64_t parent_overlap
;
1835 bool reattach
= false;
1837 auto iter
= in
->cbegin();
1839 decode(parent_image_spec
, iter
);
1840 decode(parent_overlap
, iter
);
1842 decode(reattach
, iter
);
1844 } catch (const ceph::buffer::error
&err
) {
1845 CLS_LOG(20, "cls_rbd::parent_attach: invalid decode");
1849 int r
= image::parent::attach(hctx
, {parent_image_spec
, parent_overlap
},
1863 * @returns 0 on success, negative error code on failure
1865 int parent_detach(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
1866 int r
= image::parent::detach(hctx
, false);
1876 * methods for dealing with rbd_children object
1879 static int decode_parent_common(bufferlist::const_iterator
& it
, uint64_t *pool_id
,
1880 string
*image_id
, snapid_t
*snap_id
)
1883 decode(*pool_id
, it
);
1884 decode(*image_id
, it
);
1885 decode(*snap_id
, it
);
1886 } catch (const ceph::buffer::error
&err
) {
1887 CLS_ERR("error decoding parent spec");
1893 static int decode_parent(bufferlist
*in
, uint64_t *pool_id
,
1894 string
*image_id
, snapid_t
*snap_id
)
1896 auto it
= in
->cbegin();
1897 return decode_parent_common(it
, pool_id
, image_id
, snap_id
);
1900 static int decode_parent_and_child(bufferlist
*in
, uint64_t *pool_id
,
1901 string
*image_id
, snapid_t
*snap_id
,
1904 auto it
= in
->cbegin();
1905 int r
= decode_parent_common(it
, pool_id
, image_id
, snap_id
);
1909 decode(*c_image_id
, it
);
1910 } catch (const ceph::buffer::error
&err
) {
1911 CLS_ERR("error decoding child image id");
1917 static string
parent_key(uint64_t pool_id
, string image_id
, snapid_t snap_id
)
1920 encode(pool_id
, key_bl
);
1921 encode(image_id
, key_bl
);
1922 encode(snap_id
, key_bl
);
1923 return string(key_bl
.c_str(), key_bl
.length());
1927 * add child to rbd_children directory object
1929 * rbd_children is a map of (p_pool_id, p_image_id, p_snap_id) to
1930 * [c_image_id, [c_image_id ... ]]
1933 * @param p_pool_id parent pool id
1934 * @param p_image_id parent image oid
1935 * @param p_snap_id parent snapshot id
1936 * @param c_image_id new child image oid to add
1938 * @returns 0 on success, negative error on failure
1941 int add_child(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
1947 string p_image_id
, c_image_id
;
1948 // Use set for ease of erase() for remove_child()
1949 std::set
<string
> children
;
1951 r
= decode_parent_and_child(in
, &p_pool_id
, &p_image_id
, &p_snap_id
,
1956 CLS_LOG(20, "add_child %s to (%" PRIu64
", %s, %" PRIu64
")", c_image_id
.c_str(),
1957 p_pool_id
, p_image_id
.c_str(), p_snap_id
.val
);
1959 string key
= parent_key(p_pool_id
, p_image_id
, p_snap_id
);
1961 // get current child list for parent, if any
1962 r
= read_key(hctx
, key
, &children
);
1963 if ((r
< 0) && (r
!= -ENOENT
)) {
1964 CLS_LOG(20, "add_child: omap read failed: %s", cpp_strerror(r
).c_str());
1968 if (children
.find(c_image_id
) != children
.end()) {
1969 CLS_LOG(20, "add_child: child already exists: %s", c_image_id
.c_str());
1973 children
.insert(c_image_id
);
1977 encode(children
, childbl
);
1978 r
= cls_cxx_map_set_val(hctx
, key
, &childbl
);
1980 CLS_LOG(20, "add_child: omap write failed: %s", cpp_strerror(r
).c_str());
1985 * remove child from rbd_children directory object
1988 * @param p_pool_id parent pool id
1989 * @param p_image_id parent image oid
1990 * @param p_snap_id parent snapshot id
1991 * @param c_image_id new child image oid to add
1993 * @returns 0 on success, negative error on failure
1996 int remove_child(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2002 string p_image_id
, c_image_id
;
2003 std::set
<string
> children
;
2005 r
= decode_parent_and_child(in
, &p_pool_id
, &p_image_id
, &p_snap_id
,
2010 CLS_LOG(20, "remove_child %s from (%" PRIu64
", %s, %" PRIu64
")",
2011 c_image_id
.c_str(), p_pool_id
, p_image_id
.c_str(),
2014 string key
= parent_key(p_pool_id
, p_image_id
, p_snap_id
);
2016 // get current child list for parent. Unlike add_child(), an empty list
2017 // is an error (how can we remove something that doesn't exist?)
2018 r
= read_key(hctx
, key
, &children
);
2020 CLS_LOG(20, "remove_child: read omap failed: %s", cpp_strerror(r
).c_str());
2024 if (children
.find(c_image_id
) == children
.end()) {
2025 CLS_LOG(20, "remove_child: child not found: %s", c_image_id
.c_str());
2028 // find and remove child
2029 children
.erase(c_image_id
);
2031 // now empty? remove key altogether
2032 if (children
.empty()) {
2033 r
= cls_cxx_map_remove_key(hctx
, key
);
2035 CLS_LOG(20, "remove_child: remove key failed: %s", cpp_strerror(r
).c_str());
2037 // write back shortened children list
2039 encode(children
, childbl
);
2040 r
= cls_cxx_map_set_val(hctx
, key
, &childbl
);
2042 CLS_LOG(20, "remove_child: write omap failed: %s", cpp_strerror(r
).c_str());
2049 * @param p_pool_id parent pool id
2050 * @param p_image_id parent image oid
2051 * @param p_snap_id parent snapshot id
2052 * @param c_image_id new child image oid to add
2055 * @param children set<string> of children
2057 * @returns 0 on success, negative error on failure
2059 int get_children(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2065 std::set
<string
> children
;
2067 r
= decode_parent(in
, &p_pool_id
, &p_image_id
, &p_snap_id
);
2071 CLS_LOG(20, "get_children of (%" PRIu64
", %s, %" PRIu64
")",
2072 p_pool_id
, p_image_id
.c_str(), p_snap_id
.val
);
2074 string key
= parent_key(p_pool_id
, p_image_id
, p_snap_id
);
2076 r
= read_key(hctx
, key
, &children
);
2079 CLS_LOG(20, "get_children: read omap failed: %s", cpp_strerror(r
).c_str());
2082 encode(children
, *out
);
2088 * Get the information needed to create a rados snap context for doing
2089 * I/O to the data objects. This must include all snapshots.
2092 * @param snap_seq the highest snapshot id ever associated with the image (uint64_t)
2093 * @param snap_ids existing snapshot ids in descending order (vector<uint64_t>)
2094 * @returns 0 on success, negative error code on failure
2096 int get_snapcontext(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2098 CLS_LOG(20, "get_snapcontext");
2101 int max_read
= RBD_MAX_KEYS_READ
;
2102 vector
<snapid_t
> snap_ids
;
2103 string last_read
= RBD_SNAP_KEY_PREFIX
;
2108 r
= cls_cxx_map_get_keys(hctx
, last_read
, max_read
, &keys
, &more
);
2112 for (auto it
= keys
.begin(); it
!= keys
.end(); ++it
) {
2113 if ((*it
).find(RBD_SNAP_KEY_PREFIX
) != 0)
2115 snapid_t snap_id
= snap_id_from_key(*it
);
2116 snap_ids
.push_back(snap_id
);
2119 last_read
= *(keys
.rbegin());
2123 r
= read_key(hctx
, "snap_seq", &snap_seq
);
2125 CLS_ERR("could not read the image's snap_seq off disk: %s", cpp_strerror(r
).c_str());
2129 // snap_ids must be descending in a snap context
2130 std::reverse(snap_ids
.begin(), snap_ids
.end());
2132 encode(snap_seq
, *out
);
2133 encode(snap_ids
, *out
);
2140 * @param object_prefix prefix for data object names (string)
2141 * @returns 0 on success, negative error code on failure
2143 int get_object_prefix(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2145 CLS_LOG(20, "get_object_prefix");
2147 string object_prefix
;
2148 int r
= read_key(hctx
, "object_prefix", &object_prefix
);
2150 CLS_ERR("failed to read the image's object prefix off of disk: %s",
2151 cpp_strerror(r
).c_str());
2155 encode(object_prefix
, *out
);
2165 * @param pool_id (int64_t) of data pool or -1 if none
2166 * @returns 0 on success, negative error code on failure
2168 int get_data_pool(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2170 CLS_LOG(20, "get_data_pool");
2172 int64_t data_pool_id
= -1;
2173 int r
= read_key(hctx
, "data_pool_id", &data_pool_id
);
2177 CLS_ERR("error reading image data pool id: %s", cpp_strerror(r
).c_str());
2181 encode(data_pool_id
, *out
);
2187 * @param snap_id which snapshot to query
2190 * @param name (string) of the snapshot
2191 * @returns 0 on success, negative error code on failure
2193 int get_snapshot_name(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2197 auto iter
= in
->cbegin();
2199 decode(snap_id
, iter
);
2200 } catch (const ceph::buffer::error
&err
) {
2204 CLS_LOG(20, "get_snapshot_name snap_id=%llu", (unsigned long long)snap_id
);
2206 if (snap_id
== CEPH_NOSNAP
)
2210 string snapshot_key
;
2211 key_from_snap_id(snap_id
, &snapshot_key
);
2212 int r
= read_key(hctx
, snapshot_key
, &snap
);
2216 encode(snap
.name
, *out
);
2223 * @param snap_id which snapshot to query
2226 * @param timestamp (utime_t) of the snapshot
2227 * @returns 0 on success, negative error code on failure
2229 * NOTE: deprecated - remove this method after Luminous is unsupported
2231 int get_snapshot_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2235 auto iter
= in
->cbegin();
2237 decode(snap_id
, iter
);
2238 } catch (const ceph::buffer::error
&err
) {
2242 CLS_LOG(20, "get_snapshot_timestamp snap_id=%llu", (unsigned long long)snap_id
);
2244 if (snap_id
== CEPH_NOSNAP
) {
2249 string snapshot_key
;
2250 key_from_snap_id(snap_id
, &snapshot_key
);
2251 int r
= read_key(hctx
, snapshot_key
, &snap
);
2256 encode(snap
.timestamp
, *out
);
2262 * @param snap_id which snapshot to query
2265 * @param snapshot (cls::rbd::SnapshotInfo)
2266 * @returns 0 on success, negative error code on failure
2268 int snapshot_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2272 auto iter
= in
->cbegin();
2274 decode(snap_id
, iter
);
2275 } catch (const ceph::buffer::error
&err
) {
2279 CLS_LOG(20, "snapshot_get snap_id=%llu", (unsigned long long)snap_id
);
2280 if (snap_id
== CEPH_NOSNAP
) {
2285 string snapshot_key
;
2286 key_from_snap_id(snap_id
, &snapshot_key
);
2287 int r
= read_key(hctx
, snapshot_key
, &snap
);
2292 cls::rbd::SnapshotInfo snapshot_info
{snap
.id
, snap
.snapshot_namespace
,
2293 snap
.name
, snap
.image_size
,
2294 snap
.timestamp
, snap
.child_count
};
2295 encode(snapshot_info
, *out
);
2300 * Adds a snapshot to an rbd header. Ensures the id and name are unique.
2303 * @param snap_name name of the snapshot (string)
2304 * @param snap_id id of the snapshot (uint64_t)
2305 * @param snap_namespace namespace of the snapshot (cls::rbd::SnapshotNamespace)
2308 * @returns 0 on success, negative error code on failure.
2309 * @returns -ESTALE if the input snap_id is less than the image's snap_seq
2310 * @returns -EEXIST if the id or name are already used by another snapshot
2312 int snapshot_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2314 bufferlist snap_namebl
, snap_idbl
;
2315 cls_rbd_snap snap_meta
;
2316 uint64_t snap_limit
;
2319 auto iter
= in
->cbegin();
2320 decode(snap_meta
.name
, iter
);
2321 decode(snap_meta
.id
, iter
);
2323 decode(snap_meta
.snapshot_namespace
, iter
);
2325 } catch (const ceph::buffer::error
&err
) {
2329 if (std::holds_alternative
<cls::rbd::UnknownSnapshotNamespace
>(
2330 snap_meta
.snapshot_namespace
)) {
2331 CLS_ERR("Unknown snapshot namespace provided");
2335 CLS_LOG(20, "snapshot_add name=%s id=%llu", snap_meta
.name
.c_str(),
2336 (unsigned long long)snap_meta
.id
.val
);
2338 if (snap_meta
.id
> CEPH_MAXSNAP
)
2341 uint64_t cur_snap_seq
;
2342 int r
= read_key(hctx
, "snap_seq", &cur_snap_seq
);
2344 CLS_ERR("Could not read image's snap_seq off disk: %s", cpp_strerror(r
).c_str());
2348 // client lost a race with another snapshot creation.
2349 // snap_seq must be monotonically increasing.
2350 if (snap_meta
.id
< cur_snap_seq
)
2353 r
= read_key(hctx
, "size", &snap_meta
.image_size
);
2355 CLS_ERR("Could not read image's size off disk: %s", cpp_strerror(r
).c_str());
2358 r
= read_key(hctx
, "flags", &snap_meta
.flags
);
2359 if (r
< 0 && r
!= -ENOENT
) {
2360 CLS_ERR("Could not read image's flags off disk: %s", cpp_strerror(r
).c_str());
2364 r
= read_key(hctx
, "snap_limit", &snap_limit
);
2366 snap_limit
= UINT64_MAX
;
2368 CLS_ERR("Could not read snapshot limit off disk: %s", cpp_strerror(r
).c_str());
2372 snap_meta
.timestamp
= ceph_clock_now();
2374 uint64_t total_read
= 0;
2375 auto pre_check_lambda
=
2376 [&snap_meta
, &total_read
, snap_limit
](const cls_rbd_snap
& old_meta
) {
2378 if (total_read
>= snap_limit
) {
2379 CLS_ERR("Attempt to create snapshot over limit of %" PRIu64
,
2384 if ((snap_meta
.name
== old_meta
.name
&&
2385 snap_meta
.snapshot_namespace
== old_meta
.snapshot_namespace
) ||
2386 snap_meta
.id
== old_meta
.id
) {
2387 CLS_LOG(20, "snap_name %s or snap_id %" PRIu64
" matches existing snap "
2388 "%s %" PRIu64
, snap_meta
.name
.c_str(), snap_meta
.id
.val
,
2389 old_meta
.name
.c_str(), old_meta
.id
.val
);
2395 r
= image::snapshot::iterate(hctx
, pre_check_lambda
);
2400 // snapshot inherits parent, if any
2401 cls_rbd_parent parent
;
2402 r
= read_key(hctx
, "parent", &parent
);
2403 if (r
< 0 && r
!= -ENOENT
) {
2407 // write helper method will convert to normalized format if required
2408 snap_meta
.parent
= parent
;
2411 if (cls::rbd::get_snap_namespace_type(snap_meta
.snapshot_namespace
) ==
2412 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
) {
2413 // add snap_trash feature bit if not already enabled
2414 r
= image::set_op_features(hctx
, RBD_OPERATION_FEATURE_SNAP_TRASH
,
2415 RBD_OPERATION_FEATURE_SNAP_TRASH
);
2421 r
= write_key(hctx
, "snap_seq", snap_meta
.id
);
2426 std::string snapshot_key
;
2427 key_from_snap_id(snap_meta
.id
, &snapshot_key
);
2428 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap_meta
));
2440 * @param src_snap_id old snap id of the snapshot (snapid_t)
2441 * @param dst_snap_name new name of the snapshot (string)
2444 * @returns 0 on success, negative error code on failure.
2446 int snapshot_rename(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2448 bufferlist snap_namebl
, snap_idbl
;
2449 snapid_t src_snap_id
;
2450 string dst_snap_name
;
2451 cls_rbd_snap snap_meta
;
2455 auto iter
= in
->cbegin();
2456 decode(src_snap_id
, iter
);
2457 decode(dst_snap_name
, iter
);
2458 } catch (const ceph::buffer::error
&err
) {
2462 CLS_LOG(20, "snapshot_rename id=%" PRIu64
", dst_name=%s",
2463 src_snap_id
.val
, dst_snap_name
.c_str());
2465 auto duplicate_name_lambda
= [&dst_snap_name
](const cls_rbd_snap
& snap_meta
) {
2466 if (cls::rbd::get_snap_namespace_type(snap_meta
.snapshot_namespace
) ==
2467 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER
&&
2468 snap_meta
.name
== dst_snap_name
) {
2469 CLS_LOG(20, "snap_name %s matches existing snap with snap id %" PRIu64
,
2470 dst_snap_name
.c_str(), snap_meta
.id
.val
);
2475 r
= image::snapshot::iterate(hctx
, duplicate_name_lambda
);
2480 std::string src_snap_key
;
2481 key_from_snap_id(src_snap_id
, &src_snap_key
);
2482 r
= read_key(hctx
, src_snap_key
, &snap_meta
);
2484 CLS_LOG(20, "cannot find existing snap with snap id = %" PRIu64
,
2489 if (cls::rbd::get_snap_namespace_type(snap_meta
.snapshot_namespace
) !=
2490 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER
) {
2491 // can only rename user snapshots
2495 snap_meta
.name
= dst_snap_name
;
2496 r
= image::snapshot::write(hctx
, src_snap_key
, std::move(snap_meta
));
2505 * Removes a snapshot from an rbd header.
2508 * @param snap_id the id of the snapshot to remove (uint64_t)
2511 * @returns 0 on success, negative error code on failure
2513 int snapshot_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2518 auto iter
= in
->cbegin();
2519 decode(snap_id
, iter
);
2520 } catch (const ceph::buffer::error
&err
) {
2524 CLS_LOG(20, "snapshot_remove id=%llu", (unsigned long long)snap_id
.val
);
2526 // check if the key exists. we can't rely on remove_key doing this for
2527 // us, since OMAPRMKEYS returns success if the key is not there.
2528 // bug or feature? sounds like a bug, since tmap did not have this
2529 // behavior, but cls_rgw may rely on it...
2531 string snapshot_key
;
2532 key_from_snap_id(snap_id
, &snapshot_key
);
2533 int r
= read_key(hctx
, snapshot_key
, &snap
);
2538 if (snap
.protection_status
!= RBD_PROTECTION_STATUS_UNPROTECTED
) {
2542 // snapshot is in-use by clone v2 child
2543 if (snap
.child_count
> 0) {
2547 r
= remove_key(hctx
, snapshot_key
);
2552 bool has_child_snaps
= false;
2553 bool has_trash_snaps
= false;
2554 auto remove_lambda
= [snap_id
, &has_child_snaps
, &has_trash_snaps
](
2555 const cls_rbd_snap
& snap_meta
) {
2556 if (snap_meta
.id
!= snap_id
) {
2557 if (snap_meta
.parent
.pool_id
!= -1 || snap_meta
.parent_overlap
) {
2558 has_child_snaps
= true;
2561 if (cls::rbd::get_snap_namespace_type(snap_meta
.snapshot_namespace
) ==
2562 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
) {
2563 has_trash_snaps
= true;
2569 r
= image::snapshot::iterate(hctx
, remove_lambda
);
2574 cls_rbd_parent parent
;
2575 r
= read_key(hctx
, "parent", &parent
);
2576 if (r
< 0 && r
!= -ENOENT
) {
2580 bool has_parent
= (r
>= 0 && parent
.exists());
2581 bool is_head_child
= (has_parent
&& parent
.head_overlap
);
2582 ceph_release_t require_osd_release
= cls_get_required_osd_release(hctx
);
2583 if (has_parent
&& !is_head_child
&& !has_child_snaps
&&
2584 require_osd_release
>= ceph_release_t::nautilus
) {
2585 // remove the unused parent image spec
2586 r
= remove_key(hctx
, "parent");
2587 if (r
< 0 && r
!= -ENOENT
) {
2592 uint64_t op_features_mask
= 0ULL;
2593 if (!has_child_snaps
&& !is_head_child
) {
2594 // disable clone child op feature if no longer associated
2595 op_features_mask
|= RBD_OPERATION_FEATURE_CLONE_CHILD
;
2597 if (!has_trash_snaps
) {
2598 // remove the snap_trash op feature if not in-use by any other snapshots
2599 op_features_mask
|= RBD_OPERATION_FEATURE_SNAP_TRASH
;
2602 if (op_features_mask
!= 0ULL) {
2603 r
= image::set_op_features(hctx
, 0, op_features_mask
);
2613 * Moves a snapshot to the trash namespace.
2616 * @param snap_id the id of the snapshot to move to the trash (uint64_t)
2619 * @returns 0 on success, negative error code on failure
2621 int snapshot_trash_add(cls_method_context_t hctx
, bufferlist
*in
,
2627 auto iter
= in
->cbegin();
2628 decode(snap_id
, iter
);
2629 } catch (const ceph::buffer::error
&err
) {
2633 CLS_LOG(20, "snapshot_trash_add id=%" PRIu64
, snap_id
.val
);
2636 std::string snapshot_key
;
2637 key_from_snap_id(snap_id
, &snapshot_key
);
2638 int r
= read_key(hctx
, snapshot_key
, &snap
);
2643 if (snap
.protection_status
!= RBD_PROTECTION_STATUS_UNPROTECTED
) {
2647 auto snap_type
= cls::rbd::get_snap_namespace_type(snap
.snapshot_namespace
);
2648 if (snap_type
== cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
) {
2652 // add snap_trash feature bit if not already enabled
2653 r
= image::set_op_features(hctx
, RBD_OPERATION_FEATURE_SNAP_TRASH
,
2654 RBD_OPERATION_FEATURE_SNAP_TRASH
);
2659 snap
.snapshot_namespace
= cls::rbd::TrashSnapshotNamespace
{snap_type
,
2662 uuid_gen
.generate_random();
2663 snap
.name
= uuid_gen
.to_string();
2665 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap
));
2674 * Returns a uint64_t of all the features supported by this class.
2676 int get_all_features(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2678 uint64_t all_features
= RBD_FEATURES_ALL
;
2679 encode(all_features
, *out
);
2684 * "Copy up" data from the parent of a clone to the clone's object(s).
2685 * Used for implementing copy-on-write for a clone image. Client
2686 * will pass down a chunk of data that fits completely within one
2687 * clone block (one object), and is aligned (starts at beginning of block),
2688 * but may be shorter (for non-full parent blocks). The class method
2689 * can't know the object size to validate the requested length,
2690 * so it just writes the data as given if the child object doesn't
2691 * already exist, and returns success if it does.
2694 * @param in bufferlist of data to write
2697 * @returns 0 on success, or if block already exists in child
2698 * negative error code on other error
2701 int copyup(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2703 // check for existence; if child object exists, just return success
2704 if (cls_cxx_stat(hctx
, NULL
, NULL
) == 0)
2706 CLS_LOG(20, "copyup: writing length %d\n", in
->length());
2707 return cls_cxx_write(hctx
, 0, in
->length(), in
);
2712 * @param extent_map map of extents to write
2713 * @param data bufferlist of data to write
2716 * @returns 0 on success, or if block already exists in child
2717 * negative error code on other error
2720 int sparse_copyup(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2722 std::map
<uint64_t, uint64_t> extent_map
;
2726 auto iter
= in
->cbegin();
2727 decode(extent_map
, iter
);
2729 } catch (const ceph::buffer::error
&err
) {
2730 CLS_LOG(20, "sparse_copyup: invalid decode");
2734 int r
= check_exists(hctx
);
2739 if (extent_map
.empty()) {
2740 CLS_LOG(20, "sparse_copyup: create empty object");
2741 r
= cls_cxx_create(hctx
, true);
2745 uint64_t data_offset
= 0;
2746 for (auto &it
: extent_map
) {
2747 auto off
= it
.first
;
2748 auto len
= it
.second
;
2752 tmpbl
.substr_of(data
, data_offset
, len
);
2753 } catch (const ceph::buffer::error
&err
) {
2754 CLS_LOG(20, "sparse_copyup: invalid data");
2759 CLS_LOG(20, "sparse_copyup: writing extent %" PRIu64
"~%" PRIu64
"\n", off
,
2761 int r
= cls_cxx_write(hctx
, off
, len
, &tmpbl
);
2763 CLS_ERR("sparse_copyup: error writing extent %" PRIu64
"~%" PRIu64
": %s",
2764 off
, len
, cpp_strerror(r
).c_str());
2772 /************************ rbd_id object methods **************************/
2779 * @param id the id stored in the object
2780 * @returns 0 on success, negative error code on failure
2782 int get_id(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2785 int r
= cls_cxx_stat(hctx
, &size
, NULL
);
2793 r
= cls_cxx_read(hctx
, 0, size
, &read_bl
);
2795 CLS_ERR("get_id: could not read id: %s", cpp_strerror(r
).c_str());
2801 auto iter
= read_bl
.cbegin();
2803 } catch (const ceph::buffer::error
&err
) {
2812 * Set the id of an image. The object must already exist.
2815 * @param id the id of the image, as an alpha-numeric string
2818 * @returns 0 on success, -EEXIST if the atomic create fails,
2819 * negative error code on other error
2821 int set_id(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2823 int r
= check_exists(hctx
);
2829 auto iter
= in
->cbegin();
2831 } catch (const ceph::buffer::error
&err
) {
2835 if (!is_valid_id(id
)) {
2836 CLS_ERR("set_id: invalid id '%s'", id
.c_str());
2841 r
= cls_cxx_stat(hctx
, &size
, NULL
);
2847 CLS_LOG(20, "set_id: id=%s", id
.c_str());
2849 bufferlist write_bl
;
2850 encode(id
, write_bl
);
2851 return cls_cxx_write(hctx
, 0, write_bl
.length(), &write_bl
);
2855 * Update the access timestamp of an image
2861 * @returns 0 on success, negative error code on other error
2863 int set_access_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2865 int r
= check_exists(hctx
);
2869 utime_t timestamp
= ceph_clock_now();
2870 r
= write_key(hctx
, "access_timestamp", timestamp
);
2872 CLS_ERR("error setting access_timestamp");
2880 * Update the modify timestamp of an image
2886 * @returns 0 on success, negative error code on other error
2889 int set_modify_timestamp(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
2891 int r
= check_exists(hctx
);
2895 utime_t timestamp
= ceph_clock_now();
2896 r
= write_key(hctx
, "modify_timestamp", timestamp
);
2898 CLS_ERR("error setting modify_timestamp");
2907 /*********************** methods for rbd_directory ***********************/
2909 static const string
dir_key_for_id(const string
&id
)
2911 return RBD_DIR_ID_KEY_PREFIX
+ id
;
2914 static const string
dir_key_for_name(const string
&name
)
2916 return RBD_DIR_NAME_KEY_PREFIX
+ name
;
2919 static const string
dir_name_from_key(const string
&key
)
2921 return key
.substr(strlen(RBD_DIR_NAME_KEY_PREFIX
));
2924 static int dir_add_image_helper(cls_method_context_t hctx
,
2925 const string
&name
, const string
&id
,
2926 bool check_for_unique_id
)
2928 if (!name
.size() || !is_valid_id(id
)) {
2929 CLS_ERR("dir_add_image_helper: invalid name '%s' or id '%s'",
2930 name
.c_str(), id
.c_str());
2934 CLS_LOG(20, "dir_add_image_helper name=%s id=%s", name
.c_str(), id
.c_str());
2937 string name_key
= dir_key_for_name(name
);
2938 string id_key
= dir_key_for_id(id
);
2939 int r
= read_key(hctx
, name_key
, &tmp
);
2941 CLS_LOG(10, "name already exists");
2944 r
= read_key(hctx
, id_key
, &tmp
);
2945 if (r
!= -ENOENT
&& check_for_unique_id
) {
2946 CLS_LOG(10, "id already exists");
2949 bufferlist id_bl
, name_bl
;
2951 encode(name
, name_bl
);
2952 map
<string
, bufferlist
> omap_vals
;
2953 omap_vals
[name_key
] = id_bl
;
2954 omap_vals
[id_key
] = name_bl
;
2955 return cls_cxx_map_set_vals(hctx
, &omap_vals
);
2958 static int dir_remove_image_helper(cls_method_context_t hctx
,
2959 const string
&name
, const string
&id
)
2961 CLS_LOG(20, "dir_remove_image_helper name=%s id=%s",
2962 name
.c_str(), id
.c_str());
2964 string stored_name
, stored_id
;
2965 string name_key
= dir_key_for_name(name
);
2966 string id_key
= dir_key_for_id(id
);
2967 int r
= read_key(hctx
, name_key
, &stored_id
);
2970 CLS_ERR("error reading name to id mapping: %s", cpp_strerror(r
).c_str());
2973 r
= read_key(hctx
, id_key
, &stored_name
);
2975 CLS_ERR("error reading id to name mapping: %s", cpp_strerror(r
).c_str());
2979 // check if this op raced with a rename
2980 if (stored_name
!= name
|| stored_id
!= id
) {
2981 CLS_ERR("stored name '%s' and id '%s' do not match args '%s' and '%s'",
2982 stored_name
.c_str(), stored_id
.c_str(), name
.c_str(), id
.c_str());
2986 r
= cls_cxx_map_remove_key(hctx
, name_key
);
2988 CLS_ERR("error removing name: %s", cpp_strerror(r
).c_str());
2992 r
= cls_cxx_map_remove_key(hctx
, id_key
);
2994 CLS_ERR("error removing id: %s", cpp_strerror(r
).c_str());
3002 * Rename an image in the directory, updating both indexes
3003 * atomically. This can't be done from the client calling
3004 * dir_add_image and dir_remove_image in one transaction because the
3005 * results of the first method are not visibale to later steps.
3008 * @param src original name of the image
3009 * @param dest new name of the image
3010 * @param id the id of the image
3013 * @returns -ESTALE if src and id do not map to each other
3014 * @returns -ENOENT if src or id are not in the directory
3015 * @returns -EEXIST if dest already exists
3016 * @returns 0 on success, negative error code on failure
3018 int dir_rename_image(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3020 string src
, dest
, id
;
3022 auto iter
= in
->cbegin();
3026 } catch (const ceph::buffer::error
&err
) {
3030 int r
= dir_remove_image_helper(hctx
, src
, id
);
3033 // ignore duplicate id because the result of
3034 // remove_image_helper is not visible yet
3035 return dir_add_image_helper(hctx
, dest
, id
, false);
3039 * Get the id of an image given its name.
3042 * @param name the name of the image
3045 * @param id the id of the image
3046 * @returns 0 on success, negative error code on failure
3048 int dir_get_id(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3053 auto iter
= in
->cbegin();
3055 } catch (const ceph::buffer::error
&err
) {
3059 CLS_LOG(20, "dir_get_id: name=%s", name
.c_str());
3062 int r
= read_key(hctx
, dir_key_for_name(name
), &id
);
3065 CLS_ERR("error reading id for name '%s': %s", name
.c_str(), cpp_strerror(r
).c_str());
3073 * Get the name of an image given its id.
3076 * @param id the id of the image
3079 * @param name the name of the image
3080 * @returns 0 on success, negative error code on failure
3082 int dir_get_name(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3087 auto iter
= in
->cbegin();
3089 } catch (const ceph::buffer::error
&err
) {
3093 CLS_LOG(20, "dir_get_name: id=%s", id
.c_str());
3096 int r
= read_key(hctx
, dir_key_for_id(id
), &name
);
3099 CLS_ERR("error reading name for id '%s': %s", id
.c_str(),
3100 cpp_strerror(r
).c_str());
3109 * List the names and ids of the images in the directory, sorted by
3113 * @param start_after which name to begin listing after
3114 * (use the empty string to start at the beginning)
3115 * @param max_return the maximum number of names to list
3118 * @param images map from name to id of up to max_return images
3119 * @returns 0 on success, negative error code on failure
3121 int dir_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3124 uint64_t max_return
;
3127 auto iter
= in
->cbegin();
3128 decode(start_after
, iter
);
3129 decode(max_return
, iter
);
3130 } catch (const ceph::buffer::error
&err
) {
3134 int max_read
= RBD_MAX_KEYS_READ
;
3135 map
<string
, string
> images
;
3136 string last_read
= dir_key_for_name(start_after
);
3139 while (more
&& images
.size() < max_return
) {
3140 map
<string
, bufferlist
> vals
;
3141 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
3142 int r
= cls_cxx_map_get_vals(hctx
, last_read
, RBD_DIR_NAME_KEY_PREFIX
,
3143 max_read
, &vals
, &more
);
3146 CLS_ERR("error reading directory by name: %s", cpp_strerror(r
).c_str());
3151 for (auto it
= vals
.begin(); it
!= vals
.end(); ++it
) {
3153 auto iter
= it
->second
.cbegin();
3156 } catch (const ceph::buffer::error
&err
) {
3157 CLS_ERR("could not decode id of image '%s'", it
->first
.c_str());
3160 CLS_LOG(20, "adding '%s' -> '%s'", dir_name_from_key(it
->first
).c_str(), id
.c_str());
3161 images
[dir_name_from_key(it
->first
)] = id
;
3162 if (images
.size() >= max_return
)
3165 if (!vals
.empty()) {
3166 last_read
= dir_key_for_name(images
.rbegin()->first
);
3170 encode(images
, *out
);
3176 * Add an image to the rbd directory. Creates the directory object if
3177 * needed, and updates the index from id to name and name to id.
3180 * @param name the name of the image
3181 * @param id the id of the image
3184 * @returns -EEXIST if the image name is already in the directory
3185 * @returns -EBADF if the image id is already in the directory
3186 * @returns 0 on success, negative error code on failure
3188 int dir_add_image(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3190 int r
= cls_cxx_create(hctx
, false);
3192 CLS_ERR("could not create directory: %s", cpp_strerror(r
).c_str());
3198 auto iter
= in
->cbegin();
3201 } catch (const ceph::buffer::error
&err
) {
3205 return dir_add_image_helper(hctx
, name
, id
, true);
3209 * Remove an image from the rbd directory.
3212 * @param name the name of the image
3213 * @param id the id of the image
3216 * @returns -ESTALE if the name and id do not map to each other
3217 * @returns 0 on success, negative error code on failure
3219 int dir_remove_image(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3223 auto iter
= in
->cbegin();
3226 } catch (const ceph::buffer::error
&err
) {
3230 return dir_remove_image_helper(hctx
, name
, id
);
3234 * Verify the current state of the directory
3237 * @param state the DirectoryState of the directory
3240 * @returns -ENOENT if the state does not match
3241 * @returns 0 on success, negative error code on failure
3243 int dir_state_assert(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3245 cls::rbd::DirectoryState directory_state
= cls::rbd::DIRECTORY_STATE_READY
;
3247 auto iter
= in
->cbegin();
3248 decode(directory_state
, iter
);
3249 } catch (const ceph::buffer::error
&err
) {
3253 cls::rbd::DirectoryState on_disk_directory_state
= directory_state
;
3254 int r
= read_key(hctx
, "state", &on_disk_directory_state
);
3259 if (directory_state
!= on_disk_directory_state
) {
3266 * Set the current state of the directory
3269 * @param state the DirectoryState of the directory
3272 * @returns -ENOENT if the state does not match
3273 * @returns 0 on success, negative error code on failure
3275 int dir_state_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3277 cls::rbd::DirectoryState directory_state
;
3279 auto iter
= in
->cbegin();
3280 decode(directory_state
, iter
);
3281 } catch (const ceph::buffer::error
&err
) {
3285 int r
= check_exists(hctx
);
3286 if (r
< 0 && r
!= -ENOENT
) {
3290 switch (directory_state
) {
3291 case cls::rbd::DIRECTORY_STATE_READY
:
3293 case cls::rbd::DIRECTORY_STATE_ADD_DISABLED
:
3299 // verify that the directory is empty
3300 std::map
<std::string
, bufferlist
> vals
;
3302 r
= cls_cxx_map_get_vals(hctx
, RBD_DIR_NAME_KEY_PREFIX
,
3303 RBD_DIR_NAME_KEY_PREFIX
, 1, &vals
, &more
);
3306 } else if (!vals
.empty()) {
3315 r
= write_key(hctx
, "state", directory_state
);
3323 int object_map_read(cls_method_context_t hctx
, BitVector
<2> &object_map
)
3326 int r
= cls_cxx_stat(hctx
, &size
, NULL
);
3335 r
= cls_cxx_read(hctx
, 0, size
, &bl
);
3341 auto iter
= bl
.cbegin();
3342 decode(object_map
, iter
);
3343 } catch (const ceph::buffer::error
&err
) {
3344 CLS_ERR("failed to decode object map: %s", err
.what());
3351 * Load an rbd image's object map
3357 * @param object map bit vector
3358 * @returns 0 on success, negative error code on failure
3360 int object_map_load(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3362 BitVector
<2> object_map
;
3363 int r
= object_map_read(hctx
, object_map
);
3368 object_map
.set_crc_enabled(false);
3369 encode(object_map
, *out
);
3374 * Save an rbd image's object map
3377 * @param object map bit vector
3380 * @returns 0 on success, negative error code on failure
3382 int object_map_save(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3384 BitVector
<2> object_map
;
3386 auto iter
= in
->cbegin();
3387 decode(object_map
, iter
);
3388 } catch (const ceph::buffer::error
&err
) {
3392 object_map
.set_crc_enabled(true);
3395 encode(object_map
, bl
);
3396 CLS_LOG(20, "object_map_save: object size=%" PRIu64
", byte size=%u",
3397 object_map
.size(), bl
.length());
3398 return cls_cxx_write_full(hctx
, &bl
);
3402 * Resize an rbd image's object map
3405 * @param object_count the max number of objects in the image
3406 * @param default_state the default state of newly created objects
3409 * @returns 0 on success, negative error code on failure
3411 int object_map_resize(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3413 uint64_t object_count
;
3414 uint8_t default_state
;
3416 auto iter
= in
->cbegin();
3417 decode(object_count
, iter
);
3418 decode(default_state
, iter
);
3419 } catch (const ceph::buffer::error
&err
) {
3423 // protect against excessive memory requirements
3424 if (object_count
> cls::rbd::MAX_OBJECT_MAP_OBJECT_COUNT
) {
3425 CLS_ERR("object map too large: %" PRIu64
, object_count
);
3429 BitVector
<2> object_map
;
3430 int r
= object_map_read(hctx
, object_map
);
3431 if ((r
< 0) && (r
!= -ENOENT
)) {
3435 size_t orig_object_map_size
= object_map
.size();
3436 if (object_count
< orig_object_map_size
) {
3437 auto it
= object_map
.begin() + object_count
;
3438 auto end_it
= object_map
.end() ;
3439 uint64_t i
= object_count
;
3440 for (; it
!= end_it
; ++it
, ++i
) {
3441 if (*it
!= default_state
) {
3442 CLS_ERR("object map indicates object still exists: %" PRIu64
, i
);
3446 object_map
.resize(object_count
);
3447 } else if (object_count
> orig_object_map_size
) {
3448 object_map
.resize(object_count
);
3449 auto it
= object_map
.begin() + orig_object_map_size
;
3450 auto end_it
= object_map
.end();
3451 for (; it
!= end_it
; ++it
) {
3452 *it
= default_state
;
3457 encode(object_map
, map
);
3458 CLS_LOG(20, "object_map_resize: object size=%" PRIu64
", byte size=%u",
3459 object_count
, map
.length());
3460 return cls_cxx_write_full(hctx
, &map
);
3464 * Update an rbd image's object map
3467 * @param start_object_no the start object iterator
3468 * @param end_object_no the end object iterator
3469 * @param new_object_state the new object state
3470 * @param current_object_state optional current object state filter
3473 * @returns 0 on success, negative error code on failure
3475 int object_map_update(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3477 uint64_t start_object_no
;
3478 uint64_t end_object_no
;
3479 uint8_t new_object_state
;
3480 boost::optional
<uint8_t> current_object_state
;
3482 auto iter
= in
->cbegin();
3483 decode(start_object_no
, iter
);
3484 decode(end_object_no
, iter
);
3485 decode(new_object_state
, iter
);
3486 decode(current_object_state
, iter
);
3487 } catch (const ceph::buffer::error
&err
) {
3488 CLS_ERR("failed to decode message");
3493 int r
= cls_cxx_stat(hctx
, &size
, NULL
);
3498 BitVector
<2> object_map
;
3499 bufferlist header_bl
;
3500 r
= cls_cxx_read2(hctx
, 0, object_map
.get_header_length(), &header_bl
,
3501 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3503 CLS_ERR("object map header read failed");
3508 auto it
= header_bl
.cbegin();
3509 object_map
.decode_header(it
);
3510 } catch (const ceph::buffer::error
&err
) {
3511 CLS_ERR("failed to decode object map header: %s", err
.what());
3515 uint64_t object_byte_offset
;
3516 uint64_t byte_length
;
3517 object_map
.get_header_crc_extents(&object_byte_offset
, &byte_length
);
3519 bufferlist footer_bl
;
3520 r
= cls_cxx_read2(hctx
, object_byte_offset
, byte_length
, &footer_bl
,
3521 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3523 CLS_ERR("object map footer read header CRC failed");
3528 auto it
= footer_bl
.cbegin();
3529 object_map
.decode_header_crc(it
);
3530 } catch (const ceph::buffer::error
&err
) {
3531 CLS_ERR("failed to decode object map header CRC: %s", err
.what());
3534 if (start_object_no
>= end_object_no
|| end_object_no
> object_map
.size()) {
3538 uint64_t object_count
= end_object_no
- start_object_no
;
3539 object_map
.get_data_crcs_extents(start_object_no
, object_count
,
3540 &object_byte_offset
, &byte_length
);
3541 const auto footer_object_offset
= object_byte_offset
;
3544 r
= cls_cxx_read2(hctx
, object_byte_offset
, byte_length
, &footer_bl
,
3545 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3547 CLS_ERR("object map footer read data CRCs failed");
3552 auto it
= footer_bl
.cbegin();
3553 object_map
.decode_data_crcs(it
, start_object_no
);
3554 } catch (const ceph::buffer::error
&err
) {
3555 CLS_ERR("failed to decode object map data CRCs: %s", err
.what());
3558 uint64_t data_byte_offset
;
3559 object_map
.get_data_extents(start_object_no
, object_count
,
3560 &data_byte_offset
, &object_byte_offset
,
3564 r
= cls_cxx_read2(hctx
, object_byte_offset
, byte_length
, &data_bl
,
3565 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3567 CLS_ERR("object map data read failed");
3572 auto it
= data_bl
.cbegin();
3573 object_map
.decode_data(it
, data_byte_offset
);
3574 } catch (const ceph::buffer::error
&err
) {
3575 CLS_ERR("failed to decode data chunk [%" PRIu64
"]: %s",
3576 data_byte_offset
, err
.what());
3580 bool updated
= false;
3581 auto it
= object_map
.begin() + start_object_no
;
3582 auto end_it
= object_map
.begin() + end_object_no
;
3583 for (; it
!= end_it
; ++it
) {
3584 uint8_t state
= *it
;
3585 if ((!current_object_state
|| state
== *current_object_state
||
3586 (*current_object_state
== OBJECT_EXISTS
&&
3587 state
== OBJECT_EXISTS_CLEAN
)) && state
!= new_object_state
) {
3588 *it
= new_object_state
;
3594 CLS_LOG(20, "object_map_update: %" PRIu64
"~%" PRIu64
" -> %" PRIu64
,
3595 data_byte_offset
, byte_length
, object_byte_offset
);
3598 object_map
.encode_data(data_bl
, data_byte_offset
, byte_length
);
3599 r
= cls_cxx_write2(hctx
, object_byte_offset
, data_bl
.length(), &data_bl
,
3600 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3602 CLS_ERR("failed to write object map header: %s", cpp_strerror(r
).c_str());
3607 object_map
.encode_data_crcs(footer_bl
, start_object_no
, object_count
);
3608 r
= cls_cxx_write2(hctx
, footer_object_offset
, footer_bl
.length(),
3609 &footer_bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
3611 CLS_ERR("failed to write object map footer: %s", cpp_strerror(r
).c_str());
3615 CLS_LOG(20, "object_map_update: no update necessary");
3622 * Mark all _EXISTS objects as _EXISTS_CLEAN so future writes to the
3623 * image HEAD can be tracked.
3629 * @returns 0 on success, negative error code on failure
3631 int object_map_snap_add(cls_method_context_t hctx
, bufferlist
*in
,
3634 BitVector
<2> object_map
;
3635 int r
= object_map_read(hctx
, object_map
);
3640 bool updated
= false;
3641 auto it
= object_map
.begin();
3642 auto end_it
= object_map
.end();
3643 for (; it
!= end_it
; ++it
) {
3644 if (*it
== OBJECT_EXISTS
) {
3645 *it
= OBJECT_EXISTS_CLEAN
;
3652 encode(object_map
, bl
);
3653 r
= cls_cxx_write_full(hctx
, &bl
);
3659 * Mark all _EXISTS_CLEAN objects as _EXISTS in the current object map
3660 * if the provided snapshot object map object is marked as _EXISTS.
3663 * @param snapshot object map bit vector
3666 * @returns 0 on success, negative error code on failure
3668 int object_map_snap_remove(cls_method_context_t hctx
, bufferlist
*in
,
3671 BitVector
<2> src_object_map
;
3673 auto iter
= in
->cbegin();
3674 decode(src_object_map
, iter
);
3675 } catch (const ceph::buffer::error
&err
) {
3679 BitVector
<2> dst_object_map
;
3680 int r
= object_map_read(hctx
, dst_object_map
);
3685 bool updated
= false;
3686 auto src_it
= src_object_map
.begin();
3687 auto dst_it
= dst_object_map
.begin();
3688 auto dst_it_end
= dst_object_map
.end();
3690 for (; dst_it
!= dst_it_end
; ++dst_it
) {
3691 if (*dst_it
== OBJECT_EXISTS_CLEAN
&&
3692 (i
>= src_object_map
.size() || *src_it
== OBJECT_EXISTS
)) {
3693 *dst_it
= OBJECT_EXISTS
;
3696 if (i
< src_object_map
.size())
3703 encode(dst_object_map
, bl
);
3704 r
= cls_cxx_write_full(hctx
, &bl
);
3709 static const string
metadata_key_for_name(const string
&name
)
3711 return RBD_METADATA_KEY_PREFIX
+ name
;
3714 static const string
metadata_name_from_key(const string
&key
)
3716 return key
.substr(strlen(RBD_METADATA_KEY_PREFIX
));
3721 * @param start_after which name to begin listing after
3722 * (use the empty string to start at the beginning)
3723 * @param max_return the maximum number of names to list
3727 * @returns 0 on success, negative error code on failure
3729 int metadata_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3732 uint64_t max_return
;
3735 auto iter
= in
->cbegin();
3736 decode(start_after
, iter
);
3737 decode(max_return
, iter
);
3738 } catch (const ceph::buffer::error
&err
) {
3742 // TODO remove implicit support for zero during the N-release
3743 if (max_return
== 0) {
3744 max_return
= RBD_MAX_KEYS_READ
;
3747 map
<string
, bufferlist
> data
;
3748 string last_read
= metadata_key_for_name(start_after
);
3751 while (more
&& data
.size() < max_return
) {
3752 map
<string
, bufferlist
> raw_data
;
3753 int max_read
= std::min
<uint64_t>(RBD_MAX_KEYS_READ
, max_return
- data
.size());
3754 int r
= cls_cxx_map_get_vals(hctx
, last_read
, RBD_METADATA_KEY_PREFIX
,
3755 max_read
, &raw_data
, &more
);
3758 CLS_ERR("failed to read the vals off of disk: %s",
3759 cpp_strerror(r
).c_str());
3764 for (auto& kv
: raw_data
) {
3765 data
[metadata_name_from_key(kv
.first
)].swap(kv
.second
);
3768 if (!raw_data
.empty()) {
3769 last_read
= raw_data
.rbegin()->first
;
3779 * @param data <map(key, value)>
3782 * @returns 0 on success, negative error code on failure
3784 int metadata_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3786 map
<string
, bufferlist
> data
, raw_data
;
3788 auto iter
= in
->cbegin();
3791 } catch (const ceph::buffer::error
&err
) {
3795 for (auto it
= data
.begin(); it
!= data
.end(); ++it
) {
3796 CLS_LOG(20, "metadata_set key=%s value=%.*s", it
->first
.c_str(),
3797 it
->second
.length(), it
->second
.c_str());
3798 raw_data
[metadata_key_for_name(it
->first
)].swap(it
->second
);
3800 int r
= cls_cxx_map_set_vals(hctx
, &raw_data
);
3802 CLS_ERR("error writing metadata: %s", cpp_strerror(r
).c_str());
3814 * @returns 0 on success, negative error code on failure
3816 int metadata_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3820 auto iter
= in
->cbegin();
3823 } catch (const ceph::buffer::error
&err
) {
3827 CLS_LOG(20, "metadata_remove key=%s", key
.c_str());
3829 int r
= cls_cxx_map_remove_key(hctx
, metadata_key_for_name(key
));
3831 CLS_ERR("error removing metadata: %s", cpp_strerror(r
).c_str());
3843 * @param metadata value associated with the key
3844 * @returns 0 on success, negative error code on failure
3846 int metadata_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3851 auto iter
= in
->cbegin();
3854 } catch (const ceph::buffer::error
&err
) {
3858 CLS_LOG(20, "metadata_get key=%s", key
.c_str());
3860 int r
= cls_cxx_map_get_val(hctx
, metadata_key_for_name(key
), &value
);
3863 CLS_ERR("error getting metadata: %s", cpp_strerror(r
).c_str());
3867 encode(value
, *out
);
3871 int snapshot_get_limit(cls_method_context_t hctx
, bufferlist
*in
,
3874 uint64_t snap_limit
;
3875 int r
= read_key(hctx
, "snap_limit", &snap_limit
);
3877 snap_limit
= UINT64_MAX
;
3879 CLS_ERR("error retrieving snapshot limit: %s", cpp_strerror(r
).c_str());
3883 CLS_LOG(20, "read snapshot limit %" PRIu64
, snap_limit
);
3884 encode(snap_limit
, *out
);
3889 int snapshot_set_limit(cls_method_context_t hctx
, bufferlist
*in
,
3895 size_t snap_count
= 0;
3898 auto iter
= in
->cbegin();
3899 decode(new_limit
, iter
);
3900 } catch (const ceph::buffer::error
&err
) {
3904 if (new_limit
== UINT64_MAX
) {
3905 CLS_LOG(20, "remove snapshot limit\n");
3906 rc
= cls_cxx_map_remove_key(hctx
, "snap_limit");
3910 //try to read header as v1 format
3911 rc
= snap_read_header(hctx
, bl
);
3913 // error when reading header
3914 if (rc
< 0 && rc
!= -EINVAL
) {
3916 } else if (rc
>= 0) {
3917 // success, the image is v1 format
3918 struct rbd_obj_header_ondisk
*header
;
3919 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
3920 snap_count
= header
->snap_count
;
3922 // else, the image is v2 format
3923 int max_read
= RBD_MAX_KEYS_READ
;
3924 string last_read
= RBD_SNAP_KEY_PREFIX
;
3929 rc
= cls_cxx_map_get_keys(hctx
, last_read
, max_read
, &keys
, &more
);
3931 CLS_ERR("error retrieving snapshots: %s", cpp_strerror(rc
).c_str());
3934 for (auto& key
: keys
) {
3935 if (key
.find(RBD_SNAP_KEY_PREFIX
) != 0)
3940 last_read
= *(keys
.rbegin());
3944 if (new_limit
< snap_count
) {
3946 CLS_LOG(10, "snapshot limit is less than the number of snapshots.\n");
3948 CLS_LOG(20, "set snapshot limit to %" PRIu64
"\n", new_limit
);
3950 encode(new_limit
, bl
);
3951 rc
= cls_cxx_map_set_val(hctx
, "snap_limit", &bl
);
3960 * @param snap id (uint64_t) parent snapshot id
3961 * @param child spec (cls::rbd::ChildImageSpec) child image
3964 * @returns 0 on success, negative error code on failure
3966 int child_attach(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
3969 cls::rbd::ChildImageSpec child_image
;
3971 auto it
= in
->cbegin();
3972 decode(snap_id
, it
);
3973 decode(child_image
, it
);
3974 } catch (const ceph::buffer::error
&err
) {
3978 CLS_LOG(20, "child_attach snap_id=%" PRIu64
", child_pool_id=%" PRIi64
", "
3979 "child_image_id=%s", snap_id
, child_image
.pool_id
,
3980 child_image
.image_id
.c_str());
3983 std::string snapshot_key
;
3984 key_from_snap_id(snap_id
, &snapshot_key
);
3985 int r
= read_key(hctx
, snapshot_key
, &snap
);
3990 if (cls::rbd::get_snap_namespace_type(snap
.snapshot_namespace
) ==
3991 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
) {
3992 // cannot attach to a deleted snapshot
3996 auto children_key
= image::snap_children_key_from_snap_id(snap_id
);
3997 cls::rbd::ChildImageSpecs child_images
;
3998 r
= read_key(hctx
, children_key
, &child_images
);
3999 if (r
< 0 && r
!= -ENOENT
) {
4000 CLS_ERR("error reading snapshot children: %s", cpp_strerror(r
).c_str());
4004 auto it
= child_images
.insert(child_image
);
4006 // child already attached to the snapshot
4010 r
= write_key(hctx
, children_key
, child_images
);
4012 CLS_ERR("error writing snapshot children: %s", cpp_strerror(r
).c_str());
4017 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap
));
4022 r
= image::set_op_features(hctx
, RBD_OPERATION_FEATURE_CLONE_PARENT
,
4023 RBD_OPERATION_FEATURE_CLONE_PARENT
);
4033 * @param snap id (uint64_t) parent snapshot id
4034 * @param child spec (cls::rbd::ChildImageSpec) child image
4037 * @returns 0 on success, negative error code on failure
4039 int child_detach(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4042 cls::rbd::ChildImageSpec child_image
;
4044 auto it
= in
->cbegin();
4045 decode(snap_id
, it
);
4046 decode(child_image
, it
);
4047 } catch (const ceph::buffer::error
&err
) {
4051 CLS_LOG(20, "child_detach snap_id=%" PRIu64
", child_pool_id=%" PRIi64
", "
4052 "child_image_id=%s", snap_id
, child_image
.pool_id
,
4053 child_image
.image_id
.c_str());
4056 std::string snapshot_key
;
4057 key_from_snap_id(snap_id
, &snapshot_key
);
4058 int r
= read_key(hctx
, snapshot_key
, &snap
);
4063 auto children_key
= image::snap_children_key_from_snap_id(snap_id
);
4064 cls::rbd::ChildImageSpecs child_images
;
4065 r
= read_key(hctx
, children_key
, &child_images
);
4066 if (r
< 0 && r
!= -ENOENT
) {
4067 CLS_ERR("error reading snapshot children: %s", cpp_strerror(r
).c_str());
4071 if (snap
.child_count
!= child_images
.size()) {
4072 // children and reference count don't match
4073 CLS_ERR("children reference count mismatch: %" PRIu64
, snap_id
);
4077 if (child_images
.erase(child_image
) == 0) {
4078 // child not attached to the snapshot
4082 if (child_images
.empty()) {
4083 r
= remove_key(hctx
, children_key
);
4085 r
= write_key(hctx
, children_key
, child_images
);
4087 CLS_ERR("error writing snapshot children: %s", cpp_strerror(r
).c_str());
4093 r
= image::snapshot::write(hctx
, snapshot_key
, std::move(snap
));
4098 if (snap
.child_count
== 0) {
4099 auto clone_in_use_lambda
= [snap_id
](const cls_rbd_snap
& snap_meta
) {
4100 if (snap_meta
.id
!= snap_id
&& snap_meta
.child_count
> 0) {
4106 r
= image::snapshot::iterate(hctx
, clone_in_use_lambda
);
4107 if (r
< 0 && r
!= -EEXIST
) {
4112 // remove the clone_v2 op feature if not in-use by any other snapshots
4113 r
= image::set_op_features(hctx
, 0, RBD_OPERATION_FEATURE_CLONE_PARENT
);
4125 * @param snap id (uint64_t) parent snapshot id
4128 * @param (cls::rbd::ChildImageSpecs) child images
4129 * @returns 0 on success, negative error code on failure
4131 int children_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4135 auto it
= in
->cbegin();
4136 decode(snap_id
, it
);
4137 } catch (const ceph::buffer::error
&err
) {
4141 CLS_LOG(20, "children_list snap_id=%" PRIu64
, snap_id
);
4144 std::string snapshot_key
;
4145 key_from_snap_id(snap_id
, &snapshot_key
);
4146 int r
= read_key(hctx
, snapshot_key
, &snap
);
4151 auto children_key
= image::snap_children_key_from_snap_id(snap_id
);
4152 cls::rbd::ChildImageSpecs child_images
;
4153 r
= read_key(hctx
, children_key
, &child_images
);
4157 CLS_ERR("error reading snapshot children: %s", cpp_strerror(r
).c_str());
4161 encode(child_images
, *out
);
4166 * Set image migration.
4169 * @param migration_spec (cls::rbd::MigrationSpec) image migration spec
4173 * @returns 0 on success, negative error code on failure
4175 int migration_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
4176 cls::rbd::MigrationSpec migration_spec
;
4178 auto it
= in
->cbegin();
4179 decode(migration_spec
, it
);
4180 } catch (const ceph::buffer::error
&err
) {
4184 int r
= image::set_migration(hctx
, migration_spec
, true);
4193 * Set image migration state.
4196 * @param state (cls::rbd::MigrationState) migration state
4197 * @param description (std::string) migration state description
4201 * @returns 0 on success, negative error code on failure
4203 int migration_set_state(cls_method_context_t hctx
, bufferlist
*in
,
4205 cls::rbd::MigrationState state
;
4206 std::string description
;
4208 auto it
= in
->cbegin();
4210 decode(description
, it
);
4211 } catch (const ceph::buffer::error
&err
) {
4215 cls::rbd::MigrationSpec migration_spec
;
4216 int r
= image::read_migration(hctx
, &migration_spec
);
4221 migration_spec
.state
= state
;
4222 migration_spec
.state_description
= description
;
4224 r
= image::set_migration(hctx
, migration_spec
, false);
4233 * Get image migration spec.
4238 * @param migration_spec (cls::rbd::MigrationSpec) image migration spec
4240 * @returns 0 on success, negative error code on failure
4242 int migration_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
) {
4243 cls::rbd::MigrationSpec migration_spec
;
4244 int r
= image::read_migration(hctx
, &migration_spec
);
4249 encode(migration_spec
, *out
);
4255 * Remove image migration spec.
4261 * @returns 0 on success, negative error code on failure
4263 int migration_remove(cls_method_context_t hctx
, bufferlist
*in
,
4265 int r
= image::remove_migration(hctx
);
4274 * Ensure writer snapc state
4277 * @param snap id (uint64_t) snap context sequence id
4278 * @param state (cls::rbd::AssertSnapcSeqState) snap context state
4281 * @returns -ERANGE if assertion fails
4282 * @returns 0 on success, negative error code on failure
4284 int assert_snapc_seq(cls_method_context_t hctx
, bufferlist
*in
,
4288 cls::rbd::AssertSnapcSeqState state
;
4290 auto it
= in
->cbegin();
4291 decode(snapc_seq
, it
);
4293 } catch (const ceph::buffer::error
&err
) {
4297 uint64_t snapset_seq
;
4298 int r
= cls_get_snapset_seq(hctx
, &snapset_seq
);
4299 if (r
< 0 && r
!= -ENOENT
) {
4304 case cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ
:
4305 return (r
== -ENOENT
|| snapc_seq
> snapset_seq
) ? 0 : -ERANGE
;
4306 case cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ
:
4307 return (r
== -ENOENT
|| snapc_seq
> snapset_seq
) ? -ERANGE
: 0;
4313 /****************************** Old format *******************************/
4315 int old_snapshots_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4318 struct rbd_obj_header_ondisk
*header
;
4319 int rc
= snap_read_header(hctx
, bl
);
4323 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
4324 bufferptr
p(header
->snap_names_len
);
4325 char *buf
= (char *)header
;
4326 char *name
= buf
+ sizeof(*header
) + header
->snap_count
* sizeof(struct rbd_obj_snap_ondisk
);
4327 char *end
= name
+ header
->snap_names_len
;
4329 buf
+ sizeof(*header
) + header
->snap_count
* sizeof(struct rbd_obj_snap_ondisk
),
4330 header
->snap_names_len
);
4332 encode(header
->snap_seq
, *out
);
4333 encode(header
->snap_count
, *out
);
4335 for (unsigned i
= 0; i
< header
->snap_count
; i
++) {
4337 encode(header
->snaps
[i
].id
, *out
);
4338 encode(header
->snaps
[i
].image_size
, *out
);
4341 name
+= strlen(name
) + 1;
4349 int old_snapshot_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4352 struct rbd_obj_header_ondisk
*header
;
4354 bufferptr
header_bp(sizeof(*header
));
4355 struct rbd_obj_snap_ondisk
*new_snaps
;
4357 int rc
= snap_read_header(hctx
, bl
);
4361 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
4363 int snaps_id_ofs
= sizeof(*header
);
4364 int names_ofs
= snaps_id_ofs
+ sizeof(*new_snaps
) * header
->snap_count
;
4365 const char *snap_name
;
4366 const char *snap_names
= ((char *)header
) + names_ofs
;
4367 const char *end
= snap_names
+ header
->snap_names_len
;
4368 auto iter
= in
->cbegin();
4374 decode(snap_id
, iter
);
4375 } catch (const ceph::buffer::error
&err
) {
4378 snap_name
= s
.c_str();
4380 if (header
->snap_seq
> snap_id
)
4383 uint64_t snap_limit
;
4384 rc
= read_key(hctx
, "snap_limit", &snap_limit
);
4385 if (rc
== -ENOENT
) {
4386 snap_limit
= UINT64_MAX
;
4387 } else if (rc
< 0) {
4391 if (header
->snap_count
>= snap_limit
)
4394 const char *cur_snap_name
;
4395 for (cur_snap_name
= snap_names
; cur_snap_name
< end
; cur_snap_name
+= strlen(cur_snap_name
) + 1) {
4396 if (strncmp(cur_snap_name
, snap_name
, end
- cur_snap_name
) == 0)
4399 if (cur_snap_name
> end
)
4402 int snap_name_len
= strlen(snap_name
);
4404 bufferptr
new_names_bp(header
->snap_names_len
+ snap_name_len
+ 1);
4405 bufferptr
new_snaps_bp(sizeof(*new_snaps
) * (header
->snap_count
+ 1));
4407 /* copy snap names and append to new snap name */
4408 char *new_snap_names
= new_names_bp
.c_str();
4409 strcpy(new_snap_names
, snap_name
);
4410 memcpy(new_snap_names
+ snap_name_len
+ 1, snap_names
, header
->snap_names_len
);
4412 /* append new snap id */
4413 new_snaps
= (struct rbd_obj_snap_ondisk
*)new_snaps_bp
.c_str();
4414 memcpy(new_snaps
+ 1, header
->snaps
, sizeof(*new_snaps
) * header
->snap_count
);
4416 header
->snap_count
= header
->snap_count
+ 1;
4417 header
->snap_names_len
= header
->snap_names_len
+ snap_name_len
+ 1;
4418 header
->snap_seq
= snap_id
;
4420 new_snaps
[0].id
= snap_id
;
4421 new_snaps
[0].image_size
= header
->image_size
;
4423 memcpy(header_bp
.c_str(), header
, sizeof(*header
));
4425 newbl
.push_back(header_bp
);
4426 newbl
.push_back(new_snaps_bp
);
4427 newbl
.push_back(new_names_bp
);
4429 rc
= cls_cxx_write_full(hctx
, &newbl
);
4436 int old_snapshot_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4439 struct rbd_obj_header_ondisk
*header
;
4441 bufferptr
header_bp(sizeof(*header
));
4443 int rc
= snap_read_header(hctx
, bl
);
4447 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
4449 int snaps_id_ofs
= sizeof(*header
);
4450 int names_ofs
= snaps_id_ofs
+ sizeof(struct rbd_obj_snap_ondisk
) * header
->snap_count
;
4451 const char *snap_name
;
4452 const char *snap_names
= ((char *)header
) + names_ofs
;
4453 const char *orig_names
= snap_names
;
4454 const char *end
= snap_names
+ header
->snap_names_len
;
4455 auto iter
= in
->cbegin();
4459 struct rbd_obj_snap_ondisk snap
;
4463 } catch (const ceph::buffer::error
&err
) {
4466 snap_name
= s
.c_str();
4468 for (i
= 0; snap_names
< end
; i
++) {
4469 if (strcmp(snap_names
, snap_name
) == 0) {
4470 snap
= header
->snaps
[i
];
4474 snap_names
+= strlen(snap_names
) + 1;
4477 CLS_ERR("couldn't find snap %s\n", snap_name
);
4481 header
->snap_names_len
= header
->snap_names_len
- (s
.length() + 1);
4482 header
->snap_count
= header
->snap_count
- 1;
4484 bufferptr
new_names_bp(header
->snap_names_len
);
4485 bufferptr
new_snaps_bp(sizeof(header
->snaps
[0]) * header
->snap_count
);
4487 memcpy(header_bp
.c_str(), header
, sizeof(*header
));
4488 newbl
.push_back(header_bp
);
4490 if (header
->snap_count
) {
4493 CLS_LOG(20, "i=%u\n", i
);
4495 snaps_len
= sizeof(header
->snaps
[0]) * i
;
4496 names_len
= snap_names
- orig_names
;
4497 memcpy(new_snaps_bp
.c_str(), header
->snaps
, snaps_len
);
4498 memcpy(new_names_bp
.c_str(), orig_names
, names_len
);
4500 snap_names
+= s
.length() + 1;
4502 if (i
< header
->snap_count
) {
4503 memcpy(new_snaps_bp
.c_str() + snaps_len
,
4504 header
->snaps
+ i
+ 1,
4505 sizeof(header
->snaps
[0]) * (header
->snap_count
- i
));
4506 memcpy(new_names_bp
.c_str() + names_len
, snap_names
, end
- snap_names
);
4508 newbl
.push_back(new_snaps_bp
);
4509 newbl
.push_back(new_names_bp
);
4512 rc
= cls_cxx_write_full(hctx
, &newbl
);
4520 * rename snapshot of old format.
4523 * @param src_snap_id old snap id of the snapshot (snapid_t)
4524 * @param dst_snap_name new name of the snapshot (string)
4527 * @returns 0 on success, negative error code on failure.
4529 int old_snapshot_rename(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
4532 struct rbd_obj_header_ondisk
*header
;
4534 bufferptr
header_bp(sizeof(*header
));
4535 snapid_t src_snap_id
;
4536 const char *dst_snap_name
;
4539 int rc
= snap_read_header(hctx
, bl
);
4543 header
= (struct rbd_obj_header_ondisk
*)bl
.c_str();
4545 int snaps_id_ofs
= sizeof(*header
);
4546 int names_ofs
= snaps_id_ofs
+ sizeof(rbd_obj_snap_ondisk
) * header
->snap_count
;
4547 const char *snap_names
= ((char *)header
) + names_ofs
;
4548 const char *orig_names
= snap_names
;
4549 const char *end
= snap_names
+ header
->snap_names_len
;
4550 auto iter
= in
->cbegin();
4555 decode(src_snap_id
, iter
);
4557 } catch (const ceph::buffer::error
&err
) {
4560 dst_snap_name
= dst
.c_str();
4562 const char *cur_snap_name
;
4563 for (cur_snap_name
= snap_names
; cur_snap_name
< end
;
4564 cur_snap_name
+= strlen(cur_snap_name
) + 1) {
4565 if (strcmp(cur_snap_name
, dst_snap_name
) == 0)
4568 if (cur_snap_name
> end
)
4570 for (i
= 0; i
< header
->snap_count
; i
++) {
4571 if (src_snap_id
== header
->snaps
[i
].id
) {
4575 snap_names
+= strlen(snap_names
) + 1;
4578 CLS_ERR("couldn't find snap %llu\n", (unsigned long long)src_snap_id
.val
);
4582 CLS_LOG(20, "rename snap with snap id %llu to dest name %s", (unsigned long long)src_snap_id
.val
, dst_snap_name
);
4583 header
->snap_names_len
= header
->snap_names_len
- strlen(snap_names
) + dst
.length();
4585 bufferptr
new_names_bp(header
->snap_names_len
);
4586 bufferptr
new_snaps_bp(sizeof(header
->snaps
[0]) * header
->snap_count
);
4588 if (header
->snap_count
) {
4590 CLS_LOG(20, "i=%u\n", i
);
4592 names_len
= snap_names
- orig_names
;
4593 memcpy(new_names_bp
.c_str(), orig_names
, names_len
);
4595 strcpy(new_names_bp
.c_str() + names_len
, dst_snap_name
);
4596 names_len
+= strlen(dst_snap_name
) + 1;
4597 snap_names
+= strlen(snap_names
) + 1;
4598 if (i
< header
->snap_count
) {
4599 memcpy(new_names_bp
.c_str() + names_len
, snap_names
, end
- snap_names
);
4601 memcpy(new_snaps_bp
.c_str(), header
->snaps
, sizeof(header
->snaps
[0]) * header
->snap_count
);
4604 memcpy(header_bp
.c_str(), header
, sizeof(*header
));
4605 newbl
.push_back(header_bp
);
4606 newbl
.push_back(new_snaps_bp
);
4607 newbl
.push_back(new_names_bp
);
4609 rc
= cls_cxx_write_full(hctx
, &newbl
);
4618 static const std::string
UUID("mirror_uuid");
4619 static const std::string
MODE("mirror_mode");
4620 static const std::string
PEER_KEY_PREFIX("mirror_peer_");
4621 static const std::string
IMAGE_KEY_PREFIX("image_");
4622 static const std::string
GLOBAL_KEY_PREFIX("global_");
4623 static const std::string
STATUS_GLOBAL_KEY_PREFIX("status_global_");
4624 static const std::string
REMOTE_STATUS_GLOBAL_KEY_PREFIX("remote_status_global_");
4625 static const std::string
INSTANCE_KEY_PREFIX("instance_");
4626 static const std::string
MIRROR_IMAGE_MAP_KEY_PREFIX("image_map_");
4628 std::string
peer_key(const std::string
&uuid
) {
4629 return PEER_KEY_PREFIX
+ uuid
;
4632 std::string
image_key(const string
&image_id
) {
4633 return IMAGE_KEY_PREFIX
+ image_id
;
4636 std::string
global_key(const string
&global_id
) {
4637 return GLOBAL_KEY_PREFIX
+ global_id
;
4640 std::string
remote_status_global_key(const std::string
& global_id
,
4641 const std::string
& mirror_uuid
) {
4642 return REMOTE_STATUS_GLOBAL_KEY_PREFIX
+ global_id
+ "_" + mirror_uuid
;
4645 std::string
status_global_key(const std::string
& global_id
,
4646 const std::string
& mirror_uuid
) {
4647 if (mirror_uuid
== cls::rbd::MirrorImageSiteStatus::LOCAL_MIRROR_UUID
) {
4648 return STATUS_GLOBAL_KEY_PREFIX
+ global_id
;
4650 return remote_status_global_key(global_id
, mirror_uuid
);
4654 std::string
instance_key(const string
&instance_id
) {
4655 return INSTANCE_KEY_PREFIX
+ instance_id
;
4658 std::string
mirror_image_map_key(const string
& global_image_id
) {
4659 return MIRROR_IMAGE_MAP_KEY_PREFIX
+ global_image_id
;
4662 int uuid_get(cls_method_context_t hctx
, std::string
*mirror_uuid
) {
4663 bufferlist mirror_uuid_bl
;
4664 int r
= cls_cxx_map_get_val(hctx
, mirror::UUID
, &mirror_uuid_bl
);
4667 CLS_ERR("error reading mirror uuid: %s", cpp_strerror(r
).c_str());
4672 *mirror_uuid
= std::string(mirror_uuid_bl
.c_str(), mirror_uuid_bl
.length());
4676 int list_watchers(cls_method_context_t hctx
,
4677 std::set
<entity_inst_t
> *entities
) {
4678 obj_list_watch_response_t watchers
;
4679 int r
= cls_cxx_list_watchers(hctx
, &watchers
);
4680 if (r
< 0 && r
!= -ENOENT
) {
4681 CLS_ERR("error listing watchers: '%s'", cpp_strerror(r
).c_str());
4686 for (auto &w
: watchers
.entries
) {
4687 entity_inst_t entity_inst
{w
.name
, w
.addr
};
4688 cls::rbd::sanitize_entity_inst(&entity_inst
);
4690 entities
->insert(entity_inst
);
4695 int read_peers(cls_method_context_t hctx
,
4696 std::vector
<cls::rbd::MirrorPeer
> *peers
) {
4697 std::string last_read
= PEER_KEY_PREFIX
;
4698 int max_read
= RBD_MAX_KEYS_READ
;
4701 std::map
<std::string
, bufferlist
> vals
;
4702 int r
= cls_cxx_map_get_vals(hctx
, last_read
, PEER_KEY_PREFIX
.c_str(),
4703 max_read
, &vals
, &more
);
4706 CLS_ERR("error reading peers: %s", cpp_strerror(r
).c_str());
4711 for (auto &it
: vals
) {
4713 auto bl_it
= it
.second
.cbegin();
4714 cls::rbd::MirrorPeer peer
;
4715 decode(peer
, bl_it
);
4716 peers
->push_back(peer
);
4717 } catch (const ceph::buffer::error
&err
) {
4718 CLS_ERR("could not decode peer '%s'", it
.first
.c_str());
4723 if (!vals
.empty()) {
4724 last_read
= vals
.rbegin()->first
;
4730 int read_peer(cls_method_context_t hctx
, const std::string
&id
,
4731 cls::rbd::MirrorPeer
*peer
) {
4733 int r
= cls_cxx_map_get_val(hctx
, peer_key(id
), &bl
);
4735 CLS_ERR("error reading peer '%s': %s", id
.c_str(),
4736 cpp_strerror(r
).c_str());
4741 auto bl_it
= bl
.cbegin();
4742 decode(*peer
, bl_it
);
4743 } catch (const ceph::buffer::error
&err
) {
4744 CLS_ERR("could not decode peer '%s'", id
.c_str());
4750 int write_peer(cls_method_context_t hctx
, const cls::rbd::MirrorPeer
&peer
) {
4754 int r
= cls_cxx_map_set_val(hctx
, peer_key(peer
.uuid
), &bl
);
4756 CLS_ERR("error writing peer '%s': %s", peer
.uuid
.c_str(),
4757 cpp_strerror(r
).c_str());
4763 int check_mirroring_enabled(cls_method_context_t hctx
) {
4764 uint32_t mirror_mode_decode
;
4765 int r
= read_key(hctx
, mirror::MODE
, &mirror_mode_decode
);
4766 if (r
< 0 && r
!= -ENOENT
) {
4768 } else if (r
== -ENOENT
||
4769 mirror_mode_decode
== cls::rbd::MIRROR_MODE_DISABLED
) {
4770 CLS_ERR("mirroring must be enabled on the pool");
4777 int peer_ping(cls_method_context_t hctx
, const std::string
& site_name
,
4778 const std::string
& mirror_uuid
) {
4779 int r
= check_mirroring_enabled(hctx
);
4784 if (site_name
.empty() || mirror_uuid
.empty()) {
4788 std::vector
<cls::rbd::MirrorPeer
> peers
;
4789 r
= read_peers(hctx
, &peers
);
4790 if (r
< 0 && r
!= -ENOENT
) {
4795 cls::rbd::MirrorPeer mirror_peer
;
4796 auto site_it
= std::find_if(peers
.begin(), peers
.end(),
4797 [&site_name
](auto& peer
) {
4798 return (peer
.site_name
== site_name
);
4801 auto mirror_uuid_it
= peers
.end();
4802 if (site_it
== peers
.end() ||
4803 (!site_it
->mirror_uuid
.empty() && site_it
->mirror_uuid
!= mirror_uuid
)) {
4804 // search for existing peer w/ same mirror_uuid
4805 mirror_uuid_it
= std::find_if(peers
.begin(), peers
.end(),
4806 [&mirror_uuid
](auto& peer
) {
4807 return (peer
.mirror_uuid
== mirror_uuid
);
4811 auto it
= peers
.end();
4812 if (site_it
!= peers
.end() && mirror_uuid_it
!= peers
.end()) {
4813 // implies two peers -- match by mirror_uuid but don't update site name
4814 it
= mirror_uuid_it
;
4815 } else if (mirror_uuid_it
!= peers
.end()) {
4816 // implies site name has been updated in remote
4817 mirror_uuid_it
->site_name
= site_name
;
4818 it
= mirror_uuid_it
;
4819 } else if (site_it
!= peers
.end()) {
4820 // implies empty mirror_uuid in peer
4821 site_it
->mirror_uuid
= mirror_uuid
;
4824 CLS_LOG(10, "auto-generating new TX-only peer: %s", site_name
.c_str());
4828 uuid_gen
.generate_random();
4829 mirror_peer
.uuid
= uuid_gen
.to_string();
4832 r
= cls_cxx_map_get_val(hctx
, peer_key(mirror_peer
.uuid
), &bl
);
4836 CLS_ERR("failed to retrieve mirror peer: %s", cpp_strerror(r
).c_str());
4841 mirror_peer
.mirror_peer_direction
= cls::rbd::MIRROR_PEER_DIRECTION_TX
;
4842 mirror_peer
.site_name
= site_name
;
4843 mirror_peer
.mirror_uuid
= mirror_uuid
;
4846 if (it
!= peers
.end()) {
4849 if (mirror_peer
.mirror_peer_direction
==
4850 cls::rbd::MIRROR_PEER_DIRECTION_RX
) {
4851 CLS_LOG(10, "switching to RX/TX peer: %s", site_name
.c_str());
4852 mirror_peer
.mirror_peer_direction
= cls::rbd::MIRROR_PEER_DIRECTION_RX_TX
;
4856 mirror_peer
.last_seen
= ceph_clock_now();
4858 if (!mirror_peer
.is_valid()) {
4859 CLS_ERR("attempting to update invalid peer: %s", site_name
.c_str());
4863 r
= write_peer(hctx
, mirror_peer
);
4871 int peer_add(cls_method_context_t hctx
, cls::rbd::MirrorPeer mirror_peer
) {
4872 int r
= check_mirroring_enabled(hctx
);
4877 if (!mirror_peer
.is_valid()) {
4878 CLS_ERR("mirror peer is not valid");
4882 std::string mirror_uuid
;
4883 r
= uuid_get(hctx
, &mirror_uuid
);
4885 CLS_ERR("error retrieving mirroring uuid: %s", cpp_strerror(r
).c_str());
4887 } else if (mirror_peer
.uuid
== mirror_uuid
) {
4888 CLS_ERR("peer uuid '%s' matches pool mirroring uuid",
4889 mirror_uuid
.c_str());
4891 } else if (mirror_peer
.mirror_peer_direction
==
4892 cls::rbd::MIRROR_PEER_DIRECTION_TX
) {
4893 CLS_ERR("peer uuid '%s' cannot use TX-only direction",
4894 mirror_peer
.uuid
.c_str());
4898 std::vector
<cls::rbd::MirrorPeer
> peers
;
4899 r
= read_peers(hctx
, &peers
);
4900 if (r
< 0 && r
!= -ENOENT
) {
4904 for (auto const &peer
: peers
) {
4905 if (peer
.uuid
== mirror_peer
.uuid
) {
4906 CLS_ERR("peer uuid '%s' already exists",
4909 } else if (peer
.site_name
== mirror_peer
.site_name
) {
4910 CLS_ERR("peer site name '%s' already exists",
4911 peer
.site_name
.c_str());
4913 } else if (!mirror_peer
.mirror_uuid
.empty() &&
4914 peer
.mirror_uuid
== mirror_peer
.mirror_uuid
) {
4915 CLS_ERR("peer mirror uuid '%s' already exists",
4916 peer
.mirror_uuid
.c_str());
4921 r
= write_peer(hctx
, mirror_peer
);
4928 int peer_remove(cls_method_context_t hctx
, const std::string
& uuid
) {
4929 int r
= cls_cxx_map_remove_key(hctx
, peer_key(uuid
));
4930 if (r
< 0 && r
!= -ENOENT
) {
4931 CLS_ERR("error removing peer: %s", cpp_strerror(r
).c_str());
4937 int image_get(cls_method_context_t hctx
, const string
&image_id
,
4938 cls::rbd::MirrorImage
*mirror_image
) {
4940 int r
= cls_cxx_map_get_val(hctx
, image_key(image_id
), &bl
);
4943 CLS_ERR("error reading mirrored image '%s': '%s'", image_id
.c_str(),
4944 cpp_strerror(r
).c_str());
4950 auto it
= bl
.cbegin();
4951 decode(*mirror_image
, it
);
4952 } catch (const ceph::buffer::error
&err
) {
4953 CLS_ERR("could not decode mirrored image '%s'", image_id
.c_str());
4960 int image_set(cls_method_context_t hctx
, const string
&image_id
,
4961 const cls::rbd::MirrorImage
&mirror_image
) {
4963 encode(mirror_image
, bl
);
4965 cls::rbd::MirrorImage existing_mirror_image
;
4966 int r
= image_get(hctx
, image_id
, &existing_mirror_image
);
4968 // make sure global id doesn't already exist
4969 std::string global_id_key
= global_key(mirror_image
.global_image_id
);
4970 std::string image_id
;
4971 r
= read_key(hctx
, global_id_key
, &image_id
);
4974 } else if (r
!= -ENOENT
) {
4975 CLS_ERR("error reading global image id: '%s': '%s'", image_id
.c_str(),
4976 cpp_strerror(r
).c_str());
4980 // make sure this was not a race for disabling
4981 if (mirror_image
.state
== cls::rbd::MIRROR_IMAGE_STATE_DISABLING
) {
4982 CLS_ERR("image '%s' is already disabled", image_id
.c_str());
4986 CLS_ERR("error reading mirrored image '%s': '%s'", image_id
.c_str(),
4987 cpp_strerror(r
).c_str());
4989 } else if (existing_mirror_image
.global_image_id
!=
4990 mirror_image
.global_image_id
) {
4991 // cannot change the global id
4995 r
= cls_cxx_map_set_val(hctx
, image_key(image_id
), &bl
);
4997 CLS_ERR("error adding mirrored image '%s': %s", image_id
.c_str(),
4998 cpp_strerror(r
).c_str());
5002 bufferlist image_id_bl
;
5003 encode(image_id
, image_id_bl
);
5004 r
= cls_cxx_map_set_val(hctx
, global_key(mirror_image
.global_image_id
),
5007 CLS_ERR("error adding global id for image '%s': %s", image_id
.c_str(),
5008 cpp_strerror(r
).c_str());
5014 int image_status_remove(cls_method_context_t hctx
,
5015 const string
&global_image_id
);
5017 int image_remove(cls_method_context_t hctx
, const string
&image_id
) {
5019 cls::rbd::MirrorImage mirror_image
;
5020 int r
= image_get(hctx
, image_id
, &mirror_image
);
5023 CLS_ERR("error reading mirrored image '%s': '%s'", image_id
.c_str(),
5024 cpp_strerror(r
).c_str());
5029 if (mirror_image
.state
!= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
) {
5033 r
= cls_cxx_map_remove_key(hctx
, image_key(image_id
));
5035 CLS_ERR("error removing mirrored image '%s': %s", image_id
.c_str(),
5036 cpp_strerror(r
).c_str());
5040 r
= cls_cxx_map_remove_key(hctx
, global_key(mirror_image
.global_image_id
));
5041 if (r
< 0 && r
!= -ENOENT
) {
5042 CLS_ERR("error removing global id for image '%s': %s", image_id
.c_str(),
5043 cpp_strerror(r
).c_str());
5047 r
= image_status_remove(hctx
, mirror_image
.global_image_id
);
5055 int image_status_set(cls_method_context_t hctx
, const string
&global_image_id
,
5056 const cls::rbd::MirrorImageSiteStatus
&status
) {
5057 cls::rbd::MirrorImageSiteStatusOnDisk
ondisk_status(status
);
5058 ondisk_status
.mirror_uuid
= ""; // mirror_uuid stored in key
5059 ondisk_status
.up
= false;
5060 ondisk_status
.last_update
= ceph_clock_now();
5062 std::string global_id_key
= global_key(global_image_id
);
5063 std::string image_id
;
5064 int r
= read_key(hctx
, global_id_key
, &image_id
);
5068 cls::rbd::MirrorImage mirror_image
;
5069 r
= image_get(hctx
, image_id
, &mirror_image
);
5073 if (mirror_image
.state
!= cls::rbd::MIRROR_IMAGE_STATE_ENABLED
) {
5077 r
= cls_get_request_origin(hctx
, &ondisk_status
.origin
);
5078 ceph_assert(r
== 0);
5081 encode(ondisk_status
, bl
, cls_get_features(hctx
));
5083 r
= cls_cxx_map_set_val(hctx
, status_global_key(global_image_id
,
5084 status
.mirror_uuid
), &bl
);
5086 CLS_ERR("error setting status for mirrored image, global id '%s', "
5087 "site '%s': %s", global_image_id
.c_str(),
5088 status
.mirror_uuid
.c_str(),
5089 cpp_strerror(r
).c_str());
5095 int get_remote_image_status_mirror_uuids(cls_method_context_t hctx
,
5096 const std::string
& global_image_id
,
5097 std::set
<std::string
>* mirror_uuids
) {
5098 std::string filter
= remote_status_global_key(global_image_id
, "");
5099 std::string last_read
= filter
;
5100 int max_read
= 4; // we don't expect lots of peers
5104 std::set
<std::string
> keys
;
5105 int r
= cls_cxx_map_get_keys(hctx
, last_read
, max_read
, &keys
, &more
);
5110 for (auto& key
: keys
) {
5111 if (!boost::starts_with(key
, filter
)) {
5116 mirror_uuids
->insert(key
.substr(filter
.length()));
5119 if (!keys
.empty()) {
5120 last_read
= *keys
.rbegin();
5127 int image_status_remove(cls_method_context_t hctx
,
5128 const string
&global_image_id
) {
5129 // remove all local/remote image statuses
5130 std::set
<std::string
> mirror_uuids
;
5131 int r
= get_remote_image_status_mirror_uuids(hctx
, global_image_id
,
5133 if (r
< 0 && r
!= -ENOENT
) {
5137 mirror_uuids
.insert(cls::rbd::MirrorImageSiteStatus::LOCAL_MIRROR_UUID
);
5138 for (auto& mirror_uuid
: mirror_uuids
) {
5139 CLS_LOG(20, "removing status object for mirror_uuid %s",
5140 mirror_uuid
.c_str());
5141 auto key
= status_global_key(global_image_id
, mirror_uuid
);
5142 r
= cls_cxx_map_remove_key(hctx
, key
);
5143 if (r
< 0 && r
!= -ENOENT
) {
5144 CLS_ERR("error removing stale status for key '%s': %s",
5145 key
.c_str(), cpp_strerror(r
).c_str());
5153 int image_status_get(cls_method_context_t hctx
, const string
&global_image_id
,
5154 const std::string
& mirror_uuid
, const bufferlist
& bl
,
5155 const std::set
<entity_inst_t
> &watchers
,
5156 cls::rbd::MirrorImageStatus
* status
) {
5157 cls::rbd::MirrorImageSiteStatusOnDisk ondisk_status
;
5159 auto it
= bl
.cbegin();
5160 decode(ondisk_status
, it
);
5161 } catch (const ceph::buffer::error
&err
) {
5162 CLS_ERR("could not decode status for mirrored image, global id '%s', "
5164 global_image_id
.c_str(), mirror_uuid
.c_str());
5168 auto site_status
= static_cast<cls::rbd::MirrorImageSiteStatus
>(
5170 site_status
.up
= (watchers
.find(ondisk_status
.origin
) != watchers
.end());
5171 site_status
.mirror_uuid
= mirror_uuid
;
5172 status
->mirror_image_site_statuses
.push_back(site_status
);
5176 int image_status_get_local(cls_method_context_t hctx
,
5177 const string
&global_image_id
,
5178 const std::set
<entity_inst_t
> &watchers
,
5179 cls::rbd::MirrorImageStatus
*status
) {
5181 int r
= cls_cxx_map_get_val(
5182 hctx
, status_global_key(global_image_id
,
5183 cls::rbd::MirrorImageSiteStatus::LOCAL_MIRROR_UUID
),
5188 CLS_ERR("error reading status for mirrored image, global id '%s', "
5190 global_image_id
.c_str(),
5191 cls::rbd::MirrorImageSiteStatus::LOCAL_MIRROR_UUID
.c_str(),
5192 cpp_strerror(r
).c_str());
5196 return image_status_get(hctx
, global_image_id
,
5197 cls::rbd::MirrorImageSiteStatus::LOCAL_MIRROR_UUID
,
5198 bl
, watchers
, status
);
5201 int image_status_get_remote(cls_method_context_t hctx
,
5202 const string
&global_image_id
,
5203 const std::set
<entity_inst_t
> &watchers
,
5204 cls::rbd::MirrorImageStatus
*status
) {
5205 std::string filter
= remote_status_global_key(global_image_id
, "");
5206 std::string last_read
= filter
;
5207 int max_read
= RBD_MAX_KEYS_READ
;
5211 std::map
<std::string
, bufferlist
> vals
;
5212 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
5213 int r
= cls_cxx_map_get_vals(hctx
, last_read
, filter
, max_read
, &vals
,
5221 for (auto& it
: vals
) {
5222 auto mirror_uuid
= it
.first
.substr(filter
.length());
5223 CLS_LOG(20, "mirror_uuid = '%s'", mirror_uuid
.c_str());
5224 r
= image_status_get(hctx
, global_image_id
, mirror_uuid
, it
.second
,
5231 if (!vals
.empty()) {
5232 last_read
= vals
.rbegin()->first
;
5239 int image_status_get(cls_method_context_t hctx
, const string
&global_image_id
,
5240 const std::set
<entity_inst_t
> &watchers
,
5241 cls::rbd::MirrorImageStatus
*status
) {
5242 status
->mirror_image_site_statuses
.clear();
5244 // collect local site status
5245 int r
= image_status_get_local(hctx
, global_image_id
, watchers
, status
);
5250 // collect remote site status (TX to peer)
5251 r
= image_status_get_remote(hctx
, global_image_id
, watchers
, status
);
5256 if (status
->mirror_image_site_statuses
.empty()) {
5263 int image_status_list(cls_method_context_t hctx
,
5264 const std::string
&start_after
, uint64_t max_return
,
5265 map
<std::string
, cls::rbd::MirrorImage
> *mirror_images
,
5266 map
<std::string
, cls::rbd::MirrorImageStatus
> *mirror_statuses
) {
5267 std::string last_read
= image_key(start_after
);
5268 int max_read
= RBD_MAX_KEYS_READ
;
5271 std::set
<entity_inst_t
> watchers
;
5272 int r
= list_watchers(hctx
, &watchers
);
5277 while (more
&& mirror_images
->size() < max_return
) {
5278 std::map
<std::string
, bufferlist
> vals
;
5279 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
5280 r
= cls_cxx_map_get_vals(hctx
, last_read
, IMAGE_KEY_PREFIX
, max_read
, &vals
,
5284 CLS_ERR("error reading mirror image directory by name: %s",
5285 cpp_strerror(r
).c_str());
5290 for (auto it
= vals
.begin(); it
!= vals
.end() &&
5291 mirror_images
->size() < max_return
; ++it
) {
5292 const std::string
&image_id
= it
->first
.substr(IMAGE_KEY_PREFIX
.size());
5293 cls::rbd::MirrorImage mirror_image
;
5294 auto iter
= it
->second
.cbegin();
5296 decode(mirror_image
, iter
);
5297 } catch (const ceph::buffer::error
&err
) {
5298 CLS_ERR("could not decode mirror image payload of image '%s'",
5303 (*mirror_images
)[image_id
] = mirror_image
;
5305 cls::rbd::MirrorImageStatus status
;
5306 int r1
= image_status_get(hctx
, mirror_image
.global_image_id
, watchers
,
5312 (*mirror_statuses
)[image_id
] = status
;
5314 if (!vals
.empty()) {
5315 last_read
= image_key(mirror_images
->rbegin()->first
);
5322 cls::rbd::MirrorImageStatusState
compute_image_status_summary_state(
5323 cls::rbd::MirrorPeerDirection mirror_peer_direction
,
5324 const std::set
<std::string
>& tx_peer_mirror_uuids
,
5325 const cls::rbd::MirrorImageStatus
& status
) {
5326 std::optional
<cls::rbd::MirrorImageStatusState
> state
= {};
5328 cls::rbd::MirrorImageSiteStatus local_status
;
5329 status
.get_local_mirror_image_site_status(&local_status
);
5331 uint64_t unmatched_tx_peers
= 0;
5332 switch (mirror_peer_direction
) {
5333 case cls::rbd::MIRROR_PEER_DIRECTION_RX
:
5334 // if we are RX-only, summary is based on our local status
5335 if (local_status
.up
) {
5336 state
= local_status
.state
;
5339 case cls::rbd::MIRROR_PEER_DIRECTION_RX_TX
:
5340 // if we are RX/TX, combine all statuses
5341 if (local_status
.up
) {
5342 state
= local_status
.state
;
5345 case cls::rbd::MIRROR_PEER_DIRECTION_TX
:
5346 // if we are TX-only, summary is based on remote status
5347 unmatched_tx_peers
= tx_peer_mirror_uuids
.size();
5348 for (auto& remote_status
: status
.mirror_image_site_statuses
) {
5349 if (remote_status
.mirror_uuid
==
5350 cls::rbd::MirrorImageSiteStatus::LOCAL_MIRROR_UUID
) {
5354 if (unmatched_tx_peers
> 0 &&
5355 tx_peer_mirror_uuids
.count(remote_status
.mirror_uuid
) > 0) {
5356 --unmatched_tx_peers
;
5359 auto remote_state
= (remote_status
.up
?
5360 remote_status
.state
: cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
);
5361 if (remote_status
.state
== cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR
) {
5362 state
= remote_status
.state
;
5363 } else if (!state
) {
5364 state
= remote_state
;
5365 } else if (*state
!= cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR
) {
5366 state
= std::min(*state
, remote_state
);
5374 if (!state
|| unmatched_tx_peers
> 0) {
5375 state
= cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
;
5380 int image_status_get_summary(
5381 cls_method_context_t hctx
,
5382 cls::rbd::MirrorPeerDirection mirror_peer_direction
,
5383 const std::set
<std::string
>& tx_peer_mirror_uuids
,
5384 std::map
<cls::rbd::MirrorImageStatusState
, int32_t> *states
) {
5385 std::set
<entity_inst_t
> watchers
;
5386 int r
= list_watchers(hctx
, &watchers
);
5393 string last_read
= IMAGE_KEY_PREFIX
;
5394 int max_read
= RBD_MAX_KEYS_READ
;
5397 map
<string
, bufferlist
> vals
;
5398 r
= cls_cxx_map_get_vals(hctx
, last_read
, IMAGE_KEY_PREFIX
,
5399 max_read
, &vals
, &more
);
5402 CLS_ERR("error reading mirrored images: %s", cpp_strerror(r
).c_str());
5407 for (auto &list_it
: vals
) {
5408 const string
&key
= list_it
.first
;
5410 if (0 != key
.compare(0, IMAGE_KEY_PREFIX
.size(), IMAGE_KEY_PREFIX
)) {
5414 cls::rbd::MirrorImage mirror_image
;
5415 auto iter
= list_it
.second
.cbegin();
5417 decode(mirror_image
, iter
);
5418 } catch (const ceph::buffer::error
&err
) {
5419 CLS_ERR("could not decode mirror image payload for key '%s'",
5424 cls::rbd::MirrorImageStatus status
;
5425 r
= image_status_get(hctx
, mirror_image
.global_image_id
, watchers
,
5427 if (r
< 0 && r
!= -ENOENT
) {
5431 auto state
= compute_image_status_summary_state(
5432 mirror_peer_direction
, tx_peer_mirror_uuids
, status
);
5436 if (!vals
.empty()) {
5437 last_read
= vals
.rbegin()->first
;
5444 int image_status_remove_down(cls_method_context_t hctx
) {
5445 std::set
<entity_inst_t
> watchers
;
5446 int r
= list_watchers(hctx
, &watchers
);
5451 std::vector
<std::string
> prefixes
= {
5452 STATUS_GLOBAL_KEY_PREFIX
, REMOTE_STATUS_GLOBAL_KEY_PREFIX
};
5453 for (auto& prefix
: prefixes
) {
5454 std::string last_read
= prefix
;
5455 int max_read
= RBD_MAX_KEYS_READ
;
5458 std::map
<std::string
, bufferlist
> vals
;
5459 r
= cls_cxx_map_get_vals(hctx
, last_read
, prefix
, max_read
, &vals
, &more
);
5462 CLS_ERR("error reading mirrored images: %s", cpp_strerror(r
).c_str());
5467 for (auto &list_it
: vals
) {
5468 const std::string
&key
= list_it
.first
;
5470 if (0 != key
.compare(0, prefix
.size(), prefix
)) {
5474 cls::rbd::MirrorImageSiteStatusOnDisk status
;
5476 auto it
= list_it
.second
.cbegin();
5477 status
.decode_meta(it
);
5478 } catch (const ceph::buffer::error
&err
) {
5479 CLS_ERR("could not decode status metadata for mirrored image '%s'",
5484 if (watchers
.find(status
.origin
) == watchers
.end()) {
5485 CLS_LOG(20, "removing stale status object for key %s",
5487 int r1
= cls_cxx_map_remove_key(hctx
, key
);
5489 CLS_ERR("error removing stale status for key '%s': %s",
5490 key
.c_str(), cpp_strerror(r1
).c_str());
5496 if (!vals
.empty()) {
5497 last_read
= vals
.rbegin()->first
;
5505 int image_instance_get(cls_method_context_t hctx
,
5506 const string
&global_image_id
,
5507 const std::set
<entity_inst_t
> &watchers
,
5508 entity_inst_t
*instance
) {
5509 // instance details only available for local site
5511 int r
= cls_cxx_map_get_val(
5512 hctx
, status_global_key(global_image_id
,
5513 cls::rbd::MirrorImageSiteStatus::LOCAL_MIRROR_UUID
),
5517 CLS_ERR("error reading status for mirrored image, global id '%s': '%s'",
5518 global_image_id
.c_str(), cpp_strerror(r
).c_str());
5523 cls::rbd::MirrorImageSiteStatusOnDisk ondisk_status
;
5525 auto it
= bl
.cbegin();
5526 decode(ondisk_status
, it
);
5527 } catch (const ceph::buffer::error
&err
) {
5528 CLS_ERR("could not decode status for mirrored image, global id '%s'",
5529 global_image_id
.c_str());
5533 if (watchers
.find(ondisk_status
.origin
) == watchers
.end()) {
5537 *instance
= ondisk_status
.origin
;
5541 int image_instance_list(cls_method_context_t hctx
,
5542 const std::string
&start_after
,
5543 uint64_t max_return
,
5544 map
<std::string
, entity_inst_t
> *instances
) {
5545 std::string last_read
= image_key(start_after
);
5546 int max_read
= RBD_MAX_KEYS_READ
;
5549 std::set
<entity_inst_t
> watchers
;
5550 int r
= list_watchers(hctx
, &watchers
);
5555 while (more
&& instances
->size() < max_return
) {
5556 std::map
<std::string
, bufferlist
> vals
;
5557 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
5558 r
= cls_cxx_map_get_vals(hctx
, last_read
, IMAGE_KEY_PREFIX
, max_read
, &vals
,
5562 CLS_ERR("error reading mirror image directory by name: %s",
5563 cpp_strerror(r
).c_str());
5568 for (auto it
= vals
.begin(); it
!= vals
.end() &&
5569 instances
->size() < max_return
; ++it
) {
5570 const std::string
&image_id
= it
->first
.substr(IMAGE_KEY_PREFIX
.size());
5571 cls::rbd::MirrorImage mirror_image
;
5572 auto iter
= it
->second
.cbegin();
5574 decode(mirror_image
, iter
);
5575 } catch (const ceph::buffer::error
&err
) {
5576 CLS_ERR("could not decode mirror image payload of image '%s'",
5581 entity_inst_t instance
;
5582 r
= image_instance_get(hctx
, mirror_image
.global_image_id
, watchers
,
5588 (*instances
)[image_id
] = instance
;
5590 if (!vals
.empty()) {
5591 last_read
= vals
.rbegin()->first
;
5598 int instances_list(cls_method_context_t hctx
,
5599 std::vector
<std::string
> *instance_ids
) {
5600 std::string last_read
= INSTANCE_KEY_PREFIX
;
5601 int max_read
= RBD_MAX_KEYS_READ
;
5604 std::map
<std::string
, bufferlist
> vals
;
5605 int r
= cls_cxx_map_get_vals(hctx
, last_read
, INSTANCE_KEY_PREFIX
.c_str(),
5606 max_read
, &vals
, &more
);
5609 CLS_ERR("error reading mirror instances: %s", cpp_strerror(r
).c_str());
5614 for (auto &it
: vals
) {
5615 instance_ids
->push_back(it
.first
.substr(INSTANCE_KEY_PREFIX
.size()));
5618 if (!vals
.empty()) {
5619 last_read
= vals
.rbegin()->first
;
5625 int instances_add(cls_method_context_t hctx
, const string
&instance_id
) {
5628 int r
= cls_cxx_map_set_val(hctx
, instance_key(instance_id
), &bl
);
5630 CLS_ERR("error setting mirror instance %s: %s", instance_id
.c_str(),
5631 cpp_strerror(r
).c_str());
5637 int instances_remove(cls_method_context_t hctx
, const string
&instance_id
) {
5639 int r
= cls_cxx_map_remove_key(hctx
, instance_key(instance_id
));
5641 CLS_ERR("error removing mirror instance %s: %s", instance_id
.c_str(),
5642 cpp_strerror(r
).c_str());
5648 int mirror_image_map_list(cls_method_context_t hctx
,
5649 const std::string
&start_after
,
5650 uint64_t max_return
,
5651 std::map
<std::string
, cls::rbd::MirrorImageMap
> *image_mapping
) {
5653 std::string last_read
= mirror_image_map_key(start_after
);
5655 while (more
&& image_mapping
->size() < max_return
) {
5656 std::map
<std::string
, bufferlist
> vals
;
5657 CLS_LOG(20, "last read: '%s'", last_read
.c_str());
5659 int max_read
= std::min
<uint64_t>(RBD_MAX_KEYS_READ
, max_return
- image_mapping
->size());
5660 int r
= cls_cxx_map_get_vals(hctx
, last_read
, MIRROR_IMAGE_MAP_KEY_PREFIX
,
5661 max_read
, &vals
, &more
);
5663 CLS_ERR("error reading image map: %s", cpp_strerror(r
).c_str());
5671 for (auto it
= vals
.begin(); it
!= vals
.end(); ++it
) {
5672 const std::string
&global_image_id
=
5673 it
->first
.substr(MIRROR_IMAGE_MAP_KEY_PREFIX
.size());
5675 cls::rbd::MirrorImageMap mirror_image_map
;
5676 auto iter
= it
->second
.cbegin();
5678 decode(mirror_image_map
, iter
);
5679 } catch (const ceph::buffer::error
&err
) {
5680 CLS_ERR("could not decode image map payload: %s",
5681 cpp_strerror(r
).c_str());
5685 image_mapping
->insert(std::make_pair(global_image_id
, mirror_image_map
));
5688 if (!vals
.empty()) {
5689 last_read
= vals
.rbegin()->first
;
5696 int image_snapshot_unlink_peer(cls_method_context_t hctx
,
5698 std::string mirror_peer_uuid
) {
5700 std::string snap_key
;
5701 key_from_snap_id(snap_id
, &snap_key
);
5702 int r
= read_key(hctx
, snap_key
, &snap
);
5705 CLS_ERR("Could not read snapshot meta off disk: %s",
5706 cpp_strerror(r
).c_str());
5711 auto mirror_ns
= std::get_if
<cls::rbd::MirrorSnapshotNamespace
>(
5712 &snap
.snapshot_namespace
);
5713 if (mirror_ns
== nullptr) {
5714 CLS_LOG(5, "mirror_image_snapshot_unlink_peer " \
5715 "not mirroring snapshot snap_id=%" PRIu64
, snap_id
);
5719 if (mirror_ns
->mirror_peer_uuids
.count(mirror_peer_uuid
) == 0) {
5723 mirror_ns
->mirror_peer_uuids
.erase(mirror_peer_uuid
);
5725 r
= image::snapshot::write(hctx
, snap_key
, std::move(snap
));
5733 int image_snapshot_set_copy_progress(cls_method_context_t hctx
,
5734 uint64_t snap_id
, bool complete
,
5735 uint64_t last_copied_object_number
) {
5737 std::string snap_key
;
5738 key_from_snap_id(snap_id
, &snap_key
);
5739 int r
= read_key(hctx
, snap_key
, &snap
);
5742 CLS_ERR("Could not read snapshot meta off disk: %s",
5743 cpp_strerror(r
).c_str());
5748 auto mirror_ns
= std::get_if
<cls::rbd::MirrorSnapshotNamespace
>(
5749 &snap
.snapshot_namespace
);
5750 if (mirror_ns
== nullptr) {
5751 CLS_LOG(5, "mirror_image_snapshot_set_copy_progress " \
5752 "not mirroring snapshot snap_id=%" PRIu64
, snap_id
);
5756 mirror_ns
->complete
= complete
;
5757 if (mirror_ns
->state
== cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY
||
5758 mirror_ns
->state
== cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED
) {
5759 mirror_ns
->last_copied_object_number
= last_copied_object_number
;
5762 r
= image::snapshot::write(hctx
, snap_key
, std::move(snap
));
5770 } // namespace mirror
5777 * @param uuid (std::string)
5778 * @returns 0 on success, negative error code on failure
5780 int mirror_uuid_get(cls_method_context_t hctx
, bufferlist
*in
,
5782 std::string mirror_uuid
;
5783 int r
= mirror::uuid_get(hctx
, &mirror_uuid
);
5788 encode(mirror_uuid
, *out
);
5794 * @param mirror_uuid (std::string)
5797 * @returns 0 on success, negative error code on failure
5799 int mirror_uuid_set(cls_method_context_t hctx
, bufferlist
*in
,
5801 std::string mirror_uuid
;
5803 auto bl_it
= in
->cbegin();
5804 decode(mirror_uuid
, bl_it
);
5805 } catch (const ceph::buffer::error
&err
) {
5809 if (mirror_uuid
.empty()) {
5810 CLS_ERR("cannot set empty mirror uuid");
5814 uint32_t mirror_mode
;
5815 int r
= read_key(hctx
, mirror::MODE
, &mirror_mode
);
5816 if (r
< 0 && r
!= -ENOENT
) {
5818 } else if (r
== 0 && mirror_mode
!= cls::rbd::MIRROR_MODE_DISABLED
) {
5819 CLS_ERR("cannot set mirror uuid while mirroring enabled");
5823 bufferlist mirror_uuid_bl
;
5824 mirror_uuid_bl
.append(mirror_uuid
);
5825 r
= cls_cxx_map_set_val(hctx
, mirror::UUID
, &mirror_uuid_bl
);
5827 CLS_ERR("failed to set mirror uuid");
5838 * @param cls::rbd::MirrorMode (uint32_t)
5839 * @returns 0 on success, negative error code on failure
5841 int mirror_mode_get(cls_method_context_t hctx
, bufferlist
*in
,
5843 uint32_t mirror_mode_decode
;
5844 int r
= read_key(hctx
, mirror::MODE
, &mirror_mode_decode
);
5849 encode(mirror_mode_decode
, *out
);
5855 * @param mirror_mode (cls::rbd::MirrorMode) (uint32_t)
5858 * @returns 0 on success, negative error code on failure
5860 int mirror_mode_set(cls_method_context_t hctx
, bufferlist
*in
,
5862 uint32_t mirror_mode_decode
;
5864 auto bl_it
= in
->cbegin();
5865 decode(mirror_mode_decode
, bl_it
);
5866 } catch (const ceph::buffer::error
&err
) {
5871 switch (static_cast<cls::rbd::MirrorMode
>(mirror_mode_decode
)) {
5872 case cls::rbd::MIRROR_MODE_DISABLED
:
5875 case cls::rbd::MIRROR_MODE_IMAGE
:
5876 case cls::rbd::MIRROR_MODE_POOL
:
5880 CLS_ERR("invalid mirror mode: %d", mirror_mode_decode
);
5886 std::string mirror_uuid
;
5887 r
= mirror::uuid_get(hctx
, &mirror_uuid
);
5895 encode(mirror_mode_decode
, bl
);
5897 r
= cls_cxx_map_set_val(hctx
, mirror::MODE
, &bl
);
5899 CLS_ERR("error enabling mirroring: %s", cpp_strerror(r
).c_str());
5903 std::vector
<cls::rbd::MirrorPeer
> peers
;
5904 r
= mirror::read_peers(hctx
, &peers
);
5905 if (r
< 0 && r
!= -ENOENT
) {
5909 if (!peers
.empty()) {
5910 CLS_ERR("mirroring peers still registered");
5914 r
= remove_key(hctx
, mirror::MODE
);
5919 r
= remove_key(hctx
, mirror::UUID
);
5929 * @param unique peer site name (std::string)
5930 * @param mirror_uuid (std::string)
5931 * @param direction (MirrorPeerDirection) -- future use
5934 * @returns 0 on success, negative error code on failure
5936 int mirror_peer_ping(cls_method_context_t hctx
, bufferlist
*in
,
5938 std::string site_name
;
5939 std::string mirror_uuid
;
5940 cls::rbd::MirrorPeerDirection mirror_peer_direction
;
5942 auto it
= in
->cbegin();
5943 decode(site_name
, it
);
5944 decode(mirror_uuid
, it
);
5947 decode(direction
, it
);
5948 mirror_peer_direction
= static_cast<cls::rbd::MirrorPeerDirection
>(
5950 } catch (const ceph::buffer::error
&err
) {
5954 if (mirror_peer_direction
!= cls::rbd::MIRROR_PEER_DIRECTION_TX
) {
5958 int r
= mirror::peer_ping(hctx
, site_name
, mirror_uuid
);
5971 * @param std::vector<cls::rbd::MirrorPeer>: collection of peers
5972 * @returns 0 on success, negative error code on failure
5974 int mirror_peer_list(cls_method_context_t hctx
, bufferlist
*in
,
5976 std::vector
<cls::rbd::MirrorPeer
> peers
;
5977 int r
= mirror::read_peers(hctx
, &peers
);
5978 if (r
< 0 && r
!= -ENOENT
) {
5982 encode(peers
, *out
);
5988 * @param mirror_peer (cls::rbd::MirrorPeer)
5991 * @returns 0 on success, negative error code on failure
5993 int mirror_peer_add(cls_method_context_t hctx
, bufferlist
*in
,
5995 cls::rbd::MirrorPeer mirror_peer
;
5997 auto it
= in
->cbegin();
5998 decode(mirror_peer
, it
);
5999 } catch (const ceph::buffer::error
&err
) {
6003 int r
= mirror::peer_add(hctx
, mirror_peer
);
6013 * @param uuid (std::string)
6016 * @returns 0 on success, negative error code on failure
6018 int mirror_peer_remove(cls_method_context_t hctx
, bufferlist
*in
,
6022 auto it
= in
->cbegin();
6024 } catch (const ceph::buffer::error
&err
) {
6028 int r
= mirror::peer_remove(hctx
, uuid
);
6037 * @param uuid (std::string)
6038 * @param client_name (std::string)
6041 * @returns 0 on success, negative error code on failure
6043 int mirror_peer_set_client(cls_method_context_t hctx
, bufferlist
*in
,
6046 std::string client_name
;
6048 auto it
= in
->cbegin();
6050 decode(client_name
, it
);
6051 } catch (const ceph::buffer::error
&err
) {
6055 cls::rbd::MirrorPeer peer
;
6056 int r
= mirror::read_peer(hctx
, uuid
, &peer
);
6061 peer
.client_name
= client_name
;
6062 r
= mirror::write_peer(hctx
, peer
);
6071 * @param uuid (std::string)
6072 * @param site_name (std::string)
6075 * @returns 0 on success, negative error code on failure
6077 int mirror_peer_set_cluster(cls_method_context_t hctx
, bufferlist
*in
,
6080 std::string site_name
;
6082 auto it
= in
->cbegin();
6084 decode(site_name
, it
);
6085 } catch (const ceph::buffer::error
&err
) {
6089 cls::rbd::MirrorPeer
* peer
= nullptr;
6090 std::vector
<cls::rbd::MirrorPeer
> peers
;
6091 int r
= mirror::read_peers(hctx
, &peers
);
6092 if (r
< 0 && r
!= -ENOENT
) {
6096 for (auto& p
: peers
) {
6097 if (p
.uuid
== uuid
) {
6099 } else if (p
.site_name
== site_name
) {
6104 if (peer
== nullptr) {
6108 peer
->site_name
= site_name
;
6109 r
= mirror::write_peer(hctx
, *peer
);
6118 * @param uuid (std::string)
6119 * @param direction (uint8_t)
6122 * @returns 0 on success, negative error code on failure
6124 int mirror_peer_set_direction(cls_method_context_t hctx
, bufferlist
*in
,
6127 cls::rbd::MirrorPeerDirection mirror_peer_direction
;
6129 auto it
= in
->cbegin();
6132 decode(direction
, it
);
6133 mirror_peer_direction
= static_cast<cls::rbd::MirrorPeerDirection
>(
6135 } catch (const ceph::buffer::error
&err
) {
6139 cls::rbd::MirrorPeer peer
;
6140 int r
= mirror::read_peer(hctx
, uuid
, &peer
);
6145 peer
.mirror_peer_direction
= mirror_peer_direction
;
6146 r
= mirror::write_peer(hctx
, peer
);
6155 * @param start_after which name to begin listing after
6156 * (use the empty string to start at the beginning)
6157 * @param max_return the maximum number of names to list
6160 * @param std::map<std::string, std::string>: local id to global id map
6161 * @returns 0 on success, negative error code on failure
6163 int mirror_image_list(cls_method_context_t hctx
, bufferlist
*in
,
6165 std::string start_after
;
6166 uint64_t max_return
;
6168 auto iter
= in
->cbegin();
6169 decode(start_after
, iter
);
6170 decode(max_return
, iter
);
6171 } catch (const ceph::buffer::error
&err
) {
6175 int max_read
= RBD_MAX_KEYS_READ
;
6177 std::map
<std::string
, std::string
> mirror_images
;
6178 std::string last_read
= mirror::image_key(start_after
);
6180 while (more
&& mirror_images
.size() < max_return
) {
6181 std::map
<std::string
, bufferlist
> vals
;
6182 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
6183 int r
= cls_cxx_map_get_vals(hctx
, last_read
, mirror::IMAGE_KEY_PREFIX
,
6184 max_read
, &vals
, &more
);
6187 CLS_ERR("error reading mirror image directory by name: %s",
6188 cpp_strerror(r
).c_str());
6193 for (auto it
= vals
.begin(); it
!= vals
.end(); ++it
) {
6194 const std::string
&image_id
=
6195 it
->first
.substr(mirror::IMAGE_KEY_PREFIX
.size());
6196 cls::rbd::MirrorImage mirror_image
;
6197 auto iter
= it
->second
.cbegin();
6199 decode(mirror_image
, iter
);
6200 } catch (const ceph::buffer::error
&err
) {
6201 CLS_ERR("could not decode mirror image payload of image '%s'",
6206 mirror_images
[image_id
] = mirror_image
.global_image_id
;
6207 if (mirror_images
.size() >= max_return
) {
6211 if (!vals
.empty()) {
6212 last_read
= mirror::image_key(mirror_images
.rbegin()->first
);
6216 encode(mirror_images
, *out
);
6222 * @param global_id (std::string)
6225 * @param std::string - image id
6226 * @returns 0 on success, negative error code on failure
6228 int mirror_image_get_image_id(cls_method_context_t hctx
, bufferlist
*in
,
6230 std::string global_id
;
6232 auto it
= in
->cbegin();
6233 decode(global_id
, it
);
6234 } catch (const ceph::buffer::error
&err
) {
6238 std::string image_id
;
6239 int r
= read_key(hctx
, mirror::global_key(global_id
), &image_id
);
6242 CLS_ERR("error retrieving image id for global id '%s': %s",
6243 global_id
.c_str(), cpp_strerror(r
).c_str());
6248 encode(image_id
, *out
);
6254 * @param image_id (std::string)
6257 * @param cls::rbd::MirrorImage - metadata associated with the image_id
6258 * @returns 0 on success, negative error code on failure
6260 int mirror_image_get(cls_method_context_t hctx
, bufferlist
*in
,
6264 auto it
= in
->cbegin();
6265 decode(image_id
, it
);
6266 } catch (const ceph::buffer::error
&err
) {
6270 cls::rbd::MirrorImage mirror_image
;
6271 int r
= mirror::image_get(hctx
, image_id
, &mirror_image
);
6276 encode(mirror_image
, *out
);
6282 * @param image_id (std::string)
6283 * @param mirror_image (cls::rbd::MirrorImage)
6286 * @returns 0 on success, negative error code on failure
6287 * @returns -EEXIST if there's an existing image_id with a different global_image_id
6289 int mirror_image_set(cls_method_context_t hctx
, bufferlist
*in
,
6292 cls::rbd::MirrorImage mirror_image
;
6294 auto it
= in
->cbegin();
6295 decode(image_id
, it
);
6296 decode(mirror_image
, it
);
6297 } catch (const ceph::buffer::error
&err
) {
6301 int r
= mirror::image_set(hctx
, image_id
, mirror_image
);
6310 * @param image_id (std::string)
6313 * @returns 0 on success, negative error code on failure
6315 int mirror_image_remove(cls_method_context_t hctx
, bufferlist
*in
,
6319 auto it
= in
->cbegin();
6320 decode(image_id
, it
);
6321 } catch (const ceph::buffer::error
&err
) {
6325 int r
= mirror::image_remove(hctx
, image_id
);
6334 * @param global_image_id (std::string)
6335 * @param status (cls::rbd::MirrorImageSiteStatus)
6338 * @returns 0 on success, negative error code on failure
6340 int mirror_image_status_set(cls_method_context_t hctx
, bufferlist
*in
,
6342 string global_image_id
;
6343 cls::rbd::MirrorImageSiteStatus status
;
6345 auto it
= in
->cbegin();
6346 decode(global_image_id
, it
);
6348 } catch (const ceph::buffer::error
&err
) {
6352 int r
= mirror::image_status_set(hctx
, global_image_id
, status
);
6361 * @param global_image_id (std::string)
6364 * @returns 0 on success, negative error code on failure
6367 int mirror_image_status_remove(cls_method_context_t hctx
, bufferlist
*in
,
6369 string global_image_id
;
6371 auto it
= in
->cbegin();
6372 decode(global_image_id
, it
);
6373 } catch (const ceph::buffer::error
&err
) {
6377 int r
= mirror::image_status_remove(hctx
, global_image_id
);
6386 * @param global_image_id (std::string)
6389 * @param cls::rbd::MirrorImageStatus - metadata associated with the global_image_id
6390 * @returns 0 on success, negative error code on failure
6392 int mirror_image_status_get(cls_method_context_t hctx
, bufferlist
*in
,
6394 string global_image_id
;
6396 auto it
= in
->cbegin();
6397 decode(global_image_id
, it
);
6398 } catch (const ceph::buffer::error
&err
) {
6402 std::set
<entity_inst_t
> watchers
;
6403 int r
= mirror::list_watchers(hctx
, &watchers
);
6408 cls::rbd::MirrorImageStatus status
;
6409 r
= mirror::image_status_get(hctx
, global_image_id
, watchers
, &status
);
6414 encode(status
, *out
);
6420 * @param start_after which name to begin listing after
6421 * (use the empty string to start at the beginning)
6422 * @param max_return the maximum number of names to list
6425 * @param std::map<std::string, cls::rbd::MirrorImage>: image id to image map
6426 * @param std::map<std::string, cls::rbd::MirrorImageStatus>: image it to status map
6427 * @returns 0 on success, negative error code on failure
6429 int mirror_image_status_list(cls_method_context_t hctx
, bufferlist
*in
,
6431 std::string start_after
;
6432 uint64_t max_return
;
6434 auto iter
= in
->cbegin();
6435 decode(start_after
, iter
);
6436 decode(max_return
, iter
);
6437 } catch (const ceph::buffer::error
&err
) {
6441 map
<std::string
, cls::rbd::MirrorImage
> images
;
6442 map
<std::string
, cls::rbd::MirrorImageStatus
> statuses
;
6443 int r
= mirror::image_status_list(hctx
, start_after
, max_return
, &images
,
6449 encode(images
, *out
);
6450 encode(statuses
, *out
);
6456 * @param std::vector<cls::rbd::MirrorPeer> - optional peers (backwards compatibility)
6459 * @param std::map<cls::rbd::MirrorImageStatusState, int32_t>: states counts
6460 * @returns 0 on success, negative error code on failure
6462 int mirror_image_status_get_summary(cls_method_context_t hctx
, bufferlist
*in
,
6464 std::vector
<cls::rbd::MirrorPeer
> peers
;
6466 auto iter
= in
->cbegin();
6468 decode(peers
, iter
);
6470 } catch (const ceph::buffer::error
&err
) {
6474 auto mirror_peer_direction
= cls::rbd::MIRROR_PEER_DIRECTION_RX
;
6475 if (!peers
.empty()) {
6476 mirror_peer_direction
= peers
.begin()->mirror_peer_direction
;
6479 std::set
<std::string
> tx_peer_mirror_uuids
;
6480 for (auto& peer
: peers
) {
6481 if (peer
.mirror_peer_direction
== cls::rbd::MIRROR_PEER_DIRECTION_RX
) {
6485 tx_peer_mirror_uuids
.insert(peer
.mirror_uuid
);
6486 if (mirror_peer_direction
!= cls::rbd::MIRROR_PEER_DIRECTION_RX_TX
&&
6487 mirror_peer_direction
!= peer
.mirror_peer_direction
) {
6488 mirror_peer_direction
= cls::rbd::MIRROR_PEER_DIRECTION_RX_TX
;
6492 std::map
<cls::rbd::MirrorImageStatusState
, int32_t> states
;
6493 int r
= mirror::image_status_get_summary(hctx
, mirror_peer_direction
,
6494 tx_peer_mirror_uuids
, &states
);
6499 encode(states
, *out
);
6508 * @returns 0 on success, negative error code on failure
6510 int mirror_image_status_remove_down(cls_method_context_t hctx
, bufferlist
*in
,
6512 int r
= mirror::image_status_remove_down(hctx
);
6521 * @param global_image_id (std::string)
6524 * @param entity_inst_t - instance
6525 * @returns 0 on success, negative error code on failure
6527 int mirror_image_instance_get(cls_method_context_t hctx
, bufferlist
*in
,
6529 string global_image_id
;
6531 auto it
= in
->cbegin();
6532 decode(global_image_id
, it
);
6533 } catch (const ceph::buffer::error
&err
) {
6537 std::set
<entity_inst_t
> watchers
;
6538 int r
= mirror::list_watchers(hctx
, &watchers
);
6543 entity_inst_t instance
;
6544 r
= mirror::image_instance_get(hctx
, global_image_id
, watchers
, &instance
);
6549 encode(instance
, *out
, cls_get_features(hctx
));
6555 * @param start_after which name to begin listing after
6556 * (use the empty string to start at the beginning)
6557 * @param max_return the maximum number of names to list
6560 * @param std::map<std::string, entity_inst_t>: image id to instance map
6561 * @returns 0 on success, negative error code on failure
6563 int mirror_image_instance_list(cls_method_context_t hctx
, bufferlist
*in
,
6565 std::string start_after
;
6566 uint64_t max_return
;
6568 auto iter
= in
->cbegin();
6569 decode(start_after
, iter
);
6570 decode(max_return
, iter
);
6571 } catch (const ceph::buffer::error
&err
) {
6575 map
<std::string
, entity_inst_t
> instances
;
6576 int r
= mirror::image_instance_list(hctx
, start_after
, max_return
,
6582 encode(instances
, *out
, cls_get_features(hctx
));
6591 * @param std::vector<std::string>: instance ids
6592 * @returns 0 on success, negative error code on failure
6594 int mirror_instances_list(cls_method_context_t hctx
, bufferlist
*in
,
6596 std::vector
<std::string
> instance_ids
;
6598 int r
= mirror::instances_list(hctx
, &instance_ids
);
6603 encode(instance_ids
, *out
);
6609 * @param instance_id (std::string)
6612 * @returns 0 on success, negative error code on failure
6614 int mirror_instances_add(cls_method_context_t hctx
, bufferlist
*in
,
6616 std::string instance_id
;
6618 auto iter
= in
->cbegin();
6619 decode(instance_id
, iter
);
6620 } catch (const ceph::buffer::error
&err
) {
6624 int r
= mirror::instances_add(hctx
, instance_id
);
6633 * @param instance_id (std::string)
6636 * @returns 0 on success, negative error code on failure
6638 int mirror_instances_remove(cls_method_context_t hctx
, bufferlist
*in
,
6640 std::string instance_id
;
6642 auto iter
= in
->cbegin();
6643 decode(instance_id
, iter
);
6644 } catch (const ceph::buffer::error
&err
) {
6648 int r
= mirror::instances_remove(hctx
, instance_id
);
6657 * @param start_after: key to start after
6658 * @param max_return: max return items
6661 * @param std::map<std::string, cls::rbd::MirrorImageMap>: image mapping
6662 * @returns 0 on success, negative error code on failure
6664 int mirror_image_map_list(cls_method_context_t hctx
, bufferlist
*in
,
6666 std::string start_after
;
6667 uint64_t max_return
;
6669 auto it
= in
->cbegin();
6670 decode(start_after
, it
);
6671 decode(max_return
, it
);
6672 } catch (const ceph::buffer::error
&err
) {
6676 std::map
<std::string
, cls::rbd::MirrorImageMap
> image_mapping
;
6677 int r
= mirror::mirror_image_map_list(hctx
, start_after
, max_return
, &image_mapping
);
6682 encode(image_mapping
, *out
);
6688 * @param global_image_id: global image id
6689 * @param image_map: image map
6692 * @returns 0 on success, negative error code on failure
6694 int mirror_image_map_update(cls_method_context_t hctx
, bufferlist
*in
,
6696 std::string global_image_id
;
6697 cls::rbd::MirrorImageMap image_map
;
6700 auto it
= in
->cbegin();
6701 decode(global_image_id
, it
);
6702 decode(image_map
, it
);
6703 } catch (const ceph::buffer::error
&err
) {
6708 encode(image_map
, bl
);
6710 const std::string key
= mirror::mirror_image_map_key(global_image_id
);
6711 int r
= cls_cxx_map_set_val(hctx
, key
, &bl
);
6713 CLS_ERR("error updating image map %s: %s", key
.c_str(),
6714 cpp_strerror(r
).c_str());
6723 * @param global_image_id: global image id
6726 * @returns 0 on success, negative error code on failure
6728 int mirror_image_map_remove(cls_method_context_t hctx
, bufferlist
*in
,
6730 std::string global_image_id
;
6733 auto it
= in
->cbegin();
6734 decode(global_image_id
, it
);
6735 } catch (const ceph::buffer::error
&err
) {
6739 const std::string key
= mirror::mirror_image_map_key(global_image_id
);
6740 int r
= cls_cxx_map_remove_key(hctx
, key
);
6741 if (r
< 0 && r
!= -ENOENT
) {
6742 CLS_ERR("error removing image map %s: %s", key
.c_str(),
6743 cpp_strerror(r
).c_str());
6753 * @param snap_id: snapshot id
6754 * @param mirror_peer_uuid: mirror peer uuid
6757 * @returns 0 on success, negative error code on failure
6759 int mirror_image_snapshot_unlink_peer(cls_method_context_t hctx
, bufferlist
*in
,
6762 std::string mirror_peer_uuid
;
6764 auto iter
= in
->cbegin();
6765 decode(snap_id
, iter
);
6766 decode(mirror_peer_uuid
, iter
);
6767 } catch (const ceph::buffer::error
&err
) {
6772 "mirror_image_snapshot_unlink_peer snap_id=%" PRIu64
" peer_uuid=%s",
6773 snap_id
, mirror_peer_uuid
.c_str());
6775 int r
= mirror::image_snapshot_unlink_peer(hctx
, snap_id
, mirror_peer_uuid
);
6784 * @param snap_id: snapshot id
6785 * @param complete: true if shapshot fully copied/complete
6786 * @param last_copied_object_number: last copied object number
6789 * @returns 0 on success, negative error code on failure
6791 int mirror_image_snapshot_set_copy_progress(cls_method_context_t hctx
,
6796 uint64_t last_copied_object_number
;
6798 auto iter
= in
->cbegin();
6799 decode(snap_id
, iter
);
6800 decode(complete
, iter
);
6801 decode(last_copied_object_number
, iter
);
6802 } catch (const ceph::buffer::error
&err
) {
6806 CLS_LOG(20, "mirror_image_snapshot_set_copy_progress snap_id=%" PRIu64 \
6807 " complete=%d last_copied_object_number=%" PRIu64
, snap_id
, complete
,
6808 last_copied_object_number
);
6810 int r
= mirror::image_snapshot_set_copy_progress(hctx
, snap_id
, complete
,
6811 last_copied_object_number
);
6820 /********************** methods for rbd_group_directory ***********************/
6822 int dir_add(cls_method_context_t hctx
,
6823 const string
&name
, const string
&id
,
6824 bool check_for_unique_id
)
6826 if (!name
.size() || !is_valid_id(id
)) {
6827 CLS_ERR("invalid group name '%s' or id '%s'",
6828 name
.c_str(), id
.c_str());
6832 CLS_LOG(20, "dir_add name=%s id=%s", name
.c_str(), id
.c_str());
6834 string name_key
= dir_key_for_name(name
);
6835 string id_key
= dir_key_for_id(id
);
6837 int r
= read_key(hctx
, name_key
, &tmp
);
6839 CLS_LOG(10, "name already exists");
6842 r
= read_key(hctx
, id_key
, &tmp
);
6843 if (r
!= -ENOENT
&& check_for_unique_id
) {
6844 CLS_LOG(10, "id already exists");
6847 bufferlist id_bl
, name_bl
;
6849 encode(name
, name_bl
);
6850 map
<string
, bufferlist
> omap_vals
;
6851 omap_vals
[name_key
] = id_bl
;
6852 omap_vals
[id_key
] = name_bl
;
6853 return cls_cxx_map_set_vals(hctx
, &omap_vals
);
6856 int dir_remove(cls_method_context_t hctx
,
6857 const string
&name
, const string
&id
)
6859 CLS_LOG(20, "dir_remove name=%s id=%s", name
.c_str(), id
.c_str());
6861 string name_key
= dir_key_for_name(name
);
6862 string id_key
= dir_key_for_id(id
);
6863 string stored_name
, stored_id
;
6865 int r
= read_key(hctx
, name_key
, &stored_id
);
6868 CLS_ERR("error reading name to id mapping: %s", cpp_strerror(r
).c_str());
6871 r
= read_key(hctx
, id_key
, &stored_name
);
6874 CLS_ERR("error reading id to name mapping: %s", cpp_strerror(r
).c_str());
6878 // check if this op raced with a rename
6879 if (stored_name
!= name
|| stored_id
!= id
) {
6880 CLS_ERR("stored name '%s' and id '%s' do not match args '%s' and '%s'",
6881 stored_name
.c_str(), stored_id
.c_str(), name
.c_str(), id
.c_str());
6885 r
= cls_cxx_map_remove_key(hctx
, name_key
);
6887 CLS_ERR("error removing name: %s", cpp_strerror(r
).c_str());
6891 r
= cls_cxx_map_remove_key(hctx
, id_key
);
6893 CLS_ERR("error removing id: %s", cpp_strerror(r
).c_str());
6900 static const string RBD_GROUP_SNAP_KEY_PREFIX
= "snapshot_";
6902 std::string
snap_key(const std::string
&snap_id
) {
6904 oss
<< RBD_GROUP_SNAP_KEY_PREFIX
<< snap_id
;
6908 int snap_list(cls_method_context_t hctx
, cls::rbd::GroupSnapshot start_after
,
6909 uint64_t max_return
,
6910 std::vector
<cls::rbd::GroupSnapshot
> *group_snaps
)
6912 int max_read
= RBD_MAX_KEYS_READ
;
6913 std::map
<string
, bufferlist
> vals
;
6914 string last_read
= snap_key(start_after
.id
);
6916 group_snaps
->clear();
6920 int r
= cls_cxx_map_get_vals(hctx
, last_read
,
6921 RBD_GROUP_SNAP_KEY_PREFIX
,
6922 max_read
, &vals
, &more
);
6926 for (auto it
= vals
.begin(); it
!= vals
.end() && group_snaps
->size() < max_return
; ++it
) {
6928 auto iter
= it
->second
.cbegin();
6929 cls::rbd::GroupSnapshot snap
;
6932 } catch (const ceph::buffer::error
&err
) {
6933 CLS_ERR("error decoding snapshot: %s", it
->first
.c_str());
6936 CLS_LOG(20, "Discovered snapshot %s %s",
6939 group_snaps
->push_back(snap
);
6942 if (!vals
.empty()) {
6943 last_read
= vals
.rbegin()->first
;
6945 } while (more
&& (group_snaps
->size() < max_return
));
6950 static int check_duplicate_snap_name(cls_method_context_t hctx
,
6951 const std::string
&snap_name
,
6952 const std::string
&snap_id
)
6954 const int max_read
= 1024;
6955 cls::rbd::GroupSnapshot snap_last
;
6956 std::vector
<cls::rbd::GroupSnapshot
> page
;
6959 int r
= snap_list(hctx
, snap_last
, max_read
, &page
);
6963 for (auto& snap
: page
) {
6964 if (snap
.name
== snap_name
&& snap
.id
!= snap_id
) {
6969 if (page
.size() < max_read
) {
6973 snap_last
= *page
.rbegin();
6979 } // namespace group
6982 * List groups from the directory.
6985 * @param start_after (std::string)
6986 * @param max_return (int64_t)
6989 * @param map of groups (name, id)
6990 * @return 0 on success, negative error code on failure
6992 int group_dir_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
6995 uint64_t max_return
;
6998 auto iter
= in
->cbegin();
6999 decode(start_after
, iter
);
7000 decode(max_return
, iter
);
7001 } catch (const ceph::buffer::error
&err
) {
7005 int max_read
= RBD_MAX_KEYS_READ
;
7007 map
<string
, string
> groups
;
7008 string last_read
= dir_key_for_name(start_after
);
7010 while (more
&& groups
.size() < max_return
) {
7011 map
<string
, bufferlist
> vals
;
7012 CLS_LOG(20, "last_read = '%s'", last_read
.c_str());
7013 int r
= cls_cxx_map_get_vals(hctx
, last_read
, RBD_DIR_NAME_KEY_PREFIX
,
7014 max_read
, &vals
, &more
);
7017 CLS_ERR("error reading directory by name: %s", cpp_strerror(r
).c_str());
7022 for (auto val
: vals
) {
7024 auto iter
= val
.second
.cbegin();
7027 } catch (const ceph::buffer::error
&err
) {
7028 CLS_ERR("could not decode id of group '%s'", val
.first
.c_str());
7031 CLS_LOG(20, "adding '%s' -> '%s'", dir_name_from_key(val
.first
).c_str(), id
.c_str());
7032 groups
[dir_name_from_key(val
.first
)] = id
;
7033 if (groups
.size() >= max_return
)
7036 if (!vals
.empty()) {
7037 last_read
= dir_key_for_name(groups
.rbegin()->first
);
7041 encode(groups
, *out
);
7047 * Add a group to the directory.
7050 * @param name (std::string)
7051 * @param id (std::string)
7054 * @return 0 on success, negative error code on failure
7056 int group_dir_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7058 int r
= cls_cxx_create(hctx
, false);
7061 CLS_ERR("could not create group directory: %s",
7062 cpp_strerror(r
).c_str());
7068 auto iter
= in
->cbegin();
7071 } catch (const ceph::buffer::error
&err
) {
7075 return group::dir_add(hctx
, name
, id
, true);
7079 * Rename a group to the directory.
7082 * @param src original name of the group (std::string)
7083 * @param dest new name of the group (std::string)
7084 * @param id the id of the group (std::string)
7087 * @return 0 on success, negative error code on failure
7089 int group_dir_rename(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7091 string src
, dest
, id
;
7093 auto iter
= in
->cbegin();
7097 } catch (const ceph::buffer::error
&err
) {
7101 int r
= group::dir_remove(hctx
, src
, id
);
7105 return group::dir_add(hctx
, dest
, id
, false);
7109 * Remove a group from the directory.
7112 * @param name (std::string)
7113 * @param id (std::string)
7116 * @return 0 on success, negative error code on failure
7118 int group_dir_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7122 auto iter
= in
->cbegin();
7125 } catch (const ceph::buffer::error
&err
) {
7129 return group::dir_remove(hctx
, name
, id
);
7133 * Set state of an image in the group.
7136 * @param image_status (cls::rbd::GroupImageStatus)
7139 * @return 0 on success, negative error code on failure
7141 int group_image_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7143 CLS_LOG(20, "group_image_set");
7145 cls::rbd::GroupImageStatus st
;
7147 auto iter
= in
->cbegin();
7149 } catch (const ceph::buffer::error
&err
) {
7153 string image_key
= st
.spec
.image_key();
7155 bufferlist image_val_bl
;
7156 encode(st
.state
, image_val_bl
);
7157 int r
= cls_cxx_map_set_val(hctx
, image_key
, &image_val_bl
);
7166 * Remove reference to an image from the group.
7169 * @param spec (cls::rbd::GroupImageSpec)
7172 * @return 0 on success, negative error code on failure
7174 int group_image_remove(cls_method_context_t hctx
,
7175 bufferlist
*in
, bufferlist
*out
)
7177 CLS_LOG(20, "group_image_remove");
7178 cls::rbd::GroupImageSpec spec
;
7180 auto iter
= in
->cbegin();
7182 } catch (const ceph::buffer::error
&err
) {
7186 string image_key
= spec
.image_key();
7188 int r
= cls_cxx_map_remove_key(hctx
, image_key
);
7190 CLS_ERR("error removing image from group: %s", cpp_strerror(r
).c_str());
7198 * List images in the group.
7201 * @param start_after which name to begin listing after
7202 * (use the empty string to start at the beginning)
7203 * @param max_return the maximum number of names to list
7206 * @param tuples of descriptions of the images: image_id, pool_id, image reference state.
7207 * @return 0 on success, negative error code on failure
7209 int group_image_list(cls_method_context_t hctx
,
7210 bufferlist
*in
, bufferlist
*out
)
7212 CLS_LOG(20, "group_image_list");
7213 cls::rbd::GroupImageSpec start_after
;
7214 uint64_t max_return
;
7216 auto iter
= in
->cbegin();
7217 decode(start_after
, iter
);
7218 decode(max_return
, iter
);
7219 } catch (const ceph::buffer::error
&err
) {
7223 int max_read
= RBD_MAX_KEYS_READ
;
7224 std::map
<string
, bufferlist
> vals
;
7225 string last_read
= start_after
.image_key();
7226 std::vector
<cls::rbd::GroupImageStatus
> res
;
7229 int r
= cls_cxx_map_get_vals(hctx
, last_read
,
7230 cls::rbd::RBD_GROUP_IMAGE_KEY_PREFIX
,
7231 max_read
, &vals
, &more
);
7235 for (auto it
= vals
.begin(); it
!= vals
.end() && res
.size() < max_return
; ++it
) {
7237 auto iter
= it
->second
.cbegin();
7238 cls::rbd::GroupImageLinkState state
;
7240 decode(state
, iter
);
7241 } catch (const ceph::buffer::error
&err
) {
7242 CLS_ERR("error decoding state for image: %s", it
->first
.c_str());
7245 cls::rbd::GroupImageSpec spec
;
7246 int r
= cls::rbd::GroupImageSpec::from_key(it
->first
, &spec
);
7250 CLS_LOG(20, "Discovered image %s %" PRId64
" %d", spec
.image_id
.c_str(),
7253 res
.push_back(cls::rbd::GroupImageStatus(spec
, state
));
7255 if (res
.size() > 0) {
7256 last_read
= res
.rbegin()->spec
.image_key();
7259 } while (more
&& (res
.size() < max_return
));
7266 * Reference the group this image belongs to.
7269 * @param group_id (std::string)
7270 * @param pool_id (int64_t)
7273 * @return 0 on success, negative error code on failure
7275 int image_group_add(cls_method_context_t hctx
,
7276 bufferlist
*in
, bufferlist
*out
)
7278 CLS_LOG(20, "image_group_add");
7279 cls::rbd::GroupSpec new_group
;
7281 auto iter
= in
->cbegin();
7282 decode(new_group
, iter
);
7283 } catch (const ceph::buffer::error
&err
) {
7287 bufferlist existing_refbl
;
7289 int r
= cls_cxx_map_get_val(hctx
, RBD_GROUP_REF
, &existing_refbl
);
7291 // If we are trying to link this image to the same group then return
7292 // success. If this image already belongs to another group then abort.
7293 cls::rbd::GroupSpec old_group
;
7295 auto iter
= existing_refbl
.cbegin();
7296 decode(old_group
, iter
);
7297 } catch (const ceph::buffer::error
&err
) {
7301 if ((old_group
.group_id
!= new_group
.group_id
) ||
7302 (old_group
.pool_id
!= new_group
.pool_id
)) {
7305 return 0; // In this case the values are already correct
7307 } else if (r
< 0 && r
!= -ENOENT
) {
7308 // No entry means this image is not a member of any group.
7312 r
= image::set_op_features(hctx
, RBD_OPERATION_FEATURE_GROUP
,
7313 RBD_OPERATION_FEATURE_GROUP
);
7319 encode(new_group
, refbl
);
7320 r
= cls_cxx_map_set_val(hctx
, RBD_GROUP_REF
, &refbl
);
7329 * Remove image's pointer to the group.
7332 * @param cg_id (std::string)
7333 * @param pool_id (int64_t)
7336 * @return 0 on success, negative error code on failure
7338 int image_group_remove(cls_method_context_t hctx
,
7342 CLS_LOG(20, "image_group_remove");
7343 cls::rbd::GroupSpec spec
;
7345 auto iter
= in
->cbegin();
7347 } catch (const ceph::buffer::error
&err
) {
7352 int r
= cls_cxx_map_get_val(hctx
, RBD_GROUP_REF
, &refbl
);
7357 cls::rbd::GroupSpec ref_spec
;
7358 auto iter
= refbl
.cbegin();
7360 decode(ref_spec
, iter
);
7361 } catch (const ceph::buffer::error
&err
) {
7365 if (ref_spec
.pool_id
!= spec
.pool_id
|| ref_spec
.group_id
!= spec
.group_id
) {
7369 r
= cls_cxx_map_remove_key(hctx
, RBD_GROUP_REF
);
7374 r
= image::set_op_features(hctx
, 0, RBD_OPERATION_FEATURE_GROUP
);
7383 * Retrieve the id and pool of the group this image belongs to.
7390 * @return 0 on success, negative error code on failure
7392 int image_group_get(cls_method_context_t hctx
,
7393 bufferlist
*in
, bufferlist
*out
)
7395 CLS_LOG(20, "image_group_get");
7397 int r
= cls_cxx_map_get_val(hctx
, RBD_GROUP_REF
, &refbl
);
7398 if (r
< 0 && r
!= -ENOENT
) {
7402 cls::rbd::GroupSpec spec
;
7405 auto iter
= refbl
.cbegin();
7408 } catch (const ceph::buffer::error
&err
) {
7418 * Save initial snapshot record.
7421 * @param GroupSnapshot
7424 * @return 0 on success, negative error code on failure
7426 int group_snap_set(cls_method_context_t hctx
,
7427 bufferlist
*in
, bufferlist
*out
)
7429 CLS_LOG(20, "group_snap_set");
7430 cls::rbd::GroupSnapshot group_snap
;
7432 auto iter
= in
->cbegin();
7433 decode(group_snap
, iter
);
7434 } catch (const ceph::buffer::error
&err
) {
7438 if (group_snap
.name
.empty()) {
7439 CLS_ERR("group snapshot name is empty");
7442 if (group_snap
.id
.empty()) {
7443 CLS_ERR("group snapshot id is empty");
7447 int r
= group::check_duplicate_snap_name(hctx
, group_snap
.name
,
7453 std::string key
= group::snap_key(group_snap
.id
);
7454 if (group_snap
.state
== cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
) {
7456 r
= cls_cxx_map_get_val(hctx
, key
, &snap_bl
);
7457 if (r
< 0 && r
!= -ENOENT
) {
7459 } else if (r
>= 0) {
7465 encode(group_snap
, obl
);
7466 r
= cls_cxx_map_set_val(hctx
, key
, &obl
);
7471 * Remove snapshot record.
7474 * @param id Snapshot id
7477 * @return 0 on success, negative error code on failure
7479 int group_snap_remove(cls_method_context_t hctx
,
7480 bufferlist
*in
, bufferlist
*out
)
7482 CLS_LOG(20, "group_snap_remove");
7483 std::string snap_id
;
7485 auto iter
= in
->cbegin();
7486 decode(snap_id
, iter
);
7487 } catch (const ceph::buffer::error
&err
) {
7491 std::string snap_key
= group::snap_key(snap_id
);
7493 CLS_LOG(20, "removing snapshot with key %s", snap_key
.c_str());
7494 int r
= cls_cxx_map_remove_key(hctx
, snap_key
);
7499 * Get group's snapshot by id.
7502 * @param snapshot_id the id of the snapshot to look for.
7505 * @param GroupSnapshot the requested snapshot
7506 * @return 0 on success, negative error code on failure
7508 int group_snap_get_by_id(cls_method_context_t hctx
,
7509 bufferlist
*in
, bufferlist
*out
)
7511 CLS_LOG(20, "group_snap_get_by_id");
7513 std::string snap_id
;
7515 auto iter
= in
->cbegin();
7516 decode(snap_id
, iter
);
7517 } catch (const ceph::buffer::error
&err
) {
7523 int r
= cls_cxx_map_get_val(hctx
, group::snap_key(snap_id
), &snapbl
);
7528 cls::rbd::GroupSnapshot group_snap
;
7529 auto iter
= snapbl
.cbegin();
7531 decode(group_snap
, iter
);
7532 } catch (const ceph::buffer::error
&err
) {
7533 CLS_ERR("error decoding snapshot: %s", snap_id
.c_str());
7537 encode(group_snap
, *out
);
7543 * List group's snapshots.
7546 * @param start_after which name to begin listing after
7547 * (use the empty string to start at the beginning)
7548 * @param max_return the maximum number of snapshots to list
7551 * @param list of snapshots
7552 * @return 0 on success, negative error code on failure
7554 int group_snap_list(cls_method_context_t hctx
,
7555 bufferlist
*in
, bufferlist
*out
)
7557 CLS_LOG(20, "group_snap_list");
7559 cls::rbd::GroupSnapshot start_after
;
7560 uint64_t max_return
;
7562 auto iter
= in
->cbegin();
7563 decode(start_after
, iter
);
7564 decode(max_return
, iter
);
7565 } catch (const ceph::buffer::error
&err
) {
7568 std::vector
<cls::rbd::GroupSnapshot
> group_snaps
;
7569 group::snap_list(hctx
, start_after
, max_return
, &group_snaps
);
7571 encode(group_snaps
, *out
);
7578 static const std::string
IMAGE_KEY_PREFIX("id_");
7580 std::string
image_key(const std::string
&image_id
) {
7581 return IMAGE_KEY_PREFIX
+ image_id
;
7584 std::string
image_id_from_key(const std::string
&key
) {
7585 return key
.substr(IMAGE_KEY_PREFIX
.size());
7588 } // namespace trash
7591 * Add an image entry to the rbd trash. Creates the trash object if
7592 * needed, and stores the trash spec information of the deleted image.
7595 * @param id the id of the image
7596 * @param trash_spec the spec info of the deleted image
7599 * @returns -EEXIST if the image id is already in the trash
7600 * @returns 0 on success, negative error code on failure
7602 int trash_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7604 int r
= cls_cxx_create(hctx
, false);
7606 CLS_ERR("could not create trash: %s", cpp_strerror(r
).c_str());
7611 cls::rbd::TrashImageSpec trash_spec
;
7613 auto iter
= in
->cbegin();
7615 decode(trash_spec
, iter
);
7616 } catch (const ceph::buffer::error
&err
) {
7620 if (!is_valid_id(id
)) {
7621 CLS_ERR("trash_add: invalid id '%s'", id
.c_str());
7625 CLS_LOG(20, "trash_add id=%s", id
.c_str());
7627 string key
= trash::image_key(id
);
7628 cls::rbd::TrashImageSpec tmp
;
7629 r
= read_key(hctx
, key
, &tmp
);
7630 if (r
< 0 && r
!= -ENOENT
) {
7631 CLS_ERR("could not read key %s entry from trash: %s", key
.c_str(),
7632 cpp_strerror(r
).c_str());
7634 } else if (r
== 0) {
7635 CLS_LOG(10, "id already exists");
7639 map
<string
, bufferlist
> omap_vals
;
7640 encode(trash_spec
, omap_vals
[key
]);
7641 return cls_cxx_map_set_vals(hctx
, &omap_vals
);
7645 * Removes an image entry from the rbd trash object.
7649 * @param id the id of the image
7652 * @returns -ENOENT if the image id does not exist in the trash
7653 * @returns 0 on success, negative error code on failure
7655 int trash_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7659 auto iter
= in
->cbegin();
7661 } catch (const ceph::buffer::error
&err
) {
7665 CLS_LOG(20, "trash_remove id=%s", id
.c_str());
7667 string key
= trash::image_key(id
);
7669 int r
= cls_cxx_map_get_val(hctx
, key
, &tmp
);
7672 CLS_ERR("error reading entry key %s: %s", key
.c_str(), cpp_strerror(r
).c_str());
7677 r
= cls_cxx_map_remove_key(hctx
, key
);
7679 CLS_ERR("error removing entry: %s", cpp_strerror(r
).c_str());
7687 * Returns the list of trash spec entries registered in the rbd_trash
7691 * @param start_after which name to begin listing after
7692 * (use the empty string to start at the beginning)
7693 * @param max_return the maximum number of names to list
7696 * @param data the map between image id and trash spec info
7698 * @returns 0 on success, negative error code on failure
7700 int trash_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7703 uint64_t max_return
;
7706 auto iter
= in
->cbegin();
7707 decode(start_after
, iter
);
7708 decode(max_return
, iter
);
7709 } catch (const ceph::buffer::error
&err
) {
7713 map
<string
, cls::rbd::TrashImageSpec
> data
;
7714 string last_read
= trash::image_key(start_after
);
7717 CLS_LOG(20, "trash_get_images");
7718 while (data
.size() < max_return
) {
7719 map
<string
, bufferlist
> raw_data
;
7720 int max_read
= std::min
<int32_t>(RBD_MAX_KEYS_READ
,
7721 max_return
- data
.size());
7722 int r
= cls_cxx_map_get_vals(hctx
, last_read
, trash::IMAGE_KEY_PREFIX
,
7723 max_read
, &raw_data
, &more
);
7726 CLS_ERR("failed to read the vals off of disk: %s",
7727 cpp_strerror(r
).c_str());
7731 if (raw_data
.empty()) {
7735 for (auto it
= raw_data
.begin(); it
!= raw_data
.end(); ++it
) {
7736 decode(data
[trash::image_id_from_key(it
->first
)], it
->second
);
7743 last_read
= raw_data
.rbegin()->first
;
7751 * Returns the trash spec entry of an image registered in the rbd_trash
7755 * @param id the id of the image
7758 * @param out the trash spec entry
7760 * @returns 0 on success, negative error code on failure
7762 int trash_get(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7766 auto iter
= in
->cbegin();
7768 } catch (const ceph::buffer::error
&err
) {
7772 CLS_LOG(20, "trash_get_image id=%s", id
.c_str());
7775 string key
= trash::image_key(id
);
7777 int r
= cls_cxx_map_get_val(hctx
, key
, out
);
7778 if (r
< 0 && r
!= -ENOENT
) {
7779 CLS_ERR("error reading image from trash '%s': '%s'", id
.c_str(),
7780 cpp_strerror(r
).c_str());
7786 * Set state of an image in the rbd_trash object.
7789 * @param id the id of the image
7790 * @param trash_state the state of the image to be set
7791 * @param expect_state the expected state of the image
7794 * @returns 0 on success, negative error code on failure
7796 int trash_state_set(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7799 cls::rbd::TrashImageState trash_state
;
7800 cls::rbd::TrashImageState expect_state
;
7802 auto iter
= in
->cbegin();
7804 decode(trash_state
, iter
);
7805 decode(expect_state
, iter
);
7806 } catch (const ceph::buffer::error
&err
) {
7810 CLS_LOG(20, "trash_state_set id=%s", id
.c_str());
7812 string key
= trash::image_key(id
);
7813 cls::rbd::TrashImageSpec trash_spec
;
7814 int r
= read_key(hctx
, key
, &trash_spec
);
7817 CLS_ERR("Could not read trash image spec off disk: %s",
7818 cpp_strerror(r
).c_str());
7823 if (trash_spec
.state
== expect_state
) {
7824 trash_spec
.state
= trash_state
;
7825 r
= write_key(hctx
, key
, trash_spec
);
7827 CLS_ERR("error setting trash image state: %s", cpp_strerror(r
).c_str());
7832 } else if (trash_spec
.state
== trash_state
) {
7835 CLS_ERR("Current trash state: %d do not match expected: %d or set: %d",
7836 trash_spec
.state
, expect_state
, trash_state
);
7843 const std::string
NAME_KEY_PREFIX("name_");
7845 std::string
key_for_name(const std::string
& name
) {
7846 return NAME_KEY_PREFIX
+ name
;
7849 std::string
name_from_key(const std::string
&key
) {
7850 return key
.substr(NAME_KEY_PREFIX
.size());
7853 } // namespace nspace
7856 * Add a namespace to the namespace directory.
7859 * @param name the name of the namespace
7862 * @returns -EEXIST if the namespace is already exists
7863 * @returns 0 on success, negative error code on failure
7865 int namespace_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7869 auto iter
= in
->cbegin();
7871 } catch (const ceph::buffer::error
&err
) {
7875 std::string
key(nspace::key_for_name(name
));
7877 int r
= cls_cxx_map_get_val(hctx
, key
, &value
);
7878 if (r
< 0 && r
!= -ENOENT
) {
7880 } else if (r
== 0) {
7884 r
= cls_cxx_map_set_val(hctx
, key
, &value
);
7886 CLS_ERR("failed to set omap key: %s", key
.c_str());
7894 * Remove a namespace from the namespace directory.
7897 * @param name the name of the namespace
7900 * @returns 0 on success, negative error code on failure
7902 int namespace_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7906 auto iter
= in
->cbegin();
7908 } catch (const ceph::buffer::error
&err
) {
7912 std::string
key(nspace::key_for_name(name
));
7914 int r
= cls_cxx_map_get_val(hctx
, key
, &bl
);
7919 r
= cls_cxx_map_remove_key(hctx
, key
);
7928 * Returns the list of namespaces in the rbd_namespace object
7931 * @param start_after which name to begin listing after
7932 * (use the empty string to start at the beginning)
7933 * @param max_return the maximum number of names to list
7936 * @param data list of namespace names
7937 * @returns 0 on success, negative error code on failure
7939 int namespace_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7942 uint64_t max_return
;
7944 auto iter
= in
->cbegin();
7945 decode(start_after
, iter
);
7946 decode(max_return
, iter
);
7947 } catch (const ceph::buffer::error
&err
) {
7951 std::list
<std::string
> data
;
7952 std::string last_read
= nspace::key_for_name(start_after
);
7955 CLS_LOG(20, "namespace_list");
7956 while (data
.size() < max_return
) {
7957 std::map
<std::string
, bufferlist
> raw_data
;
7958 int max_read
= std::min
<int32_t>(RBD_MAX_KEYS_READ
,
7959 max_return
- data
.size());
7960 int r
= cls_cxx_map_get_vals(hctx
, last_read
, nspace::NAME_KEY_PREFIX
,
7961 max_read
, &raw_data
, &more
);
7964 CLS_ERR("failed to read the vals off of disk: %s",
7965 cpp_strerror(r
).c_str());
7970 for (auto& it
: raw_data
) {
7971 data
.push_back(nspace::name_from_key(it
.first
));
7974 if (raw_data
.empty() || !more
) {
7978 last_read
= raw_data
.rbegin()->first
;
7986 * Reclaim space for zeroed extents
7989 * @param sparse_size minimal zeroed block to sparse
7990 * @param remove_empty boolean, true if the object should be removed if empty
7993 * @returns -ENOENT if the object does not exist or has been removed
7994 * @returns 0 on success, negative error code on failure
7996 int sparsify(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
7998 uint64_t sparse_size
;
8001 auto iter
= in
->cbegin();
8002 decode(sparse_size
, iter
);
8003 decode(remove_empty
, iter
);
8004 } catch (const ceph::buffer::error
&err
) {
8008 int r
= check_exists(hctx
);
8014 r
= cls_cxx_read(hctx
, 0, 0, &bl
);
8016 CLS_ERR("failed to read data off of disk: %s", cpp_strerror(r
).c_str());
8022 CLS_LOG(20, "remove");
8023 r
= cls_cxx_remove(hctx
);
8025 CLS_ERR("remove failed: %s", cpp_strerror(r
).c_str());
8028 } else if (bl
.length() > 0) {
8029 CLS_LOG(20, "truncate");
8030 bufferlist write_bl
;
8031 r
= cls_cxx_replace(hctx
, 0, 0, &write_bl
);
8033 CLS_ERR("truncate failed: %s", cpp_strerror(r
).c_str());
8037 CLS_LOG(20, "skip empty");
8042 bl
.rebuild(ceph::buffer::ptr_node::create(bl
.length()));
8043 size_t write_offset
= 0;
8044 size_t write_length
= 0;
8046 size_t length
= bl
.length();
8047 const auto& ptr
= bl
.front();
8048 bool replace
= true;
8049 while (offset
< length
) {
8050 if (calc_sparse_extent(ptr
, sparse_size
, length
, &write_offset
,
8051 &write_length
, &offset
)) {
8052 if (write_offset
== 0 && write_length
== length
) {
8053 CLS_LOG(20, "nothing to do");
8056 CLS_LOG(20, "write%s %" PRIu64
"~%" PRIu64
, (replace
? "(replace)" : ""),
8057 write_offset
, write_length
);
8058 bufferlist write_bl
;
8059 write_bl
.push_back(ceph::buffer::ptr_node::create(ptr
, write_offset
,
8062 r
= cls_cxx_replace(hctx
, write_offset
, write_length
, &write_bl
);
8065 r
= cls_cxx_write(hctx
, write_offset
, write_length
, &write_bl
);
8068 CLS_ERR("write failed: %s", cpp_strerror(r
).c_str());
8071 write_offset
= offset
;
8081 CLS_LOG(20, "Loaded rbd class!");
8083 cls_handle_t h_class
;
8084 cls_method_handle_t h_create
;
8085 cls_method_handle_t h_get_features
;
8086 cls_method_handle_t h_set_features
;
8087 cls_method_handle_t h_get_size
;
8088 cls_method_handle_t h_set_size
;
8089 cls_method_handle_t h_get_parent
;
8090 cls_method_handle_t h_set_parent
;
8091 cls_method_handle_t h_remove_parent
;
8092 cls_method_handle_t h_parent_get
;
8093 cls_method_handle_t h_parent_overlap_get
;
8094 cls_method_handle_t h_parent_attach
;
8095 cls_method_handle_t h_parent_detach
;
8096 cls_method_handle_t h_get_protection_status
;
8097 cls_method_handle_t h_set_protection_status
;
8098 cls_method_handle_t h_get_stripe_unit_count
;
8099 cls_method_handle_t h_set_stripe_unit_count
;
8100 cls_method_handle_t h_get_create_timestamp
;
8101 cls_method_handle_t h_get_access_timestamp
;
8102 cls_method_handle_t h_get_modify_timestamp
;
8103 cls_method_handle_t h_get_flags
;
8104 cls_method_handle_t h_set_flags
;
8105 cls_method_handle_t h_op_features_get
;
8106 cls_method_handle_t h_op_features_set
;
8107 cls_method_handle_t h_add_child
;
8108 cls_method_handle_t h_remove_child
;
8109 cls_method_handle_t h_get_children
;
8110 cls_method_handle_t h_get_snapcontext
;
8111 cls_method_handle_t h_get_object_prefix
;
8112 cls_method_handle_t h_get_data_pool
;
8113 cls_method_handle_t h_get_snapshot_name
;
8114 cls_method_handle_t h_get_snapshot_timestamp
;
8115 cls_method_handle_t h_snapshot_get
;
8116 cls_method_handle_t h_snapshot_add
;
8117 cls_method_handle_t h_snapshot_remove
;
8118 cls_method_handle_t h_snapshot_rename
;
8119 cls_method_handle_t h_snapshot_trash_add
;
8120 cls_method_handle_t h_get_all_features
;
8121 cls_method_handle_t h_get_id
;
8122 cls_method_handle_t h_set_id
;
8123 cls_method_handle_t h_set_modify_timestamp
;
8124 cls_method_handle_t h_set_access_timestamp
;
8125 cls_method_handle_t h_dir_get_id
;
8126 cls_method_handle_t h_dir_get_name
;
8127 cls_method_handle_t h_dir_list
;
8128 cls_method_handle_t h_dir_add_image
;
8129 cls_method_handle_t h_dir_remove_image
;
8130 cls_method_handle_t h_dir_rename_image
;
8131 cls_method_handle_t h_dir_state_assert
;
8132 cls_method_handle_t h_dir_state_set
;
8133 cls_method_handle_t h_object_map_load
;
8134 cls_method_handle_t h_object_map_save
;
8135 cls_method_handle_t h_object_map_resize
;
8136 cls_method_handle_t h_object_map_update
;
8137 cls_method_handle_t h_object_map_snap_add
;
8138 cls_method_handle_t h_object_map_snap_remove
;
8139 cls_method_handle_t h_metadata_set
;
8140 cls_method_handle_t h_metadata_remove
;
8141 cls_method_handle_t h_metadata_list
;
8142 cls_method_handle_t h_metadata_get
;
8143 cls_method_handle_t h_snapshot_get_limit
;
8144 cls_method_handle_t h_snapshot_set_limit
;
8145 cls_method_handle_t h_child_attach
;
8146 cls_method_handle_t h_child_detach
;
8147 cls_method_handle_t h_children_list
;
8148 cls_method_handle_t h_migration_set
;
8149 cls_method_handle_t h_migration_set_state
;
8150 cls_method_handle_t h_migration_get
;
8151 cls_method_handle_t h_migration_remove
;
8152 cls_method_handle_t h_old_snapshots_list
;
8153 cls_method_handle_t h_old_snapshot_add
;
8154 cls_method_handle_t h_old_snapshot_remove
;
8155 cls_method_handle_t h_old_snapshot_rename
;
8156 cls_method_handle_t h_mirror_uuid_get
;
8157 cls_method_handle_t h_mirror_uuid_set
;
8158 cls_method_handle_t h_mirror_mode_get
;
8159 cls_method_handle_t h_mirror_mode_set
;
8160 cls_method_handle_t h_mirror_peer_ping
;
8161 cls_method_handle_t h_mirror_peer_list
;
8162 cls_method_handle_t h_mirror_peer_add
;
8163 cls_method_handle_t h_mirror_peer_remove
;
8164 cls_method_handle_t h_mirror_peer_set_client
;
8165 cls_method_handle_t h_mirror_peer_set_cluster
;
8166 cls_method_handle_t h_mirror_peer_set_direction
;
8167 cls_method_handle_t h_mirror_image_list
;
8168 cls_method_handle_t h_mirror_image_get_image_id
;
8169 cls_method_handle_t h_mirror_image_get
;
8170 cls_method_handle_t h_mirror_image_set
;
8171 cls_method_handle_t h_mirror_image_remove
;
8172 cls_method_handle_t h_mirror_image_status_set
;
8173 cls_method_handle_t h_mirror_image_status_remove
;
8174 cls_method_handle_t h_mirror_image_status_get
;
8175 cls_method_handle_t h_mirror_image_status_list
;
8176 cls_method_handle_t h_mirror_image_status_get_summary
;
8177 cls_method_handle_t h_mirror_image_status_remove_down
;
8178 cls_method_handle_t h_mirror_image_instance_get
;
8179 cls_method_handle_t h_mirror_image_instance_list
;
8180 cls_method_handle_t h_mirror_instances_list
;
8181 cls_method_handle_t h_mirror_instances_add
;
8182 cls_method_handle_t h_mirror_instances_remove
;
8183 cls_method_handle_t h_mirror_image_map_list
;
8184 cls_method_handle_t h_mirror_image_map_update
;
8185 cls_method_handle_t h_mirror_image_map_remove
;
8186 cls_method_handle_t h_mirror_image_snapshot_unlink_peer
;
8187 cls_method_handle_t h_mirror_image_snapshot_set_copy_progress
;
8188 cls_method_handle_t h_group_dir_list
;
8189 cls_method_handle_t h_group_dir_add
;
8190 cls_method_handle_t h_group_dir_remove
;
8191 cls_method_handle_t h_group_dir_rename
;
8192 cls_method_handle_t h_group_image_remove
;
8193 cls_method_handle_t h_group_image_list
;
8194 cls_method_handle_t h_group_image_set
;
8195 cls_method_handle_t h_image_group_add
;
8196 cls_method_handle_t h_image_group_remove
;
8197 cls_method_handle_t h_image_group_get
;
8198 cls_method_handle_t h_group_snap_set
;
8199 cls_method_handle_t h_group_snap_remove
;
8200 cls_method_handle_t h_group_snap_get_by_id
;
8201 cls_method_handle_t h_group_snap_list
;
8202 cls_method_handle_t h_trash_add
;
8203 cls_method_handle_t h_trash_remove
;
8204 cls_method_handle_t h_trash_list
;
8205 cls_method_handle_t h_trash_get
;
8206 cls_method_handle_t h_trash_state_set
;
8207 cls_method_handle_t h_namespace_add
;
8208 cls_method_handle_t h_namespace_remove
;
8209 cls_method_handle_t h_namespace_list
;
8210 cls_method_handle_t h_copyup
;
8211 cls_method_handle_t h_sparse_copyup
;
8212 cls_method_handle_t h_assert_snapc_seq
;
8213 cls_method_handle_t h_sparsify
;
8215 cls_register("rbd", &h_class
);
8216 cls_register_cxx_method(h_class
, "create",
8217 CLS_METHOD_RD
| CLS_METHOD_WR
,
8219 cls_register_cxx_method(h_class
, "get_features",
8221 get_features
, &h_get_features
);
8222 cls_register_cxx_method(h_class
, "set_features",
8223 CLS_METHOD_RD
| CLS_METHOD_WR
,
8224 set_features
, &h_set_features
);
8225 cls_register_cxx_method(h_class
, "get_size",
8227 get_size
, &h_get_size
);
8228 cls_register_cxx_method(h_class
, "set_size",
8229 CLS_METHOD_RD
| CLS_METHOD_WR
,
8230 set_size
, &h_set_size
);
8231 cls_register_cxx_method(h_class
, "get_snapcontext",
8233 get_snapcontext
, &h_get_snapcontext
);
8234 cls_register_cxx_method(h_class
, "get_object_prefix",
8236 get_object_prefix
, &h_get_object_prefix
);
8237 cls_register_cxx_method(h_class
, "get_data_pool", CLS_METHOD_RD
,
8238 get_data_pool
, &h_get_data_pool
);
8239 cls_register_cxx_method(h_class
, "get_snapshot_name",
8241 get_snapshot_name
, &h_get_snapshot_name
);
8242 cls_register_cxx_method(h_class
, "get_snapshot_timestamp",
8244 get_snapshot_timestamp
, &h_get_snapshot_timestamp
);
8245 cls_register_cxx_method(h_class
, "snapshot_get",
8247 snapshot_get
, &h_snapshot_get
);
8248 cls_register_cxx_method(h_class
, "snapshot_add",
8249 CLS_METHOD_RD
| CLS_METHOD_WR
,
8250 snapshot_add
, &h_snapshot_add
);
8251 cls_register_cxx_method(h_class
, "snapshot_remove",
8252 CLS_METHOD_RD
| CLS_METHOD_WR
,
8253 snapshot_remove
, &h_snapshot_remove
);
8254 cls_register_cxx_method(h_class
, "snapshot_rename",
8255 CLS_METHOD_RD
| CLS_METHOD_WR
,
8256 snapshot_rename
, &h_snapshot_rename
);
8257 cls_register_cxx_method(h_class
, "snapshot_trash_add",
8258 CLS_METHOD_RD
| CLS_METHOD_WR
,
8259 snapshot_trash_add
, &h_snapshot_trash_add
);
8260 cls_register_cxx_method(h_class
, "get_all_features",
8262 get_all_features
, &h_get_all_features
);
8264 // NOTE: deprecate v1 parent APIs after mimic EOLed
8265 cls_register_cxx_method(h_class
, "get_parent",
8267 get_parent
, &h_get_parent
);
8268 cls_register_cxx_method(h_class
, "set_parent",
8269 CLS_METHOD_RD
| CLS_METHOD_WR
,
8270 set_parent
, &h_set_parent
);
8271 cls_register_cxx_method(h_class
, "remove_parent",
8272 CLS_METHOD_RD
| CLS_METHOD_WR
,
8273 remove_parent
, &h_remove_parent
);
8275 cls_register_cxx_method(h_class
, "parent_get",
8276 CLS_METHOD_RD
, parent_get
, &h_parent_get
);
8277 cls_register_cxx_method(h_class
, "parent_overlap_get",
8278 CLS_METHOD_RD
, parent_overlap_get
,
8279 &h_parent_overlap_get
);
8280 cls_register_cxx_method(h_class
, "parent_attach",
8281 CLS_METHOD_RD
| CLS_METHOD_WR
,
8282 parent_attach
, &h_parent_attach
);
8283 cls_register_cxx_method(h_class
, "parent_detach",
8284 CLS_METHOD_RD
| CLS_METHOD_WR
,
8285 parent_detach
, &h_parent_detach
);
8287 cls_register_cxx_method(h_class
, "set_protection_status",
8288 CLS_METHOD_RD
| CLS_METHOD_WR
,
8289 set_protection_status
, &h_set_protection_status
);
8290 cls_register_cxx_method(h_class
, "get_protection_status",
8292 get_protection_status
, &h_get_protection_status
);
8293 cls_register_cxx_method(h_class
, "get_stripe_unit_count",
8295 get_stripe_unit_count
, &h_get_stripe_unit_count
);
8296 cls_register_cxx_method(h_class
, "set_stripe_unit_count",
8297 CLS_METHOD_RD
| CLS_METHOD_WR
,
8298 set_stripe_unit_count
, &h_set_stripe_unit_count
);
8299 cls_register_cxx_method(h_class
, "get_create_timestamp",
8301 get_create_timestamp
, &h_get_create_timestamp
);
8302 cls_register_cxx_method(h_class
, "get_access_timestamp",
8304 get_access_timestamp
, &h_get_access_timestamp
);
8305 cls_register_cxx_method(h_class
, "get_modify_timestamp",
8307 get_modify_timestamp
, &h_get_modify_timestamp
);
8308 cls_register_cxx_method(h_class
, "get_flags",
8310 get_flags
, &h_get_flags
);
8311 cls_register_cxx_method(h_class
, "set_flags",
8312 CLS_METHOD_RD
| CLS_METHOD_WR
,
8313 set_flags
, &h_set_flags
);
8314 cls_register_cxx_method(h_class
, "op_features_get", CLS_METHOD_RD
,
8315 op_features_get
, &h_op_features_get
);
8316 cls_register_cxx_method(h_class
, "op_features_set",
8317 CLS_METHOD_RD
| CLS_METHOD_WR
,
8318 op_features_set
, &h_op_features_set
);
8319 cls_register_cxx_method(h_class
, "metadata_list",
8321 metadata_list
, &h_metadata_list
);
8322 cls_register_cxx_method(h_class
, "metadata_set",
8323 CLS_METHOD_RD
| CLS_METHOD_WR
,
8324 metadata_set
, &h_metadata_set
);
8325 cls_register_cxx_method(h_class
, "metadata_remove",
8326 CLS_METHOD_RD
| CLS_METHOD_WR
,
8327 metadata_remove
, &h_metadata_remove
);
8328 cls_register_cxx_method(h_class
, "metadata_get",
8330 metadata_get
, &h_metadata_get
);
8331 cls_register_cxx_method(h_class
, "snapshot_get_limit",
8333 snapshot_get_limit
, &h_snapshot_get_limit
);
8334 cls_register_cxx_method(h_class
, "snapshot_set_limit",
8335 CLS_METHOD_RD
| CLS_METHOD_WR
,
8336 snapshot_set_limit
, &h_snapshot_set_limit
);
8337 cls_register_cxx_method(h_class
, "child_attach",
8338 CLS_METHOD_RD
| CLS_METHOD_WR
,
8339 child_attach
, &h_child_attach
);
8340 cls_register_cxx_method(h_class
, "child_detach",
8341 CLS_METHOD_RD
| CLS_METHOD_WR
,
8342 child_detach
, &h_child_detach
);
8343 cls_register_cxx_method(h_class
, "children_list",
8345 children_list
, &h_children_list
);
8346 cls_register_cxx_method(h_class
, "migration_set",
8347 CLS_METHOD_RD
| CLS_METHOD_WR
,
8348 migration_set
, &h_migration_set
);
8349 cls_register_cxx_method(h_class
, "migration_set_state",
8350 CLS_METHOD_RD
| CLS_METHOD_WR
,
8351 migration_set_state
, &h_migration_set_state
);
8352 cls_register_cxx_method(h_class
, "migration_get",
8354 migration_get
, &h_migration_get
);
8355 cls_register_cxx_method(h_class
, "migration_remove",
8356 CLS_METHOD_RD
| CLS_METHOD_WR
,
8357 migration_remove
, &h_migration_remove
);
8359 cls_register_cxx_method(h_class
, "set_modify_timestamp",
8360 CLS_METHOD_RD
| CLS_METHOD_WR
,
8361 set_modify_timestamp
, &h_set_modify_timestamp
);
8363 cls_register_cxx_method(h_class
, "set_access_timestamp",
8364 CLS_METHOD_RD
| CLS_METHOD_WR
,
8365 set_access_timestamp
, &h_set_access_timestamp
);
8367 /* methods for the rbd_children object */
8368 cls_register_cxx_method(h_class
, "add_child",
8369 CLS_METHOD_RD
| CLS_METHOD_WR
,
8370 add_child
, &h_add_child
);
8371 cls_register_cxx_method(h_class
, "remove_child",
8372 CLS_METHOD_RD
| CLS_METHOD_WR
,
8373 remove_child
, &h_remove_child
);
8374 cls_register_cxx_method(h_class
, "get_children",
8376 get_children
, &h_get_children
);
8378 /* methods for the rbd_id.$image_name objects */
8379 cls_register_cxx_method(h_class
, "get_id",
8382 cls_register_cxx_method(h_class
, "set_id",
8383 CLS_METHOD_RD
| CLS_METHOD_WR
,
8386 /* methods for the rbd_directory object */
8387 cls_register_cxx_method(h_class
, "dir_get_id",
8389 dir_get_id
, &h_dir_get_id
);
8390 cls_register_cxx_method(h_class
, "dir_get_name",
8392 dir_get_name
, &h_dir_get_name
);
8393 cls_register_cxx_method(h_class
, "dir_list",
8395 dir_list
, &h_dir_list
);
8396 cls_register_cxx_method(h_class
, "dir_add_image",
8397 CLS_METHOD_RD
| CLS_METHOD_WR
,
8398 dir_add_image
, &h_dir_add_image
);
8399 cls_register_cxx_method(h_class
, "dir_remove_image",
8400 CLS_METHOD_RD
| CLS_METHOD_WR
,
8401 dir_remove_image
, &h_dir_remove_image
);
8402 cls_register_cxx_method(h_class
, "dir_rename_image",
8403 CLS_METHOD_RD
| CLS_METHOD_WR
,
8404 dir_rename_image
, &h_dir_rename_image
);
8405 cls_register_cxx_method(h_class
, "dir_state_assert", CLS_METHOD_RD
,
8406 dir_state_assert
, &h_dir_state_assert
);
8407 cls_register_cxx_method(h_class
, "dir_state_set",
8408 CLS_METHOD_RD
| CLS_METHOD_WR
,
8409 dir_state_set
, &h_dir_state_set
);
8411 /* methods for the rbd_object_map.$image_id object */
8412 cls_register_cxx_method(h_class
, "object_map_load",
8414 object_map_load
, &h_object_map_load
);
8415 cls_register_cxx_method(h_class
, "object_map_save",
8416 CLS_METHOD_RD
| CLS_METHOD_WR
,
8417 object_map_save
, &h_object_map_save
);
8418 cls_register_cxx_method(h_class
, "object_map_resize",
8419 CLS_METHOD_RD
| CLS_METHOD_WR
,
8420 object_map_resize
, &h_object_map_resize
);
8421 cls_register_cxx_method(h_class
, "object_map_update",
8422 CLS_METHOD_RD
| CLS_METHOD_WR
,
8423 object_map_update
, &h_object_map_update
);
8424 cls_register_cxx_method(h_class
, "object_map_snap_add",
8425 CLS_METHOD_RD
| CLS_METHOD_WR
,
8426 object_map_snap_add
, &h_object_map_snap_add
);
8427 cls_register_cxx_method(h_class
, "object_map_snap_remove",
8428 CLS_METHOD_RD
| CLS_METHOD_WR
,
8429 object_map_snap_remove
, &h_object_map_snap_remove
);
8431 /* methods for the old format */
8432 cls_register_cxx_method(h_class
, "snap_list",
8434 old_snapshots_list
, &h_old_snapshots_list
);
8435 cls_register_cxx_method(h_class
, "snap_add",
8436 CLS_METHOD_RD
| CLS_METHOD_WR
,
8437 old_snapshot_add
, &h_old_snapshot_add
);
8438 cls_register_cxx_method(h_class
, "snap_remove",
8439 CLS_METHOD_RD
| CLS_METHOD_WR
,
8440 old_snapshot_remove
, &h_old_snapshot_remove
);
8441 cls_register_cxx_method(h_class
, "snap_rename",
8442 CLS_METHOD_RD
| CLS_METHOD_WR
,
8443 old_snapshot_rename
, &h_old_snapshot_rename
);
8445 /* methods for the rbd_mirroring object */
8446 cls_register_cxx_method(h_class
, "mirror_uuid_get", CLS_METHOD_RD
,
8447 mirror_uuid_get
, &h_mirror_uuid_get
);
8448 cls_register_cxx_method(h_class
, "mirror_uuid_set",
8449 CLS_METHOD_RD
| CLS_METHOD_WR
,
8450 mirror_uuid_set
, &h_mirror_uuid_set
);
8451 cls_register_cxx_method(h_class
, "mirror_mode_get", CLS_METHOD_RD
,
8452 mirror_mode_get
, &h_mirror_mode_get
);
8453 cls_register_cxx_method(h_class
, "mirror_mode_set",
8454 CLS_METHOD_RD
| CLS_METHOD_WR
,
8455 mirror_mode_set
, &h_mirror_mode_set
);
8456 cls_register_cxx_method(h_class
, "mirror_peer_ping",
8457 CLS_METHOD_RD
| CLS_METHOD_WR
,
8458 mirror_peer_ping
, &h_mirror_peer_ping
);
8459 cls_register_cxx_method(h_class
, "mirror_peer_list", CLS_METHOD_RD
,
8460 mirror_peer_list
, &h_mirror_peer_list
);
8461 cls_register_cxx_method(h_class
, "mirror_peer_add",
8462 CLS_METHOD_RD
| CLS_METHOD_WR
,
8463 mirror_peer_add
, &h_mirror_peer_add
);
8464 cls_register_cxx_method(h_class
, "mirror_peer_remove",
8465 CLS_METHOD_RD
| CLS_METHOD_WR
,
8466 mirror_peer_remove
, &h_mirror_peer_remove
);
8467 cls_register_cxx_method(h_class
, "mirror_peer_set_client",
8468 CLS_METHOD_RD
| CLS_METHOD_WR
,
8469 mirror_peer_set_client
, &h_mirror_peer_set_client
);
8470 cls_register_cxx_method(h_class
, "mirror_peer_set_cluster",
8471 CLS_METHOD_RD
| CLS_METHOD_WR
,
8472 mirror_peer_set_cluster
, &h_mirror_peer_set_cluster
);
8473 cls_register_cxx_method(h_class
, "mirror_peer_set_direction",
8474 CLS_METHOD_RD
| CLS_METHOD_WR
,
8475 mirror_peer_set_direction
,
8476 &h_mirror_peer_set_direction
);
8477 cls_register_cxx_method(h_class
, "mirror_image_list", CLS_METHOD_RD
,
8478 mirror_image_list
, &h_mirror_image_list
);
8479 cls_register_cxx_method(h_class
, "mirror_image_get_image_id", CLS_METHOD_RD
,
8480 mirror_image_get_image_id
,
8481 &h_mirror_image_get_image_id
);
8482 cls_register_cxx_method(h_class
, "mirror_image_get", CLS_METHOD_RD
,
8483 mirror_image_get
, &h_mirror_image_get
);
8484 cls_register_cxx_method(h_class
, "mirror_image_set",
8485 CLS_METHOD_RD
| CLS_METHOD_WR
,
8486 mirror_image_set
, &h_mirror_image_set
);
8487 cls_register_cxx_method(h_class
, "mirror_image_remove",
8488 CLS_METHOD_RD
| CLS_METHOD_WR
,
8489 mirror_image_remove
, &h_mirror_image_remove
);
8490 cls_register_cxx_method(h_class
, "mirror_image_status_set",
8491 CLS_METHOD_RD
| CLS_METHOD_WR
| CLS_METHOD_PROMOTE
,
8492 mirror_image_status_set
, &h_mirror_image_status_set
);
8493 cls_register_cxx_method(h_class
, "mirror_image_status_remove",
8494 CLS_METHOD_RD
| CLS_METHOD_WR
,
8495 mirror_image_status_remove
,
8496 &h_mirror_image_status_remove
);
8497 cls_register_cxx_method(h_class
, "mirror_image_status_get", CLS_METHOD_RD
,
8498 mirror_image_status_get
, &h_mirror_image_status_get
);
8499 cls_register_cxx_method(h_class
, "mirror_image_status_list", CLS_METHOD_RD
,
8500 mirror_image_status_list
,
8501 &h_mirror_image_status_list
);
8502 cls_register_cxx_method(h_class
, "mirror_image_status_get_summary",
8503 CLS_METHOD_RD
, mirror_image_status_get_summary
,
8504 &h_mirror_image_status_get_summary
);
8505 cls_register_cxx_method(h_class
, "mirror_image_status_remove_down",
8506 CLS_METHOD_RD
| CLS_METHOD_WR
,
8507 mirror_image_status_remove_down
,
8508 &h_mirror_image_status_remove_down
);
8509 cls_register_cxx_method(h_class
, "mirror_image_instance_get", CLS_METHOD_RD
,
8510 mirror_image_instance_get
,
8511 &h_mirror_image_instance_get
);
8512 cls_register_cxx_method(h_class
, "mirror_image_instance_list", CLS_METHOD_RD
,
8513 mirror_image_instance_list
,
8514 &h_mirror_image_instance_list
);
8515 cls_register_cxx_method(h_class
, "mirror_instances_list", CLS_METHOD_RD
,
8516 mirror_instances_list
, &h_mirror_instances_list
);
8517 cls_register_cxx_method(h_class
, "mirror_instances_add",
8518 CLS_METHOD_RD
| CLS_METHOD_WR
| CLS_METHOD_PROMOTE
,
8519 mirror_instances_add
, &h_mirror_instances_add
);
8520 cls_register_cxx_method(h_class
, "mirror_instances_remove",
8521 CLS_METHOD_RD
| CLS_METHOD_WR
,
8522 mirror_instances_remove
,
8523 &h_mirror_instances_remove
);
8524 cls_register_cxx_method(h_class
, "mirror_image_map_list",
8525 CLS_METHOD_RD
, mirror_image_map_list
,
8526 &h_mirror_image_map_list
);
8527 cls_register_cxx_method(h_class
, "mirror_image_map_update",
8528 CLS_METHOD_WR
, mirror_image_map_update
,
8529 &h_mirror_image_map_update
);
8530 cls_register_cxx_method(h_class
, "mirror_image_map_remove",
8531 CLS_METHOD_WR
, mirror_image_map_remove
,
8532 &h_mirror_image_map_remove
);
8533 cls_register_cxx_method(h_class
, "mirror_image_snapshot_unlink_peer",
8534 CLS_METHOD_RD
| CLS_METHOD_WR
,
8535 mirror_image_snapshot_unlink_peer
,
8536 &h_mirror_image_snapshot_unlink_peer
);
8537 cls_register_cxx_method(h_class
, "mirror_image_snapshot_set_copy_progress",
8538 CLS_METHOD_RD
| CLS_METHOD_WR
,
8539 mirror_image_snapshot_set_copy_progress
,
8540 &h_mirror_image_snapshot_set_copy_progress
);
8542 /* methods for the groups feature */
8543 cls_register_cxx_method(h_class
, "group_dir_list",
8545 group_dir_list
, &h_group_dir_list
);
8546 cls_register_cxx_method(h_class
, "group_dir_add",
8547 CLS_METHOD_RD
| CLS_METHOD_WR
,
8548 group_dir_add
, &h_group_dir_add
);
8549 cls_register_cxx_method(h_class
, "group_dir_remove",
8550 CLS_METHOD_RD
| CLS_METHOD_WR
,
8551 group_dir_remove
, &h_group_dir_remove
);
8552 cls_register_cxx_method(h_class
, "group_dir_rename",
8553 CLS_METHOD_RD
| CLS_METHOD_WR
,
8554 group_dir_rename
, &h_group_dir_rename
);
8555 cls_register_cxx_method(h_class
, "group_image_remove",
8556 CLS_METHOD_RD
| CLS_METHOD_WR
,
8557 group_image_remove
, &h_group_image_remove
);
8558 cls_register_cxx_method(h_class
, "group_image_list",
8560 group_image_list
, &h_group_image_list
);
8561 cls_register_cxx_method(h_class
, "group_image_set",
8562 CLS_METHOD_RD
| CLS_METHOD_WR
,
8563 group_image_set
, &h_group_image_set
);
8564 cls_register_cxx_method(h_class
, "image_group_add",
8565 CLS_METHOD_RD
| CLS_METHOD_WR
,
8566 image_group_add
, &h_image_group_add
);
8567 cls_register_cxx_method(h_class
, "image_group_remove",
8568 CLS_METHOD_RD
| CLS_METHOD_WR
,
8569 image_group_remove
, &h_image_group_remove
);
8570 cls_register_cxx_method(h_class
, "image_group_get",
8572 image_group_get
, &h_image_group_get
);
8573 cls_register_cxx_method(h_class
, "group_snap_set",
8574 CLS_METHOD_RD
| CLS_METHOD_WR
,
8575 group_snap_set
, &h_group_snap_set
);
8576 cls_register_cxx_method(h_class
, "group_snap_remove",
8577 CLS_METHOD_RD
| CLS_METHOD_WR
,
8578 group_snap_remove
, &h_group_snap_remove
);
8579 cls_register_cxx_method(h_class
, "group_snap_get_by_id",
8581 group_snap_get_by_id
, &h_group_snap_get_by_id
);
8582 cls_register_cxx_method(h_class
, "group_snap_list",
8584 group_snap_list
, &h_group_snap_list
);
8586 /* rbd_trash object methods */
8587 cls_register_cxx_method(h_class
, "trash_add",
8588 CLS_METHOD_RD
| CLS_METHOD_WR
,
8589 trash_add
, &h_trash_add
);
8590 cls_register_cxx_method(h_class
, "trash_remove",
8591 CLS_METHOD_RD
| CLS_METHOD_WR
,
8592 trash_remove
, &h_trash_remove
);
8593 cls_register_cxx_method(h_class
, "trash_list",
8595 trash_list
, &h_trash_list
);
8596 cls_register_cxx_method(h_class
, "trash_get",
8598 trash_get
, &h_trash_get
);
8599 cls_register_cxx_method(h_class
, "trash_state_set",
8600 CLS_METHOD_RD
| CLS_METHOD_WR
,
8601 trash_state_set
, &h_trash_state_set
);
8603 /* rbd_namespace object methods */
8604 cls_register_cxx_method(h_class
, "namespace_add",
8605 CLS_METHOD_RD
| CLS_METHOD_WR
,
8606 namespace_add
, &h_namespace_add
);
8607 cls_register_cxx_method(h_class
, "namespace_remove",
8608 CLS_METHOD_RD
| CLS_METHOD_WR
,
8609 namespace_remove
, &h_namespace_remove
);
8610 cls_register_cxx_method(h_class
, "namespace_list", CLS_METHOD_RD
,
8611 namespace_list
, &h_namespace_list
);
8613 /* data object methods */
8614 cls_register_cxx_method(h_class
, "copyup",
8615 CLS_METHOD_RD
| CLS_METHOD_WR
,
8617 cls_register_cxx_method(h_class
, "sparse_copyup",
8618 CLS_METHOD_RD
| CLS_METHOD_WR
,
8619 sparse_copyup
, &h_sparse_copyup
);
8620 cls_register_cxx_method(h_class
, "assert_snapc_seq",
8621 CLS_METHOD_RD
| CLS_METHOD_WR
,
8623 &h_assert_snapc_seq
);
8624 cls_register_cxx_method(h_class
, "sparsify",
8625 CLS_METHOD_RD
| CLS_METHOD_WR
,
8626 sparsify
, &h_sparsify
);