]> git.proxmox.com Git - ceph.git/blob - ceph/src/cls/rbd/cls_rbd.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / cls / rbd / cls_rbd.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 /** \file
5 *
6 * This is an OSD class that implements methods for
7 * use with rbd.
8 *
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.
12 *
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.
23 *
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.
27 */
28 #include "include/types.h"
29
30 #include <algorithm>
31 #include <errno.h>
32 #include <sstream>
33
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"
41
42 #include "cls/rbd/cls_rbd.h"
43 #include "cls/rbd/cls_rbd_types.h"
44
45
46 /*
47 * Object keys:
48 *
49 * <partial list>
50 *
51 * stripe_unit: size in bytes of the stripe unit. if not present,
52 * the stripe unit is assumed to match the object size (1 << order).
53 *
54 * stripe_count: number of objects to stripe over before looping back.
55 * if not present or 1, striping is disabled. this is the default.
56 *
57 */
58
59 CLS_VER(2,0)
60 CLS_NAME(rbd)
61
62 #define RBD_MAX_KEYS_READ 64
63 #define RBD_SNAP_KEY_PREFIX "snapshot_"
64 #define RBD_SNAP_CHILDREN_KEY_PREFIX "snap_children_"
65 #define RBD_DIR_ID_KEY_PREFIX "id_"
66 #define RBD_DIR_NAME_KEY_PREFIX "name_"
67 #define RBD_METADATA_KEY_PREFIX "metadata_"
68
69 namespace {
70
71 uint64_t get_encode_features(cls_method_context_t hctx) {
72 uint64_t features = 0;
73 int8_t require_osd_release = cls_get_required_osd_release(hctx);
74 if (require_osd_release >= CEPH_RELEASE_NAUTILUS) {
75 features |= CEPH_FEATURE_SERVER_NAUTILUS;
76 }
77 return features;
78 }
79
80 bool calc_sparse_extent(const bufferptr &bp, size_t sparse_size,
81 uint64_t length, size_t *write_offset,
82 size_t *write_length, size_t *offset) {
83 size_t extent_size;
84 if (*offset + sparse_size > length) {
85 extent_size = length - *offset;
86 } else {
87 extent_size = sparse_size;
88 }
89
90 bufferptr extent(bp, *offset, extent_size);
91 *offset += extent_size;
92
93 bool extent_is_zero = extent.is_zero();
94 if (!extent_is_zero) {
95 *write_length += extent_size;
96 }
97 if (extent_is_zero && *write_length == 0) {
98 *write_offset += extent_size;
99 }
100
101 if ((extent_is_zero || *offset == length) && *write_length != 0) {
102 return true;
103 }
104 return false;
105 }
106
107 } // anonymous namespace
108
109 static int snap_read_header(cls_method_context_t hctx, bufferlist& bl)
110 {
111 unsigned snap_count = 0;
112 uint64_t snap_names_len = 0;
113 struct rbd_obj_header_ondisk *header;
114
115 CLS_LOG(20, "snapshots_list");
116
117 while (1) {
118 int len = sizeof(*header) +
119 snap_count * sizeof(struct rbd_obj_snap_ondisk) +
120 snap_names_len;
121
122 int rc = cls_cxx_read(hctx, 0, len, &bl);
123 if (rc < 0)
124 return rc;
125
126 if (bl.length() < sizeof(*header))
127 return -EINVAL;
128
129 header = (struct rbd_obj_header_ondisk *)bl.c_str();
130 ceph_assert(header);
131
132 if ((snap_count != header->snap_count) ||
133 (snap_names_len != header->snap_names_len)) {
134 snap_count = header->snap_count;
135 snap_names_len = header->snap_names_len;
136 bl.clear();
137 continue;
138 }
139 break;
140 }
141
142 return 0;
143 }
144
145 static void key_from_snap_id(snapid_t snap_id, string *out)
146 {
147 ostringstream oss;
148 oss << RBD_SNAP_KEY_PREFIX
149 << std::setw(16) << std::setfill('0') << std::hex << snap_id;
150 *out = oss.str();
151 }
152
153 static snapid_t snap_id_from_key(const string &key) {
154 istringstream iss(key);
155 uint64_t id;
156 iss.ignore(strlen(RBD_SNAP_KEY_PREFIX)) >> std::hex >> id;
157 return id;
158 }
159
160 template<typename T>
161 static int read_key(cls_method_context_t hctx, const string &key, T *out)
162 {
163 bufferlist bl;
164 int r = cls_cxx_map_get_val(hctx, key, &bl);
165 if (r < 0) {
166 if (r != -ENOENT) {
167 CLS_ERR("error reading omap key %s: %s", key.c_str(), cpp_strerror(r).c_str());
168 }
169 return r;
170 }
171
172 try {
173 auto it = bl.cbegin();
174 decode(*out, it);
175 } catch (const buffer::error &err) {
176 CLS_ERR("error decoding %s", key.c_str());
177 return -EIO;
178 }
179
180 return 0;
181 }
182
183 template <typename T>
184 static int write_key(cls_method_context_t hctx, const string &key, const T &t) {
185 bufferlist bl;
186 encode(t, bl);
187
188 int r = cls_cxx_map_set_val(hctx, key, &bl);
189 if (r < 0) {
190 CLS_ERR("failed to set omap key: %s", key.c_str());
191 return r;
192 }
193 return 0;
194 }
195
196 template <typename T>
197 static int write_key(cls_method_context_t hctx, const string &key, const T &t,
198 uint64_t features) {
199 bufferlist bl;
200 encode(t, bl, features);
201
202 int r = cls_cxx_map_set_val(hctx, key, &bl);
203 if (r < 0) {
204 CLS_ERR("failed to set omap key: %s", key.c_str());
205 return r;
206 }
207 return 0;
208 }
209
210 static int remove_key(cls_method_context_t hctx, const string &key) {
211 int r = cls_cxx_map_remove_key(hctx, key);
212 if (r < 0 && r != -ENOENT) {
213 CLS_ERR("failed to remove key: %s", key.c_str());
214 return r;
215 }
216 return 0;
217 }
218
219 static bool is_valid_id(const string &id) {
220 if (!id.size())
221 return false;
222 for (size_t i = 0; i < id.size(); ++i) {
223 if (!isalnum(id[i])) {
224 return false;
225 }
226 }
227 return true;
228 }
229
230 /**
231 * verify that the header object exists
232 *
233 * @return 0 if the object exists, -ENOENT if it does not, or other error
234 */
235 static int check_exists(cls_method_context_t hctx)
236 {
237 uint64_t size;
238 time_t mtime;
239 return cls_cxx_stat(hctx, &size, &mtime);
240 }
241
242 namespace image {
243
244 /**
245 * check that given feature(s) are set
246 *
247 * @param hctx context
248 * @param need features needed
249 * @return 0 if features are set, negative error (like ENOEXEC) otherwise
250 */
251 int require_feature(cls_method_context_t hctx, uint64_t need)
252 {
253 uint64_t features;
254 int r = read_key(hctx, "features", &features);
255 if (r == -ENOENT) // this implies it's an old-style image with no features
256 return -ENOEXEC;
257 if (r < 0)
258 return r;
259 if ((features & need) != need) {
260 CLS_LOG(10, "require_feature missing feature %llx, have %llx",
261 (unsigned long long)need, (unsigned long long)features);
262 return -ENOEXEC;
263 }
264 return 0;
265 }
266
267 std::string snap_children_key_from_snap_id(snapid_t snap_id)
268 {
269 ostringstream oss;
270 oss << RBD_SNAP_CHILDREN_KEY_PREFIX
271 << std::setw(16) << std::setfill('0') << std::hex << snap_id;
272 return oss.str();
273 }
274
275 int set_op_features(cls_method_context_t hctx, uint64_t op_features,
276 uint64_t mask) {
277 uint64_t orig_features;
278 int r = read_key(hctx, "features", &orig_features);
279 if (r < 0) {
280 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r).c_str());
281 return r;
282 }
283
284 uint64_t orig_op_features = 0;
285 r = read_key(hctx, "op_features", &orig_op_features);
286 if (r < 0 && r != -ENOENT) {
287 CLS_ERR("Could not read op features off disk: %s", cpp_strerror(r).c_str());
288 return r;
289 }
290
291 op_features = (orig_op_features & ~mask) | (op_features & mask);
292 CLS_LOG(10, "op_features=%" PRIu64 " orig_op_features=%" PRIu64,
293 op_features, orig_op_features);
294 if (op_features == orig_op_features) {
295 return 0;
296 }
297
298 uint64_t features = orig_features;
299 if (op_features == 0ULL) {
300 features &= ~RBD_FEATURE_OPERATIONS;
301
302 r = cls_cxx_map_remove_key(hctx, "op_features");
303 if (r == -ENOENT) {
304 r = 0;
305 }
306 } else {
307 features |= RBD_FEATURE_OPERATIONS;
308
309 bufferlist bl;
310 encode(op_features, bl);
311 r = cls_cxx_map_set_val(hctx, "op_features", &bl);
312 }
313
314 if (r < 0) {
315 CLS_ERR("error updating op features: %s", cpp_strerror(r).c_str());
316 return r;
317 }
318
319 if (features != orig_features) {
320 bufferlist bl;
321 encode(features, bl);
322 r = cls_cxx_map_set_val(hctx, "features", &bl);
323 if (r < 0) {
324 CLS_ERR("error updating features: %s", cpp_strerror(r).c_str());
325 return r;
326 }
327 }
328
329 return 0;
330 }
331
332 int set_migration(cls_method_context_t hctx,
333 const cls::rbd::MigrationSpec &migration_spec, bool init) {
334 if (init) {
335 bufferlist bl;
336 int r = cls_cxx_map_get_val(hctx, "migration", &bl);
337 if (r != -ENOENT) {
338 if (r == 0) {
339 CLS_LOG(10, "migration already set");
340 return -EEXIST;
341 }
342 CLS_ERR("failed to read migration off disk: %s", cpp_strerror(r).c_str());
343 return r;
344 }
345
346 uint64_t features = 0;
347 r = read_key(hctx, "features", &features);
348 if (r == -ENOENT) {
349 CLS_LOG(20, "no features, assuming v1 format");
350 bufferlist header;
351 r = cls_cxx_read(hctx, 0, sizeof(RBD_HEADER_TEXT), &header);
352 if (r < 0) {
353 CLS_ERR("failed to read v1 header: %s", cpp_strerror(r).c_str());
354 return r;
355 }
356 if (header.length() != sizeof(RBD_HEADER_TEXT)) {
357 CLS_ERR("unrecognized v1 header format");
358 return -ENXIO;
359 }
360 if (memcmp(RBD_HEADER_TEXT, header.c_str(), header.length()) != 0) {
361 if (memcmp(RBD_MIGRATE_HEADER_TEXT, header.c_str(),
362 header.length()) == 0) {
363 CLS_LOG(10, "migration already set");
364 return -EEXIST;
365 } else {
366 CLS_ERR("unrecognized v1 header format");
367 return -ENXIO;
368 }
369 }
370 if (migration_spec.header_type != cls::rbd::MIGRATION_HEADER_TYPE_SRC) {
371 CLS_LOG(10, "v1 format image can only be migration source");
372 return -EINVAL;
373 }
374
375 header.clear();
376 header.append(RBD_MIGRATE_HEADER_TEXT);
377 r = cls_cxx_write(hctx, 0, header.length(), &header);
378 if (r < 0) {
379 CLS_ERR("error updating v1 header: %s", cpp_strerror(r).c_str());
380 return r;
381 }
382 } else if (r < 0) {
383 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r).c_str());
384 return r;
385 } else if ((features & RBD_FEATURE_MIGRATING) != 0ULL) {
386 if (migration_spec.header_type != cls::rbd::MIGRATION_HEADER_TYPE_DST) {
387 CLS_LOG(10, "migrating feature already set");
388 return -EEXIST;
389 }
390 } else {
391 features |= RBD_FEATURE_MIGRATING;
392 bl.clear();
393 encode(features, bl);
394 r = cls_cxx_map_set_val(hctx, "features", &bl);
395 if (r < 0) {
396 CLS_ERR("error updating features: %s", cpp_strerror(r).c_str());
397 return r;
398 }
399 }
400 }
401
402 bufferlist bl;
403 encode(migration_spec, bl);
404 int r = cls_cxx_map_set_val(hctx, "migration", &bl);
405 if (r < 0) {
406 CLS_ERR("error setting migration: %s", cpp_strerror(r).c_str());
407 return r;
408 }
409
410 return 0;
411 }
412
413 int read_migration(cls_method_context_t hctx,
414 cls::rbd::MigrationSpec *migration_spec) {
415 uint64_t features = 0;
416 int r = read_key(hctx, "features", &features);
417 if (r == -ENOENT) {
418 CLS_LOG(20, "no features, assuming v1 format");
419 bufferlist header;
420 r = cls_cxx_read(hctx, 0, sizeof(RBD_HEADER_TEXT), &header);
421 if (r < 0) {
422 CLS_ERR("failed to read v1 header: %s", cpp_strerror(r).c_str());
423 return r;
424 }
425 if (header.length() != sizeof(RBD_HEADER_TEXT)) {
426 CLS_ERR("unrecognized v1 header format");
427 return -ENXIO;
428 }
429 if (memcmp(RBD_MIGRATE_HEADER_TEXT, header.c_str(), header.length()) != 0) {
430 if (memcmp(RBD_HEADER_TEXT, header.c_str(), header.length()) == 0) {
431 CLS_LOG(10, "migration feature not set");
432 return -EINVAL;
433 } else {
434 CLS_ERR("unrecognized v1 header format");
435 return -ENXIO;
436 }
437 }
438 if (migration_spec->header_type != cls::rbd::MIGRATION_HEADER_TYPE_SRC) {
439 CLS_LOG(10, "v1 format image can only be migration source");
440 return -EINVAL;
441 }
442 } else if (r < 0) {
443 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r).c_str());
444 return r;
445 } else if ((features & RBD_FEATURE_MIGRATING) == 0ULL) {
446 CLS_LOG(10, "migration feature not set");
447 return -EINVAL;
448 }
449
450 r = read_key(hctx, "migration", migration_spec);
451 if (r < 0) {
452 CLS_ERR("failed to read migration off disk: %s", cpp_strerror(r).c_str());
453 return r;
454 }
455
456 return 0;
457 }
458
459 int remove_migration(cls_method_context_t hctx) {
460 int r = remove_key(hctx, "migration");
461 if (r < 0) {
462 return r;
463 }
464
465 uint64_t features = 0;
466 r = read_key(hctx, "features", &features);
467 if (r == -ENOENT) {
468 CLS_LOG(20, "no features, assuming v1 format");
469 bufferlist header;
470 r = cls_cxx_read(hctx, 0, sizeof(RBD_MIGRATE_HEADER_TEXT), &header);
471 if (header.length() != sizeof(RBD_MIGRATE_HEADER_TEXT)) {
472 CLS_ERR("unrecognized v1 header format");
473 return -ENXIO;
474 }
475 if (memcmp(RBD_MIGRATE_HEADER_TEXT, header.c_str(), header.length()) != 0) {
476 if (memcmp(RBD_HEADER_TEXT, header.c_str(), header.length()) == 0) {
477 CLS_LOG(10, "migration feature not set");
478 return -EINVAL;
479 } else {
480 CLS_ERR("unrecognized v1 header format");
481 return -ENXIO;
482 }
483 }
484 header.clear();
485 header.append(RBD_HEADER_TEXT);
486 r = cls_cxx_write(hctx, 0, header.length(), &header);
487 if (r < 0) {
488 CLS_ERR("error updating v1 header: %s", cpp_strerror(r).c_str());
489 return r;
490 }
491 } else if (r < 0) {
492 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r).c_str());
493 return r;
494 } else if ((features & RBD_FEATURE_MIGRATING) == 0ULL) {
495 CLS_LOG(10, "migrating feature not set");
496 } else {
497 features &= ~RBD_FEATURE_MIGRATING;
498 bufferlist bl;
499 encode(features, bl);
500 r = cls_cxx_map_set_val(hctx, "features", &bl);
501 if (r < 0) {
502 CLS_ERR("error updating features: %s", cpp_strerror(r).c_str());
503 return r;
504 }
505 }
506
507 return 0;
508 }
509
510 namespace snapshot {
511
512 template<typename L>
513 int iterate(cls_method_context_t hctx, L& lambda) {
514 int max_read = RBD_MAX_KEYS_READ;
515 string last_read = RBD_SNAP_KEY_PREFIX;
516 bool more = false;
517 do {
518 map<string, bufferlist> vals;
519 int r = cls_cxx_map_get_vals(hctx, last_read, RBD_SNAP_KEY_PREFIX,
520 max_read, &vals, &more);
521 if (r < 0) {
522 return r;
523 }
524
525 cls_rbd_snap snap_meta;
526 for (auto& val : vals) {
527 auto iter = val.second.cbegin();
528 try {
529 decode(snap_meta, iter);
530 } catch (const buffer::error &err) {
531 CLS_ERR("error decoding snapshot metadata for snap : %s",
532 val.first.c_str());
533 return -EIO;
534 }
535
536 r = lambda(snap_meta);
537 if (r < 0) {
538 return r;
539 }
540 }
541
542 if (!vals.empty()) {
543 last_read = vals.rbegin()->first;
544 }
545 } while (more);
546
547 return 0;
548 }
549
550 int write(cls_method_context_t hctx, const std::string& snap_key,
551 cls_rbd_snap&& snap) {
552 int r;
553 uint64_t encode_features = get_encode_features(hctx);
554 if (snap.migrate_parent_format(encode_features)) {
555 // ensure the normalized parent link exists before removing it from the
556 // snapshot record
557 cls_rbd_parent on_disk_parent;
558 r = read_key(hctx, "parent", &on_disk_parent);
559 if (r < 0 && r != -ENOENT) {
560 return r;
561 }
562
563 if (!on_disk_parent.exists()) {
564 on_disk_parent = snap.parent;
565 on_disk_parent.head_overlap = std::nullopt;
566
567 r = write_key(hctx, "parent", on_disk_parent, encode_features);
568 if (r < 0) {
569 return r;
570 }
571 }
572
573 // only store the parent overlap in the snapshot
574 snap.parent_overlap = snap.parent.head_overlap;
575 snap.parent = {};
576 }
577
578 r = write_key(hctx, snap_key, snap, encode_features);
579 if (r < 0) {
580 return r;
581 }
582 return 0;
583 }
584
585 } // namespace snapshot
586
587 namespace parent {
588
589 int attach(cls_method_context_t hctx, cls_rbd_parent parent,
590 bool reattach) {
591 int r = check_exists(hctx);
592 if (r < 0) {
593 CLS_LOG(20, "cls_rbd::image::parent::attach: child doesn't exist");
594 return r;
595 }
596
597 r = image::require_feature(hctx, RBD_FEATURE_LAYERING);
598 if (r < 0) {
599 CLS_LOG(20, "cls_rbd::image::parent::attach: child does not support "
600 "layering");
601 return r;
602 }
603
604 CLS_LOG(20, "cls_rbd::image::parent::attach: pool=%" PRIi64 ", ns=%s, id=%s, "
605 "snapid=%" PRIu64 ", size=%" PRIu64,
606 parent.pool_id, parent.pool_namespace.c_str(),
607 parent.image_id.c_str(), parent.snap_id.val,
608 parent.head_overlap.value_or(0ULL));
609 if (!parent.exists() || parent.head_overlap.value_or(0ULL) == 0ULL) {
610 return -EINVAL;
611 }
612
613 // make sure there isn't already a parent
614 cls_rbd_parent on_disk_parent;
615 r = read_key(hctx, "parent", &on_disk_parent);
616 if (r < 0 && r != -ENOENT) {
617 return r;
618 }
619
620 auto on_disk_parent_without_overlap{on_disk_parent};
621 on_disk_parent_without_overlap.head_overlap = parent.head_overlap;
622
623 if (r == 0 &&
624 (on_disk_parent.head_overlap ||
625 on_disk_parent_without_overlap != parent) &&
626 !reattach) {
627 CLS_LOG(20, "cls_rbd::parent::attach: existing legacy parent "
628 "pool=%" PRIi64 ", ns=%s, id=%s, snapid=%" PRIu64 ", "
629 "overlap=%" PRIu64,
630 on_disk_parent.pool_id, on_disk_parent.pool_namespace.c_str(),
631 on_disk_parent.image_id.c_str(), on_disk_parent.snap_id.val,
632 on_disk_parent.head_overlap.value_or(0ULL));
633 return -EEXIST;
634 }
635
636 // our overlap is the min of our size and the parent's size.
637 uint64_t our_size;
638 r = read_key(hctx, "size", &our_size);
639 if (r < 0) {
640 return r;
641 }
642
643 parent.head_overlap = std::min(*parent.head_overlap, our_size);
644
645 r = write_key(hctx, "parent", parent, get_encode_features(hctx));
646 if (r < 0) {
647 return r;
648 }
649
650 return 0;
651 }
652
653 int detach(cls_method_context_t hctx, bool legacy_api) {
654 int r = check_exists(hctx);
655 if (r < 0) {
656 CLS_LOG(20, "cls_rbd::parent::detach: child doesn't exist");
657 return r;
658 }
659
660 uint64_t features;
661 r = read_key(hctx, "features", &features);
662 if (r == -ENOENT || ((features & RBD_FEATURE_LAYERING) == 0)) {
663 CLS_LOG(20, "cls_rbd::image::parent::detach: child does not support "
664 "layering");
665 return -ENOEXEC;
666 } else if (r < 0) {
667 return r;
668 }
669
670 cls_rbd_parent on_disk_parent;
671 r = read_key(hctx, "parent", &on_disk_parent);
672 if (r < 0) {
673 return r;
674 } else if (legacy_api && !on_disk_parent.pool_namespace.empty()) {
675 return -EXDEV;
676 } else if (!on_disk_parent.head_overlap) {
677 return -ENOENT;
678 }
679
680 auto detach_lambda = [hctx, features](const cls_rbd_snap& snap_meta) {
681 if (snap_meta.parent.pool_id != -1 || snap_meta.parent_overlap) {
682 if ((features & RBD_FEATURE_DEEP_FLATTEN) != 0ULL) {
683 // remove parent reference from snapshot
684 cls_rbd_snap snap_meta_copy = snap_meta;
685 snap_meta_copy.parent = {};
686 snap_meta_copy.parent_overlap = std::nullopt;
687
688 std::string snap_key;
689 key_from_snap_id(snap_meta_copy.id, &snap_key);
690 int r = snapshot::write(hctx, snap_key, std::move(snap_meta_copy));
691 if (r < 0) {
692 return r;
693 }
694 } else {
695 return -EEXIST;
696 }
697 }
698 return 0;
699 };
700
701 r = snapshot::iterate(hctx, detach_lambda);
702 bool has_child_snaps = (r == -EEXIST);
703 if (r < 0 && r != -EEXIST) {
704 return r;
705 }
706
707 int8_t require_osd_release = cls_get_required_osd_release(hctx);
708 if (has_child_snaps && require_osd_release >= CEPH_RELEASE_NAUTILUS) {
709 // remove overlap from HEAD revision but keep spec for snapshots
710 on_disk_parent.head_overlap = std::nullopt;
711 r = write_key(hctx, "parent", on_disk_parent, get_encode_features(hctx));
712 if (r < 0) {
713 return r;
714 }
715 } else {
716 r = remove_key(hctx, "parent");
717 if (r < 0 && r != -ENOENT) {
718 return r;
719 }
720 }
721
722 if (!has_child_snaps) {
723 // disable clone child op feature if no longer associated
724 r = set_op_features(hctx, 0, RBD_OPERATION_FEATURE_CLONE_CHILD);
725 if (r < 0) {
726 return r;
727 }
728 }
729 return 0;
730 }
731
732 } // namespace parent
733 } // namespace image
734
735 /**
736 * Initialize the header with basic metadata.
737 * Extra features may initialize more fields in the future.
738 * Everything is stored as key/value pairs as omaps in the header object.
739 *
740 * If features the OSD does not understand are requested, -ENOSYS is
741 * returned.
742 *
743 * Input:
744 * @param size number of bytes in the image (uint64_t)
745 * @param order bits to shift to determine the size of data objects (uint8_t)
746 * @param features what optional things this image will use (uint64_t)
747 * @param object_prefix a prefix for all the data objects
748 * @param data_pool_id pool id where data objects is stored (int64_t)
749 *
750 * Output:
751 * @return 0 on success, negative error code on failure
752 */
753 int create(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
754 {
755 string object_prefix;
756 uint64_t features, size;
757 uint8_t order;
758 int64_t data_pool_id = -1;
759
760 try {
761 auto iter = in->cbegin();
762 decode(size, iter);
763 decode(order, iter);
764 decode(features, iter);
765 decode(object_prefix, iter);
766 if (!iter.end()) {
767 decode(data_pool_id, iter);
768 }
769 } catch (const buffer::error &err) {
770 return -EINVAL;
771 }
772
773 CLS_LOG(20, "create object_prefix=%s size=%llu order=%u features=%llu",
774 object_prefix.c_str(), (unsigned long long)size, order,
775 (unsigned long long)features);
776
777 if (features & ~RBD_FEATURES_ALL) {
778 return -ENOSYS;
779 }
780
781 if (!object_prefix.size()) {
782 return -EINVAL;
783 }
784
785 bufferlist stored_prefixbl;
786 int r = cls_cxx_map_get_val(hctx, "object_prefix", &stored_prefixbl);
787 if (r != -ENOENT) {
788 CLS_ERR("reading object_prefix returned %d", r);
789 return -EEXIST;
790 }
791
792 bufferlist sizebl;
793 bufferlist orderbl;
794 bufferlist featuresbl;
795 bufferlist object_prefixbl;
796 bufferlist snap_seqbl;
797 bufferlist timestampbl;
798 uint64_t snap_seq = 0;
799 utime_t timestamp = ceph_clock_now();
800 encode(size, sizebl);
801 encode(order, orderbl);
802 encode(features, featuresbl);
803 encode(object_prefix, object_prefixbl);
804 encode(snap_seq, snap_seqbl);
805 encode(timestamp, timestampbl);
806
807 map<string, bufferlist> omap_vals;
808 omap_vals["size"] = sizebl;
809 omap_vals["order"] = orderbl;
810 omap_vals["features"] = featuresbl;
811 omap_vals["object_prefix"] = object_prefixbl;
812 omap_vals["snap_seq"] = snap_seqbl;
813 omap_vals["create_timestamp"] = timestampbl;
814 omap_vals["access_timestamp"] = timestampbl;
815 omap_vals["modify_timestamp"] = timestampbl;
816
817 if ((features & RBD_FEATURE_OPERATIONS) != 0ULL) {
818 CLS_ERR("Attempting to set internal feature: operations");
819 return -EINVAL;
820 }
821
822 if (features & RBD_FEATURE_DATA_POOL) {
823 if (data_pool_id == -1) {
824 CLS_ERR("data pool not provided with feature enabled");
825 return -EINVAL;
826 }
827
828 bufferlist data_pool_id_bl;
829 encode(data_pool_id, data_pool_id_bl);
830 omap_vals["data_pool_id"] = data_pool_id_bl;
831 } else if (data_pool_id != -1) {
832 CLS_ERR("data pool provided with feature disabled");
833 return -EINVAL;
834 }
835
836 r = cls_cxx_map_set_vals(hctx, &omap_vals);
837 if (r < 0)
838 return r;
839
840 return 0;
841 }
842
843 /**
844 * Input:
845 * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t) (deprecated)
846 * @param read_only true if the image will be used read-only (bool)
847 *
848 * Output:
849 * @param features list of enabled features for the given snapshot (uint64_t)
850 * @param incompatible incompatible feature bits
851 * @returns 0 on success, negative error code on failure
852 */
853 int get_features(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
854 {
855 bool read_only = false;
856
857 auto iter = in->cbegin();
858 try {
859 uint64_t snap_id;
860 decode(snap_id, iter);
861 if (!iter.end()) {
862 decode(read_only, iter);
863 }
864 } catch (const buffer::error &err) {
865 return -EINVAL;
866 }
867
868 CLS_LOG(20, "get_features read_only=%d", read_only);
869
870 uint64_t features;
871 int r = read_key(hctx, "features", &features);
872 if (r < 0) {
873 CLS_ERR("failed to read features off disk: %s", cpp_strerror(r).c_str());
874 return r;
875 }
876
877 uint64_t incompatible = (read_only ? features & RBD_FEATURES_INCOMPATIBLE :
878 features & RBD_FEATURES_RW_INCOMPATIBLE);
879 encode(features, *out);
880 encode(incompatible, *out);
881 return 0;
882 }
883
884 /**
885 * set the image features
886 *
887 * Input:
888 * @param features image features
889 * @param mask image feature mask
890 *
891 * Output:
892 * none
893 *
894 * @returns 0 on success, negative error code upon failure
895 */
896 int set_features(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
897 {
898 uint64_t features;
899 uint64_t mask;
900 auto iter = in->cbegin();
901 try {
902 decode(features, iter);
903 decode(mask, iter);
904 } catch (const buffer::error &err) {
905 return -EINVAL;
906 }
907
908 // check that features exists to make sure this is a header object
909 // that was created correctly
910 uint64_t orig_features = 0;
911 int r = read_key(hctx, "features", &orig_features);
912 if (r < 0 && r != -ENOENT) {
913 CLS_ERR("Could not read image's features off disk: %s",
914 cpp_strerror(r).c_str());
915 return r;
916 }
917
918 if ((mask & RBD_FEATURES_INTERNAL) != 0ULL) {
919 CLS_ERR("Attempting to set internal feature: %" PRIu64,
920 static_cast<uint64_t>(mask & RBD_FEATURES_INTERNAL));
921 return -EINVAL;
922 }
923
924 // newer clients might attempt to mask off features we don't support
925 mask &= RBD_FEATURES_ALL;
926
927 uint64_t enabled_features = features & mask;
928 if ((enabled_features & RBD_FEATURES_MUTABLE) != enabled_features) {
929 CLS_ERR("Attempting to enable immutable feature: %" PRIu64,
930 static_cast<uint64_t>(enabled_features & ~RBD_FEATURES_MUTABLE));
931 return -EINVAL;
932 }
933
934 uint64_t disabled_features = ~features & mask;
935 uint64_t disable_mask = (RBD_FEATURES_MUTABLE | RBD_FEATURES_DISABLE_ONLY);
936 if ((disabled_features & disable_mask) != disabled_features) {
937 CLS_ERR("Attempting to disable immutable feature: %" PRIu64,
938 enabled_features & ~disable_mask);
939 return -EINVAL;
940 }
941
942 features = (orig_features & ~mask) | (features & mask);
943 CLS_LOG(10, "set_features features=%" PRIu64 " orig_features=%" PRIu64,
944 features, orig_features);
945
946 bufferlist bl;
947 encode(features, bl);
948 r = cls_cxx_map_set_val(hctx, "features", &bl);
949 if (r < 0) {
950 CLS_ERR("error updating features: %s", cpp_strerror(r).c_str());
951 return r;
952 }
953 return 0;
954 }
955
956 /**
957 * Input:
958 * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t)
959 *
960 * Output:
961 * @param order bits to shift to get the size of data objects (uint8_t)
962 * @param size size of the image in bytes for the given snapshot (uint64_t)
963 * @returns 0 on success, negative error code on failure
964 */
965 int get_size(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
966 {
967 uint64_t snap_id, size;
968 uint8_t order;
969
970 auto iter = in->cbegin();
971 try {
972 decode(snap_id, iter);
973 } catch (const buffer::error &err) {
974 return -EINVAL;
975 }
976
977 CLS_LOG(20, "get_size snap_id=%llu", (unsigned long long)snap_id);
978
979 int r = read_key(hctx, "order", &order);
980 if (r < 0) {
981 CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r).c_str());
982 return r;
983 }
984
985 if (snap_id == CEPH_NOSNAP) {
986 r = read_key(hctx, "size", &size);
987 if (r < 0) {
988 CLS_ERR("failed to read the image's size off of disk: %s", cpp_strerror(r).c_str());
989 return r;
990 }
991 } else {
992 cls_rbd_snap snap;
993 string snapshot_key;
994 key_from_snap_id(snap_id, &snapshot_key);
995 int r = read_key(hctx, snapshot_key, &snap);
996 if (r < 0)
997 return r;
998
999 size = snap.image_size;
1000 }
1001
1002 encode(order, *out);
1003 encode(size, *out);
1004
1005 return 0;
1006 }
1007
1008 /**
1009 * Input:
1010 * @param size new capacity of the image in bytes (uint64_t)
1011 *
1012 * Output:
1013 * @returns 0 on success, negative error code on failure
1014 */
1015 int set_size(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1016 {
1017 uint64_t size;
1018
1019 auto iter = in->cbegin();
1020 try {
1021 decode(size, iter);
1022 } catch (const buffer::error &err) {
1023 return -EINVAL;
1024 }
1025
1026 // check that size exists to make sure this is a header object
1027 // that was created correctly
1028 uint64_t orig_size;
1029 int r = read_key(hctx, "size", &orig_size);
1030 if (r < 0) {
1031 CLS_ERR("Could not read image's size off disk: %s", cpp_strerror(r).c_str());
1032 return r;
1033 }
1034
1035 CLS_LOG(20, "set_size size=%llu orig_size=%llu", (unsigned long long)size,
1036 (unsigned long long)orig_size);
1037
1038 bufferlist sizebl;
1039 encode(size, sizebl);
1040 r = cls_cxx_map_set_val(hctx, "size", &sizebl);
1041 if (r < 0) {
1042 CLS_ERR("error writing snapshot metadata: %s", cpp_strerror(r).c_str());
1043 return r;
1044 }
1045
1046 // if we are shrinking, and have a parent, shrink our overlap with
1047 // the parent, too.
1048 if (size < orig_size) {
1049 cls_rbd_parent parent;
1050 r = read_key(hctx, "parent", &parent);
1051 if (r == -ENOENT)
1052 r = 0;
1053 if (r < 0)
1054 return r;
1055 if (parent.exists() && parent.head_overlap.value_or(0ULL) > size) {
1056 parent.head_overlap = size;
1057 r = write_key(hctx, "parent", parent, get_encode_features(hctx));
1058 if (r < 0) {
1059 return r;
1060 }
1061 }
1062 }
1063
1064 return 0;
1065 }
1066
1067 /**
1068 * get the current protection status of the specified snapshot
1069 *
1070 * Input:
1071 * @param snap_id (uint64_t) which snapshot to get the status of
1072 *
1073 * Output:
1074 * @param status (uint8_t) one of:
1075 * RBD_PROTECTION_STATUS_{PROTECTED, UNPROTECTED, UNPROTECTING}
1076 *
1077 * @returns 0 on success, negative error code on failure
1078 * @returns -EINVAL if snapid is CEPH_NOSNAP
1079 */
1080 int get_protection_status(cls_method_context_t hctx, bufferlist *in,
1081 bufferlist *out)
1082 {
1083 snapid_t snap_id;
1084
1085 auto iter = in->cbegin();
1086 try {
1087 decode(snap_id, iter);
1088 } catch (const buffer::error &err) {
1089 CLS_LOG(20, "get_protection_status: invalid decode");
1090 return -EINVAL;
1091 }
1092
1093 int r = check_exists(hctx);
1094 if (r < 0)
1095 return r;
1096
1097 CLS_LOG(20, "get_protection_status snap_id=%llu",
1098 (unsigned long long)snap_id.val);
1099
1100 if (snap_id == CEPH_NOSNAP)
1101 return -EINVAL;
1102
1103 cls_rbd_snap snap;
1104 string snapshot_key;
1105 key_from_snap_id(snap_id.val, &snapshot_key);
1106 r = read_key(hctx, snapshot_key, &snap);
1107 if (r < 0) {
1108 CLS_ERR("could not read key for snapshot id %" PRIu64, snap_id.val);
1109 return r;
1110 }
1111
1112 if (snap.protection_status >= RBD_PROTECTION_STATUS_LAST) {
1113 CLS_ERR("invalid protection status for snap id %llu: %u",
1114 (unsigned long long)snap_id.val, snap.protection_status);
1115 return -EIO;
1116 }
1117
1118 encode(snap.protection_status, *out);
1119 return 0;
1120 }
1121
1122 /**
1123 * set the proctection status of a snapshot
1124 *
1125 * Input:
1126 * @param snapid (uint64_t) which snapshot to set the status of
1127 * @param status (uint8_t) one of:
1128 * RBD_PROTECTION_STATUS_{PROTECTED, UNPROTECTED, UNPROTECTING}
1129 *
1130 * @returns 0 on success, negative error code on failure
1131 * @returns -EINVAL if snapid is CEPH_NOSNAP
1132 */
1133 int set_protection_status(cls_method_context_t hctx, bufferlist *in,
1134 bufferlist *out)
1135 {
1136 snapid_t snap_id;
1137 uint8_t status;
1138
1139 auto iter = in->cbegin();
1140 try {
1141 decode(snap_id, iter);
1142 decode(status, iter);
1143 } catch (const buffer::error &err) {
1144 CLS_LOG(20, "set_protection_status: invalid decode");
1145 return -EINVAL;
1146 }
1147
1148 int r = check_exists(hctx);
1149 if (r < 0)
1150 return r;
1151
1152 r = image::require_feature(hctx, RBD_FEATURE_LAYERING);
1153 if (r < 0) {
1154 CLS_LOG(20, "image does not support layering");
1155 return r;
1156 }
1157
1158 CLS_LOG(20, "set_protection_status snapid=%llu status=%u",
1159 (unsigned long long)snap_id.val, status);
1160
1161 if (snap_id == CEPH_NOSNAP)
1162 return -EINVAL;
1163
1164 if (status >= RBD_PROTECTION_STATUS_LAST) {
1165 CLS_LOG(10, "invalid protection status for snap id %llu: %u",
1166 (unsigned long long)snap_id.val, status);
1167 return -EINVAL;
1168 }
1169
1170 cls_rbd_snap snap;
1171 string snapshot_key;
1172 key_from_snap_id(snap_id.val, &snapshot_key);
1173 r = read_key(hctx, snapshot_key, &snap);
1174 if (r < 0) {
1175 CLS_ERR("could not read key for snapshot id %" PRIu64, snap_id.val);
1176 return r;
1177 }
1178
1179 snap.protection_status = status;
1180 r = image::snapshot::write(hctx, snapshot_key, std::move(snap));
1181 if (r < 0) {
1182 return r;
1183 }
1184
1185 return 0;
1186 }
1187
1188 /**
1189 * get striping parameters
1190 *
1191 * Input:
1192 * none
1193 *
1194 * Output:
1195 * @param stripe unit (bytes)
1196 * @param stripe count (num objects)
1197 *
1198 * @returns 0 on success
1199 */
1200 int get_stripe_unit_count(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1201 {
1202 int r = check_exists(hctx);
1203 if (r < 0)
1204 return r;
1205
1206 CLS_LOG(20, "get_stripe_unit_count");
1207
1208 r = image::require_feature(hctx, RBD_FEATURE_STRIPINGV2);
1209 if (r < 0)
1210 return r;
1211
1212 uint64_t stripe_unit = 0, stripe_count = 0;
1213 r = read_key(hctx, "stripe_unit", &stripe_unit);
1214 if (r == -ENOENT) {
1215 // default to object size
1216 uint8_t order;
1217 r = read_key(hctx, "order", &order);
1218 if (r < 0) {
1219 CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r).c_str());
1220 return -EIO;
1221 }
1222 stripe_unit = 1ull << order;
1223 }
1224 if (r < 0)
1225 return r;
1226 r = read_key(hctx, "stripe_count", &stripe_count);
1227 if (r == -ENOENT) {
1228 // default to 1
1229 stripe_count = 1;
1230 r = 0;
1231 }
1232 if (r < 0)
1233 return r;
1234
1235 encode(stripe_unit, *out);
1236 encode(stripe_count, *out);
1237 return 0;
1238 }
1239
1240 /**
1241 * set striping parameters
1242 *
1243 * Input:
1244 * @param stripe unit (bytes)
1245 * @param stripe count (num objects)
1246 *
1247 * @returns 0 on success
1248 */
1249 int set_stripe_unit_count(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1250 {
1251 uint64_t stripe_unit, stripe_count;
1252
1253 auto iter = in->cbegin();
1254 try {
1255 decode(stripe_unit, iter);
1256 decode(stripe_count, iter);
1257 } catch (const buffer::error &err) {
1258 CLS_LOG(20, "set_stripe_unit_count: invalid decode");
1259 return -EINVAL;
1260 }
1261
1262 if (!stripe_count || !stripe_unit)
1263 return -EINVAL;
1264
1265 int r = check_exists(hctx);
1266 if (r < 0)
1267 return r;
1268
1269 CLS_LOG(20, "set_stripe_unit_count");
1270
1271 r = image::require_feature(hctx, RBD_FEATURE_STRIPINGV2);
1272 if (r < 0)
1273 return r;
1274
1275 uint8_t order;
1276 r = read_key(hctx, "order", &order);
1277 if (r < 0) {
1278 CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r).c_str());
1279 return r;
1280 }
1281 if ((1ull << order) % stripe_unit || stripe_unit > (1ull << order)) {
1282 CLS_ERR("stripe unit %llu is not a factor of the object size %llu",
1283 (unsigned long long)stripe_unit, 1ull << order);
1284 return -EINVAL;
1285 }
1286
1287 bufferlist bl, bl2;
1288 encode(stripe_unit, bl);
1289 r = cls_cxx_map_set_val(hctx, "stripe_unit", &bl);
1290 if (r < 0) {
1291 CLS_ERR("error writing stripe_unit metadata: %s", cpp_strerror(r).c_str());
1292 return r;
1293 }
1294
1295 encode(stripe_count, bl2);
1296 r = cls_cxx_map_set_val(hctx, "stripe_count", &bl2);
1297 if (r < 0) {
1298 CLS_ERR("error writing stripe_count metadata: %s", cpp_strerror(r).c_str());
1299 return r;
1300 }
1301
1302 return 0;
1303 }
1304
1305 int get_create_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1306 {
1307 CLS_LOG(20, "get_create_timestamp");
1308
1309 utime_t timestamp;
1310 bufferlist bl;
1311 int r = cls_cxx_map_get_val(hctx, "create_timestamp", &bl);
1312 if (r < 0) {
1313 if (r != -ENOENT) {
1314 CLS_ERR("error reading create_timestamp: %s", cpp_strerror(r).c_str());
1315 return r;
1316 }
1317 } else {
1318 try {
1319 auto it = bl.cbegin();
1320 decode(timestamp, it);
1321 } catch (const buffer::error &err) {
1322 CLS_ERR("could not decode create_timestamp");
1323 return -EIO;
1324 }
1325 }
1326
1327 encode(timestamp, *out);
1328 return 0;
1329 }
1330
1331 /**
1332 * get the image access timestamp
1333 *
1334 * Input:
1335 * @param none
1336 *
1337 * Output:
1338 * @param timestamp the image access timestamp
1339 *
1340 * @returns 0 on success, negative error code upon failure
1341 */
1342 int get_access_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1343 {
1344 CLS_LOG(20, "get_access_timestamp");
1345
1346 utime_t timestamp;
1347 bufferlist bl;
1348 int r = cls_cxx_map_get_val(hctx, "access_timestamp", &bl);
1349 if (r < 0) {
1350 if (r != -ENOENT) {
1351 CLS_ERR("error reading access_timestamp: %s", cpp_strerror(r).c_str());
1352 return r;
1353 }
1354 } else {
1355 try {
1356 auto it = bl.cbegin();
1357 decode(timestamp, it);
1358 } catch (const buffer::error &err) {
1359 CLS_ERR("could not decode access_timestamp");
1360 return -EIO;
1361 }
1362 }
1363
1364 encode(timestamp, *out);
1365 return 0;
1366 }
1367
1368 /**
1369 * get the image modify timestamp
1370 *
1371 * Input:
1372 * @param none
1373 *
1374 * Output:
1375 * @param timestamp the image modify timestamp
1376 *
1377 * @returns 0 on success, negative error code upon failure
1378 */
1379 int get_modify_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1380 {
1381 CLS_LOG(20, "get_modify_timestamp");
1382
1383 utime_t timestamp;
1384 bufferlist bl;
1385 int r = cls_cxx_map_get_val(hctx, "modify_timestamp", &bl);
1386 if (r < 0) {
1387 if (r != -ENOENT) {
1388 CLS_ERR("error reading modify_timestamp: %s", cpp_strerror(r).c_str());
1389 return r;
1390 }
1391 } else {
1392 try {
1393 auto it = bl.cbegin();
1394 decode(timestamp, it);
1395 } catch (const buffer::error &err) {
1396 CLS_ERR("could not decode modify_timestamp");
1397 return -EIO;
1398 }
1399 }
1400
1401 encode(timestamp, *out);
1402 return 0;
1403 }
1404
1405
1406 /**
1407 * get the image flags
1408 *
1409 * Input:
1410 * @param snap_id which snapshot to query, to CEPH_NOSNAP (uint64_t)
1411 *
1412 * Output:
1413 * @param flags image flags
1414 *
1415 * @returns 0 on success, negative error code upon failure
1416 */
1417 int get_flags(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1418 {
1419 uint64_t snap_id;
1420 auto iter = in->cbegin();
1421 try {
1422 decode(snap_id, iter);
1423 } catch (const buffer::error &err) {
1424 return -EINVAL;
1425 }
1426
1427 CLS_LOG(20, "get_flags snap_id=%llu", (unsigned long long)snap_id);
1428
1429 uint64_t flags = 0;
1430 if (snap_id == CEPH_NOSNAP) {
1431 int r = read_key(hctx, "flags", &flags);
1432 if (r < 0 && r != -ENOENT) {
1433 CLS_ERR("failed to read flags off disk: %s", cpp_strerror(r).c_str());
1434 return r;
1435 }
1436 } else {
1437 cls_rbd_snap snap;
1438 string snapshot_key;
1439 key_from_snap_id(snap_id, &snapshot_key);
1440 int r = read_key(hctx, snapshot_key, &snap);
1441 if (r < 0) {
1442 return r;
1443 }
1444 flags = snap.flags;
1445 }
1446
1447 encode(flags, *out);
1448 return 0;
1449 }
1450
1451 /**
1452 * set the image flags
1453 *
1454 * Input:
1455 * @param flags image flags
1456 * @param mask image flag mask
1457 * @param snap_id which snapshot to update, or CEPH_NOSNAP (uint64_t)
1458 *
1459 * Output:
1460 * none
1461 *
1462 * @returns 0 on success, negative error code upon failure
1463 */
1464 int set_flags(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1465 {
1466 uint64_t flags;
1467 uint64_t mask;
1468 uint64_t snap_id = CEPH_NOSNAP;
1469 auto iter = in->cbegin();
1470 try {
1471 decode(flags, iter);
1472 decode(mask, iter);
1473 if (!iter.end()) {
1474 decode(snap_id, iter);
1475 }
1476 } catch (const buffer::error &err) {
1477 return -EINVAL;
1478 }
1479
1480 // check that size exists to make sure this is a header object
1481 // that was created correctly
1482 int r;
1483 uint64_t orig_flags = 0;
1484 cls_rbd_snap snap_meta;
1485 string snap_meta_key;
1486 if (snap_id == CEPH_NOSNAP) {
1487 r = read_key(hctx, "flags", &orig_flags);
1488 if (r < 0 && r != -ENOENT) {
1489 CLS_ERR("Could not read image's flags off disk: %s",
1490 cpp_strerror(r).c_str());
1491 return r;
1492 }
1493 } else {
1494 key_from_snap_id(snap_id, &snap_meta_key);
1495 r = read_key(hctx, snap_meta_key, &snap_meta);
1496 if (r < 0) {
1497 CLS_ERR("Could not read snapshot: snap_id=%" PRIu64 ": %s",
1498 snap_id, cpp_strerror(r).c_str());
1499 return r;
1500 }
1501 orig_flags = snap_meta.flags;
1502 }
1503
1504 flags = (orig_flags & ~mask) | (flags & mask);
1505 CLS_LOG(20, "set_flags snap_id=%" PRIu64 ", orig_flags=%" PRIu64 ", "
1506 "new_flags=%" PRIu64 ", mask=%" PRIu64, snap_id, orig_flags,
1507 flags, mask);
1508
1509 if (snap_id == CEPH_NOSNAP) {
1510 r = write_key(hctx, "flags", flags);
1511 } else {
1512 snap_meta.flags = flags;
1513 r = image::snapshot::write(hctx, snap_meta_key, std::move(snap_meta));
1514 }
1515
1516 if (r < 0) {
1517 return r;
1518 }
1519 return 0;
1520 }
1521
1522 /**
1523 * Get the operation-based image features
1524 *
1525 * Input:
1526 *
1527 * Output:
1528 * @param bitmask of enabled op features (uint64_t)
1529 * @returns 0 on success, negative error code on failure
1530 */
1531 int op_features_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1532 {
1533 CLS_LOG(20, "op_features_get");
1534
1535 uint64_t op_features = 0;
1536 int r = read_key(hctx, "op_features", &op_features);
1537 if (r < 0 && r != -ENOENT) {
1538 CLS_ERR("failed to read op features off disk: %s", cpp_strerror(r).c_str());
1539 return r;
1540 }
1541
1542 encode(op_features, *out);
1543 return 0;
1544 }
1545
1546 /**
1547 * Set the operation-based image features
1548 *
1549 * Input:
1550 * @param op_features image op features
1551 * @param mask image op feature mask
1552 *
1553 * Output:
1554 * none
1555 *
1556 * @returns 0 on success, negative error code upon failure
1557 */
1558 int op_features_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1559 {
1560 uint64_t op_features;
1561 uint64_t mask;
1562 auto iter = in->cbegin();
1563 try {
1564 decode(op_features, iter);
1565 decode(mask, iter);
1566 } catch (const buffer::error &err) {
1567 return -EINVAL;
1568 }
1569
1570 uint64_t unsupported_op_features = (mask & ~RBD_OPERATION_FEATURES_ALL);
1571 if (unsupported_op_features != 0ULL) {
1572 CLS_ERR("unsupported op features: %" PRIu64, unsupported_op_features);
1573 return -EINVAL;
1574 }
1575
1576 return image::set_op_features(hctx, op_features, mask);
1577 }
1578
1579 /**
1580 * get the current parent, if any
1581 *
1582 * Input:
1583 * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t)
1584 *
1585 * Output:
1586 * @param pool parent pool id (-1 if parent does not exist)
1587 * @param image parent image id
1588 * @param snapid parent snapid
1589 * @param size portion of parent mapped under the child
1590 *
1591 * @returns 0 on success or parent does not exist, negative error code on failure
1592 */
1593 int get_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1594 {
1595 uint64_t snap_id;
1596
1597 auto iter = in->cbegin();
1598 try {
1599 decode(snap_id, iter);
1600 } catch (const buffer::error &err) {
1601 return -EINVAL;
1602 }
1603
1604 int r = check_exists(hctx);
1605 if (r < 0) {
1606 return r;
1607 }
1608
1609 CLS_LOG(20, "get_parent snap_id=%" PRIu64, snap_id);
1610
1611 cls_rbd_parent parent;
1612 r = image::require_feature(hctx, RBD_FEATURE_LAYERING);
1613 if (r == 0) {
1614 r = read_key(hctx, "parent", &parent);
1615 if (r < 0 && r != -ENOENT) {
1616 return r;
1617 } else if (!parent.pool_namespace.empty()) {
1618 return -EXDEV;
1619 }
1620
1621 if (snap_id != CEPH_NOSNAP) {
1622 cls_rbd_snap snap;
1623 std::string snapshot_key;
1624 key_from_snap_id(snap_id, &snapshot_key);
1625 r = read_key(hctx, snapshot_key, &snap);
1626 if (r < 0 && r != -ENOENT) {
1627 return r;
1628 }
1629
1630 if (snap.parent.exists()) {
1631 // legacy format where full parent spec is written within
1632 // each snapshot record
1633 parent = snap.parent;
1634 } else if (snap.parent_overlap) {
1635 // normalized parent reference
1636 if (!parent.exists()) {
1637 CLS_ERR("get_parent: snap_id=%" PRIu64 ": invalid parent spec",
1638 snap_id);
1639 return -EINVAL;
1640 }
1641 parent.head_overlap = *snap.parent_overlap;
1642 } else {
1643 // snapshot doesn't have associated parent
1644 parent = {};
1645 }
1646 }
1647 }
1648
1649 encode(parent.pool_id, *out);
1650 encode(parent.image_id, *out);
1651 encode(parent.snap_id, *out);
1652 encode(parent.head_overlap.value_or(0ULL), *out);
1653 return 0;
1654 }
1655
1656 /**
1657 * set the image parent
1658 *
1659 * Input:
1660 * @param pool parent pool
1661 * @param id parent image id
1662 * @param snapid parent snapid
1663 * @param size parent size
1664 *
1665 * @returns 0 on success, or negative error code
1666 */
1667 int set_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1668 {
1669 cls_rbd_parent parent;
1670 auto iter = in->cbegin();
1671 try {
1672 decode(parent.pool_id, iter);
1673 decode(parent.image_id, iter);
1674 decode(parent.snap_id, iter);
1675
1676 uint64_t overlap;
1677 decode(overlap, iter);
1678 parent.head_overlap = overlap;
1679 } catch (const buffer::error &err) {
1680 CLS_LOG(20, "cls_rbd::set_parent: invalid decode");
1681 return -EINVAL;
1682 }
1683
1684 int r = image::parent::attach(hctx, parent, false);
1685 if (r < 0) {
1686 return r;
1687 }
1688
1689 return 0;
1690 }
1691
1692
1693 /**
1694 * remove the parent pointer
1695 *
1696 * This can only happen on the head, not on a snapshot. No arguments.
1697 *
1698 * @returns 0 on success, negative error code on failure.
1699 */
1700 int remove_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1701 {
1702 int r = image::parent::detach(hctx, true);
1703 if (r < 0) {
1704 return r;
1705 }
1706
1707 return 0;
1708 }
1709
1710 /**
1711 * Input:
1712 * none
1713 *
1714 * Output:
1715 * @param parent spec (cls::rbd::ParentImageSpec)
1716 * @returns 0 on success, negative error code on failure
1717 */
1718 int parent_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out) {
1719 int r = check_exists(hctx);
1720 if (r < 0) {
1721 return r;
1722 }
1723
1724 CLS_LOG(20, "parent_get");
1725
1726 cls_rbd_parent parent;
1727 r = image::require_feature(hctx, RBD_FEATURE_LAYERING);
1728 if (r == 0) {
1729 r = read_key(hctx, "parent", &parent);
1730 if (r < 0 && r != -ENOENT) {
1731 return r;
1732 } else if (r == -ENOENT) {
1733 // examine oldest snapshot to see if it has a denormalized parent
1734 auto parent_lambda = [hctx, &parent](const cls_rbd_snap& snap_meta) {
1735 if (snap_meta.parent.exists()) {
1736 parent = snap_meta.parent;
1737 }
1738 return 0;
1739 };
1740
1741 r = image::snapshot::iterate(hctx, parent_lambda);
1742 if (r < 0) {
1743 return r;
1744 }
1745 }
1746 }
1747
1748 cls::rbd::ParentImageSpec parent_image_spec{
1749 parent.pool_id, parent.pool_namespace, parent.image_id,
1750 parent.snap_id};
1751 encode(parent_image_spec, *out);
1752 return 0;
1753 }
1754
1755 /**
1756 * Input:
1757 * @param snap id (uint64_t) parent snapshot id
1758 *
1759 * Output:
1760 * @param byte overlap of parent image (std::optional<uint64_t>)
1761 * @returns 0 on success, negative error code on failure
1762 */
1763 int parent_overlap_get(cls_method_context_t hctx, bufferlist *in,
1764 bufferlist *out) {
1765 uint64_t snap_id;
1766 auto iter = in->cbegin();
1767 try {
1768 decode(snap_id, iter);
1769 } catch (const buffer::error &err) {
1770 return -EINVAL;
1771 }
1772
1773 int r = check_exists(hctx);
1774 CLS_LOG(20, "parent_overlap_get");
1775
1776 std::optional<uint64_t> parent_overlap = std::nullopt;
1777 r = image::require_feature(hctx, RBD_FEATURE_LAYERING);
1778 if (r == 0) {
1779 if (snap_id == CEPH_NOSNAP) {
1780 cls_rbd_parent parent;
1781 r = read_key(hctx, "parent", &parent);
1782 if (r < 0 && r != -ENOENT) {
1783 return r;
1784 } else if (r == 0) {
1785 parent_overlap = parent.head_overlap;
1786 }
1787 } else {
1788 cls_rbd_snap snap;
1789 std::string snapshot_key;
1790 key_from_snap_id(snap_id, &snapshot_key);
1791 r = read_key(hctx, snapshot_key, &snap);
1792 if (r < 0) {
1793 return r;
1794 }
1795
1796 if (snap.parent_overlap) {
1797 parent_overlap = snap.parent_overlap;
1798 } else if (snap.parent.exists()) {
1799 // legacy format where full parent spec is written within
1800 // each snapshot record
1801 parent_overlap = snap.parent.head_overlap;
1802 }
1803 }
1804 };
1805
1806 encode(parent_overlap, *out);
1807 return 0;
1808 }
1809
1810 /**
1811 * Input:
1812 * @param parent spec (cls::rbd::ParentImageSpec)
1813 * @param size parent size (uint64_t)
1814 *
1815 * Output:
1816 * @returns 0 on success, negative error code on failure
1817 */
1818 int parent_attach(cls_method_context_t hctx, bufferlist *in, bufferlist *out) {
1819 cls::rbd::ParentImageSpec parent_image_spec;
1820 uint64_t parent_overlap;
1821 bool reattach = false;
1822
1823 auto iter = in->cbegin();
1824 try {
1825 decode(parent_image_spec, iter);
1826 decode(parent_overlap, iter);
1827 if (!iter.end()) {
1828 decode(reattach, iter);
1829 }
1830 } catch (const buffer::error &err) {
1831 CLS_LOG(20, "cls_rbd::parent_attach: invalid decode");
1832 return -EINVAL;
1833 }
1834
1835 int r = image::parent::attach(hctx, {parent_image_spec, parent_overlap},
1836 reattach);
1837 if (r < 0) {
1838 return r;
1839 }
1840
1841 return 0;
1842 }
1843
1844 /**
1845 * Input:
1846 * none
1847 *
1848 * Output:
1849 * @returns 0 on success, negative error code on failure
1850 */
1851 int parent_detach(cls_method_context_t hctx, bufferlist *in, bufferlist *out) {
1852 int r = image::parent::detach(hctx, false);
1853 if (r < 0) {
1854 return r;
1855 }
1856
1857 return 0;
1858 }
1859
1860
1861 /**
1862 * methods for dealing with rbd_children object
1863 */
1864
1865 static int decode_parent_common(bufferlist::const_iterator& it, uint64_t *pool_id,
1866 string *image_id, snapid_t *snap_id)
1867 {
1868 try {
1869 decode(*pool_id, it);
1870 decode(*image_id, it);
1871 decode(*snap_id, it);
1872 } catch (const buffer::error &err) {
1873 CLS_ERR("error decoding parent spec");
1874 return -EINVAL;
1875 }
1876 return 0;
1877 }
1878
1879 static int decode_parent(bufferlist *in, uint64_t *pool_id,
1880 string *image_id, snapid_t *snap_id)
1881 {
1882 auto it = in->cbegin();
1883 return decode_parent_common(it, pool_id, image_id, snap_id);
1884 }
1885
1886 static int decode_parent_and_child(bufferlist *in, uint64_t *pool_id,
1887 string *image_id, snapid_t *snap_id,
1888 string *c_image_id)
1889 {
1890 auto it = in->cbegin();
1891 int r = decode_parent_common(it, pool_id, image_id, snap_id);
1892 if (r < 0)
1893 return r;
1894 try {
1895 decode(*c_image_id, it);
1896 } catch (const buffer::error &err) {
1897 CLS_ERR("error decoding child image id");
1898 return -EINVAL;
1899 }
1900 return 0;
1901 }
1902
1903 static string parent_key(uint64_t pool_id, string image_id, snapid_t snap_id)
1904 {
1905 bufferlist key_bl;
1906 encode(pool_id, key_bl);
1907 encode(image_id, key_bl);
1908 encode(snap_id, key_bl);
1909 return string(key_bl.c_str(), key_bl.length());
1910 }
1911
1912 /**
1913 * add child to rbd_children directory object
1914 *
1915 * rbd_children is a map of (p_pool_id, p_image_id, p_snap_id) to
1916 * [c_image_id, [c_image_id ... ]]
1917 *
1918 * Input:
1919 * @param p_pool_id parent pool id
1920 * @param p_image_id parent image oid
1921 * @param p_snap_id parent snapshot id
1922 * @param c_image_id new child image oid to add
1923 *
1924 * @returns 0 on success, negative error on failure
1925 */
1926
1927 int add_child(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1928 {
1929 int r;
1930
1931 uint64_t p_pool_id;
1932 snapid_t p_snap_id;
1933 string p_image_id, c_image_id;
1934 // Use set for ease of erase() for remove_child()
1935 std::set<string> children;
1936
1937 r = decode_parent_and_child(in, &p_pool_id, &p_image_id, &p_snap_id,
1938 &c_image_id);
1939 if (r < 0)
1940 return r;
1941
1942 CLS_LOG(20, "add_child %s to (%" PRIu64 ", %s, %" PRIu64 ")", c_image_id.c_str(),
1943 p_pool_id, p_image_id.c_str(), p_snap_id.val);
1944
1945 string key = parent_key(p_pool_id, p_image_id, p_snap_id);
1946
1947 // get current child list for parent, if any
1948 r = read_key(hctx, key, &children);
1949 if ((r < 0) && (r != -ENOENT)) {
1950 CLS_LOG(20, "add_child: omap read failed: %s", cpp_strerror(r).c_str());
1951 return r;
1952 }
1953
1954 if (children.find(c_image_id) != children.end()) {
1955 CLS_LOG(20, "add_child: child already exists: %s", c_image_id.c_str());
1956 return -EEXIST;
1957 }
1958 // add new child
1959 children.insert(c_image_id);
1960
1961 // write back
1962 bufferlist childbl;
1963 encode(children, childbl);
1964 r = cls_cxx_map_set_val(hctx, key, &childbl);
1965 if (r < 0)
1966 CLS_LOG(20, "add_child: omap write failed: %s", cpp_strerror(r).c_str());
1967 return r;
1968 }
1969
1970 /**
1971 * remove child from rbd_children directory object
1972 *
1973 * Input:
1974 * @param p_pool_id parent pool id
1975 * @param p_image_id parent image oid
1976 * @param p_snap_id parent snapshot id
1977 * @param c_image_id new child image oid to add
1978 *
1979 * @returns 0 on success, negative error on failure
1980 */
1981
1982 int remove_child(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1983 {
1984 int r;
1985
1986 uint64_t p_pool_id;
1987 snapid_t p_snap_id;
1988 string p_image_id, c_image_id;
1989 std::set<string> children;
1990
1991 r = decode_parent_and_child(in, &p_pool_id, &p_image_id, &p_snap_id,
1992 &c_image_id);
1993 if (r < 0)
1994 return r;
1995
1996 CLS_LOG(20, "remove_child %s from (%" PRIu64 ", %s, %" PRIu64 ")",
1997 c_image_id.c_str(), p_pool_id, p_image_id.c_str(),
1998 p_snap_id.val);
1999
2000 string key = parent_key(p_pool_id, p_image_id, p_snap_id);
2001
2002 // get current child list for parent. Unlike add_child(), an empty list
2003 // is an error (how can we remove something that doesn't exist?)
2004 r = read_key(hctx, key, &children);
2005 if (r < 0) {
2006 CLS_LOG(20, "remove_child: read omap failed: %s", cpp_strerror(r).c_str());
2007 return r;
2008 }
2009
2010 if (children.find(c_image_id) == children.end()) {
2011 CLS_LOG(20, "remove_child: child not found: %s", c_image_id.c_str());
2012 return -ENOENT;
2013 }
2014 // find and remove child
2015 children.erase(c_image_id);
2016
2017 // now empty? remove key altogether
2018 if (children.empty()) {
2019 r = cls_cxx_map_remove_key(hctx, key);
2020 if (r < 0)
2021 CLS_LOG(20, "remove_child: remove key failed: %s", cpp_strerror(r).c_str());
2022 } else {
2023 // write back shortened children list
2024 bufferlist childbl;
2025 encode(children, childbl);
2026 r = cls_cxx_map_set_val(hctx, key, &childbl);
2027 if (r < 0)
2028 CLS_LOG(20, "remove_child: write omap failed: %s", cpp_strerror(r).c_str());
2029 }
2030 return r;
2031 }
2032
2033 /**
2034 * Input:
2035 * @param p_pool_id parent pool id
2036 * @param p_image_id parent image oid
2037 * @param p_snap_id parent snapshot id
2038 * @param c_image_id new child image oid to add
2039 *
2040 * Output:
2041 * @param children set<string> of children
2042 *
2043 * @returns 0 on success, negative error on failure
2044 */
2045 int get_children(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2046 {
2047 int r;
2048 uint64_t p_pool_id;
2049 snapid_t p_snap_id;
2050 string p_image_id;
2051 std::set<string> children;
2052
2053 r = decode_parent(in, &p_pool_id, &p_image_id, &p_snap_id);
2054 if (r < 0)
2055 return r;
2056
2057 CLS_LOG(20, "get_children of (%" PRIu64 ", %s, %" PRIu64 ")",
2058 p_pool_id, p_image_id.c_str(), p_snap_id.val);
2059
2060 string key = parent_key(p_pool_id, p_image_id, p_snap_id);
2061
2062 r = read_key(hctx, key, &children);
2063 if (r < 0) {
2064 if (r != -ENOENT)
2065 CLS_LOG(20, "get_children: read omap failed: %s", cpp_strerror(r).c_str());
2066 return r;
2067 }
2068 encode(children, *out);
2069 return 0;
2070 }
2071
2072
2073 /**
2074 * Get the information needed to create a rados snap context for doing
2075 * I/O to the data objects. This must include all snapshots.
2076 *
2077 * Output:
2078 * @param snap_seq the highest snapshot id ever associated with the image (uint64_t)
2079 * @param snap_ids existing snapshot ids in descending order (vector<uint64_t>)
2080 * @returns 0 on success, negative error code on failure
2081 */
2082 int get_snapcontext(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2083 {
2084 CLS_LOG(20, "get_snapcontext");
2085
2086 int r;
2087 int max_read = RBD_MAX_KEYS_READ;
2088 vector<snapid_t> snap_ids;
2089 string last_read = RBD_SNAP_KEY_PREFIX;
2090 bool more;
2091
2092 do {
2093 set<string> keys;
2094 r = cls_cxx_map_get_keys(hctx, last_read, max_read, &keys, &more);
2095 if (r < 0)
2096 return r;
2097
2098 for (set<string>::const_iterator it = keys.begin();
2099 it != keys.end(); ++it) {
2100 if ((*it).find(RBD_SNAP_KEY_PREFIX) != 0)
2101 break;
2102 snapid_t snap_id = snap_id_from_key(*it);
2103 snap_ids.push_back(snap_id);
2104 }
2105 if (!keys.empty())
2106 last_read = *(keys.rbegin());
2107 } while (more);
2108
2109 uint64_t snap_seq;
2110 r = read_key(hctx, "snap_seq", &snap_seq);
2111 if (r < 0) {
2112 CLS_ERR("could not read the image's snap_seq off disk: %s", cpp_strerror(r).c_str());
2113 return r;
2114 }
2115
2116 // snap_ids must be descending in a snap context
2117 std::reverse(snap_ids.begin(), snap_ids.end());
2118
2119 encode(snap_seq, *out);
2120 encode(snap_ids, *out);
2121
2122 return 0;
2123 }
2124
2125 /**
2126 * Output:
2127 * @param object_prefix prefix for data object names (string)
2128 * @returns 0 on success, negative error code on failure
2129 */
2130 int get_object_prefix(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2131 {
2132 CLS_LOG(20, "get_object_prefix");
2133
2134 string object_prefix;
2135 int r = read_key(hctx, "object_prefix", &object_prefix);
2136 if (r < 0) {
2137 CLS_ERR("failed to read the image's object prefix off of disk: %s",
2138 cpp_strerror(r).c_str());
2139 return r;
2140 }
2141
2142 encode(object_prefix, *out);
2143
2144 return 0;
2145 }
2146
2147 /**
2148 * Input:
2149 * none
2150 *
2151 * Output:
2152 * @param pool_id (int64_t) of data pool or -1 if none
2153 * @returns 0 on success, negative error code on failure
2154 */
2155 int get_data_pool(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2156 {
2157 CLS_LOG(20, "get_data_pool");
2158
2159 int64_t data_pool_id = -1;
2160 int r = read_key(hctx, "data_pool_id", &data_pool_id);
2161 if (r == -ENOENT) {
2162 data_pool_id = -1;
2163 } else if (r < 0) {
2164 CLS_ERR("error reading image data pool id: %s", cpp_strerror(r).c_str());
2165 return r;
2166 }
2167
2168 encode(data_pool_id, *out);
2169 return 0;
2170 }
2171
2172 /**
2173 * Input:
2174 * @param snap_id which snapshot to query
2175 *
2176 * Output:
2177 * @param name (string) of the snapshot
2178 * @returns 0 on success, negative error code on failure
2179 */
2180 int get_snapshot_name(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2181 {
2182 uint64_t snap_id;
2183
2184 auto iter = in->cbegin();
2185 try {
2186 decode(snap_id, iter);
2187 } catch (const buffer::error &err) {
2188 return -EINVAL;
2189 }
2190
2191 CLS_LOG(20, "get_snapshot_name snap_id=%llu", (unsigned long long)snap_id);
2192
2193 if (snap_id == CEPH_NOSNAP)
2194 return -EINVAL;
2195
2196 cls_rbd_snap snap;
2197 string snapshot_key;
2198 key_from_snap_id(snap_id, &snapshot_key);
2199 int r = read_key(hctx, snapshot_key, &snap);
2200 if (r < 0)
2201 return r;
2202
2203 encode(snap.name, *out);
2204
2205 return 0;
2206 }
2207
2208 /**
2209 * Input:
2210 * @param snap_id which snapshot to query
2211 *
2212 * Output:
2213 * @param timestamp (utime_t) of the snapshot
2214 * @returns 0 on success, negative error code on failure
2215 *
2216 * NOTE: deprecated - remove this method after Luminous is unsupported
2217 */
2218 int get_snapshot_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2219 {
2220 uint64_t snap_id;
2221
2222 auto iter = in->cbegin();
2223 try {
2224 decode(snap_id, iter);
2225 } catch (const buffer::error &err) {
2226 return -EINVAL;
2227 }
2228
2229 CLS_LOG(20, "get_snapshot_timestamp snap_id=%llu", (unsigned long long)snap_id);
2230
2231 if (snap_id == CEPH_NOSNAP) {
2232 return -EINVAL;
2233 }
2234
2235 cls_rbd_snap snap;
2236 string snapshot_key;
2237 key_from_snap_id(snap_id, &snapshot_key);
2238 int r = read_key(hctx, snapshot_key, &snap);
2239 if (r < 0) {
2240 return r;
2241 }
2242
2243 encode(snap.timestamp, *out);
2244 return 0;
2245 }
2246
2247 /**
2248 * Input:
2249 * @param snap_id which snapshot to query
2250 *
2251 * Output:
2252 * @param snapshot (cls::rbd::SnapshotInfo)
2253 * @returns 0 on success, negative error code on failure
2254 */
2255 int snapshot_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2256 {
2257 uint64_t snap_id;
2258
2259 auto iter = in->cbegin();
2260 try {
2261 decode(snap_id, iter);
2262 } catch (const buffer::error &err) {
2263 return -EINVAL;
2264 }
2265
2266 CLS_LOG(20, "snapshot_get snap_id=%llu", (unsigned long long)snap_id);
2267 if (snap_id == CEPH_NOSNAP) {
2268 return -EINVAL;
2269 }
2270
2271 cls_rbd_snap snap;
2272 string snapshot_key;
2273 key_from_snap_id(snap_id, &snapshot_key);
2274 int r = read_key(hctx, snapshot_key, &snap);
2275 if (r < 0) {
2276 return r;
2277 }
2278
2279 cls::rbd::SnapshotInfo snapshot_info{snap.id, snap.snapshot_namespace,
2280 snap.name, snap.image_size,
2281 snap.timestamp, snap.child_count};
2282 encode(snapshot_info, *out);
2283 return 0;
2284 }
2285
2286 /**
2287 * Adds a snapshot to an rbd header. Ensures the id and name are unique.
2288 *
2289 * Input:
2290 * @param snap_name name of the snapshot (string)
2291 * @param snap_id id of the snapshot (uint64_t)
2292 * @param snap_namespace namespace of the snapshot (cls::rbd::SnapshotNamespace)
2293 *
2294 * Output:
2295 * @returns 0 on success, negative error code on failure.
2296 * @returns -ESTALE if the input snap_id is less than the image's snap_seq
2297 * @returns -EEXIST if the id or name are already used by another snapshot
2298 */
2299 int snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2300 {
2301 bufferlist snap_namebl, snap_idbl;
2302 cls_rbd_snap snap_meta;
2303 uint64_t snap_limit;
2304
2305 try {
2306 auto iter = in->cbegin();
2307 decode(snap_meta.name, iter);
2308 decode(snap_meta.id, iter);
2309 if (!iter.end()) {
2310 decode(snap_meta.snapshot_namespace, iter);
2311 }
2312 } catch (const buffer::error &err) {
2313 return -EINVAL;
2314 }
2315
2316 if (boost::get<cls::rbd::UnknownSnapshotNamespace>(
2317 &snap_meta.snapshot_namespace) != nullptr) {
2318 CLS_ERR("Unknown snapshot namespace provided");
2319 return -EINVAL;
2320 }
2321
2322 CLS_LOG(20, "snapshot_add name=%s id=%llu", snap_meta.name.c_str(),
2323 (unsigned long long)snap_meta.id.val);
2324
2325 if (snap_meta.id > CEPH_MAXSNAP)
2326 return -EINVAL;
2327
2328 uint64_t cur_snap_seq;
2329 int r = read_key(hctx, "snap_seq", &cur_snap_seq);
2330 if (r < 0) {
2331 CLS_ERR("Could not read image's snap_seq off disk: %s", cpp_strerror(r).c_str());
2332 return r;
2333 }
2334
2335 // client lost a race with another snapshot creation.
2336 // snap_seq must be monotonically increasing.
2337 if (snap_meta.id < cur_snap_seq)
2338 return -ESTALE;
2339
2340 r = read_key(hctx, "size", &snap_meta.image_size);
2341 if (r < 0) {
2342 CLS_ERR("Could not read image's size off disk: %s", cpp_strerror(r).c_str());
2343 return r;
2344 }
2345 r = read_key(hctx, "flags", &snap_meta.flags);
2346 if (r < 0 && r != -ENOENT) {
2347 CLS_ERR("Could not read image's flags off disk: %s", cpp_strerror(r).c_str());
2348 return r;
2349 }
2350
2351 r = read_key(hctx, "snap_limit", &snap_limit);
2352 if (r == -ENOENT) {
2353 snap_limit = UINT64_MAX;
2354 } else if (r < 0) {
2355 CLS_ERR("Could not read snapshot limit off disk: %s", cpp_strerror(r).c_str());
2356 return r;
2357 }
2358
2359 snap_meta.timestamp = ceph_clock_now();
2360
2361 uint64_t total_read = 0;
2362 auto pre_check_lambda =
2363 [&snap_meta, &total_read, snap_limit](const cls_rbd_snap& old_meta) {
2364 ++total_read;
2365 if (total_read >= snap_limit) {
2366 CLS_ERR("Attempt to create snapshot over limit of %" PRIu64,
2367 snap_limit);
2368 return -EDQUOT;
2369 }
2370
2371 if ((snap_meta.name == old_meta.name &&
2372 snap_meta.snapshot_namespace == old_meta.snapshot_namespace) ||
2373 snap_meta.id == old_meta.id) {
2374 CLS_LOG(20, "snap_name %s or snap_id %" PRIu64 " matches existing snap "
2375 "%s %" PRIu64, snap_meta.name.c_str(), snap_meta.id.val,
2376 old_meta.name.c_str(), old_meta.id.val);
2377 return -EEXIST;
2378 }
2379 return 0;
2380 };
2381
2382 r = image::snapshot::iterate(hctx, pre_check_lambda);
2383 if (r < 0) {
2384 return r;
2385 }
2386
2387 // snapshot inherits parent, if any
2388 cls_rbd_parent parent;
2389 r = read_key(hctx, "parent", &parent);
2390 if (r < 0 && r != -ENOENT) {
2391 return r;
2392 }
2393 if (r == 0) {
2394 // write helper method will convert to normalized format if required
2395 snap_meta.parent = parent;
2396 }
2397
2398 if (cls::rbd::get_snap_namespace_type(snap_meta.snapshot_namespace) ==
2399 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
2400 // add snap_trash feature bit if not already enabled
2401 r = image::set_op_features(hctx, RBD_OPERATION_FEATURE_SNAP_TRASH,
2402 RBD_OPERATION_FEATURE_SNAP_TRASH);
2403 if (r < 0) {
2404 return r;
2405 }
2406 }
2407
2408 r = write_key(hctx, "snap_seq", snap_meta.id);
2409 if (r < 0) {
2410 return r;
2411 }
2412
2413 std::string snapshot_key;
2414 key_from_snap_id(snap_meta.id, &snapshot_key);
2415 r = image::snapshot::write(hctx, snapshot_key, std::move(snap_meta));
2416 if (r < 0) {
2417 return r;
2418 }
2419
2420 return 0;
2421 }
2422
2423 /**
2424 * rename snapshot .
2425 *
2426 * Input:
2427 * @param src_snap_id old snap id of the snapshot (snapid_t)
2428 * @param dst_snap_name new name of the snapshot (string)
2429 *
2430 * Output:
2431 * @returns 0 on success, negative error code on failure.
2432 */
2433 int snapshot_rename(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2434 {
2435 bufferlist snap_namebl, snap_idbl;
2436 snapid_t src_snap_id;
2437 string dst_snap_name;
2438 cls_rbd_snap snap_meta;
2439 int r;
2440
2441 try {
2442 auto iter = in->cbegin();
2443 decode(src_snap_id, iter);
2444 decode(dst_snap_name, iter);
2445 } catch (const buffer::error &err) {
2446 return -EINVAL;
2447 }
2448
2449 CLS_LOG(20, "snapshot_rename id=%" PRIu64 ", dst_name=%s",
2450 src_snap_id.val, dst_snap_name.c_str());
2451
2452 auto duplicate_name_lambda = [&dst_snap_name](const cls_rbd_snap& snap_meta) {
2453 if (cls::rbd::get_snap_namespace_type(snap_meta.snapshot_namespace) ==
2454 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER &&
2455 snap_meta.name == dst_snap_name) {
2456 CLS_LOG(20, "snap_name %s matches existing snap with snap id %" PRIu64,
2457 dst_snap_name.c_str(), snap_meta.id.val);
2458 return -EEXIST;
2459 }
2460 return 0;
2461 };
2462 r = image::snapshot::iterate(hctx, duplicate_name_lambda);
2463 if (r < 0) {
2464 return r;
2465 }
2466
2467 std::string src_snap_key;
2468 key_from_snap_id(src_snap_id, &src_snap_key);
2469 r = read_key(hctx, src_snap_key, &snap_meta);
2470 if (r == -ENOENT) {
2471 CLS_LOG(20, "cannot find existing snap with snap id = %" PRIu64,
2472 src_snap_id.val);
2473 return r;
2474 }
2475
2476 if (cls::rbd::get_snap_namespace_type(snap_meta.snapshot_namespace) !=
2477 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER) {
2478 // can only rename user snapshots
2479 return -EINVAL;
2480 }
2481
2482 snap_meta.name = dst_snap_name;
2483 r = image::snapshot::write(hctx, src_snap_key, std::move(snap_meta));
2484 if (r < 0) {
2485 return r;
2486 }
2487
2488 return 0;
2489 }
2490
2491 /**
2492 * Removes a snapshot from an rbd header.
2493 *
2494 * Input:
2495 * @param snap_id the id of the snapshot to remove (uint64_t)
2496 *
2497 * Output:
2498 * @returns 0 on success, negative error code on failure
2499 */
2500 int snapshot_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2501 {
2502 snapid_t snap_id;
2503
2504 try {
2505 auto iter = in->cbegin();
2506 decode(snap_id, iter);
2507 } catch (const buffer::error &err) {
2508 return -EINVAL;
2509 }
2510
2511 CLS_LOG(20, "snapshot_remove id=%llu", (unsigned long long)snap_id.val);
2512
2513 // check if the key exists. we can't rely on remove_key doing this for
2514 // us, since OMAPRMKEYS returns success if the key is not there.
2515 // bug or feature? sounds like a bug, since tmap did not have this
2516 // behavior, but cls_rgw may rely on it...
2517 cls_rbd_snap snap;
2518 string snapshot_key;
2519 key_from_snap_id(snap_id, &snapshot_key);
2520 int r = read_key(hctx, snapshot_key, &snap);
2521 if (r == -ENOENT) {
2522 return -ENOENT;
2523 }
2524
2525 if (snap.protection_status != RBD_PROTECTION_STATUS_UNPROTECTED) {
2526 return -EBUSY;
2527 }
2528
2529 // snapshot is in-use by clone v2 child
2530 if (snap.child_count > 0) {
2531 return -EBUSY;
2532 }
2533
2534 r = remove_key(hctx, snapshot_key);
2535 if (r < 0) {
2536 return r;
2537 }
2538
2539 bool has_child_snaps = false;
2540 bool has_trash_snaps = false;
2541 auto remove_lambda = [snap_id, &has_child_snaps, &has_trash_snaps](
2542 const cls_rbd_snap& snap_meta) {
2543 if (snap_meta.id != snap_id) {
2544 if (snap_meta.parent.pool_id != -1 || snap_meta.parent_overlap) {
2545 has_child_snaps = true;
2546 }
2547
2548 if (cls::rbd::get_snap_namespace_type(snap_meta.snapshot_namespace) ==
2549 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
2550 has_trash_snaps = true;
2551 }
2552 }
2553 return 0;
2554 };
2555
2556 r = image::snapshot::iterate(hctx, remove_lambda);
2557 if (r < 0) {
2558 return r;
2559 }
2560
2561 cls_rbd_parent parent;
2562 r = read_key(hctx, "parent", &parent);
2563 if (r < 0 && r != -ENOENT) {
2564 return r;
2565 }
2566
2567 bool has_parent = (r >= 0 && parent.exists());
2568 bool is_head_child = (has_parent && parent.head_overlap);
2569 int8_t require_osd_release = cls_get_required_osd_release(hctx);
2570 if (has_parent && !is_head_child && !has_child_snaps &&
2571 require_osd_release >= CEPH_RELEASE_NAUTILUS) {
2572 // remove the unused parent image spec
2573 r = remove_key(hctx, "parent");
2574 if (r < 0 && r != -ENOENT) {
2575 return r;
2576 }
2577 }
2578
2579 uint64_t op_features_mask = 0ULL;
2580 if (!has_child_snaps && !is_head_child) {
2581 // disable clone child op feature if no longer associated
2582 op_features_mask |= RBD_OPERATION_FEATURE_CLONE_CHILD;
2583 }
2584 if (!has_trash_snaps) {
2585 // remove the snap_trash op feature if not in-use by any other snapshots
2586 op_features_mask |= RBD_OPERATION_FEATURE_SNAP_TRASH;
2587 }
2588
2589 if (op_features_mask != 0ULL) {
2590 r = image::set_op_features(hctx, 0, op_features_mask);
2591 if (r < 0) {
2592 return r;
2593 }
2594 }
2595
2596 return 0;
2597 }
2598
2599 /**
2600 * Moves a snapshot to the trash namespace.
2601 *
2602 * Input:
2603 * @param snap_id the id of the snapshot to move to the trash (uint64_t)
2604 *
2605 * Output:
2606 * @returns 0 on success, negative error code on failure
2607 */
2608 int snapshot_trash_add(cls_method_context_t hctx, bufferlist *in,
2609 bufferlist *out)
2610 {
2611 snapid_t snap_id;
2612
2613 try {
2614 auto iter = in->cbegin();
2615 decode(snap_id, iter);
2616 } catch (const buffer::error &err) {
2617 return -EINVAL;
2618 }
2619
2620 CLS_LOG(20, "snapshot_trash_add id=%" PRIu64, snap_id.val);
2621
2622 cls_rbd_snap snap;
2623 std::string snapshot_key;
2624 key_from_snap_id(snap_id, &snapshot_key);
2625 int r = read_key(hctx, snapshot_key, &snap);
2626 if (r == -ENOENT) {
2627 return r;
2628 }
2629
2630 if (snap.protection_status != RBD_PROTECTION_STATUS_UNPROTECTED) {
2631 return -EBUSY;
2632 }
2633
2634 auto snap_type = cls::rbd::get_snap_namespace_type(snap.snapshot_namespace);
2635 if (snap_type == cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
2636 return -EEXIST;
2637 }
2638
2639 // add snap_trash feature bit if not already enabled
2640 r = image::set_op_features(hctx, RBD_OPERATION_FEATURE_SNAP_TRASH,
2641 RBD_OPERATION_FEATURE_SNAP_TRASH);
2642 if (r < 0) {
2643 return r;
2644 }
2645
2646 snap.snapshot_namespace = cls::rbd::TrashSnapshotNamespace{snap_type,
2647 snap.name};
2648 uuid_d uuid_gen;
2649 uuid_gen.generate_random();
2650 snap.name = uuid_gen.to_string();
2651
2652 r = image::snapshot::write(hctx, snapshot_key, std::move(snap));
2653 if (r < 0) {
2654 return r;
2655 }
2656
2657 return 0;
2658 }
2659
2660 /**
2661 * Returns a uint64_t of all the features supported by this class.
2662 */
2663 int get_all_features(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2664 {
2665 uint64_t all_features = RBD_FEATURES_ALL;
2666 encode(all_features, *out);
2667 return 0;
2668 }
2669
2670 /**
2671 * "Copy up" data from the parent of a clone to the clone's object(s).
2672 * Used for implementing copy-on-write for a clone image. Client
2673 * will pass down a chunk of data that fits completely within one
2674 * clone block (one object), and is aligned (starts at beginning of block),
2675 * but may be shorter (for non-full parent blocks). The class method
2676 * can't know the object size to validate the requested length,
2677 * so it just writes the data as given if the child object doesn't
2678 * already exist, and returns success if it does.
2679 *
2680 * Input:
2681 * @param in bufferlist of data to write
2682 *
2683 * Output:
2684 * @returns 0 on success, or if block already exists in child
2685 * negative error code on other error
2686 */
2687
2688 int copyup(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2689 {
2690 // check for existence; if child object exists, just return success
2691 if (cls_cxx_stat(hctx, NULL, NULL) == 0)
2692 return 0;
2693 CLS_LOG(20, "copyup: writing length %d\n", in->length());
2694 return cls_cxx_write(hctx, 0, in->length(), in);
2695 }
2696
2697
2698 /************************ rbd_id object methods **************************/
2699
2700 /**
2701 * Input:
2702 * @param in ignored
2703 *
2704 * Output:
2705 * @param id the id stored in the object
2706 * @returns 0 on success, negative error code on failure
2707 */
2708 int get_id(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2709 {
2710 uint64_t size;
2711 int r = cls_cxx_stat(hctx, &size, NULL);
2712 if (r < 0)
2713 return r;
2714
2715 if (size == 0)
2716 return -ENOENT;
2717
2718 bufferlist read_bl;
2719 r = cls_cxx_read(hctx, 0, size, &read_bl);
2720 if (r < 0) {
2721 CLS_ERR("get_id: could not read id: %s", cpp_strerror(r).c_str());
2722 return r;
2723 }
2724
2725 string id;
2726 try {
2727 auto iter = read_bl.cbegin();
2728 decode(id, iter);
2729 } catch (const buffer::error &err) {
2730 return -EIO;
2731 }
2732
2733 encode(id, *out);
2734 return 0;
2735 }
2736
2737 /**
2738 * Set the id of an image. The object must already exist.
2739 *
2740 * Input:
2741 * @param id the id of the image, as an alpha-numeric string
2742 *
2743 * Output:
2744 * @returns 0 on success, -EEXIST if the atomic create fails,
2745 * negative error code on other error
2746 */
2747 int set_id(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2748 {
2749 int r = check_exists(hctx);
2750 if (r < 0)
2751 return r;
2752
2753 string id;
2754 try {
2755 auto iter = in->cbegin();
2756 decode(id, iter);
2757 } catch (const buffer::error &err) {
2758 return -EINVAL;
2759 }
2760
2761 if (!is_valid_id(id)) {
2762 CLS_ERR("set_id: invalid id '%s'", id.c_str());
2763 return -EINVAL;
2764 }
2765
2766 uint64_t size;
2767 r = cls_cxx_stat(hctx, &size, NULL);
2768 if (r < 0)
2769 return r;
2770 if (size != 0)
2771 return -EEXIST;
2772
2773 CLS_LOG(20, "set_id: id=%s", id.c_str());
2774
2775 bufferlist write_bl;
2776 encode(id, write_bl);
2777 return cls_cxx_write(hctx, 0, write_bl.length(), &write_bl);
2778 }
2779
2780 /**
2781 * Update the access timestamp of an image
2782 *
2783 * Input:
2784 * @param none
2785 *
2786 * Output:
2787 * @returns 0 on success, negative error code on other error
2788 */
2789 int set_access_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2790 {
2791 int r = check_exists(hctx);
2792 if(r < 0)
2793 return r;
2794
2795 utime_t timestamp = ceph_clock_now();
2796 r = write_key(hctx, "access_timestamp", timestamp);
2797 if(r < 0) {
2798 CLS_ERR("error setting access_timestamp");
2799 return r;
2800 }
2801
2802 return 0;
2803 }
2804
2805 /**
2806 * Update the modify timestamp of an image
2807 *
2808 * Input:
2809 * @param none
2810 *
2811 * Output:
2812 * @returns 0 on success, negative error code on other error
2813 */
2814
2815 int set_modify_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2816 {
2817 int r = check_exists(hctx);
2818 if(r < 0)
2819 return r;
2820
2821 utime_t timestamp = ceph_clock_now();
2822 r = write_key(hctx, "modify_timestamp", timestamp);
2823 if(r < 0) {
2824 CLS_ERR("error setting modify_timestamp");
2825 return r;
2826 }
2827
2828 return 0;
2829 }
2830
2831
2832
2833 /*********************** methods for rbd_directory ***********************/
2834
2835 static const string dir_key_for_id(const string &id)
2836 {
2837 return RBD_DIR_ID_KEY_PREFIX + id;
2838 }
2839
2840 static const string dir_key_for_name(const string &name)
2841 {
2842 return RBD_DIR_NAME_KEY_PREFIX + name;
2843 }
2844
2845 static const string dir_name_from_key(const string &key)
2846 {
2847 return key.substr(strlen(RBD_DIR_NAME_KEY_PREFIX));
2848 }
2849
2850 static int dir_add_image_helper(cls_method_context_t hctx,
2851 const string &name, const string &id,
2852 bool check_for_unique_id)
2853 {
2854 if (!name.size() || !is_valid_id(id)) {
2855 CLS_ERR("dir_add_image_helper: invalid name '%s' or id '%s'",
2856 name.c_str(), id.c_str());
2857 return -EINVAL;
2858 }
2859
2860 CLS_LOG(20, "dir_add_image_helper name=%s id=%s", name.c_str(), id.c_str());
2861
2862 string tmp;
2863 string name_key = dir_key_for_name(name);
2864 string id_key = dir_key_for_id(id);
2865 int r = read_key(hctx, name_key, &tmp);
2866 if (r != -ENOENT) {
2867 CLS_LOG(10, "name already exists");
2868 return -EEXIST;
2869 }
2870 r = read_key(hctx, id_key, &tmp);
2871 if (r != -ENOENT && check_for_unique_id) {
2872 CLS_LOG(10, "id already exists");
2873 return -EBADF;
2874 }
2875 bufferlist id_bl, name_bl;
2876 encode(id, id_bl);
2877 encode(name, name_bl);
2878 map<string, bufferlist> omap_vals;
2879 omap_vals[name_key] = id_bl;
2880 omap_vals[id_key] = name_bl;
2881 return cls_cxx_map_set_vals(hctx, &omap_vals);
2882 }
2883
2884 static int dir_remove_image_helper(cls_method_context_t hctx,
2885 const string &name, const string &id)
2886 {
2887 CLS_LOG(20, "dir_remove_image_helper name=%s id=%s",
2888 name.c_str(), id.c_str());
2889
2890 string stored_name, stored_id;
2891 string name_key = dir_key_for_name(name);
2892 string id_key = dir_key_for_id(id);
2893 int r = read_key(hctx, name_key, &stored_id);
2894 if (r < 0) {
2895 if (r != -ENOENT)
2896 CLS_ERR("error reading name to id mapping: %s", cpp_strerror(r).c_str());
2897 return r;
2898 }
2899 r = read_key(hctx, id_key, &stored_name);
2900 if (r < 0) {
2901 CLS_ERR("error reading id to name mapping: %s", cpp_strerror(r).c_str());
2902 return r;
2903 }
2904
2905 // check if this op raced with a rename
2906 if (stored_name != name || stored_id != id) {
2907 CLS_ERR("stored name '%s' and id '%s' do not match args '%s' and '%s'",
2908 stored_name.c_str(), stored_id.c_str(), name.c_str(), id.c_str());
2909 return -ESTALE;
2910 }
2911
2912 r = cls_cxx_map_remove_key(hctx, name_key);
2913 if (r < 0) {
2914 CLS_ERR("error removing name: %s", cpp_strerror(r).c_str());
2915 return r;
2916 }
2917
2918 r = cls_cxx_map_remove_key(hctx, id_key);
2919 if (r < 0) {
2920 CLS_ERR("error removing id: %s", cpp_strerror(r).c_str());
2921 return r;
2922 }
2923
2924 return 0;
2925 }
2926
2927 /**
2928 * Rename an image in the directory, updating both indexes
2929 * atomically. This can't be done from the client calling
2930 * dir_add_image and dir_remove_image in one transaction because the
2931 * results of the first method are not visibale to later steps.
2932 *
2933 * Input:
2934 * @param src original name of the image
2935 * @param dest new name of the image
2936 * @param id the id of the image
2937 *
2938 * Output:
2939 * @returns -ESTALE if src and id do not map to each other
2940 * @returns -ENOENT if src or id are not in the directory
2941 * @returns -EEXIST if dest already exists
2942 * @returns 0 on success, negative error code on failure
2943 */
2944 int dir_rename_image(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2945 {
2946 string src, dest, id;
2947 try {
2948 auto iter = in->cbegin();
2949 decode(src, iter);
2950 decode(dest, iter);
2951 decode(id, iter);
2952 } catch (const buffer::error &err) {
2953 return -EINVAL;
2954 }
2955
2956 int r = dir_remove_image_helper(hctx, src, id);
2957 if (r < 0)
2958 return r;
2959 // ignore duplicate id because the result of
2960 // remove_image_helper is not visible yet
2961 return dir_add_image_helper(hctx, dest, id, false);
2962 }
2963
2964 /**
2965 * Get the id of an image given its name.
2966 *
2967 * Input:
2968 * @param name the name of the image
2969 *
2970 * Output:
2971 * @param id the id of the image
2972 * @returns 0 on success, negative error code on failure
2973 */
2974 int dir_get_id(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
2975 {
2976 string name;
2977
2978 try {
2979 auto iter = in->cbegin();
2980 decode(name, iter);
2981 } catch (const buffer::error &err) {
2982 return -EINVAL;
2983 }
2984
2985 CLS_LOG(20, "dir_get_id: name=%s", name.c_str());
2986
2987 string id;
2988 int r = read_key(hctx, dir_key_for_name(name), &id);
2989 if (r < 0) {
2990 if (r != -ENOENT)
2991 CLS_ERR("error reading id for name '%s': %s", name.c_str(), cpp_strerror(r).c_str());
2992 return r;
2993 }
2994 encode(id, *out);
2995 return 0;
2996 }
2997
2998 /**
2999 * Get the name of an image given its id.
3000 *
3001 * Input:
3002 * @param id the id of the image
3003 *
3004 * Output:
3005 * @param name the name of the image
3006 * @returns 0 on success, negative error code on failure
3007 */
3008 int dir_get_name(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3009 {
3010 string id;
3011
3012 try {
3013 auto iter = in->cbegin();
3014 decode(id, iter);
3015 } catch (const buffer::error &err) {
3016 return -EINVAL;
3017 }
3018
3019 CLS_LOG(20, "dir_get_name: id=%s", id.c_str());
3020
3021 string name;
3022 int r = read_key(hctx, dir_key_for_id(id), &name);
3023 if (r < 0) {
3024 if (r != -ENOENT) {
3025 CLS_ERR("error reading name for id '%s': %s", id.c_str(),
3026 cpp_strerror(r).c_str());
3027 }
3028 return r;
3029 }
3030 encode(name, *out);
3031 return 0;
3032 }
3033
3034 /**
3035 * List the names and ids of the images in the directory, sorted by
3036 * name.
3037 *
3038 * Input:
3039 * @param start_after which name to begin listing after
3040 * (use the empty string to start at the beginning)
3041 * @param max_return the maximum number of names to list
3042 *
3043 * Output:
3044 * @param images map from name to id of up to max_return images
3045 * @returns 0 on success, negative error code on failure
3046 */
3047 int dir_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3048 {
3049 string start_after;
3050 uint64_t max_return;
3051
3052 try {
3053 auto iter = in->cbegin();
3054 decode(start_after, iter);
3055 decode(max_return, iter);
3056 } catch (const buffer::error &err) {
3057 return -EINVAL;
3058 }
3059
3060 int max_read = RBD_MAX_KEYS_READ;
3061 map<string, string> images;
3062 string last_read = dir_key_for_name(start_after);
3063 bool more = true;
3064
3065 while (more && images.size() < max_return) {
3066 map<string, bufferlist> vals;
3067 CLS_LOG(20, "last_read = '%s'", last_read.c_str());
3068 int r = cls_cxx_map_get_vals(hctx, last_read, RBD_DIR_NAME_KEY_PREFIX,
3069 max_read, &vals, &more);
3070 if (r < 0) {
3071 if (r != -ENOENT) {
3072 CLS_ERR("error reading directory by name: %s", cpp_strerror(r).c_str());
3073 }
3074 return r;
3075 }
3076
3077 for (map<string, bufferlist>::iterator it = vals.begin();
3078 it != vals.end(); ++it) {
3079 string id;
3080 auto iter = it->second.cbegin();
3081 try {
3082 decode(id, iter);
3083 } catch (const buffer::error &err) {
3084 CLS_ERR("could not decode id of image '%s'", it->first.c_str());
3085 return -EIO;
3086 }
3087 CLS_LOG(20, "adding '%s' -> '%s'", dir_name_from_key(it->first).c_str(), id.c_str());
3088 images[dir_name_from_key(it->first)] = id;
3089 if (images.size() >= max_return)
3090 break;
3091 }
3092 if (!vals.empty()) {
3093 last_read = dir_key_for_name(images.rbegin()->first);
3094 }
3095 }
3096
3097 encode(images, *out);
3098
3099 return 0;
3100 }
3101
3102 /**
3103 * Add an image to the rbd directory. Creates the directory object if
3104 * needed, and updates the index from id to name and name to id.
3105 *
3106 * Input:
3107 * @param name the name of the image
3108 * @param id the id of the image
3109 *
3110 * Output:
3111 * @returns -EEXIST if the image name is already in the directory
3112 * @returns -EBADF if the image id is already in the directory
3113 * @returns 0 on success, negative error code on failure
3114 */
3115 int dir_add_image(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3116 {
3117 int r = cls_cxx_create(hctx, false);
3118 if (r < 0) {
3119 CLS_ERR("could not create directory: %s", cpp_strerror(r).c_str());
3120 return r;
3121 }
3122
3123 string name, id;
3124 try {
3125 auto iter = in->cbegin();
3126 decode(name, iter);
3127 decode(id, iter);
3128 } catch (const buffer::error &err) {
3129 return -EINVAL;
3130 }
3131
3132 return dir_add_image_helper(hctx, name, id, true);
3133 }
3134
3135 /**
3136 * Remove an image from the rbd directory.
3137 *
3138 * Input:
3139 * @param name the name of the image
3140 * @param id the id of the image
3141 *
3142 * Output:
3143 * @returns -ESTALE if the name and id do not map to each other
3144 * @returns 0 on success, negative error code on failure
3145 */
3146 int dir_remove_image(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3147 {
3148 string name, id;
3149 try {
3150 auto iter = in->cbegin();
3151 decode(name, iter);
3152 decode(id, iter);
3153 } catch (const buffer::error &err) {
3154 return -EINVAL;
3155 }
3156
3157 return dir_remove_image_helper(hctx, name, id);
3158 }
3159
3160 /**
3161 * Verify the current state of the directory
3162 *
3163 * Input:
3164 * @param state the DirectoryState of the directory
3165 *
3166 * Output:
3167 * @returns -ENOENT if the state does not match
3168 * @returns 0 on success, negative error code on failure
3169 */
3170 int dir_state_assert(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3171 {
3172 cls::rbd::DirectoryState directory_state = cls::rbd::DIRECTORY_STATE_READY;
3173 try {
3174 auto iter = in->cbegin();
3175 decode(directory_state, iter);
3176 } catch (const buffer::error &err) {
3177 return -EINVAL;
3178 }
3179
3180 cls::rbd::DirectoryState on_disk_directory_state = directory_state;
3181 int r = read_key(hctx, "state", &on_disk_directory_state);
3182 if (r < 0) {
3183 return r;
3184 }
3185
3186 if (directory_state != on_disk_directory_state) {
3187 return -ENOENT;
3188 }
3189 return 0;
3190 }
3191
3192 /**
3193 * Set the current state of the directory
3194 *
3195 * Input:
3196 * @param state the DirectoryState of the directory
3197 *
3198 * Output:
3199 * @returns -ENOENT if the state does not match
3200 * @returns 0 on success, negative error code on failure
3201 */
3202 int dir_state_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3203 {
3204 cls::rbd::DirectoryState directory_state;
3205 try {
3206 auto iter = in->cbegin();
3207 decode(directory_state, iter);
3208 } catch (const buffer::error &err) {
3209 return -EINVAL;
3210 }
3211
3212 int r = check_exists(hctx);
3213 if (r < 0 && r != -ENOENT) {
3214 return r;
3215 }
3216
3217 switch (directory_state) {
3218 case cls::rbd::DIRECTORY_STATE_READY:
3219 break;
3220 case cls::rbd::DIRECTORY_STATE_ADD_DISABLED:
3221 {
3222 if (r == -ENOENT) {
3223 return r;
3224 }
3225
3226 // verify that the directory is empty
3227 std::map<std::string, bufferlist> vals;
3228 bool more;
3229 r = cls_cxx_map_get_vals(hctx, RBD_DIR_NAME_KEY_PREFIX,
3230 RBD_DIR_NAME_KEY_PREFIX, 1, &vals, &more);
3231 if (r < 0) {
3232 return r;
3233 } else if (!vals.empty()) {
3234 return -EBUSY;
3235 }
3236 }
3237 break;
3238 default:
3239 return -EINVAL;
3240 }
3241
3242 r = write_key(hctx, "state", directory_state);
3243 if (r < 0) {
3244 return r;
3245 }
3246
3247 return 0;
3248 }
3249
3250 int object_map_read(cls_method_context_t hctx, BitVector<2> &object_map)
3251 {
3252 uint64_t size;
3253 int r = cls_cxx_stat(hctx, &size, NULL);
3254 if (r < 0) {
3255 return r;
3256 }
3257 if (size == 0) {
3258 return -ENOENT;
3259 }
3260
3261 bufferlist bl;
3262 r = cls_cxx_read(hctx, 0, size, &bl);
3263 if (r < 0) {
3264 return r;
3265 }
3266
3267 try {
3268 auto iter = bl.cbegin();
3269 decode(object_map, iter);
3270 } catch (const buffer::error &err) {
3271 CLS_ERR("failed to decode object map: %s", err.what());
3272 return -EINVAL;
3273 }
3274 return 0;
3275 }
3276
3277 /**
3278 * Load an rbd image's object map
3279 *
3280 * Input:
3281 * none
3282 *
3283 * Output:
3284 * @param object map bit vector
3285 * @returns 0 on success, negative error code on failure
3286 */
3287 int object_map_load(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3288 {
3289 BitVector<2> object_map;
3290 int r = object_map_read(hctx, object_map);
3291 if (r < 0) {
3292 return r;
3293 }
3294
3295 object_map.set_crc_enabled(false);
3296 encode(object_map, *out);
3297 return 0;
3298 }
3299
3300 /**
3301 * Save an rbd image's object map
3302 *
3303 * Input:
3304 * @param object map bit vector
3305 *
3306 * Output:
3307 * @returns 0 on success, negative error code on failure
3308 */
3309 int object_map_save(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3310 {
3311 BitVector<2> object_map;
3312 try {
3313 auto iter = in->cbegin();
3314 decode(object_map, iter);
3315 } catch (const buffer::error &err) {
3316 return -EINVAL;
3317 }
3318
3319 object_map.set_crc_enabled(true);
3320
3321 bufferlist bl;
3322 encode(object_map, bl);
3323 CLS_LOG(20, "object_map_save: object size=%" PRIu64 ", byte size=%u",
3324 object_map.size(), bl.length());
3325 return cls_cxx_write_full(hctx, &bl);
3326 }
3327
3328 /**
3329 * Resize an rbd image's object map
3330 *
3331 * Input:
3332 * @param object_count the max number of objects in the image
3333 * @param default_state the default state of newly created objects
3334 *
3335 * Output:
3336 * @returns 0 on success, negative error code on failure
3337 */
3338 int object_map_resize(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3339 {
3340 uint64_t object_count;
3341 uint8_t default_state;
3342 try {
3343 auto iter = in->cbegin();
3344 decode(object_count, iter);
3345 decode(default_state, iter);
3346 } catch (const buffer::error &err) {
3347 return -EINVAL;
3348 }
3349
3350 // protect against excessive memory requirements
3351 if (object_count > cls::rbd::MAX_OBJECT_MAP_OBJECT_COUNT) {
3352 CLS_ERR("object map too large: %" PRIu64, object_count);
3353 return -EINVAL;
3354 }
3355
3356 BitVector<2> object_map;
3357 int r = object_map_read(hctx, object_map);
3358 if ((r < 0) && (r != -ENOENT)) {
3359 return r;
3360 }
3361
3362 size_t orig_object_map_size = object_map.size();
3363 if (object_count < orig_object_map_size) {
3364 auto it = object_map.begin() + object_count;
3365 auto end_it = object_map.end() ;
3366 uint64_t i = object_count;
3367 for (; it != end_it; ++it, ++i) {
3368 if (*it != default_state) {
3369 CLS_ERR("object map indicates object still exists: %" PRIu64, i);
3370 return -ESTALE;
3371 }
3372 }
3373 object_map.resize(object_count);
3374 } else if (object_count > orig_object_map_size) {
3375 object_map.resize(object_count);
3376 auto it = object_map.begin() + orig_object_map_size;
3377 auto end_it = object_map.end();
3378 for (; it != end_it; ++it) {
3379 *it = default_state;
3380 }
3381 }
3382
3383 bufferlist map;
3384 encode(object_map, map);
3385 CLS_LOG(20, "object_map_resize: object size=%" PRIu64 ", byte size=%u",
3386 object_count, map.length());
3387 return cls_cxx_write_full(hctx, &map);
3388 }
3389
3390 /**
3391 * Update an rbd image's object map
3392 *
3393 * Input:
3394 * @param start_object_no the start object iterator
3395 * @param end_object_no the end object iterator
3396 * @param new_object_state the new object state
3397 * @param current_object_state optional current object state filter
3398 *
3399 * Output:
3400 * @returns 0 on success, negative error code on failure
3401 */
3402 int object_map_update(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3403 {
3404 uint64_t start_object_no;
3405 uint64_t end_object_no;
3406 uint8_t new_object_state;
3407 boost::optional<uint8_t> current_object_state;
3408 try {
3409 auto iter = in->cbegin();
3410 decode(start_object_no, iter);
3411 decode(end_object_no, iter);
3412 decode(new_object_state, iter);
3413 decode(current_object_state, iter);
3414 } catch (const buffer::error &err) {
3415 CLS_ERR("failed to decode message");
3416 return -EINVAL;
3417 }
3418
3419 uint64_t size;
3420 int r = cls_cxx_stat(hctx, &size, NULL);
3421 if (r < 0) {
3422 return r;
3423 }
3424
3425 BitVector<2> object_map;
3426 bufferlist header_bl;
3427 r = cls_cxx_read2(hctx, 0, object_map.get_header_length(), &header_bl,
3428 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
3429 if (r < 0) {
3430 CLS_ERR("object map header read failed");
3431 return r;
3432 }
3433
3434 try {
3435 auto it = header_bl.cbegin();
3436 object_map.decode_header(it);
3437 } catch (const buffer::error &err) {
3438 CLS_ERR("failed to decode object map header: %s", err.what());
3439 return -EINVAL;
3440 }
3441
3442 uint64_t object_byte_offset;
3443 uint64_t byte_length;
3444 object_map.get_header_crc_extents(&object_byte_offset, &byte_length);
3445
3446 bufferlist footer_bl;
3447 r = cls_cxx_read2(hctx, object_byte_offset, byte_length, &footer_bl,
3448 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
3449 if (r < 0) {
3450 CLS_ERR("object map footer read header CRC failed");
3451 return r;
3452 }
3453
3454 try {
3455 auto it = footer_bl.cbegin();
3456 object_map.decode_header_crc(it);
3457 } catch (const buffer::error &err) {
3458 CLS_ERR("failed to decode object map header CRC: %s", err.what());
3459 }
3460
3461 if (start_object_no >= end_object_no || end_object_no > object_map.size()) {
3462 return -ERANGE;
3463 }
3464
3465 uint64_t object_count = end_object_no - start_object_no;
3466 object_map.get_data_crcs_extents(start_object_no, object_count,
3467 &object_byte_offset, &byte_length);
3468 const auto footer_object_offset = object_byte_offset;
3469
3470 footer_bl.clear();
3471 r = cls_cxx_read2(hctx, object_byte_offset, byte_length, &footer_bl,
3472 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
3473 if (r < 0) {
3474 CLS_ERR("object map footer read data CRCs failed");
3475 return r;
3476 }
3477
3478 try {
3479 auto it = footer_bl.cbegin();
3480 object_map.decode_data_crcs(it, start_object_no);
3481 } catch (const buffer::error &err) {
3482 CLS_ERR("failed to decode object map data CRCs: %s", err.what());
3483 }
3484
3485 uint64_t data_byte_offset;
3486 object_map.get_data_extents(start_object_no, object_count,
3487 &data_byte_offset, &object_byte_offset,
3488 &byte_length);
3489
3490 bufferlist data_bl;
3491 r = cls_cxx_read2(hctx, object_byte_offset, byte_length, &data_bl,
3492 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
3493 if (r < 0) {
3494 CLS_ERR("object map data read failed");
3495 return r;
3496 }
3497
3498 try {
3499 auto it = data_bl.cbegin();
3500 object_map.decode_data(it, data_byte_offset);
3501 } catch (const buffer::error &err) {
3502 CLS_ERR("failed to decode data chunk [%" PRIu64 "]: %s",
3503 data_byte_offset, err.what());
3504 return -EINVAL;
3505 }
3506
3507 bool updated = false;
3508 auto it = object_map.begin() + start_object_no;
3509 auto end_it = object_map.begin() + end_object_no;
3510 for (; it != end_it; ++it) {
3511 uint8_t state = *it;
3512 if ((!current_object_state || state == *current_object_state ||
3513 (*current_object_state == OBJECT_EXISTS &&
3514 state == OBJECT_EXISTS_CLEAN)) && state != new_object_state) {
3515 *it = new_object_state;
3516 updated = true;
3517 }
3518 }
3519
3520 if (updated) {
3521 CLS_LOG(20, "object_map_update: %" PRIu64 "~%" PRIu64 " -> %" PRIu64,
3522 data_byte_offset, byte_length, object_byte_offset);
3523
3524 bufferlist data_bl;
3525 object_map.encode_data(data_bl, data_byte_offset, byte_length);
3526 r = cls_cxx_write2(hctx, object_byte_offset, data_bl.length(), &data_bl,
3527 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
3528 if (r < 0) {
3529 CLS_ERR("failed to write object map header: %s", cpp_strerror(r).c_str());
3530 return r;
3531 }
3532
3533 footer_bl.clear();
3534 object_map.encode_data_crcs(footer_bl, start_object_no, object_count);
3535 r = cls_cxx_write2(hctx, footer_object_offset, footer_bl.length(),
3536 &footer_bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
3537 if (r < 0) {
3538 CLS_ERR("failed to write object map footer: %s", cpp_strerror(r).c_str());
3539 return r;
3540 }
3541 } else {
3542 CLS_LOG(20, "object_map_update: no update necessary");
3543 }
3544
3545 return 0;
3546 }
3547
3548 /**
3549 * Mark all _EXISTS objects as _EXISTS_CLEAN so future writes to the
3550 * image HEAD can be tracked.
3551 *
3552 * Input:
3553 * none
3554 *
3555 * Output:
3556 * @returns 0 on success, negative error code on failure
3557 */
3558 int object_map_snap_add(cls_method_context_t hctx, bufferlist *in,
3559 bufferlist *out)
3560 {
3561 BitVector<2> object_map;
3562 int r = object_map_read(hctx, object_map);
3563 if (r < 0) {
3564 return r;
3565 }
3566
3567 bool updated = false;
3568 auto it = object_map.begin();
3569 auto end_it = object_map.end();
3570 for (; it != end_it; ++it) {
3571 if (*it == OBJECT_EXISTS) {
3572 *it = OBJECT_EXISTS_CLEAN;
3573 updated = true;
3574 }
3575 }
3576
3577 if (updated) {
3578 bufferlist bl;
3579 encode(object_map, bl);
3580 r = cls_cxx_write_full(hctx, &bl);
3581 }
3582 return r;
3583 }
3584
3585 /**
3586 * Mark all _EXISTS_CLEAN objects as _EXISTS in the current object map
3587 * if the provided snapshot object map object is marked as _EXISTS.
3588 *
3589 * Input:
3590 * @param snapshot object map bit vector
3591 *
3592 * Output:
3593 * @returns 0 on success, negative error code on failure
3594 */
3595 int object_map_snap_remove(cls_method_context_t hctx, bufferlist *in,
3596 bufferlist *out)
3597 {
3598 BitVector<2> src_object_map;
3599 try {
3600 auto iter = in->cbegin();
3601 decode(src_object_map, iter);
3602 } catch (const buffer::error &err) {
3603 return -EINVAL;
3604 }
3605
3606 BitVector<2> dst_object_map;
3607 int r = object_map_read(hctx, dst_object_map);
3608 if (r < 0) {
3609 return r;
3610 }
3611
3612 bool updated = false;
3613 auto src_it = src_object_map.begin();
3614 auto dst_it = dst_object_map.begin();
3615 auto dst_it_end = dst_object_map.end();
3616 uint64_t i = 0;
3617 for (; dst_it != dst_it_end; ++dst_it) {
3618 if (*dst_it == OBJECT_EXISTS_CLEAN &&
3619 (i >= src_object_map.size() || *src_it == OBJECT_EXISTS)) {
3620 *dst_it = OBJECT_EXISTS;
3621 updated = true;
3622 }
3623 if (i < src_object_map.size())
3624 ++src_it;
3625 ++i;
3626 }
3627
3628 if (updated) {
3629 bufferlist bl;
3630 encode(dst_object_map, bl);
3631 r = cls_cxx_write_full(hctx, &bl);
3632 }
3633 return r;
3634 }
3635
3636 static const string metadata_key_for_name(const string &name)
3637 {
3638 return RBD_METADATA_KEY_PREFIX + name;
3639 }
3640
3641 static const string metadata_name_from_key(const string &key)
3642 {
3643 return key.substr(strlen(RBD_METADATA_KEY_PREFIX));
3644 }
3645
3646 /**
3647 * Input:
3648 * @param start_after which name to begin listing after
3649 * (use the empty string to start at the beginning)
3650 * @param max_return the maximum number of names to list
3651
3652 * Output:
3653 * @param value
3654 * @returns 0 on success, negative error code on failure
3655 */
3656 int metadata_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3657 {
3658 string start_after;
3659 uint64_t max_return;
3660
3661 try {
3662 auto iter = in->cbegin();
3663 decode(start_after, iter);
3664 decode(max_return, iter);
3665 } catch (const buffer::error &err) {
3666 return -EINVAL;
3667 }
3668
3669 // TODO remove implicit support for zero during the N-release
3670 if (max_return == 0) {
3671 max_return = RBD_MAX_KEYS_READ;
3672 }
3673
3674 map<string, bufferlist> data;
3675 string last_read = metadata_key_for_name(start_after);
3676 bool more = true;
3677
3678 while (more && data.size() < max_return) {
3679 map<string, bufferlist> raw_data;
3680 int max_read = std::min<uint64_t>(RBD_MAX_KEYS_READ, max_return - data.size());
3681 int r = cls_cxx_map_get_vals(hctx, last_read, RBD_METADATA_KEY_PREFIX,
3682 max_read, &raw_data, &more);
3683 if (r < 0) {
3684 if (r != -ENOENT) {
3685 CLS_ERR("failed to read the vals off of disk: %s",
3686 cpp_strerror(r).c_str());
3687 }
3688 return r;
3689 }
3690
3691 for (auto& kv : raw_data) {
3692 data[metadata_name_from_key(kv.first)].swap(kv.second);
3693 }
3694
3695 if (!raw_data.empty()) {
3696 last_read = raw_data.rbegin()->first;
3697 }
3698 }
3699
3700 encode(data, *out);
3701 return 0;
3702 }
3703
3704 /**
3705 * Input:
3706 * @param data <map(key, value)>
3707 *
3708 * Output:
3709 * @returns 0 on success, negative error code on failure
3710 */
3711 int metadata_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3712 {
3713 map<string, bufferlist> data, raw_data;
3714
3715 auto iter = in->cbegin();
3716 try {
3717 decode(data, iter);
3718 } catch (const buffer::error &err) {
3719 return -EINVAL;
3720 }
3721
3722 for (map<string, bufferlist>::iterator it = data.begin();
3723 it != data.end(); ++it) {
3724 CLS_LOG(20, "metadata_set key=%s value=%.*s", it->first.c_str(),
3725 it->second.length(), it->second.c_str());
3726 raw_data[metadata_key_for_name(it->first)].swap(it->second);
3727 }
3728 int r = cls_cxx_map_set_vals(hctx, &raw_data);
3729 if (r < 0) {
3730 CLS_ERR("error writing metadata: %s", cpp_strerror(r).c_str());
3731 return r;
3732 }
3733
3734 return 0;
3735 }
3736
3737 /**
3738 * Input:
3739 * @param key
3740 *
3741 * Output:
3742 * @returns 0 on success, negative error code on failure
3743 */
3744 int metadata_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3745 {
3746 string key;
3747
3748 auto iter = in->cbegin();
3749 try {
3750 decode(key, iter);
3751 } catch (const buffer::error &err) {
3752 return -EINVAL;
3753 }
3754
3755 CLS_LOG(20, "metadata_remove key=%s", key.c_str());
3756
3757 int r = cls_cxx_map_remove_key(hctx, metadata_key_for_name(key));
3758 if (r < 0) {
3759 CLS_ERR("error removing metadata: %s", cpp_strerror(r).c_str());
3760 return r;
3761 }
3762
3763 return 0;
3764 }
3765
3766 /**
3767 * Input:
3768 * @param key
3769 *
3770 * Output:
3771 * @param metadata value associated with the key
3772 * @returns 0 on success, negative error code on failure
3773 */
3774 int metadata_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3775 {
3776 string key;
3777 bufferlist value;
3778
3779 auto iter = in->cbegin();
3780 try {
3781 decode(key, iter);
3782 } catch (const buffer::error &err) {
3783 return -EINVAL;
3784 }
3785
3786 CLS_LOG(20, "metadata_get key=%s", key.c_str());
3787
3788 int r = cls_cxx_map_get_val(hctx, metadata_key_for_name(key), &value);
3789 if (r < 0) {
3790 if (r != -ENOENT)
3791 CLS_ERR("error getting metadata: %s", cpp_strerror(r).c_str());
3792 return r;
3793 }
3794
3795 encode(value, *out);
3796 return 0;
3797 }
3798
3799 int snapshot_get_limit(cls_method_context_t hctx, bufferlist *in,
3800 bufferlist *out)
3801 {
3802 uint64_t snap_limit;
3803 int r = read_key(hctx, "snap_limit", &snap_limit);
3804 if (r == -ENOENT) {
3805 snap_limit = UINT64_MAX;
3806 } else if (r < 0) {
3807 CLS_ERR("error retrieving snapshot limit: %s", cpp_strerror(r).c_str());
3808 return r;
3809 }
3810
3811 CLS_LOG(20, "read snapshot limit %" PRIu64, snap_limit);
3812 encode(snap_limit, *out);
3813
3814 return 0;
3815 }
3816
3817 int snapshot_set_limit(cls_method_context_t hctx, bufferlist *in,
3818 bufferlist *out)
3819 {
3820 int rc;
3821 uint64_t new_limit;
3822 bufferlist bl;
3823 size_t snap_count = 0;
3824
3825 try {
3826 auto iter = in->cbegin();
3827 decode(new_limit, iter);
3828 } catch (const buffer::error &err) {
3829 return -EINVAL;
3830 }
3831
3832 if (new_limit == UINT64_MAX) {
3833 CLS_LOG(20, "remove snapshot limit\n");
3834 rc = cls_cxx_map_remove_key(hctx, "snap_limit");
3835 return rc;
3836 }
3837
3838 //try to read header as v1 format
3839 rc = snap_read_header(hctx, bl);
3840
3841 // error when reading header
3842 if (rc < 0 && rc != -EINVAL) {
3843 return rc;
3844 } else if (rc >= 0) {
3845 // success, the image is v1 format
3846 struct rbd_obj_header_ondisk *header;
3847 header = (struct rbd_obj_header_ondisk *)bl.c_str();
3848 snap_count = header->snap_count;
3849 } else {
3850 // else, the image is v2 format
3851 int max_read = RBD_MAX_KEYS_READ;
3852 string last_read = RBD_SNAP_KEY_PREFIX;
3853 bool more;
3854
3855 do {
3856 set<string> keys;
3857 rc = cls_cxx_map_get_keys(hctx, last_read, max_read, &keys, &more);
3858 if (rc < 0) {
3859 CLS_ERR("error retrieving snapshots: %s", cpp_strerror(rc).c_str());
3860 return rc;
3861 }
3862 for (auto& key : keys) {
3863 if (key.find(RBD_SNAP_KEY_PREFIX) != 0)
3864 break;
3865 snap_count++;
3866 }
3867 if (!keys.empty())
3868 last_read = *(keys.rbegin());
3869 } while (more);
3870 }
3871
3872 if (new_limit < snap_count) {
3873 rc = -ERANGE;
3874 CLS_LOG(10, "snapshot limit is less than the number of snapshots.\n");
3875 } else {
3876 CLS_LOG(20, "set snapshot limit to %" PRIu64 "\n", new_limit);
3877 bl.clear();
3878 encode(new_limit, bl);
3879 rc = cls_cxx_map_set_val(hctx, "snap_limit", &bl);
3880 }
3881
3882 return rc;
3883 }
3884
3885
3886 /**
3887 * Input:
3888 * @param snap id (uint64_t) parent snapshot id
3889 * @param child spec (cls::rbd::ChildImageSpec) child image
3890 *
3891 * Output:
3892 * @returns 0 on success, negative error code on failure
3893 */
3894 int child_attach(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3895 {
3896 uint64_t snap_id;
3897 cls::rbd::ChildImageSpec child_image;
3898 try {
3899 auto it = in->cbegin();
3900 decode(snap_id, it);
3901 decode(child_image, it);
3902 } catch (const buffer::error &err) {
3903 return -EINVAL;
3904 }
3905
3906 CLS_LOG(20, "child_attach snap_id=%" PRIu64 ", child_pool_id=%" PRIi64 ", "
3907 "child_image_id=%s", snap_id, child_image.pool_id,
3908 child_image.image_id.c_str());
3909
3910 cls_rbd_snap snap;
3911 std::string snapshot_key;
3912 key_from_snap_id(snap_id, &snapshot_key);
3913 int r = read_key(hctx, snapshot_key, &snap);
3914 if (r < 0) {
3915 return r;
3916 }
3917
3918 if (cls::rbd::get_snap_namespace_type(snap.snapshot_namespace) ==
3919 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
3920 // cannot attach to a deleted snapshot
3921 return -ENOENT;
3922 }
3923
3924 auto children_key = image::snap_children_key_from_snap_id(snap_id);
3925 cls::rbd::ChildImageSpecs child_images;
3926 r = read_key(hctx, children_key, &child_images);
3927 if (r < 0 && r != -ENOENT) {
3928 CLS_ERR("error reading snapshot children: %s", cpp_strerror(r).c_str());
3929 return r;
3930 }
3931
3932 auto it = child_images.insert(child_image);
3933 if (!it.second) {
3934 // child already attached to the snapshot
3935 return -EEXIST;
3936 }
3937
3938 r = write_key(hctx, children_key, child_images);
3939 if (r < 0) {
3940 CLS_ERR("error writing snapshot children: %s", cpp_strerror(r).c_str());
3941 return r;
3942 }
3943
3944 ++snap.child_count;
3945 r = image::snapshot::write(hctx, snapshot_key, std::move(snap));
3946 if (r < 0) {
3947 return r;
3948 }
3949
3950 r = image::set_op_features(hctx, RBD_OPERATION_FEATURE_CLONE_PARENT,
3951 RBD_OPERATION_FEATURE_CLONE_PARENT);
3952 if (r < 0) {
3953 return r;
3954 }
3955
3956 return 0;
3957 }
3958
3959 /**
3960 * Input:
3961 * @param snap id (uint64_t) parent snapshot id
3962 * @param child spec (cls::rbd::ChildImageSpec) child image
3963 *
3964 * Output:
3965 * @returns 0 on success, negative error code on failure
3966 */
3967 int child_detach(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
3968 {
3969 uint64_t snap_id;
3970 cls::rbd::ChildImageSpec child_image;
3971 try {
3972 auto it = in->cbegin();
3973 decode(snap_id, it);
3974 decode(child_image, it);
3975 } catch (const buffer::error &err) {
3976 return -EINVAL;
3977 }
3978
3979 CLS_LOG(20, "child_detach snap_id=%" PRIu64 ", child_pool_id=%" PRIi64 ", "
3980 "child_image_id=%s", snap_id, child_image.pool_id,
3981 child_image.image_id.c_str());
3982
3983 cls_rbd_snap snap;
3984 std::string snapshot_key;
3985 key_from_snap_id(snap_id, &snapshot_key);
3986 int r = read_key(hctx, snapshot_key, &snap);
3987 if (r < 0) {
3988 return r;
3989 }
3990
3991 auto children_key = image::snap_children_key_from_snap_id(snap_id);
3992 cls::rbd::ChildImageSpecs child_images;
3993 r = read_key(hctx, children_key, &child_images);
3994 if (r < 0 && r != -ENOENT) {
3995 CLS_ERR("error reading snapshot children: %s", cpp_strerror(r).c_str());
3996 return r;
3997 }
3998
3999 if (snap.child_count != child_images.size()) {
4000 // children and reference count don't match
4001 CLS_ERR("children reference count mismatch: %" PRIu64, snap_id);
4002 return -EINVAL;
4003 }
4004
4005 if (child_images.erase(child_image) == 0) {
4006 // child not attached to the snapshot
4007 return -ENOENT;
4008 }
4009
4010 if (child_images.empty()) {
4011 r = remove_key(hctx, children_key);
4012 } else {
4013 r = write_key(hctx, children_key, child_images);
4014 if (r < 0) {
4015 CLS_ERR("error writing snapshot children: %s", cpp_strerror(r).c_str());
4016 return r;
4017 }
4018 }
4019
4020 --snap.child_count;
4021 r = image::snapshot::write(hctx, snapshot_key, std::move(snap));
4022 if (r < 0) {
4023 return r;
4024 }
4025
4026 if (snap.child_count == 0) {
4027 auto clone_in_use_lambda = [snap_id](const cls_rbd_snap& snap_meta) {
4028 if (snap_meta.id != snap_id && snap_meta.child_count > 0) {
4029 return -EEXIST;
4030 }
4031 return 0;
4032 };
4033
4034 r = image::snapshot::iterate(hctx, clone_in_use_lambda);
4035 if (r < 0 && r != -EEXIST) {
4036 return r;
4037 }
4038
4039 if (r != -EEXIST) {
4040 // remove the clone_v2 op feature if not in-use by any other snapshots
4041 r = image::set_op_features(hctx, 0, RBD_OPERATION_FEATURE_CLONE_PARENT);
4042 if (r < 0) {
4043 return r;
4044 }
4045 }
4046 }
4047
4048 return 0;
4049 }
4050
4051 /**
4052 * Input:
4053 * @param snap id (uint64_t) parent snapshot id
4054 *
4055 * Output:
4056 * @param (cls::rbd::ChildImageSpecs) child images
4057 * @returns 0 on success, negative error code on failure
4058 */
4059 int children_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
4060 {
4061 uint64_t snap_id;
4062 try {
4063 auto it = in->cbegin();
4064 decode(snap_id, it);
4065 } catch (const buffer::error &err) {
4066 return -EINVAL;
4067 }
4068
4069 CLS_LOG(20, "child_detach snap_id=%" PRIu64, snap_id);
4070
4071 cls_rbd_snap snap;
4072 std::string snapshot_key;
4073 key_from_snap_id(snap_id, &snapshot_key);
4074 int r = read_key(hctx, snapshot_key, &snap);
4075 if (r < 0) {
4076 return r;
4077 }
4078
4079 auto children_key = image::snap_children_key_from_snap_id(snap_id);
4080 cls::rbd::ChildImageSpecs child_images;
4081 r = read_key(hctx, children_key, &child_images);
4082 if (r == -ENOENT) {
4083 return r;
4084 } else if (r < 0) {
4085 CLS_ERR("error reading snapshot children: %s", cpp_strerror(r).c_str());
4086 return r;
4087 }
4088
4089 encode(child_images, *out);
4090 return 0;
4091 }
4092
4093 /**
4094 * Set image migration.
4095 *
4096 * Input:
4097 * @param migration_spec (cls::rbd::MigrationSpec) image migration spec
4098 *
4099 * Output:
4100 *
4101 * @returns 0 on success, negative error code on failure
4102 */
4103 int migration_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out) {
4104 cls::rbd::MigrationSpec migration_spec;
4105 try {
4106 auto it = in->cbegin();
4107 decode(migration_spec, it);
4108 } catch (const buffer::error &err) {
4109 return -EINVAL;
4110 }
4111
4112 int r = image::set_migration(hctx, migration_spec, true);
4113 if (r < 0) {
4114 return r;
4115 }
4116
4117 return 0;
4118 }
4119
4120 /**
4121 * Set image migration state.
4122 *
4123 * Input:
4124 * @param state (cls::rbd::MigrationState) migration state
4125 * @param description (std::string) migration state description
4126 *
4127 * Output:
4128 *
4129 * @returns 0 on success, negative error code on failure
4130 */
4131 int migration_set_state(cls_method_context_t hctx, bufferlist *in,
4132 bufferlist *out) {
4133 cls::rbd::MigrationState state;
4134 std::string description;
4135 try {
4136 auto it = in->cbegin();
4137 decode(state, it);
4138 decode(description, it);
4139 } catch (const buffer::error &err) {
4140 return -EINVAL;
4141 }
4142
4143 cls::rbd::MigrationSpec migration_spec;
4144 int r = image::read_migration(hctx, &migration_spec);
4145 if (r < 0) {
4146 return r;
4147 }
4148
4149 migration_spec.state = state;
4150 migration_spec.state_description = description;
4151
4152 r = image::set_migration(hctx, migration_spec, false);
4153 if (r < 0) {
4154 return r;
4155 }
4156
4157 return 0;
4158 }
4159
4160 /**
4161 * Get image migration spec.
4162 *
4163 * Input:
4164 *
4165 * Output:
4166 * @param migration_spec (cls::rbd::MigrationSpec) image migration spec
4167 *
4168 * @returns 0 on success, negative error code on failure
4169 */
4170 int migration_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out) {
4171 cls::rbd::MigrationSpec migration_spec;
4172 int r = image::read_migration(hctx, &migration_spec);
4173 if (r < 0) {
4174 return r;
4175 }
4176
4177 encode(migration_spec, *out);
4178
4179 return 0;
4180 }
4181
4182 /**
4183 * Remove image migration spec.
4184 *
4185 * Input:
4186 *
4187 * Output:
4188 *
4189 * @returns 0 on success, negative error code on failure
4190 */
4191 int migration_remove(cls_method_context_t hctx, bufferlist *in,
4192 bufferlist *out) {
4193 int r = image::remove_migration(hctx);
4194 if (r < 0) {
4195 return r;
4196 }
4197
4198 return 0;
4199 }
4200
4201 /**
4202 * Ensure writer snapc state
4203 *
4204 * Input:
4205 * @param snap id (uint64_t) snap context sequence id
4206 * @param state (cls::rbd::AssertSnapcSeqState) snap context state
4207 *
4208 * Output:
4209 * @returns -ERANGE if assertion fails
4210 * @returns 0 on success, negative error code on failure
4211 */
4212 int assert_snapc_seq(cls_method_context_t hctx, bufferlist *in,
4213 bufferlist *out)
4214 {
4215 uint64_t snapc_seq;
4216 cls::rbd::AssertSnapcSeqState state;
4217 try {
4218 auto it = in->cbegin();
4219 decode(snapc_seq, it);
4220 decode(state, it);
4221 } catch (const buffer::error &err) {
4222 return -EINVAL;
4223 }
4224
4225 uint64_t snapset_seq;
4226 int r = cls_get_snapset_seq(hctx, &snapset_seq);
4227 if (r < 0 && r != -ENOENT) {
4228 return r;
4229 }
4230
4231 switch (state) {
4232 case cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ:
4233 return (r == -ENOENT || snapc_seq > snapset_seq) ? 0 : -ERANGE;
4234 case cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ:
4235 return (r == -ENOENT || snapc_seq > snapset_seq) ? -ERANGE : 0;
4236 default:
4237 return -EOPNOTSUPP;
4238 }
4239 }
4240
4241 /****************************** Old format *******************************/
4242
4243 int old_snapshots_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
4244 {
4245 bufferlist bl;
4246 struct rbd_obj_header_ondisk *header;
4247 int rc = snap_read_header(hctx, bl);
4248 if (rc < 0)
4249 return rc;
4250
4251 header = (struct rbd_obj_header_ondisk *)bl.c_str();
4252 bufferptr p(header->snap_names_len);
4253 char *buf = (char *)header;
4254 char *name = buf + sizeof(*header) + header->snap_count * sizeof(struct rbd_obj_snap_ondisk);
4255 char *end = name + header->snap_names_len;
4256 memcpy(p.c_str(),
4257 buf + sizeof(*header) + header->snap_count * sizeof(struct rbd_obj_snap_ondisk),
4258 header->snap_names_len);
4259
4260 encode(header->snap_seq, *out);
4261 encode(header->snap_count, *out);
4262
4263 for (unsigned i = 0; i < header->snap_count; i++) {
4264 string s = name;
4265 encode(header->snaps[i].id, *out);
4266 encode(header->snaps[i].image_size, *out);
4267 encode(s, *out);
4268
4269 name += strlen(name) + 1;
4270 if (name > end)
4271 return -EIO;
4272 }
4273
4274 return 0;
4275 }
4276
4277 int old_snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
4278 {
4279 bufferlist bl;
4280 struct rbd_obj_header_ondisk *header;
4281 bufferlist newbl;
4282 bufferptr header_bp(sizeof(*header));
4283 struct rbd_obj_snap_ondisk *new_snaps;
4284
4285 int rc = snap_read_header(hctx, bl);
4286 if (rc < 0)
4287 return rc;
4288
4289 header = (struct rbd_obj_header_ondisk *)bl.c_str();
4290
4291 int snaps_id_ofs = sizeof(*header);
4292 int names_ofs = snaps_id_ofs + sizeof(*new_snaps) * header->snap_count;
4293 const char *snap_name;
4294 const char *snap_names = ((char *)header) + names_ofs;
4295 const char *end = snap_names + header->snap_names_len;
4296 auto iter = in->cbegin();
4297 string s;
4298 uint64_t snap_id;
4299
4300 try {
4301 decode(s, iter);
4302 decode(snap_id, iter);
4303 } catch (const buffer::error &err) {
4304 return -EINVAL;
4305 }
4306 snap_name = s.c_str();
4307
4308 if (header->snap_seq > snap_id)
4309 return -ESTALE;
4310
4311 uint64_t snap_limit;
4312 rc = read_key(hctx, "snap_limit", &snap_limit);
4313 if (rc == -ENOENT) {
4314 snap_limit = UINT64_MAX;
4315 } else if (rc < 0) {
4316 return rc;
4317 }
4318
4319 if (header->snap_count >= snap_limit)
4320 return -EDQUOT;
4321
4322 const char *cur_snap_name;
4323 for (cur_snap_name = snap_names; cur_snap_name < end; cur_snap_name += strlen(cur_snap_name) + 1) {
4324 if (strncmp(cur_snap_name, snap_name, end - cur_snap_name) == 0)
4325 return -EEXIST;
4326 }
4327 if (cur_snap_name > end)
4328 return -EIO;
4329
4330 int snap_name_len = strlen(snap_name);
4331
4332 bufferptr new_names_bp(header->snap_names_len + snap_name_len + 1);
4333 bufferptr new_snaps_bp(sizeof(*new_snaps) * (header->snap_count + 1));
4334
4335 /* copy snap names and append to new snap name */
4336 char *new_snap_names = new_names_bp.c_str();
4337 strcpy(new_snap_names, snap_name);
4338 memcpy(new_snap_names + snap_name_len + 1, snap_names, header->snap_names_len);
4339
4340 /* append new snap id */
4341 new_snaps = (struct rbd_obj_snap_ondisk *)new_snaps_bp.c_str();
4342 memcpy(new_snaps + 1, header->snaps, sizeof(*new_snaps) * header->snap_count);
4343
4344 header->snap_count = header->snap_count + 1;
4345 header->snap_names_len = header->snap_names_len + snap_name_len + 1;
4346 header->snap_seq = snap_id;
4347
4348 new_snaps[0].id = snap_id;
4349 new_snaps[0].image_size = header->image_size;
4350
4351 memcpy(header_bp.c_str(), header, sizeof(*header));
4352
4353 newbl.push_back(header_bp);
4354 newbl.push_back(new_snaps_bp);
4355 newbl.push_back(new_names_bp);
4356
4357 rc = cls_cxx_write_full(hctx, &newbl);
4358 if (rc < 0)
4359 return rc;
4360
4361 return 0;
4362 }
4363
4364 int old_snapshot_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
4365 {
4366 bufferlist bl;
4367 struct rbd_obj_header_ondisk *header;
4368 bufferlist newbl;
4369 bufferptr header_bp(sizeof(*header));
4370
4371 int rc = snap_read_header(hctx, bl);
4372 if (rc < 0)
4373 return rc;
4374
4375 header = (struct rbd_obj_header_ondisk *)bl.c_str();
4376
4377 int snaps_id_ofs = sizeof(*header);
4378 int names_ofs = snaps_id_ofs + sizeof(struct rbd_obj_snap_ondisk) * header->snap_count;
4379 const char *snap_name;
4380 const char *snap_names = ((char *)header) + names_ofs;
4381 const char *orig_names = snap_names;
4382 const char *end = snap_names + header->snap_names_len;
4383 auto iter = in->cbegin();
4384 string s;
4385 unsigned i;
4386 bool found = false;
4387 struct rbd_obj_snap_ondisk snap;
4388
4389 try {
4390 decode(s, iter);
4391 } catch (const buffer::error &err) {
4392 return -EINVAL;
4393 }
4394 snap_name = s.c_str();
4395
4396 for (i = 0; snap_names < end; i++) {
4397 if (strcmp(snap_names, snap_name) == 0) {
4398 snap = header->snaps[i];
4399 found = true;
4400 break;
4401 }
4402 snap_names += strlen(snap_names) + 1;
4403 }
4404 if (!found) {
4405 CLS_ERR("couldn't find snap %s\n", snap_name);
4406 return -ENOENT;
4407 }
4408
4409 header->snap_names_len = header->snap_names_len - (s.length() + 1);
4410 header->snap_count = header->snap_count - 1;
4411
4412 bufferptr new_names_bp(header->snap_names_len);
4413 bufferptr new_snaps_bp(sizeof(header->snaps[0]) * header->snap_count);
4414
4415 memcpy(header_bp.c_str(), header, sizeof(*header));
4416 newbl.push_back(header_bp);
4417
4418 if (header->snap_count) {
4419 int snaps_len = 0;
4420 int names_len = 0;
4421 CLS_LOG(20, "i=%u\n", i);
4422 if (i > 0) {
4423 snaps_len = sizeof(header->snaps[0]) * i;
4424 names_len = snap_names - orig_names;
4425 memcpy(new_snaps_bp.c_str(), header->snaps, snaps_len);
4426 memcpy(new_names_bp.c_str(), orig_names, names_len);
4427 }
4428 snap_names += s.length() + 1;
4429
4430 if (i < header->snap_count) {
4431 memcpy(new_snaps_bp.c_str() + snaps_len,
4432 header->snaps + i + 1,
4433 sizeof(header->snaps[0]) * (header->snap_count - i));
4434 memcpy(new_names_bp.c_str() + names_len, snap_names , end - snap_names);
4435 }
4436 newbl.push_back(new_snaps_bp);
4437 newbl.push_back(new_names_bp);
4438 }
4439
4440 rc = cls_cxx_write_full(hctx, &newbl);
4441 if (rc < 0)
4442 return rc;
4443
4444 return 0;
4445 }
4446
4447 /**
4448 * rename snapshot of old format.
4449 *
4450 * Input:
4451 * @param src_snap_id old snap id of the snapshot (snapid_t)
4452 * @param dst_snap_name new name of the snapshot (string)
4453 *
4454 * Output:
4455 * @returns 0 on success, negative error code on failure.
4456 */
4457 int old_snapshot_rename(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
4458 {
4459 bufferlist bl;
4460 struct rbd_obj_header_ondisk *header;
4461 bufferlist newbl;
4462 bufferptr header_bp(sizeof(*header));
4463 snapid_t src_snap_id;
4464 const char *dst_snap_name;
4465 string dst;
4466
4467 int rc = snap_read_header(hctx, bl);
4468 if (rc < 0)
4469 return rc;
4470
4471 header = (struct rbd_obj_header_ondisk *)bl.c_str();
4472
4473 int snaps_id_ofs = sizeof(*header);
4474 int names_ofs = snaps_id_ofs + sizeof(rbd_obj_snap_ondisk) * header->snap_count;
4475 const char *snap_names = ((char *)header) + names_ofs;
4476 const char *orig_names = snap_names;
4477 const char *end = snap_names + header->snap_names_len;
4478 auto iter = in->cbegin();
4479 unsigned i;
4480 bool found = false;
4481
4482 try {
4483 decode(src_snap_id, iter);
4484 decode(dst, iter);
4485 } catch (const buffer::error &err) {
4486 return -EINVAL;
4487 }
4488 dst_snap_name = dst.c_str();
4489
4490 const char *cur_snap_name;
4491 for (cur_snap_name = snap_names; cur_snap_name < end;
4492 cur_snap_name += strlen(cur_snap_name) + 1) {
4493 if (strcmp(cur_snap_name, dst_snap_name) == 0)
4494 return -EEXIST;
4495 }
4496 if (cur_snap_name > end)
4497 return -EIO;
4498 for (i = 0; i < header->snap_count; i++) {
4499 if (src_snap_id == header->snaps[i].id) {
4500 found = true;
4501 break;
4502 }
4503 snap_names += strlen(snap_names) + 1;
4504 }
4505 if (!found) {
4506 CLS_ERR("couldn't find snap %llu\n", (unsigned long long)src_snap_id.val);
4507 return -ENOENT;
4508 }
4509
4510 CLS_LOG(20, "rename snap with snap id %llu to dest name %s", (unsigned long long)src_snap_id.val, dst_snap_name);
4511 header->snap_names_len = header->snap_names_len - strlen(snap_names) + dst.length();
4512
4513 bufferptr new_names_bp(header->snap_names_len);
4514 bufferptr new_snaps_bp(sizeof(header->snaps[0]) * header->snap_count);
4515
4516 if (header->snap_count) {
4517 int names_len = 0;
4518 CLS_LOG(20, "i=%u\n", i);
4519 if (i > 0) {
4520 names_len = snap_names - orig_names;
4521 memcpy(new_names_bp.c_str(), orig_names, names_len);
4522 }
4523 strcpy(new_names_bp.c_str() + names_len, dst_snap_name);
4524 names_len += strlen(dst_snap_name) + 1;
4525 snap_names += strlen(snap_names) + 1;
4526 if (i < header->snap_count) {
4527 memcpy(new_names_bp.c_str() + names_len, snap_names , end - snap_names);
4528 }
4529 memcpy(new_snaps_bp.c_str(), header->snaps, sizeof(header->snaps[0]) * header->snap_count);
4530 }
4531
4532 memcpy(header_bp.c_str(), header, sizeof(*header));
4533 newbl.push_back(header_bp);
4534 newbl.push_back(new_snaps_bp);
4535 newbl.push_back(new_names_bp);
4536
4537 rc = cls_cxx_write_full(hctx, &newbl);
4538 if (rc < 0)
4539 return rc;
4540 return 0;
4541 }
4542
4543
4544 namespace mirror {
4545
4546 static const std::string UUID("mirror_uuid");
4547 static const std::string MODE("mirror_mode");
4548 static const std::string PEER_KEY_PREFIX("mirror_peer_");
4549 static const std::string IMAGE_KEY_PREFIX("image_");
4550 static const std::string GLOBAL_KEY_PREFIX("global_");
4551 static const std::string STATUS_GLOBAL_KEY_PREFIX("status_global_");
4552 static const std::string INSTANCE_KEY_PREFIX("instance_");
4553 static const std::string MIRROR_IMAGE_MAP_KEY_PREFIX("image_map_");
4554
4555 std::string peer_key(const std::string &uuid) {
4556 return PEER_KEY_PREFIX + uuid;
4557 }
4558
4559 std::string image_key(const string &image_id) {
4560 return IMAGE_KEY_PREFIX + image_id;
4561 }
4562
4563 std::string global_key(const string &global_id) {
4564 return GLOBAL_KEY_PREFIX + global_id;
4565 }
4566
4567 std::string status_global_key(const string &global_id) {
4568 return STATUS_GLOBAL_KEY_PREFIX + global_id;
4569 }
4570
4571 std::string instance_key(const string &instance_id) {
4572 return INSTANCE_KEY_PREFIX + instance_id;
4573 }
4574
4575 std::string mirror_image_map_key(const string& global_image_id) {
4576 return MIRROR_IMAGE_MAP_KEY_PREFIX + global_image_id;
4577 }
4578
4579 int uuid_get(cls_method_context_t hctx, std::string *mirror_uuid) {
4580 bufferlist mirror_uuid_bl;
4581 int r = cls_cxx_map_get_val(hctx, mirror::UUID, &mirror_uuid_bl);
4582 if (r < 0) {
4583 if (r != -ENOENT) {
4584 CLS_ERR("error reading mirror uuid: %s", cpp_strerror(r).c_str());
4585 }
4586 return r;
4587 }
4588
4589 *mirror_uuid = std::string(mirror_uuid_bl.c_str(), mirror_uuid_bl.length());
4590 return 0;
4591 }
4592
4593 int list_watchers(cls_method_context_t hctx,
4594 std::set<entity_inst_t> *entities) {
4595 obj_list_watch_response_t watchers;
4596 int r = cls_cxx_list_watchers(hctx, &watchers);
4597 if (r < 0 && r != -ENOENT) {
4598 CLS_ERR("error listing watchers: '%s'", cpp_strerror(r).c_str());
4599 return r;
4600 }
4601
4602 entities->clear();
4603 for (auto &w : watchers.entries) {
4604 entities->emplace(w.name, w.addr);
4605 }
4606 return 0;
4607 }
4608
4609 int read_peers(cls_method_context_t hctx,
4610 std::vector<cls::rbd::MirrorPeer> *peers) {
4611 std::string last_read = PEER_KEY_PREFIX;
4612 int max_read = RBD_MAX_KEYS_READ;
4613 bool more = true;
4614 while (more) {
4615 std::map<std::string, bufferlist> vals;
4616 int r = cls_cxx_map_get_vals(hctx, last_read, PEER_KEY_PREFIX.c_str(),
4617 max_read, &vals, &more);
4618 if (r < 0) {
4619 if (r != -ENOENT) {
4620 CLS_ERR("error reading peers: %s", cpp_strerror(r).c_str());
4621 }
4622 return r;
4623 }
4624
4625 for (auto &it : vals) {
4626 try {
4627 auto bl_it = it.second.cbegin();
4628 cls::rbd::MirrorPeer peer;
4629 decode(peer, bl_it);
4630 peers->push_back(peer);
4631 } catch (const buffer::error &err) {
4632 CLS_ERR("could not decode peer '%s'", it.first.c_str());
4633 return -EIO;
4634 }
4635 }
4636
4637 if (!vals.empty()) {
4638 last_read = vals.rbegin()->first;
4639 }
4640 }
4641 return 0;
4642 }
4643
4644 int read_peer(cls_method_context_t hctx, const std::string &id,
4645 cls::rbd::MirrorPeer *peer) {
4646 bufferlist bl;
4647 int r = cls_cxx_map_get_val(hctx, peer_key(id), &bl);
4648 if (r < 0) {
4649 CLS_ERR("error reading peer '%s': %s", id.c_str(),
4650 cpp_strerror(r).c_str());
4651 return r;
4652 }
4653
4654 try {
4655 auto bl_it = bl.cbegin();
4656 decode(*peer, bl_it);
4657 } catch (const buffer::error &err) {
4658 CLS_ERR("could not decode peer '%s'", id.c_str());
4659 return -EIO;
4660 }
4661 return 0;
4662 }
4663
4664 int write_peer(cls_method_context_t hctx, const std::string &id,
4665 const cls::rbd::MirrorPeer &peer) {
4666 bufferlist bl;
4667 encode(peer, bl);
4668
4669 int r = cls_cxx_map_set_val(hctx, peer_key(id), &bl);
4670 if (r < 0) {
4671 CLS_ERR("error writing peer '%s': %s", id.c_str(),
4672 cpp_strerror(r).c_str());
4673 return r;
4674 }
4675 return 0;
4676 }
4677
4678 int image_get(cls_method_context_t hctx, const string &image_id,
4679 cls::rbd::MirrorImage *mirror_image) {
4680 bufferlist bl;
4681 int r = cls_cxx_map_get_val(hctx, image_key(image_id), &bl);
4682 if (r < 0) {
4683 if (r != -ENOENT) {
4684 CLS_ERR("error reading mirrored image '%s': '%s'", image_id.c_str(),
4685 cpp_strerror(r).c_str());
4686 }
4687 return r;
4688 }
4689
4690 try {
4691 auto it = bl.cbegin();
4692 decode(*mirror_image, it);
4693 } catch (const buffer::error &err) {
4694 CLS_ERR("could not decode mirrored image '%s'", image_id.c_str());
4695 return -EIO;
4696 }
4697
4698 return 0;
4699 }
4700
4701 int image_set(cls_method_context_t hctx, const string &image_id,
4702 const cls::rbd::MirrorImage &mirror_image) {
4703 bufferlist bl;
4704 encode(mirror_image, bl);
4705
4706 cls::rbd::MirrorImage existing_mirror_image;
4707 int r = image_get(hctx, image_id, &existing_mirror_image);
4708 if (r == -ENOENT) {
4709 // make sure global id doesn't already exist
4710 std::string global_id_key = global_key(mirror_image.global_image_id);
4711 std::string image_id;
4712 r = read_key(hctx, global_id_key, &image_id);
4713 if (r >= 0) {
4714 return -EEXIST;
4715 } else if (r != -ENOENT) {
4716 CLS_ERR("error reading global image id: '%s': '%s'", image_id.c_str(),
4717 cpp_strerror(r).c_str());
4718 return r;
4719 }
4720
4721 // make sure this was not a race for disabling
4722 if (mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_DISABLING) {
4723 CLS_ERR("image '%s' is already disabled", image_id.c_str());
4724 return r;
4725 }
4726 } else if (r < 0) {
4727 CLS_ERR("error reading mirrored image '%s': '%s'", image_id.c_str(),
4728 cpp_strerror(r).c_str());
4729 return r;
4730 } else if (existing_mirror_image.global_image_id !=
4731 mirror_image.global_image_id) {
4732 // cannot change the global id
4733 return -EINVAL;
4734 }
4735
4736 r = cls_cxx_map_set_val(hctx, image_key(image_id), &bl);
4737 if (r < 0) {
4738 CLS_ERR("error adding mirrored image '%s': %s", image_id.c_str(),
4739 cpp_strerror(r).c_str());
4740 return r;
4741 }
4742
4743 bufferlist image_id_bl;
4744 encode(image_id, image_id_bl);
4745 r = cls_cxx_map_set_val(hctx, global_key(mirror_image.global_image_id),
4746 &image_id_bl);
4747 if (r < 0) {
4748 CLS_ERR("error adding global id for image '%s': %s", image_id.c_str(),
4749 cpp_strerror(r).c_str());
4750 return r;
4751 }
4752 return 0;
4753 }
4754
4755 int image_remove(cls_method_context_t hctx, const string &image_id) {
4756 bufferlist bl;
4757 cls::rbd::MirrorImage mirror_image;
4758 int r = image_get(hctx, image_id, &mirror_image);
4759 if (r < 0) {
4760 if (r != -ENOENT) {
4761 CLS_ERR("error reading mirrored image '%s': '%s'", image_id.c_str(),
4762 cpp_strerror(r).c_str());
4763 }
4764 return r;
4765 }
4766
4767 if (mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_DISABLING) {
4768 return -EBUSY;
4769 }
4770
4771 r = cls_cxx_map_remove_key(hctx, image_key(image_id));
4772 if (r < 0) {
4773 CLS_ERR("error removing mirrored image '%s': %s", image_id.c_str(),
4774 cpp_strerror(r).c_str());
4775 return r;
4776 }
4777
4778 r = cls_cxx_map_remove_key(hctx, global_key(mirror_image.global_image_id));
4779 if (r < 0 && r != -ENOENT) {
4780 CLS_ERR("error removing global id for image '%s': %s", image_id.c_str(),
4781 cpp_strerror(r).c_str());
4782 return r;
4783 }
4784
4785 r = cls_cxx_map_remove_key(hctx,
4786 status_global_key(mirror_image.global_image_id));
4787 if (r < 0 && r != -ENOENT) {
4788 CLS_ERR("error removing global status for image '%s': %s", image_id.c_str(),
4789 cpp_strerror(r).c_str());
4790 return r;
4791 }
4792
4793 return 0;
4794 }
4795
4796 struct MirrorImageStatusOnDisk : cls::rbd::MirrorImageStatus {
4797 entity_inst_t origin;
4798
4799 MirrorImageStatusOnDisk() {
4800 }
4801 MirrorImageStatusOnDisk(const cls::rbd::MirrorImageStatus &status) :
4802 cls::rbd::MirrorImageStatus(status) {
4803 }
4804
4805 void encode_meta(bufferlist &bl, uint64_t features) const {
4806 ENCODE_START(1, 1, bl);
4807 encode(origin, bl, features);
4808 ENCODE_FINISH(bl);
4809 }
4810
4811 void encode(bufferlist &bl, uint64_t features) const {
4812 encode_meta(bl, features);
4813 cls::rbd::MirrorImageStatus::encode(bl);
4814 }
4815
4816 void decode_meta(bufferlist::const_iterator &it) {
4817 DECODE_START(1, it);
4818 decode(origin, it);
4819 DECODE_FINISH(it);
4820 }
4821
4822 void decode(bufferlist::const_iterator &it) {
4823 decode_meta(it);
4824 cls::rbd::MirrorImageStatus::decode(it);
4825 }
4826 };
4827 WRITE_CLASS_ENCODER_FEATURES(MirrorImageStatusOnDisk)
4828
4829 int image_status_set(cls_method_context_t hctx, const string &global_image_id,
4830 const cls::rbd::MirrorImageStatus &status) {
4831 MirrorImageStatusOnDisk ondisk_status(status);
4832 ondisk_status.up = false;
4833 ondisk_status.last_update = ceph_clock_now();
4834
4835 int r = cls_get_request_origin(hctx, &ondisk_status.origin);
4836 ceph_assert(r == 0);
4837
4838 bufferlist bl;
4839 encode(ondisk_status, bl, cls_get_features(hctx));
4840
4841 r = cls_cxx_map_set_val(hctx, status_global_key(global_image_id), &bl);
4842 if (r < 0) {
4843 CLS_ERR("error setting status for mirrored image, global id '%s': %s",
4844 global_image_id.c_str(), cpp_strerror(r).c_str());
4845 return r;
4846 }
4847 return 0;
4848 }
4849
4850 int image_status_remove(cls_method_context_t hctx,
4851 const string &global_image_id) {
4852
4853 int r = cls_cxx_map_remove_key(hctx, status_global_key(global_image_id));
4854 if (r < 0) {
4855 CLS_ERR("error removing status for mirrored image, global id '%s': %s",
4856 global_image_id.c_str(), cpp_strerror(r).c_str());
4857 return r;
4858 }
4859 return 0;
4860 }
4861
4862 int image_status_get(cls_method_context_t hctx, const string &global_image_id,
4863 const std::set<entity_inst_t> &watchers,
4864 cls::rbd::MirrorImageStatus *status) {
4865
4866 bufferlist bl;
4867 int r = cls_cxx_map_get_val(hctx, status_global_key(global_image_id), &bl);
4868 if (r < 0) {
4869 if (r != -ENOENT) {
4870 CLS_ERR("error reading status for mirrored image, global id '%s': '%s'",
4871 global_image_id.c_str(), cpp_strerror(r).c_str());
4872 }
4873 return r;
4874 }
4875
4876 MirrorImageStatusOnDisk ondisk_status;
4877 try {
4878 auto it = bl.cbegin();
4879 decode(ondisk_status, it);
4880 } catch (const buffer::error &err) {
4881 CLS_ERR("could not decode status for mirrored image, global id '%s'",
4882 global_image_id.c_str());
4883 return -EIO;
4884 }
4885
4886
4887 *status = static_cast<cls::rbd::MirrorImageStatus>(ondisk_status);
4888 status->up = (watchers.find(ondisk_status.origin) != watchers.end());
4889 return 0;
4890 }
4891
4892 int image_status_list(cls_method_context_t hctx,
4893 const std::string &start_after, uint64_t max_return,
4894 map<std::string, cls::rbd::MirrorImage> *mirror_images,
4895 map<std::string, cls::rbd::MirrorImageStatus> *mirror_statuses) {
4896 std::string last_read = image_key(start_after);
4897 int max_read = RBD_MAX_KEYS_READ;
4898 bool more = true;
4899
4900 std::set<entity_inst_t> watchers;
4901 int r = list_watchers(hctx, &watchers);
4902 if (r < 0) {
4903 return r;
4904 }
4905
4906 while (more && mirror_images->size() < max_return) {
4907 std::map<std::string, bufferlist> vals;
4908 CLS_LOG(20, "last_read = '%s'", last_read.c_str());
4909 r = cls_cxx_map_get_vals(hctx, last_read, IMAGE_KEY_PREFIX, max_read, &vals,
4910 &more);
4911 if (r < 0) {
4912 if (r != -ENOENT) {
4913 CLS_ERR("error reading mirror image directory by name: %s",
4914 cpp_strerror(r).c_str());
4915 }
4916 return r;
4917 }
4918
4919 for (auto it = vals.begin(); it != vals.end() &&
4920 mirror_images->size() < max_return; ++it) {
4921 const std::string &image_id = it->first.substr(IMAGE_KEY_PREFIX.size());
4922 cls::rbd::MirrorImage mirror_image;
4923 auto iter = it->second.cbegin();
4924 try {
4925 decode(mirror_image, iter);
4926 } catch (const buffer::error &err) {
4927 CLS_ERR("could not decode mirror image payload of image '%s'",
4928 image_id.c_str());
4929 return -EIO;
4930 }
4931
4932 (*mirror_images)[image_id] = mirror_image;
4933
4934 cls::rbd::MirrorImageStatus status;
4935 int r1 = image_status_get(hctx, mirror_image.global_image_id, watchers,
4936 &status);
4937 if (r1 < 0) {
4938 continue;
4939 }
4940
4941 (*mirror_statuses)[image_id] = status;
4942 }
4943 if (!vals.empty()) {
4944 last_read = image_key(mirror_images->rbegin()->first);
4945 }
4946 }
4947
4948 return 0;
4949 }
4950
4951 int image_status_get_summary(
4952 cls_method_context_t hctx,
4953 std::map<cls::rbd::MirrorImageStatusState, int> *states) {
4954 std::set<entity_inst_t> watchers;
4955 int r = list_watchers(hctx, &watchers);
4956 if (r < 0) {
4957 return r;
4958 }
4959
4960 states->clear();
4961
4962 string last_read = IMAGE_KEY_PREFIX;
4963 int max_read = RBD_MAX_KEYS_READ;
4964 bool more = true;
4965 while (more) {
4966 map<string, bufferlist> vals;
4967 r = cls_cxx_map_get_vals(hctx, last_read, IMAGE_KEY_PREFIX,
4968 max_read, &vals, &more);
4969 if (r < 0) {
4970 if (r != -ENOENT) {
4971 CLS_ERR("error reading mirrored images: %s", cpp_strerror(r).c_str());
4972 }
4973 return r;
4974 }
4975
4976 for (auto &list_it : vals) {
4977 const string &key = list_it.first;
4978
4979 if (0 != key.compare(0, IMAGE_KEY_PREFIX.size(), IMAGE_KEY_PREFIX)) {
4980 break;
4981 }
4982
4983 cls::rbd::MirrorImage mirror_image;
4984 auto iter = list_it.second.cbegin();
4985 try {
4986 decode(mirror_image, iter);
4987 } catch (const buffer::error &err) {
4988 CLS_ERR("could not decode mirror image payload for key '%s'",
4989 key.c_str());
4990 return -EIO;
4991 }
4992
4993 cls::rbd::MirrorImageStatus status;
4994 image_status_get(hctx, mirror_image.global_image_id, watchers, &status);
4995
4996 cls::rbd::MirrorImageStatusState state = status.up ? status.state :
4997 cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN;
4998 (*states)[state]++;
4999 }
5000
5001 if (!vals.empty()) {
5002 last_read = vals.rbegin()->first;
5003 }
5004 }
5005
5006 return 0;
5007 }
5008
5009 int image_status_remove_down(cls_method_context_t hctx) {
5010 std::set<entity_inst_t> watchers;
5011 int r = list_watchers(hctx, &watchers);
5012 if (r < 0) {
5013 return r;
5014 }
5015
5016 string last_read = STATUS_GLOBAL_KEY_PREFIX;
5017 int max_read = RBD_MAX_KEYS_READ;
5018 bool more = true;
5019 while (more) {
5020 map<string, bufferlist> vals;
5021 r = cls_cxx_map_get_vals(hctx, last_read, STATUS_GLOBAL_KEY_PREFIX,
5022 max_read, &vals, &more);
5023 if (r < 0) {
5024 if (r != -ENOENT) {
5025 CLS_ERR("error reading mirrored images: %s", cpp_strerror(r).c_str());
5026 }
5027 return r;
5028 }
5029
5030 for (auto &list_it : vals) {
5031 const string &key = list_it.first;
5032
5033 if (0 != key.compare(0, STATUS_GLOBAL_KEY_PREFIX.size(),
5034 STATUS_GLOBAL_KEY_PREFIX)) {
5035 break;
5036 }
5037
5038 MirrorImageStatusOnDisk status;
5039 try {
5040 auto it = list_it.second.cbegin();
5041 status.decode_meta(it);
5042 } catch (const buffer::error &err) {
5043 CLS_ERR("could not decode status metadata for mirrored image '%s'",
5044 key.c_str());
5045 return -EIO;
5046 }
5047
5048 if (watchers.find(status.origin) == watchers.end()) {
5049 CLS_LOG(20, "removing stale status object for key %s",
5050 key.c_str());
5051 int r1 = cls_cxx_map_remove_key(hctx, key);
5052 if (r1 < 0) {
5053 CLS_ERR("error removing stale status for key '%s': %s",
5054 key.c_str(), cpp_strerror(r1).c_str());
5055 return r1;
5056 }
5057 }
5058 }
5059
5060 if (!vals.empty()) {
5061 last_read = vals.rbegin()->first;
5062 }
5063 }
5064
5065 return 0;
5066 }
5067
5068 int image_instance_get(cls_method_context_t hctx,
5069 const string &global_image_id,
5070 const std::set<entity_inst_t> &watchers,
5071 entity_inst_t *instance) {
5072 bufferlist bl;
5073 int r = cls_cxx_map_get_val(hctx, status_global_key(global_image_id), &bl);
5074 if (r < 0) {
5075 if (r != -ENOENT) {
5076 CLS_ERR("error reading status for mirrored image, global id '%s': '%s'",
5077 global_image_id.c_str(), cpp_strerror(r).c_str());
5078 }
5079 return r;
5080 }
5081
5082 MirrorImageStatusOnDisk ondisk_status;
5083 try {
5084 auto it = bl.cbegin();
5085 decode(ondisk_status, it);
5086 } catch (const buffer::error &err) {
5087 CLS_ERR("could not decode status for mirrored image, global id '%s'",
5088 global_image_id.c_str());
5089 return -EIO;
5090 }
5091
5092 if (watchers.find(ondisk_status.origin) == watchers.end()) {
5093 return -ESTALE;
5094 }
5095
5096 *instance = ondisk_status.origin;
5097 return 0;
5098 }
5099
5100 int image_instance_list(cls_method_context_t hctx,
5101 const std::string &start_after,
5102 uint64_t max_return,
5103 map<std::string, entity_inst_t> *instances) {
5104 std::string last_read = image_key(start_after);
5105 int max_read = RBD_MAX_KEYS_READ;
5106 bool more = true;
5107
5108 std::set<entity_inst_t> watchers;
5109 int r = list_watchers(hctx, &watchers);
5110 if (r < 0) {
5111 return r;
5112 }
5113
5114 while (more && instances->size() < max_return) {
5115 std::map<std::string, bufferlist> vals;
5116 CLS_LOG(20, "last_read = '%s'", last_read.c_str());
5117 r = cls_cxx_map_get_vals(hctx, last_read, IMAGE_KEY_PREFIX, max_read, &vals,
5118 &more);
5119 if (r < 0) {
5120 if (r != -ENOENT) {
5121 CLS_ERR("error reading mirror image directory by name: %s",
5122 cpp_strerror(r).c_str());
5123 }
5124 return r;
5125 }
5126
5127 for (auto it = vals.begin(); it != vals.end() &&
5128 instances->size() < max_return; ++it) {
5129 const std::string &image_id = it->first.substr(IMAGE_KEY_PREFIX.size());
5130 cls::rbd::MirrorImage mirror_image;
5131 auto iter = it->second.cbegin();
5132 try {
5133 decode(mirror_image, iter);
5134 } catch (const buffer::error &err) {
5135 CLS_ERR("could not decode mirror image payload of image '%s'",
5136 image_id.c_str());
5137 return -EIO;
5138 }
5139
5140 entity_inst_t instance;
5141 r = image_instance_get(hctx, mirror_image.global_image_id, watchers,
5142 &instance);
5143 if (r < 0) {
5144 continue;
5145 }
5146
5147 (*instances)[image_id] = instance;
5148 }
5149 if (!vals.empty()) {
5150 last_read = vals.rbegin()->first;
5151 }
5152 }
5153
5154 return 0;
5155 }
5156
5157 int instances_list(cls_method_context_t hctx,
5158 std::vector<std::string> *instance_ids) {
5159 std::string last_read = INSTANCE_KEY_PREFIX;
5160 int max_read = RBD_MAX_KEYS_READ;
5161 bool more = true;
5162 while (more) {
5163 std::map<std::string, bufferlist> vals;
5164 int r = cls_cxx_map_get_vals(hctx, last_read, INSTANCE_KEY_PREFIX.c_str(),
5165 max_read, &vals, &more);
5166 if (r < 0) {
5167 if (r != -ENOENT) {
5168 CLS_ERR("error reading mirror instances: %s", cpp_strerror(r).c_str());
5169 }
5170 return r;
5171 }
5172
5173 for (auto &it : vals) {
5174 instance_ids->push_back(it.first.substr(INSTANCE_KEY_PREFIX.size()));
5175 }
5176
5177 if (!vals.empty()) {
5178 last_read = vals.rbegin()->first;
5179 }
5180 }
5181 return 0;
5182 }
5183
5184 int instances_add(cls_method_context_t hctx, const string &instance_id) {
5185 bufferlist bl;
5186
5187 int r = cls_cxx_map_set_val(hctx, instance_key(instance_id), &bl);
5188 if (r < 0) {
5189 CLS_ERR("error setting mirror instance %s: %s", instance_id.c_str(),
5190 cpp_strerror(r).c_str());
5191 return r;
5192 }
5193 return 0;
5194 }
5195
5196 int instances_remove(cls_method_context_t hctx, const string &instance_id) {
5197
5198 int r = cls_cxx_map_remove_key(hctx, instance_key(instance_id));
5199 if (r < 0) {
5200 CLS_ERR("error removing mirror instance %s: %s", instance_id.c_str(),
5201 cpp_strerror(r).c_str());
5202 return r;
5203 }
5204 return 0;
5205 }
5206
5207 int mirror_image_map_list(cls_method_context_t hctx,
5208 const std::string &start_after,
5209 uint64_t max_return,
5210 std::map<std::string, cls::rbd::MirrorImageMap> *image_mapping) {
5211 bool more = true;
5212 std::string last_read = mirror_image_map_key(start_after);
5213
5214 while (more && image_mapping->size() < max_return) {
5215 std::map<std::string, bufferlist> vals;
5216 CLS_LOG(20, "last read: '%s'", last_read.c_str());
5217
5218 int max_read = std::min<uint64_t>(RBD_MAX_KEYS_READ, max_return - image_mapping->size());
5219 int r = cls_cxx_map_get_vals(hctx, last_read, MIRROR_IMAGE_MAP_KEY_PREFIX,
5220 max_read, &vals, &more);
5221 if (r < 0) {
5222 CLS_ERR("error reading image map: %s", cpp_strerror(r).c_str());
5223 return r;
5224 }
5225
5226 if (vals.empty()) {
5227 return 0;
5228 }
5229
5230 for (auto it = vals.begin(); it != vals.end(); ++it) {
5231 const std::string &global_image_id =
5232 it->first.substr(MIRROR_IMAGE_MAP_KEY_PREFIX.size());
5233
5234 cls::rbd::MirrorImageMap mirror_image_map;
5235 auto iter = it->second.cbegin();
5236 try {
5237 decode(mirror_image_map, iter);
5238 } catch (const buffer::error &err) {
5239 CLS_ERR("could not decode image map payload: %s",
5240 cpp_strerror(r).c_str());
5241 return -EINVAL;
5242 }
5243
5244 image_mapping->insert(std::make_pair(global_image_id, mirror_image_map));
5245 }
5246
5247 if (!vals.empty()) {
5248 last_read = vals.rbegin()->first;
5249 }
5250 }
5251
5252 return 0;
5253 }
5254
5255 } // namespace mirror
5256
5257 /**
5258 * Input:
5259 * none
5260 *
5261 * Output:
5262 * @param uuid (std::string)
5263 * @returns 0 on success, negative error code on failure
5264 */
5265 int mirror_uuid_get(cls_method_context_t hctx, bufferlist *in,
5266 bufferlist *out) {
5267 std::string mirror_uuid;
5268 int r = mirror::uuid_get(hctx, &mirror_uuid);
5269 if (r < 0) {
5270 return r;
5271 }
5272
5273 encode(mirror_uuid, *out);
5274 return 0;
5275 }
5276
5277 /**
5278 * Input:
5279 * @param mirror_uuid (std::string)
5280 *
5281 * Output:
5282 * @returns 0 on success, negative error code on failure
5283 */
5284 int mirror_uuid_set(cls_method_context_t hctx, bufferlist *in,
5285 bufferlist *out) {
5286 std::string mirror_uuid;
5287 try {
5288 auto bl_it = in->cbegin();
5289 decode(mirror_uuid, bl_it);
5290 } catch (const buffer::error &err) {
5291 return -EINVAL;
5292 }
5293
5294 if (mirror_uuid.empty()) {
5295 CLS_ERR("cannot set empty mirror uuid");
5296 return -EINVAL;
5297 }
5298
5299 uint32_t mirror_mode;
5300 int r = read_key(hctx, mirror::MODE, &mirror_mode);
5301 if (r < 0 && r != -ENOENT) {
5302 return r;
5303 } else if (r == 0 && mirror_mode != cls::rbd::MIRROR_MODE_DISABLED) {
5304 CLS_ERR("cannot set mirror uuid while mirroring enabled");
5305 return -EINVAL;
5306 }
5307
5308 bufferlist mirror_uuid_bl;
5309 mirror_uuid_bl.append(mirror_uuid);
5310 r = cls_cxx_map_set_val(hctx, mirror::UUID, &mirror_uuid_bl);
5311 if (r < 0) {
5312 CLS_ERR("failed to set mirror uuid");
5313 return r;
5314 }
5315 return 0;
5316 }
5317
5318 /**
5319 * Input:
5320 * none
5321 *
5322 * Output:
5323 * @param cls::rbd::MirrorMode (uint32_t)
5324 * @returns 0 on success, negative error code on failure
5325 */
5326 int mirror_mode_get(cls_method_context_t hctx, bufferlist *in,
5327 bufferlist *out) {
5328 uint32_t mirror_mode_decode;
5329 int r = read_key(hctx, mirror::MODE, &mirror_mode_decode);
5330 if (r < 0) {
5331 return r;
5332 }
5333
5334 encode(mirror_mode_decode, *out);
5335 return 0;
5336 }
5337
5338 /**
5339 * Input:
5340 * @param mirror_mode (cls::rbd::MirrorMode) (uint32_t)
5341 *
5342 * Output:
5343 * @returns 0 on success, negative error code on failure
5344 */
5345 int mirror_mode_set(cls_method_context_t hctx, bufferlist *in,
5346 bufferlist *out) {
5347 uint32_t mirror_mode_decode;
5348 try {
5349 auto bl_it = in->cbegin();
5350 decode(mirror_mode_decode, bl_it);
5351 } catch (const buffer::error &err) {
5352 return -EINVAL;
5353 }
5354
5355 bool enabled;
5356 switch (static_cast<cls::rbd::MirrorMode>(mirror_mode_decode)) {
5357 case cls::rbd::MIRROR_MODE_DISABLED:
5358 enabled = false;
5359 break;
5360 case cls::rbd::MIRROR_MODE_IMAGE:
5361 case cls::rbd::MIRROR_MODE_POOL:
5362 enabled = true;
5363 break;
5364 default:
5365 CLS_ERR("invalid mirror mode: %d", mirror_mode_decode);
5366 return -EINVAL;
5367 }
5368
5369 int r;
5370 if (enabled) {
5371 std::string mirror_uuid;
5372 r = mirror::uuid_get(hctx, &mirror_uuid);
5373 if (r == -ENOENT) {
5374 return -EINVAL;
5375 } else if (r < 0) {
5376 return r;
5377 }
5378
5379 bufferlist bl;
5380 encode(mirror_mode_decode, bl);
5381
5382 r = cls_cxx_map_set_val(hctx, mirror::MODE, &bl);
5383 if (r < 0) {
5384 CLS_ERR("error enabling mirroring: %s", cpp_strerror(r).c_str());
5385 return r;
5386 }
5387 } else {
5388 std::vector<cls::rbd::MirrorPeer> peers;
5389 r = mirror::read_peers(hctx, &peers);
5390 if (r < 0 && r != -ENOENT) {
5391 return r;
5392 }
5393
5394 if (!peers.empty()) {
5395 CLS_ERR("mirroring peers still registered");
5396 return -EBUSY;
5397 }
5398
5399 r = remove_key(hctx, mirror::MODE);
5400 if (r < 0) {
5401 return r;
5402 }
5403
5404 r = remove_key(hctx, mirror::UUID);
5405 if (r < 0) {
5406 return r;
5407 }
5408 }
5409 return 0;
5410 }
5411
5412 /**
5413 * Input:
5414 * none
5415 *
5416 * Output:
5417 * @param std::vector<cls::rbd::MirrorPeer>: collection of peers
5418 * @returns 0 on success, negative error code on failure
5419 */
5420 int mirror_peer_list(cls_method_context_t hctx, bufferlist *in,
5421 bufferlist *out) {
5422 std::vector<cls::rbd::MirrorPeer> peers;
5423 int r = mirror::read_peers(hctx, &peers);
5424 if (r < 0 && r != -ENOENT) {
5425 return r;
5426 }
5427
5428 encode(peers, *out);
5429 return 0;
5430 }
5431
5432 /**
5433 * Input:
5434 * @param mirror_peer (cls::rbd::MirrorPeer)
5435 *
5436 * Output:
5437 * @returns 0 on success, negative error code on failure
5438 */
5439 int mirror_peer_add(cls_method_context_t hctx, bufferlist *in,
5440 bufferlist *out) {
5441 cls::rbd::MirrorPeer mirror_peer;
5442 try {
5443 auto it = in->cbegin();
5444 decode(mirror_peer, it);
5445 } catch (const buffer::error &err) {
5446 return -EINVAL;
5447 }
5448
5449 uint32_t mirror_mode_decode;
5450 int r = read_key(hctx, mirror::MODE, &mirror_mode_decode);
5451 if (r < 0 && r != -ENOENT) {
5452 return r;
5453 } else if (r == -ENOENT ||
5454 mirror_mode_decode == cls::rbd::MIRROR_MODE_DISABLED) {
5455 CLS_ERR("mirroring must be enabled on the pool");
5456 return -EINVAL;
5457 } else if (!mirror_peer.is_valid()) {
5458 CLS_ERR("mirror peer is not valid");
5459 return -EINVAL;
5460 }
5461
5462 std::string mirror_uuid;
5463 r = mirror::uuid_get(hctx, &mirror_uuid);
5464 if (r < 0) {
5465 CLS_ERR("error retrieving mirroring uuid: %s", cpp_strerror(r).c_str());
5466 return r;
5467 } else if (mirror_peer.uuid == mirror_uuid) {
5468 CLS_ERR("peer uuid '%s' matches pool mirroring uuid",
5469 mirror_uuid.c_str());
5470 return -EINVAL;
5471 }
5472
5473 std::vector<cls::rbd::MirrorPeer> peers;
5474 r = mirror::read_peers(hctx, &peers);
5475 if (r < 0 && r != -ENOENT) {
5476 return r;
5477 }
5478
5479 for (auto const &peer : peers) {
5480 if (peer.uuid == mirror_peer.uuid) {
5481 CLS_ERR("peer uuid '%s' already exists",
5482 peer.uuid.c_str());
5483 return -ESTALE;
5484 } else if (peer.cluster_name == mirror_peer.cluster_name &&
5485 (peer.pool_id == -1 || mirror_peer.pool_id == -1 ||
5486 peer.pool_id == mirror_peer.pool_id)) {
5487 CLS_ERR("peer cluster name '%s' already exists",
5488 peer.cluster_name.c_str());
5489 return -EEXIST;
5490 }
5491 }
5492
5493 bufferlist bl;
5494 encode(mirror_peer, bl);
5495 r = cls_cxx_map_set_val(hctx, mirror::peer_key(mirror_peer.uuid),
5496 &bl);
5497 if (r < 0) {
5498 CLS_ERR("error adding peer: %s", cpp_strerror(r).c_str());
5499 return r;
5500 }
5501 return 0;
5502 }
5503
5504 /**
5505 * Input:
5506 * @param uuid (std::string)
5507 *
5508 * Output:
5509 * @returns 0 on success, negative error code on failure
5510 */
5511 int mirror_peer_remove(cls_method_context_t hctx, bufferlist *in,
5512 bufferlist *out) {
5513 std::string uuid;
5514 try {
5515 auto it = in->cbegin();
5516 decode(uuid, it);
5517 } catch (const buffer::error &err) {
5518 return -EINVAL;
5519 }
5520
5521 int r = cls_cxx_map_remove_key(hctx, mirror::peer_key(uuid));
5522 if (r < 0 && r != -ENOENT) {
5523 CLS_ERR("error removing peer: %s", cpp_strerror(r).c_str());
5524 return r;
5525 }
5526 return 0;
5527 }
5528
5529 /**
5530 * Input:
5531 * @param uuid (std::string)
5532 * @param client_name (std::string)
5533 *
5534 * Output:
5535 * @returns 0 on success, negative error code on failure
5536 */
5537 int mirror_peer_set_client(cls_method_context_t hctx, bufferlist *in,
5538 bufferlist *out) {
5539 std::string uuid;
5540 std::string client_name;
5541 try {
5542 auto it = in->cbegin();
5543 decode(uuid, it);
5544 decode(client_name, it);
5545 } catch (const buffer::error &err) {
5546 return -EINVAL;
5547 }
5548
5549 cls::rbd::MirrorPeer peer;
5550 int r = mirror::read_peer(hctx, uuid, &peer);
5551 if (r < 0) {
5552 return r;
5553 }
5554
5555 peer.client_name = client_name;
5556 r = mirror::write_peer(hctx, uuid, peer);
5557 if (r < 0) {
5558 return r;
5559 }
5560 return 0;
5561 }
5562
5563 /**
5564 * Input:
5565 * @param uuid (std::string)
5566 * @param cluster_name (std::string)
5567 *
5568 * Output:
5569 * @returns 0 on success, negative error code on failure
5570 */
5571 int mirror_peer_set_cluster(cls_method_context_t hctx, bufferlist *in,
5572 bufferlist *out) {
5573 std::string uuid;
5574 std::string cluster_name;
5575 try {
5576 auto it = in->cbegin();
5577 decode(uuid, it);
5578 decode(cluster_name, it);
5579 } catch (const buffer::error &err) {
5580 return -EINVAL;
5581 }
5582
5583 cls::rbd::MirrorPeer peer;
5584 int r = mirror::read_peer(hctx, uuid, &peer);
5585 if (r < 0) {
5586 return r;
5587 }
5588
5589 peer.cluster_name = cluster_name;
5590 r = mirror::write_peer(hctx, uuid, peer);
5591 if (r < 0) {
5592 return r;
5593 }
5594 return 0;
5595 }
5596
5597 /**
5598 * Input:
5599 * @param start_after which name to begin listing after
5600 * (use the empty string to start at the beginning)
5601 * @param max_return the maximum number of names to list
5602 *
5603 * Output:
5604 * @param std::map<std::string, std::string>: local id to global id map
5605 * @returns 0 on success, negative error code on failure
5606 */
5607 int mirror_image_list(cls_method_context_t hctx, bufferlist *in,
5608 bufferlist *out) {
5609 std::string start_after;
5610 uint64_t max_return;
5611 try {
5612 auto iter = in->cbegin();
5613 decode(start_after, iter);
5614 decode(max_return, iter);
5615 } catch (const buffer::error &err) {
5616 return -EINVAL;
5617 }
5618
5619 int max_read = RBD_MAX_KEYS_READ;
5620 bool more = true;
5621 std::map<std::string, std::string> mirror_images;
5622 std::string last_read = mirror::image_key(start_after);
5623
5624 while (more && mirror_images.size() < max_return) {
5625 std::map<std::string, bufferlist> vals;
5626 CLS_LOG(20, "last_read = '%s'", last_read.c_str());
5627 int r = cls_cxx_map_get_vals(hctx, last_read, mirror::IMAGE_KEY_PREFIX,
5628 max_read, &vals, &more);
5629 if (r < 0) {
5630 if (r != -ENOENT) {
5631 CLS_ERR("error reading mirror image directory by name: %s",
5632 cpp_strerror(r).c_str());
5633 }
5634 return r;
5635 }
5636
5637 for (auto it = vals.begin(); it != vals.end(); ++it) {
5638 const std::string &image_id =
5639 it->first.substr(mirror::IMAGE_KEY_PREFIX.size());
5640 cls::rbd::MirrorImage mirror_image;
5641 auto iter = it->second.cbegin();
5642 try {
5643 decode(mirror_image, iter);
5644 } catch (const buffer::error &err) {
5645 CLS_ERR("could not decode mirror image payload of image '%s'",
5646 image_id.c_str());
5647 return -EIO;
5648 }
5649
5650 mirror_images[image_id] = mirror_image.global_image_id;
5651 if (mirror_images.size() >= max_return) {
5652 break;
5653 }
5654 }
5655 if (!vals.empty()) {
5656 last_read = mirror::image_key(mirror_images.rbegin()->first);
5657 }
5658 }
5659
5660 encode(mirror_images, *out);
5661 return 0;
5662 }
5663
5664 /**
5665 * Input:
5666 * @param global_id (std::string)
5667 *
5668 * Output:
5669 * @param std::string - image id
5670 * @returns 0 on success, negative error code on failure
5671 */
5672 int mirror_image_get_image_id(cls_method_context_t hctx, bufferlist *in,
5673 bufferlist *out) {
5674 std::string global_id;
5675 try {
5676 auto it = in->cbegin();
5677 decode(global_id, it);
5678 } catch (const buffer::error &err) {
5679 return -EINVAL;
5680 }
5681
5682 std::string image_id;
5683 int r = read_key(hctx, mirror::global_key(global_id), &image_id);
5684 if (r < 0) {
5685 if (r != -ENOENT) {
5686 CLS_ERR("error retrieving image id for global id '%s': %s",
5687 global_id.c_str(), cpp_strerror(r).c_str());
5688 }
5689 return r;
5690 }
5691
5692 encode(image_id, *out);
5693 return 0;
5694 }
5695
5696 /**
5697 * Input:
5698 * @param image_id (std::string)
5699 *
5700 * Output:
5701 * @param cls::rbd::MirrorImage - metadata associated with the image_id
5702 * @returns 0 on success, negative error code on failure
5703 */
5704 int mirror_image_get(cls_method_context_t hctx, bufferlist *in,
5705 bufferlist *out) {
5706 string image_id;
5707 try {
5708 auto it = in->cbegin();
5709 decode(image_id, it);
5710 } catch (const buffer::error &err) {
5711 return -EINVAL;
5712 }
5713
5714 cls::rbd::MirrorImage mirror_image;
5715 int r = mirror::image_get(hctx, image_id, &mirror_image);
5716 if (r < 0) {
5717 return r;
5718 }
5719
5720 encode(mirror_image, *out);
5721 return 0;
5722 }
5723
5724 /**
5725 * Input:
5726 * @param image_id (std::string)
5727 * @param mirror_image (cls::rbd::MirrorImage)
5728 *
5729 * Output:
5730 * @returns 0 on success, negative error code on failure
5731 * @returns -EEXIST if there's an existing image_id with a different global_image_id
5732 */
5733 int mirror_image_set(cls_method_context_t hctx, bufferlist *in,
5734 bufferlist *out) {
5735 string image_id;
5736 cls::rbd::MirrorImage mirror_image;
5737 try {
5738 auto it = in->cbegin();
5739 decode(image_id, it);
5740 decode(mirror_image, it);
5741 } catch (const buffer::error &err) {
5742 return -EINVAL;
5743 }
5744
5745 int r = mirror::image_set(hctx, image_id, mirror_image);
5746 if (r < 0) {
5747 return r;
5748 }
5749 return 0;
5750 }
5751
5752 /**
5753 * Input:
5754 * @param image_id (std::string)
5755 *
5756 * Output:
5757 * @returns 0 on success, negative error code on failure
5758 */
5759 int mirror_image_remove(cls_method_context_t hctx, bufferlist *in,
5760 bufferlist *out) {
5761 string image_id;
5762 try {
5763 auto it = in->cbegin();
5764 decode(image_id, it);
5765 } catch (const buffer::error &err) {
5766 return -EINVAL;
5767 }
5768
5769 int r = mirror::image_remove(hctx, image_id);
5770 if (r < 0) {
5771 return r;
5772 }
5773 return 0;
5774 }
5775
5776 /**
5777 * Input:
5778 * @param global_image_id (std::string)
5779 * @param status (cls::rbd::MirrorImageStatus)
5780 *
5781 * Output:
5782 * @returns 0 on success, negative error code on failure
5783 */
5784 int mirror_image_status_set(cls_method_context_t hctx, bufferlist *in,
5785 bufferlist *out) {
5786 string global_image_id;
5787 cls::rbd::MirrorImageStatus status;
5788 try {
5789 auto it = in->cbegin();
5790 decode(global_image_id, it);
5791 decode(status, it);
5792 } catch (const buffer::error &err) {
5793 return -EINVAL;
5794 }
5795
5796 int r = mirror::image_status_set(hctx, global_image_id, status);
5797 if (r < 0) {
5798 return r;
5799 }
5800 return 0;
5801 }
5802
5803 /**
5804 * Input:
5805 * @param global_image_id (std::string)
5806 *
5807 * Output:
5808 * @returns 0 on success, negative error code on failure
5809 */
5810 int mirror_image_status_remove(cls_method_context_t hctx, bufferlist *in,
5811 bufferlist *out) {
5812 string global_image_id;
5813 try {
5814 auto it = in->cbegin();
5815 decode(global_image_id, it);
5816 } catch (const buffer::error &err) {
5817 return -EINVAL;
5818 }
5819
5820 int r = mirror::image_status_remove(hctx, global_image_id);
5821 if (r < 0) {
5822 return r;
5823 }
5824 return 0;
5825 }
5826
5827 /**
5828 * Input:
5829 * @param global_image_id (std::string)
5830 *
5831 * Output:
5832 * @param cls::rbd::MirrorImageStatus - metadata associated with the global_image_id
5833 * @returns 0 on success, negative error code on failure
5834 */
5835 int mirror_image_status_get(cls_method_context_t hctx, bufferlist *in,
5836 bufferlist *out) {
5837 string global_image_id;
5838 try {
5839 auto it = in->cbegin();
5840 decode(global_image_id, it);
5841 } catch (const buffer::error &err) {
5842 return -EINVAL;
5843 }
5844
5845 std::set<entity_inst_t> watchers;
5846 int r = mirror::list_watchers(hctx, &watchers);
5847 if (r < 0) {
5848 return r;
5849 }
5850
5851 cls::rbd::MirrorImageStatus status;
5852 r = mirror::image_status_get(hctx, global_image_id, watchers, &status);
5853 if (r < 0) {
5854 return r;
5855 }
5856
5857 encode(status, *out);
5858 return 0;
5859 }
5860
5861 /**
5862 * Input:
5863 * @param start_after which name to begin listing after
5864 * (use the empty string to start at the beginning)
5865 * @param max_return the maximum number of names to list
5866 *
5867 * Output:
5868 * @param std::map<std::string, cls::rbd::MirrorImage>: image id to image map
5869 * @param std::map<std::string, cls::rbd::MirrorImageStatus>: image it to status map
5870 * @returns 0 on success, negative error code on failure
5871 */
5872 int mirror_image_status_list(cls_method_context_t hctx, bufferlist *in,
5873 bufferlist *out) {
5874 std::string start_after;
5875 uint64_t max_return;
5876 try {
5877 auto iter = in->cbegin();
5878 decode(start_after, iter);
5879 decode(max_return, iter);
5880 } catch (const buffer::error &err) {
5881 return -EINVAL;
5882 }
5883
5884 map<std::string, cls::rbd::MirrorImage> images;
5885 map<std::string, cls::rbd::MirrorImageStatus> statuses;
5886 int r = mirror::image_status_list(hctx, start_after, max_return, &images,
5887 &statuses);
5888 if (r < 0) {
5889 return r;
5890 }
5891
5892 encode(images, *out);
5893 encode(statuses, *out);
5894 return 0;
5895 }
5896
5897 /**
5898 * Input:
5899 * none
5900 *
5901 * Output:
5902 * @param std::map<cls::rbd::MirrorImageStatusState, int>: states counts
5903 * @returns 0 on success, negative error code on failure
5904 */
5905 int mirror_image_status_get_summary(cls_method_context_t hctx, bufferlist *in,
5906 bufferlist *out) {
5907 std::map<cls::rbd::MirrorImageStatusState, int> states;
5908
5909 int r = mirror::image_status_get_summary(hctx, &states);
5910 if (r < 0) {
5911 return r;
5912 }
5913
5914 encode(states, *out);
5915 return 0;
5916 }
5917
5918 /**
5919 * Input:
5920 * none
5921 *
5922 * Output:
5923 * @returns 0 on success, negative error code on failure
5924 */
5925 int mirror_image_status_remove_down(cls_method_context_t hctx, bufferlist *in,
5926 bufferlist *out) {
5927 int r = mirror::image_status_remove_down(hctx);
5928 if (r < 0) {
5929 return r;
5930 }
5931 return 0;
5932 }
5933
5934 /**
5935 * Input:
5936 * @param global_image_id (std::string)
5937 *
5938 * Output:
5939 * @param entity_inst_t - instance
5940 * @returns 0 on success, negative error code on failure
5941 */
5942 int mirror_image_instance_get(cls_method_context_t hctx, bufferlist *in,
5943 bufferlist *out) {
5944 string global_image_id;
5945 try {
5946 auto it = in->cbegin();
5947 decode(global_image_id, it);
5948 } catch (const buffer::error &err) {
5949 return -EINVAL;
5950 }
5951
5952 std::set<entity_inst_t> watchers;
5953 int r = mirror::list_watchers(hctx, &watchers);
5954 if (r < 0) {
5955 return r;
5956 }
5957
5958 entity_inst_t instance;
5959 r = mirror::image_instance_get(hctx, global_image_id, watchers, &instance);
5960 if (r < 0) {
5961 return r;
5962 }
5963
5964 encode(instance, *out, cls_get_features(hctx));
5965 return 0;
5966 }
5967
5968 /**
5969 * Input:
5970 * @param start_after which name to begin listing after
5971 * (use the empty string to start at the beginning)
5972 * @param max_return the maximum number of names to list
5973 *
5974 * Output:
5975 * @param std::map<std::string, entity_inst_t>: image id to instance map
5976 * @returns 0 on success, negative error code on failure
5977 */
5978 int mirror_image_instance_list(cls_method_context_t hctx, bufferlist *in,
5979 bufferlist *out) {
5980 std::string start_after;
5981 uint64_t max_return;
5982 try {
5983 auto iter = in->cbegin();
5984 decode(start_after, iter);
5985 decode(max_return, iter);
5986 } catch (const buffer::error &err) {
5987 return -EINVAL;
5988 }
5989
5990 map<std::string, entity_inst_t> instances;
5991 int r = mirror::image_instance_list(hctx, start_after, max_return,
5992 &instances);
5993 if (r < 0) {
5994 return r;
5995 }
5996
5997 encode(instances, *out, cls_get_features(hctx));
5998 return 0;
5999 }
6000
6001 /**
6002 * Input:
6003 * none
6004 *
6005 * Output:
6006 * @param std::vector<std::string>: instance ids
6007 * @returns 0 on success, negative error code on failure
6008 */
6009 int mirror_instances_list(cls_method_context_t hctx, bufferlist *in,
6010 bufferlist *out) {
6011 std::vector<std::string> instance_ids;
6012
6013 int r = mirror::instances_list(hctx, &instance_ids);
6014 if (r < 0) {
6015 return r;
6016 }
6017
6018 encode(instance_ids, *out);
6019 return 0;
6020 }
6021
6022 /**
6023 * Input:
6024 * @param instance_id (std::string)
6025 *
6026 * Output:
6027 * @returns 0 on success, negative error code on failure
6028 */
6029 int mirror_instances_add(cls_method_context_t hctx, bufferlist *in,
6030 bufferlist *out) {
6031 std::string instance_id;
6032 try {
6033 auto iter = in->cbegin();
6034 decode(instance_id, iter);
6035 } catch (const buffer::error &err) {
6036 return -EINVAL;
6037 }
6038
6039 int r = mirror::instances_add(hctx, instance_id);
6040 if (r < 0) {
6041 return r;
6042 }
6043 return 0;
6044 }
6045
6046 /**
6047 * Input:
6048 * @param instance_id (std::string)
6049 *
6050 * Output:
6051 * @returns 0 on success, negative error code on failure
6052 */
6053 int mirror_instances_remove(cls_method_context_t hctx, bufferlist *in,
6054 bufferlist *out) {
6055 std::string instance_id;
6056 try {
6057 auto iter = in->cbegin();
6058 decode(instance_id, iter);
6059 } catch (const buffer::error &err) {
6060 return -EINVAL;
6061 }
6062
6063 int r = mirror::instances_remove(hctx, instance_id);
6064 if (r < 0) {
6065 return r;
6066 }
6067 return 0;
6068 }
6069
6070 /**
6071 * Input:
6072 * @param start_after: key to start after
6073 * @param max_return: max return items
6074 *
6075 * Output:
6076 * @param std::map<std::string, cls::rbd::MirrorImageMap>: image mapping
6077 * @returns 0 on success, negative error code on failure
6078 */
6079 int mirror_image_map_list(cls_method_context_t hctx, bufferlist *in,
6080 bufferlist *out) {
6081 std::string start_after;
6082 uint64_t max_return;
6083 try {
6084 auto it = in->cbegin();
6085 decode(start_after, it);
6086 decode(max_return, it);
6087 } catch (const buffer::error &err) {
6088 return -EINVAL;
6089 }
6090
6091 std::map<std::string, cls::rbd::MirrorImageMap> image_mapping;
6092 int r = mirror::mirror_image_map_list(hctx, start_after, max_return, &image_mapping);
6093 if (r < 0) {
6094 return r;
6095 }
6096
6097 encode(image_mapping, *out);
6098 return 0;
6099 }
6100
6101 /**
6102 * Input:
6103 * @param global_image_id: global image id
6104 * @param image_map: image map
6105 *
6106 * Output:
6107 * @returns 0 on success, negative error code on failure
6108 */
6109 int mirror_image_map_update(cls_method_context_t hctx, bufferlist *in,
6110 bufferlist *out) {
6111 std::string global_image_id;
6112 cls::rbd::MirrorImageMap image_map;
6113
6114 try {
6115 auto it = in->cbegin();
6116 decode(global_image_id, it);
6117 decode(image_map, it);
6118 } catch (const buffer::error &err) {
6119 return -EINVAL;
6120 }
6121
6122 bufferlist bl;
6123 encode(image_map, bl);
6124
6125 const std::string key = mirror::mirror_image_map_key(global_image_id);
6126 int r = cls_cxx_map_set_val(hctx, key, &bl);
6127 if (r < 0) {
6128 CLS_ERR("error updating image map %s: %s", key.c_str(),
6129 cpp_strerror(r).c_str());
6130 return r;
6131 }
6132
6133 return 0;
6134 }
6135
6136 /**
6137 * Input:
6138 * @param global_image_id: global image id
6139 *
6140 * Output:
6141 * @returns 0 on success, negative error code on failure
6142 */
6143 int mirror_image_map_remove(cls_method_context_t hctx, bufferlist *in,
6144 bufferlist *out) {
6145 std::string global_image_id;
6146
6147 try {
6148 auto it = in->cbegin();
6149 decode(global_image_id, it);
6150 } catch (const buffer::error &err) {
6151 return -EINVAL;
6152 }
6153
6154 const std::string key = mirror::mirror_image_map_key(global_image_id);
6155 int r = cls_cxx_map_remove_key(hctx, key);
6156 if (r < 0 && r != -ENOENT) {
6157 CLS_ERR("error removing image map %s: %s", key.c_str(),
6158 cpp_strerror(r).c_str());
6159 return r;
6160 }
6161
6162 return 0;
6163 }
6164
6165 namespace group {
6166
6167 /********************** methods for rbd_group_directory ***********************/
6168
6169 int dir_add(cls_method_context_t hctx,
6170 const string &name, const string &id,
6171 bool check_for_unique_id)
6172 {
6173 if (!name.size() || !is_valid_id(id)) {
6174 CLS_ERR("invalid group name '%s' or id '%s'",
6175 name.c_str(), id.c_str());
6176 return -EINVAL;
6177 }
6178
6179 CLS_LOG(20, "dir_add name=%s id=%s", name.c_str(), id.c_str());
6180
6181 string name_key = dir_key_for_name(name);
6182 string id_key = dir_key_for_id(id);
6183 string tmp;
6184 int r = read_key(hctx, name_key, &tmp);
6185 if (r != -ENOENT) {
6186 CLS_LOG(10, "name already exists");
6187 return -EEXIST;
6188 }
6189 r = read_key(hctx, id_key, &tmp);
6190 if (r != -ENOENT && check_for_unique_id) {
6191 CLS_LOG(10, "id already exists");
6192 return -EBADF;
6193 }
6194 bufferlist id_bl, name_bl;
6195 encode(id, id_bl);
6196 encode(name, name_bl);
6197 map<string, bufferlist> omap_vals;
6198 omap_vals[name_key] = id_bl;
6199 omap_vals[id_key] = name_bl;
6200 return cls_cxx_map_set_vals(hctx, &omap_vals);
6201 }
6202
6203 int dir_remove(cls_method_context_t hctx,
6204 const string &name, const string &id)
6205 {
6206 CLS_LOG(20, "dir_remove name=%s id=%s", name.c_str(), id.c_str());
6207
6208 string name_key = dir_key_for_name(name);
6209 string id_key = dir_key_for_id(id);
6210 string stored_name, stored_id;
6211
6212 int r = read_key(hctx, name_key, &stored_id);
6213 if (r < 0) {
6214 if (r != -ENOENT)
6215 CLS_ERR("error reading name to id mapping: %s", cpp_strerror(r).c_str());
6216 return r;
6217 }
6218 r = read_key(hctx, id_key, &stored_name);
6219 if (r < 0) {
6220 if (r != -ENOENT)
6221 CLS_ERR("error reading id to name mapping: %s", cpp_strerror(r).c_str());
6222 return r;
6223 }
6224
6225 // check if this op raced with a rename
6226 if (stored_name != name || stored_id != id) {
6227 CLS_ERR("stored name '%s' and id '%s' do not match args '%s' and '%s'",
6228 stored_name.c_str(), stored_id.c_str(), name.c_str(), id.c_str());
6229 return -ESTALE;
6230 }
6231
6232 r = cls_cxx_map_remove_key(hctx, name_key);
6233 if (r < 0) {
6234 CLS_ERR("error removing name: %s", cpp_strerror(r).c_str());
6235 return r;
6236 }
6237
6238 r = cls_cxx_map_remove_key(hctx, id_key);
6239 if (r < 0) {
6240 CLS_ERR("error removing id: %s", cpp_strerror(r).c_str());
6241 return r;
6242 }
6243
6244 return 0;
6245 }
6246
6247 static const string RBD_GROUP_SNAP_KEY_PREFIX = "snapshot_";
6248
6249 std::string snap_key(const std::string &snap_id) {
6250 ostringstream oss;
6251 oss << RBD_GROUP_SNAP_KEY_PREFIX << snap_id;
6252 return oss.str();
6253 }
6254
6255 int snap_list(cls_method_context_t hctx, cls::rbd::GroupSnapshot start_after,
6256 uint64_t max_return,
6257 std::vector<cls::rbd::GroupSnapshot> *group_snaps)
6258 {
6259 int max_read = RBD_MAX_KEYS_READ;
6260 std::map<string, bufferlist> vals;
6261 string last_read = snap_key(start_after.id);
6262
6263 group_snaps->clear();
6264
6265 bool more;
6266 do {
6267 int r = cls_cxx_map_get_vals(hctx, last_read,
6268 RBD_GROUP_SNAP_KEY_PREFIX,
6269 max_read, &vals, &more);
6270 if (r < 0)
6271 return r;
6272
6273 for (map<string, bufferlist>::iterator it = vals.begin();
6274 it != vals.end() && group_snaps->size() < max_return; ++it) {
6275
6276 auto iter = it->second.cbegin();
6277 cls::rbd::GroupSnapshot snap;
6278 try {
6279 decode(snap, iter);
6280 } catch (const buffer::error &err) {
6281 CLS_ERR("error decoding snapshot: %s", it->first.c_str());
6282 return -EIO;
6283 }
6284 CLS_LOG(20, "Discovered snapshot %s %s",
6285 snap.name.c_str(),
6286 snap.id.c_str());
6287 group_snaps->push_back(snap);
6288 }
6289
6290 } while (more && (group_snaps->size() < max_return));
6291
6292 return 0;
6293 }
6294
6295 static int check_duplicate_snap_name(cls_method_context_t hctx,
6296 const std::string &snap_name,
6297 const std::string &snap_id)
6298 {
6299 const int max_read = 1024;
6300 cls::rbd::GroupSnapshot snap_last;
6301 std::vector<cls::rbd::GroupSnapshot> page;
6302
6303 for (;;) {
6304 int r = snap_list(hctx, snap_last, max_read, &page);
6305 if (r < 0) {
6306 return r;
6307 }
6308 for (auto& snap: page) {
6309 if (snap.name == snap_name && snap.id != snap_id) {
6310 return -EEXIST;
6311 }
6312 }
6313
6314 if (page.size() < max_read) {
6315 break;
6316 }
6317
6318 snap_last = *page.rbegin();
6319 }
6320
6321 return 0;
6322 }
6323
6324 } // namespace group
6325
6326 /**
6327 * List groups from the directory.
6328 *
6329 * Input:
6330 * @param start_after (std::string)
6331 * @param max_return (int64_t)
6332 *
6333 * Output:
6334 * @param map of groups (name, id)
6335 * @return 0 on success, negative error code on failure
6336 */
6337 int group_dir_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
6338 {
6339 string start_after;
6340 uint64_t max_return;
6341
6342 try {
6343 auto iter = in->cbegin();
6344 decode(start_after, iter);
6345 decode(max_return, iter);
6346 } catch (const buffer::error &err) {
6347 return -EINVAL;
6348 }
6349
6350 int max_read = RBD_MAX_KEYS_READ;
6351 bool more = true;
6352 map<string, string> groups;
6353 string last_read = dir_key_for_name(start_after);
6354
6355 while (more && groups.size() < max_return) {
6356 map<string, bufferlist> vals;
6357 CLS_LOG(20, "last_read = '%s'", last_read.c_str());
6358 int r = cls_cxx_map_get_vals(hctx, last_read, RBD_DIR_NAME_KEY_PREFIX,
6359 max_read, &vals, &more);
6360 if (r < 0) {
6361 if (r != -ENOENT) {
6362 CLS_ERR("error reading directory by name: %s", cpp_strerror(r).c_str());
6363 }
6364 return r;
6365 }
6366
6367 for (pair<string, bufferlist> val: vals) {
6368 string id;
6369 auto iter = val.second.cbegin();
6370 try {
6371 decode(id, iter);
6372 } catch (const buffer::error &err) {
6373 CLS_ERR("could not decode id of group '%s'", val.first.c_str());
6374 return -EIO;
6375 }
6376 CLS_LOG(20, "adding '%s' -> '%s'", dir_name_from_key(val.first).c_str(), id.c_str());
6377 groups[dir_name_from_key(val.first)] = id;
6378 if (groups.size() >= max_return)
6379 break;
6380 }
6381 if (!vals.empty()) {
6382 last_read = dir_key_for_name(groups.rbegin()->first);
6383 }
6384 }
6385
6386 encode(groups, *out);
6387
6388 return 0;
6389 }
6390
6391 /**
6392 * Add a group to the directory.
6393 *
6394 * Input:
6395 * @param name (std::string)
6396 * @param id (std::string)
6397 *
6398 * Output:
6399 * @return 0 on success, negative error code on failure
6400 */
6401 int group_dir_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
6402 {
6403 int r = cls_cxx_create(hctx, false);
6404
6405 if (r < 0) {
6406 CLS_ERR("could not create group directory: %s",
6407 cpp_strerror(r).c_str());
6408 return r;
6409 }
6410
6411 string name, id;
6412 try {
6413 auto iter = in->cbegin();
6414 decode(name, iter);
6415 decode(id, iter);
6416 } catch (const buffer::error &err) {
6417 return -EINVAL;
6418 }
6419
6420 return group::dir_add(hctx, name, id, true);
6421 }
6422
6423 /**
6424 * Rename a group to the directory.
6425 *
6426 * Input:
6427 * @param src original name of the group (std::string)
6428 * @param dest new name of the group (std::string)
6429 * @param id the id of the group (std::string)
6430 *
6431 * Output:
6432 * @return 0 on success, negative error code on failure
6433 */
6434 int group_dir_rename(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
6435 {
6436 string src, dest, id;
6437 try {
6438 auto iter = in->cbegin();
6439 decode(src, iter);
6440 decode(dest, iter);
6441 decode(id, iter);
6442 } catch (const buffer::error &err) {
6443 return -EINVAL;
6444 }
6445
6446 int r = group::dir_remove(hctx, src, id);
6447 if (r < 0)
6448 return r;
6449
6450 return group::dir_add(hctx, dest, id, false);
6451 }
6452
6453 /**
6454 * Remove a group from the directory.
6455 *
6456 * Input:
6457 * @param name (std::string)
6458 * @param id (std::string)
6459 *
6460 * Output:
6461 * @return 0 on success, negative error code on failure
6462 */
6463 int group_dir_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
6464 {
6465 string name, id;
6466 try {
6467 auto iter = in->cbegin();
6468 decode(name, iter);
6469 decode(id, iter);
6470 } catch (const buffer::error &err) {
6471 return -EINVAL;
6472 }
6473
6474 return group::dir_remove(hctx, name, id);
6475 }
6476
6477 /**
6478 * Set state of an image in the group.
6479 *
6480 * Input:
6481 * @param image_status (cls::rbd::GroupImageStatus)
6482 *
6483 * Output:
6484 * @return 0 on success, negative error code on failure
6485 */
6486 int group_image_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
6487 {
6488 CLS_LOG(20, "group_image_set");
6489
6490 cls::rbd::GroupImageStatus st;
6491 try {
6492 auto iter = in->cbegin();
6493 decode(st, iter);
6494 } catch (const buffer::error &err) {
6495 return -EINVAL;
6496 }
6497
6498 string image_key = st.spec.image_key();
6499
6500 bufferlist image_val_bl;
6501 encode(st.state, image_val_bl);
6502 int r = cls_cxx_map_set_val(hctx, image_key, &image_val_bl);
6503 if (r < 0) {
6504 return r;
6505 }
6506
6507 return 0;
6508 }
6509
6510 /**
6511 * Remove reference to an image from the group.
6512 *
6513 * Input:
6514 * @param spec (cls::rbd::GroupImageSpec)
6515 *
6516 * Output:
6517 * @return 0 on success, negative error code on failure
6518 */
6519 int group_image_remove(cls_method_context_t hctx,
6520 bufferlist *in, bufferlist *out)
6521 {
6522 CLS_LOG(20, "group_image_remove");
6523 cls::rbd::GroupImageSpec spec;
6524 try {
6525 auto iter = in->cbegin();
6526 decode(spec, iter);
6527 } catch (const buffer::error &err) {
6528 return -EINVAL;
6529 }
6530
6531 string image_key = spec.image_key();
6532
6533 int r = cls_cxx_map_remove_key(hctx, image_key);
6534 if (r < 0) {
6535 CLS_ERR("error removing image from group: %s", cpp_strerror(r).c_str());
6536 return r;
6537 }
6538
6539 return 0;
6540 }
6541
6542 /*
6543 * List images in the group.
6544 *
6545 * Input:
6546 * @param start_after which name to begin listing after
6547 * (use the empty string to start at the beginning)
6548 * @param max_return the maximum number of names to list
6549 *
6550 * Output:
6551 * @param tuples of descriptions of the images: image_id, pool_id, image reference state.
6552 * @return 0 on success, negative error code on failure
6553 */
6554 int group_image_list(cls_method_context_t hctx,
6555 bufferlist *in, bufferlist *out)
6556 {
6557 CLS_LOG(20, "group_image_list");
6558 cls::rbd::GroupImageSpec start_after;
6559 uint64_t max_return;
6560 try {
6561 auto iter = in->cbegin();
6562 decode(start_after, iter);
6563 decode(max_return, iter);
6564 } catch (const buffer::error &err) {
6565 return -EINVAL;
6566 }
6567
6568 int max_read = RBD_MAX_KEYS_READ;
6569 std::map<string, bufferlist> vals;
6570 string last_read = start_after.image_key();
6571 std::vector<cls::rbd::GroupImageStatus> res;
6572 bool more;
6573 do {
6574 int r = cls_cxx_map_get_vals(hctx, last_read,
6575 cls::rbd::RBD_GROUP_IMAGE_KEY_PREFIX,
6576 max_read, &vals, &more);
6577 if (r < 0)
6578 return r;
6579
6580 for (map<string, bufferlist>::iterator it = vals.begin();
6581 it != vals.end() && res.size() < max_return; ++it) {
6582
6583 auto iter = it->second.cbegin();
6584 cls::rbd::GroupImageLinkState state;
6585 try {
6586 decode(state, iter);
6587 } catch (const buffer::error &err) {
6588 CLS_ERR("error decoding state for image: %s", it->first.c_str());
6589 return -EIO;
6590 }
6591 cls::rbd::GroupImageSpec spec;
6592 int r = cls::rbd::GroupImageSpec::from_key(it->first, &spec);
6593 if (r < 0)
6594 return r;
6595
6596 CLS_LOG(20, "Discovered image %s %" PRId64 " %d", spec.image_id.c_str(),
6597 spec.pool_id,
6598 (int)state);
6599 res.push_back(cls::rbd::GroupImageStatus(spec, state));
6600 }
6601 if (res.size() > 0) {
6602 last_read = res.rbegin()->spec.image_key();
6603 }
6604
6605 } while (more && (res.size() < max_return));
6606 encode(res, *out);
6607
6608 return 0;
6609 }
6610
6611 /**
6612 * Reference the group this image belongs to.
6613 *
6614 * Input:
6615 * @param group_id (std::string)
6616 * @param pool_id (int64_t)
6617 *
6618 * Output:
6619 * @return 0 on success, negative error code on failure
6620 */
6621 int image_group_add(cls_method_context_t hctx,
6622 bufferlist *in, bufferlist *out)
6623 {
6624 CLS_LOG(20, "image_group_add");
6625 cls::rbd::GroupSpec new_group;
6626 try {
6627 auto iter = in->cbegin();
6628 decode(new_group, iter);
6629 } catch (const buffer::error &err) {
6630 return -EINVAL;
6631 }
6632
6633 bufferlist existing_refbl;
6634
6635 int r = cls_cxx_map_get_val(hctx, RBD_GROUP_REF, &existing_refbl);
6636 if (r == 0) {
6637 // If we are trying to link this image to the same group then return
6638 // success. If this image already belongs to another group then abort.
6639 cls::rbd::GroupSpec old_group;
6640 try {
6641 auto iter = existing_refbl.cbegin();
6642 decode(old_group, iter);
6643 } catch (const buffer::error &err) {
6644 return -EINVAL;
6645 }
6646
6647 if ((old_group.group_id != new_group.group_id) ||
6648 (old_group.pool_id != new_group.pool_id)) {
6649 return -EEXIST;
6650 } else {
6651 return 0; // In this case the values are already correct
6652 }
6653 } else if (r < 0 && r != -ENOENT) {
6654 // No entry means this image is not a member of any group.
6655 return r;
6656 }
6657
6658 r = image::set_op_features(hctx, RBD_OPERATION_FEATURE_GROUP,
6659 RBD_OPERATION_FEATURE_GROUP);
6660 if (r < 0) {
6661 return r;
6662 }
6663
6664 bufferlist refbl;
6665 encode(new_group, refbl);
6666 r = cls_cxx_map_set_val(hctx, RBD_GROUP_REF, &refbl);
6667 if (r < 0) {
6668 return r;
6669 }
6670
6671 return 0;
6672 }
6673
6674 /**
6675 * Remove image's pointer to the group.
6676 *
6677 * Input:
6678 * @param cg_id (std::string)
6679 * @param pool_id (int64_t)
6680 *
6681 * Output:
6682 * @return 0 on success, negative error code on failure
6683 */
6684 int image_group_remove(cls_method_context_t hctx,
6685 bufferlist *in,
6686 bufferlist *out)
6687 {
6688 CLS_LOG(20, "image_group_remove");
6689 cls::rbd::GroupSpec spec;
6690 try {
6691 auto iter = in->cbegin();
6692 decode(spec, iter);
6693 } catch (const buffer::error &err) {
6694 return -EINVAL;
6695 }
6696
6697 bufferlist refbl;
6698 int r = cls_cxx_map_get_val(hctx, RBD_GROUP_REF, &refbl);
6699 if (r < 0) {
6700 return r;
6701 }
6702
6703 cls::rbd::GroupSpec ref_spec;
6704 auto iter = refbl.cbegin();
6705 try {
6706 decode(ref_spec, iter);
6707 } catch (const buffer::error &err) {
6708 return -EINVAL;
6709 }
6710
6711 if (ref_spec.pool_id != spec.pool_id || ref_spec.group_id != spec.group_id) {
6712 return -EBADF;
6713 }
6714
6715 r = cls_cxx_map_remove_key(hctx, RBD_GROUP_REF);
6716 if (r < 0) {
6717 return r;
6718 }
6719
6720 r = image::set_op_features(hctx, 0, RBD_OPERATION_FEATURE_GROUP);
6721 if (r < 0) {
6722 return r;
6723 }
6724
6725 return 0;
6726 }
6727
6728 /**
6729 * Retrieve the id and pool of the group this image belongs to.
6730 *
6731 * Input:
6732 * none
6733 *
6734 * Output:
6735 * @param GroupSpec
6736 * @return 0 on success, negative error code on failure
6737 */
6738 int image_group_get(cls_method_context_t hctx,
6739 bufferlist *in, bufferlist *out)
6740 {
6741 CLS_LOG(20, "image_group_get");
6742 bufferlist refbl;
6743 int r = cls_cxx_map_get_val(hctx, RBD_GROUP_REF, &refbl);
6744 if (r < 0 && r != -ENOENT) {
6745 return r;
6746 }
6747
6748 cls::rbd::GroupSpec spec;
6749
6750 if (r != -ENOENT) {
6751 auto iter = refbl.cbegin();
6752 try {
6753 decode(spec, iter);
6754 } catch (const buffer::error &err) {
6755 return -EINVAL;
6756 }
6757 }
6758
6759 encode(spec, *out);
6760 return 0;
6761 }
6762
6763 /**
6764 * Save initial snapshot record.
6765 *
6766 * Input:
6767 * @param GroupSnapshot
6768 *
6769 * Output:
6770 * @return 0 on success, negative error code on failure
6771 */
6772 int group_snap_set(cls_method_context_t hctx,
6773 bufferlist *in, bufferlist *out)
6774 {
6775 CLS_LOG(20, "group_snap_set");
6776 cls::rbd::GroupSnapshot group_snap;
6777 try {
6778 auto iter = in->cbegin();
6779 decode(group_snap, iter);
6780 } catch (const buffer::error &err) {
6781 return -EINVAL;
6782 }
6783
6784 if (group_snap.name.empty()) {
6785 CLS_ERR("group snapshot name is empty");
6786 return -EINVAL;
6787 }
6788 if (group_snap.id.empty()) {
6789 CLS_ERR("group snapshot id is empty");
6790 return -EINVAL;
6791 }
6792
6793 int r = group::check_duplicate_snap_name(hctx, group_snap.name,
6794 group_snap.id);
6795 if (r < 0) {
6796 return r;
6797 }
6798
6799 std::string key = group::snap_key(group_snap.id);
6800 if (group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
6801 bufferlist snap_bl;
6802 r = cls_cxx_map_get_val(hctx, key, &snap_bl);
6803 if (r < 0 && r != -ENOENT) {
6804 return r;
6805 } else if (r >= 0) {
6806 return -EEXIST;
6807 }
6808 }
6809
6810 bufferlist obl;
6811 encode(group_snap, obl);
6812 r = cls_cxx_map_set_val(hctx, key, &obl);
6813 return r;
6814 }
6815
6816 /**
6817 * Remove snapshot record.
6818 *
6819 * Input:
6820 * @param id Snapshot id
6821 *
6822 * Output:
6823 * @return 0 on success, negative error code on failure
6824 */
6825 int group_snap_remove(cls_method_context_t hctx,
6826 bufferlist *in, bufferlist *out)
6827 {
6828 CLS_LOG(20, "group_snap_remove");
6829 std::string snap_id;
6830 try {
6831 auto iter = in->cbegin();
6832 decode(snap_id, iter);
6833 } catch (const buffer::error &err) {
6834 return -EINVAL;
6835 }
6836
6837 std::string snap_key = group::snap_key(snap_id);
6838
6839 CLS_LOG(20, "removing snapshot with key %s", snap_key.c_str());
6840 int r = cls_cxx_map_remove_key(hctx, snap_key);
6841 return r;
6842 }
6843
6844 /**
6845 * Get group's snapshot by id.
6846 *
6847 * Input:
6848 * @param snapshot_id the id of the snapshot to look for.
6849 *
6850 * Output:
6851 * @param GroupSnapshot the requested snapshot
6852 * @return 0 on success, negative error code on failure
6853 */
6854 int group_snap_get_by_id(cls_method_context_t hctx,
6855 bufferlist *in, bufferlist *out)
6856 {
6857 CLS_LOG(20, "group_snap_get_by_id");
6858
6859 std::string snap_id;
6860 try {
6861 auto iter = in->cbegin();
6862 decode(snap_id, iter);
6863 } catch (const buffer::error &err) {
6864 return -EINVAL;
6865 }
6866
6867 bufferlist snapbl;
6868
6869 int r = cls_cxx_map_get_val(hctx, group::snap_key(snap_id), &snapbl);
6870 if (r < 0) {
6871 return r;
6872 }
6873
6874 cls::rbd::GroupSnapshot group_snap;
6875 auto iter = snapbl.cbegin();
6876 try {
6877 decode(group_snap, iter);
6878 } catch (const buffer::error &err) {
6879 CLS_ERR("error decoding snapshot: %s", snap_id.c_str());
6880 return -EIO;
6881 }
6882
6883 encode(group_snap, *out);
6884
6885 return 0;
6886 }
6887
6888 /**
6889 * List group's snapshots.
6890 *
6891 * Input:
6892 * @param start_after which name to begin listing after
6893 * (use the empty string to start at the beginning)
6894 * @param max_return the maximum number of snapshots to list
6895 *
6896 * Output:
6897 * @param list of snapshots
6898 * @return 0 on success, negative error code on failure
6899 */
6900 int group_snap_list(cls_method_context_t hctx,
6901 bufferlist *in, bufferlist *out)
6902 {
6903 CLS_LOG(20, "group_snap_list");
6904
6905 cls::rbd::GroupSnapshot start_after;
6906 uint64_t max_return;
6907 try {
6908 auto iter = in->cbegin();
6909 decode(start_after, iter);
6910 decode(max_return, iter);
6911 } catch (const buffer::error &err) {
6912 return -EINVAL;
6913 }
6914 std::vector<cls::rbd::GroupSnapshot> group_snaps;
6915 group::snap_list(hctx, start_after, max_return, &group_snaps);
6916
6917 encode(group_snaps, *out);
6918
6919 return 0;
6920 }
6921
6922 namespace trash {
6923
6924 static const std::string IMAGE_KEY_PREFIX("id_");
6925
6926 std::string image_key(const std::string &image_id) {
6927 return IMAGE_KEY_PREFIX + image_id;
6928 }
6929
6930 std::string image_id_from_key(const std::string &key) {
6931 return key.substr(IMAGE_KEY_PREFIX.size());
6932 }
6933
6934 } // namespace trash
6935
6936 /**
6937 * Add an image entry to the rbd trash. Creates the trash object if
6938 * needed, and stores the trash spec information of the deleted image.
6939 *
6940 * Input:
6941 * @param id the id of the image
6942 * @param trash_spec the spec info of the deleted image
6943 *
6944 * Output:
6945 * @returns -EEXIST if the image id is already in the trash
6946 * @returns 0 on success, negative error code on failure
6947 */
6948 int trash_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
6949 {
6950 int r = cls_cxx_create(hctx, false);
6951 if (r < 0) {
6952 CLS_ERR("could not create trash: %s", cpp_strerror(r).c_str());
6953 return r;
6954 }
6955
6956 string id;
6957 cls::rbd::TrashImageSpec trash_spec;
6958 try {
6959 auto iter = in->cbegin();
6960 decode(id, iter);
6961 decode(trash_spec, iter);
6962 } catch (const buffer::error &err) {
6963 return -EINVAL;
6964 }
6965
6966 if (!is_valid_id(id)) {
6967 CLS_ERR("trash_add: invalid id '%s'", id.c_str());
6968 return -EINVAL;
6969 }
6970
6971 CLS_LOG(20, "trash_add id=%s", id.c_str());
6972
6973 string key = trash::image_key(id);
6974 cls::rbd::TrashImageSpec tmp;
6975 r = read_key(hctx, key, &tmp);
6976 if (r < 0 && r != -ENOENT) {
6977 CLS_ERR("could not read key %s entry from trash: %s", key.c_str(),
6978 cpp_strerror(r).c_str());
6979 return r;
6980 } else if (r == 0) {
6981 CLS_LOG(10, "id already exists");
6982 return -EEXIST;
6983 }
6984
6985 map<string, bufferlist> omap_vals;
6986 encode(trash_spec, omap_vals[key]);
6987 return cls_cxx_map_set_vals(hctx, &omap_vals);
6988 }
6989
6990 /**
6991 * Removes an image entry from the rbd trash object.
6992 * image.
6993 *
6994 * Input:
6995 * @param id the id of the image
6996 *
6997 * Output:
6998 * @returns -ENOENT if the image id does not exist in the trash
6999 * @returns 0 on success, negative error code on failure
7000 */
7001 int trash_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
7002 {
7003 string id;
7004 try {
7005 auto iter = in->cbegin();
7006 decode(id, iter);
7007 } catch (const buffer::error &err) {
7008 return -EINVAL;
7009 }
7010
7011 CLS_LOG(20, "trash_remove id=%s", id.c_str());
7012
7013 string key = trash::image_key(id);
7014 bufferlist tmp;
7015 int r = cls_cxx_map_get_val(hctx, key, &tmp);
7016 if (r < 0) {
7017 if (r != -ENOENT) {
7018 CLS_ERR("error reading entry key %s: %s", key.c_str(), cpp_strerror(r).c_str());
7019 }
7020 return r;
7021 }
7022
7023 r = cls_cxx_map_remove_key(hctx, key);
7024 if (r < 0) {
7025 CLS_ERR("error removing entry: %s", cpp_strerror(r).c_str());
7026 return r;
7027 }
7028
7029 return 0;
7030 }
7031
7032 /**
7033 * Returns the list of trash spec entries registered in the rbd_trash
7034 * object.
7035 *
7036 * Input:
7037 * @param start_after which name to begin listing after
7038 * (use the empty string to start at the beginning)
7039 * @param max_return the maximum number of names to list
7040 *
7041 * Output:
7042 * @param data the map between image id and trash spec info
7043 *
7044 * @returns 0 on success, negative error code on failure
7045 */
7046 int trash_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
7047 {
7048 string start_after;
7049 uint64_t max_return;
7050
7051 try {
7052 auto iter = in->cbegin();
7053 decode(start_after, iter);
7054 decode(max_return, iter);
7055 } catch (const buffer::error &err) {
7056 return -EINVAL;
7057 }
7058
7059 map<string, cls::rbd::TrashImageSpec> data;
7060 string last_read = trash::image_key(start_after);
7061 bool more = true;
7062
7063 CLS_LOG(20, "trash_get_images");
7064 while (data.size() < max_return) {
7065 map<string, bufferlist> raw_data;
7066 int max_read = std::min<int32_t>(RBD_MAX_KEYS_READ,
7067 max_return - data.size());
7068 int r = cls_cxx_map_get_vals(hctx, last_read, trash::IMAGE_KEY_PREFIX,
7069 max_read, &raw_data, &more);
7070 if (r < 0) {
7071 if (r != -ENOENT) {
7072 CLS_ERR("failed to read the vals off of disk: %s",
7073 cpp_strerror(r).c_str());
7074 }
7075 return r;
7076 }
7077 if (raw_data.empty()) {
7078 break;
7079 }
7080
7081 map<string, bufferlist>::iterator it = raw_data.begin();
7082 for (; it != raw_data.end(); ++it) {
7083 decode(data[trash::image_id_from_key(it->first)], it->second);
7084 }
7085
7086 if (!more) {
7087 break;
7088 }
7089
7090 last_read = raw_data.rbegin()->first;
7091 }
7092
7093 encode(data, *out);
7094 return 0;
7095 }
7096
7097 /**
7098 * Returns the trash spec entry of an image registered in the rbd_trash
7099 * object.
7100 *
7101 * Input:
7102 * @param id the id of the image
7103 *
7104 * Output:
7105 * @param out the trash spec entry
7106 *
7107 * @returns 0 on success, negative error code on failure
7108 */
7109 int trash_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
7110 {
7111 string id;
7112 try {
7113 auto iter = in->cbegin();
7114 decode(id, iter);
7115 } catch (const buffer::error &err) {
7116 return -EINVAL;
7117 }
7118
7119 CLS_LOG(20, "trash_get_image id=%s", id.c_str());
7120
7121
7122 string key = trash::image_key(id);
7123 bufferlist bl;
7124 int r = cls_cxx_map_get_val(hctx, key, out);
7125 if (r < 0 && r != -ENOENT) {
7126 CLS_ERR("error reading image from trash '%s': '%s'", id.c_str(),
7127 cpp_strerror(r).c_str());
7128 }
7129 return r;
7130 }
7131
7132 /**
7133 * Set state of an image in the rbd_trash object.
7134 *
7135 * Input:
7136 * @param id the id of the image
7137 * @param trash_state the state of the image to be set
7138 * @param expect_state the expected state of the image
7139 *
7140 * Output:
7141 * @returns 0 on success, negative error code on failure
7142 */
7143 int trash_state_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
7144 {
7145 string id;
7146 cls::rbd::TrashImageState trash_state;
7147 cls::rbd::TrashImageState expect_state;
7148 try {
7149 bufferlist::const_iterator iter = in->begin();
7150 decode(id, iter);
7151 decode(trash_state, iter);
7152 decode(expect_state, iter);
7153 } catch (const buffer::error &err) {
7154 return -EINVAL;
7155 }
7156
7157 CLS_LOG(20, "trash_state_set id=%s", id.c_str());
7158
7159 string key = trash::image_key(id);
7160 cls::rbd::TrashImageSpec trash_spec;
7161 int r = read_key(hctx, key, &trash_spec);
7162 if (r < 0) {
7163 if (r != -ENOENT) {
7164 CLS_ERR("Could not read trash image spec off disk: %s",
7165 cpp_strerror(r).c_str());
7166 }
7167 return r;
7168 }
7169
7170 if (trash_spec.state == expect_state) {
7171 trash_spec.state = trash_state;
7172 r = write_key(hctx, key, trash_spec);
7173 if (r < 0) {
7174 CLS_ERR("error setting trash image state: %s", cpp_strerror(r).c_str());
7175 return r;
7176 }
7177
7178 return 0;
7179 } else if (trash_spec.state == trash_state) {
7180 return 0;
7181 } else {
7182 CLS_ERR("Current trash state: %d do not match expected: %d or set: %d",
7183 trash_spec.state, expect_state, trash_state);
7184 return -ESTALE;
7185 }
7186 }
7187
7188 namespace nspace {
7189
7190 const std::string NAME_KEY_PREFIX("name_");
7191
7192 std::string key_for_name(const std::string& name) {
7193 return NAME_KEY_PREFIX + name;
7194 }
7195
7196 std::string name_from_key(const std::string &key) {
7197 return key.substr(NAME_KEY_PREFIX.size());
7198 }
7199
7200 } // namespace nspace
7201
7202 /**
7203 * Add a namespace to the namespace directory.
7204 *
7205 * Input:
7206 * @param name the name of the namespace
7207 *
7208 * Output:
7209 * @returns -EEXIST if the namespace is already exists
7210 * @returns 0 on success, negative error code on failure
7211 */
7212 int namespace_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
7213 {
7214 std::string name;
7215 try {
7216 auto iter = in->cbegin();
7217 decode(name, iter);
7218 } catch (const buffer::error &err) {
7219 return -EINVAL;
7220 }
7221
7222 std::string key(nspace::key_for_name(name));
7223 bufferlist value;
7224 int r = cls_cxx_map_get_val(hctx, key, &value);
7225 if (r < 0 && r != -ENOENT) {
7226 return r;
7227 } else if (r == 0) {
7228 return -EEXIST;
7229 }
7230
7231 r = cls_cxx_map_set_val(hctx, key, &value);
7232 if (r < 0) {
7233 CLS_ERR("failed to set omap key: %s", key.c_str());
7234 return r;
7235 }
7236
7237 return 0;
7238 }
7239
7240 /**
7241 * Remove a namespace from the namespace directory.
7242 *
7243 * Input:
7244 * @param name the name of the namespace
7245 *
7246 * Output:
7247 * @returns 0 on success, negative error code on failure
7248 */
7249 int namespace_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
7250 {
7251 std::string name;
7252 try {
7253 auto iter = in->cbegin();
7254 decode(name, iter);
7255 } catch (const buffer::error &err) {
7256 return -EINVAL;
7257 }
7258
7259 std::string key(nspace::key_for_name(name));
7260 bufferlist bl;
7261 int r = cls_cxx_map_get_val(hctx, key, &bl);
7262 if (r < 0) {
7263 return r;
7264 }
7265
7266 r = cls_cxx_map_remove_key(hctx, key);
7267 if (r < 0) {
7268 return r;
7269 }
7270
7271 return 0;
7272 }
7273
7274 /**
7275 * Returns the list of namespaces in the rbd_namespace object
7276 *
7277 * Input:
7278 * @param start_after which name to begin listing after
7279 * (use the empty string to start at the beginning)
7280 * @param max_return the maximum number of names to list
7281 *
7282 * Output:
7283 * @param data list of namespace names
7284 * @returns 0 on success, negative error code on failure
7285 */
7286 int namespace_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
7287 {
7288 string start_after;
7289 uint64_t max_return;
7290 try {
7291 auto iter = in->cbegin();
7292 decode(start_after, iter);
7293 decode(max_return, iter);
7294 } catch (const buffer::error &err) {
7295 return -EINVAL;
7296 }
7297
7298 std::list<std::string> data;
7299 std::string last_read = nspace::key_for_name(start_after);
7300 bool more = true;
7301
7302 CLS_LOG(20, "namespace_list");
7303 while (data.size() < max_return) {
7304 std::map<std::string, bufferlist> raw_data;
7305 int max_read = std::min<int32_t>(RBD_MAX_KEYS_READ,
7306 max_return - data.size());
7307 int r = cls_cxx_map_get_vals(hctx, last_read, nspace::NAME_KEY_PREFIX,
7308 max_read, &raw_data, &more);
7309 if (r < 0) {
7310 if (r != -ENOENT) {
7311 CLS_ERR("failed to read the vals off of disk: %s",
7312 cpp_strerror(r).c_str());
7313 }
7314 return r;
7315 }
7316
7317 for (auto& it : raw_data) {
7318 data.push_back(nspace::name_from_key(it.first));
7319 }
7320
7321 if (raw_data.empty() || !more) {
7322 break;
7323 }
7324
7325 last_read = raw_data.rbegin()->first;
7326 }
7327
7328 encode(data, *out);
7329 return 0;
7330 }
7331
7332 /**
7333 * Reclaim space for zeroed extents
7334 *
7335 * Input:
7336 * @param sparse_size minimal zeroed block to sparse
7337 * @param remove_empty boolean, true if the object should be removed if empty
7338 *
7339 * Output:
7340 * @returns -ENOENT if the object does not exist or has been removed
7341 * @returns 0 on success, negative error code on failure
7342 */
7343 int sparsify(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
7344 {
7345 size_t sparse_size;
7346 bool remove_empty;
7347 try {
7348 auto iter = in->cbegin();
7349 decode(sparse_size, iter);
7350 decode(remove_empty, iter);
7351 } catch (const buffer::error &err) {
7352 return -EINVAL;
7353 }
7354
7355 int r = check_exists(hctx);
7356 if (r < 0) {
7357 return r;
7358 }
7359
7360 bufferlist bl;
7361 r = cls_cxx_read(hctx, 0, 0, &bl);
7362 if (r < 0) {
7363 CLS_ERR("failed to read data off of disk: %s", cpp_strerror(r).c_str());
7364 return r;
7365 }
7366
7367 if (bl.is_zero()) {
7368 if (remove_empty) {
7369 CLS_LOG(20, "remove");
7370 r = cls_cxx_remove(hctx);
7371 if (r < 0) {
7372 CLS_ERR("remove failed: %s", cpp_strerror(r).c_str());
7373 return r;
7374 }
7375 } else if (bl.length() > 0) {
7376 CLS_LOG(20, "truncate");
7377 bufferlist write_bl;
7378 r = cls_cxx_replace(hctx, 0, 0, &write_bl);
7379 if (r < 0) {
7380 CLS_ERR("truncate failed: %s", cpp_strerror(r).c_str());
7381 return r;
7382 }
7383 } else {
7384 CLS_LOG(20, "skip empty");
7385 }
7386 return 0;
7387 }
7388
7389 bl.rebuild(buffer::ptr_node::create(bl.length()));
7390 size_t write_offset = 0;
7391 size_t write_length = 0;
7392 size_t offset = 0;
7393 size_t length = bl.length();
7394 const auto& ptr = bl.front();
7395 bool replace = true;
7396 while (offset < length) {
7397 if (calc_sparse_extent(ptr, sparse_size, length, &write_offset,
7398 &write_length, &offset)) {
7399 if (write_offset == 0 && write_length == length) {
7400 CLS_LOG(20, "nothing to do");
7401 return 0;
7402 }
7403 CLS_LOG(20, "write%s %" PRIu64 "~%" PRIu64, (replace ? "(replace)" : ""),
7404 write_offset, write_length);
7405 bufferlist write_bl;
7406 write_bl.push_back(buffer::ptr_node::create(ptr, write_offset,
7407 write_length));
7408 if (replace) {
7409 r = cls_cxx_replace(hctx, write_offset, write_length, &write_bl);
7410 replace = false;
7411 } else {
7412 r = cls_cxx_write(hctx, write_offset, write_length, &write_bl);
7413 }
7414 if (r < 0) {
7415 CLS_ERR("write failed: %s", cpp_strerror(r).c_str());
7416 return r;
7417 }
7418 write_offset = offset;
7419 write_length = 0;
7420 }
7421 }
7422
7423 return 0;
7424 }
7425
7426 CLS_INIT(rbd)
7427 {
7428 CLS_LOG(20, "Loaded rbd class!");
7429
7430 cls_handle_t h_class;
7431 cls_method_handle_t h_create;
7432 cls_method_handle_t h_get_features;
7433 cls_method_handle_t h_set_features;
7434 cls_method_handle_t h_get_size;
7435 cls_method_handle_t h_set_size;
7436 cls_method_handle_t h_get_parent;
7437 cls_method_handle_t h_set_parent;
7438 cls_method_handle_t h_remove_parent;
7439 cls_method_handle_t h_parent_get;
7440 cls_method_handle_t h_parent_overlap_get;
7441 cls_method_handle_t h_parent_attach;
7442 cls_method_handle_t h_parent_detach;
7443 cls_method_handle_t h_get_protection_status;
7444 cls_method_handle_t h_set_protection_status;
7445 cls_method_handle_t h_get_stripe_unit_count;
7446 cls_method_handle_t h_set_stripe_unit_count;
7447 cls_method_handle_t h_get_create_timestamp;
7448 cls_method_handle_t h_get_access_timestamp;
7449 cls_method_handle_t h_get_modify_timestamp;
7450 cls_method_handle_t h_get_flags;
7451 cls_method_handle_t h_set_flags;
7452 cls_method_handle_t h_op_features_get;
7453 cls_method_handle_t h_op_features_set;
7454 cls_method_handle_t h_add_child;
7455 cls_method_handle_t h_remove_child;
7456 cls_method_handle_t h_get_children;
7457 cls_method_handle_t h_get_snapcontext;
7458 cls_method_handle_t h_get_object_prefix;
7459 cls_method_handle_t h_get_data_pool;
7460 cls_method_handle_t h_get_snapshot_name;
7461 cls_method_handle_t h_get_snapshot_timestamp;
7462 cls_method_handle_t h_snapshot_get;
7463 cls_method_handle_t h_snapshot_add;
7464 cls_method_handle_t h_snapshot_remove;
7465 cls_method_handle_t h_snapshot_rename;
7466 cls_method_handle_t h_snapshot_trash_add;
7467 cls_method_handle_t h_get_all_features;
7468 cls_method_handle_t h_get_id;
7469 cls_method_handle_t h_set_id;
7470 cls_method_handle_t h_set_modify_timestamp;
7471 cls_method_handle_t h_set_access_timestamp;
7472 cls_method_handle_t h_dir_get_id;
7473 cls_method_handle_t h_dir_get_name;
7474 cls_method_handle_t h_dir_list;
7475 cls_method_handle_t h_dir_add_image;
7476 cls_method_handle_t h_dir_remove_image;
7477 cls_method_handle_t h_dir_rename_image;
7478 cls_method_handle_t h_dir_state_assert;
7479 cls_method_handle_t h_dir_state_set;
7480 cls_method_handle_t h_object_map_load;
7481 cls_method_handle_t h_object_map_save;
7482 cls_method_handle_t h_object_map_resize;
7483 cls_method_handle_t h_object_map_update;
7484 cls_method_handle_t h_object_map_snap_add;
7485 cls_method_handle_t h_object_map_snap_remove;
7486 cls_method_handle_t h_metadata_set;
7487 cls_method_handle_t h_metadata_remove;
7488 cls_method_handle_t h_metadata_list;
7489 cls_method_handle_t h_metadata_get;
7490 cls_method_handle_t h_snapshot_get_limit;
7491 cls_method_handle_t h_snapshot_set_limit;
7492 cls_method_handle_t h_child_attach;
7493 cls_method_handle_t h_child_detach;
7494 cls_method_handle_t h_children_list;
7495 cls_method_handle_t h_migration_set;
7496 cls_method_handle_t h_migration_set_state;
7497 cls_method_handle_t h_migration_get;
7498 cls_method_handle_t h_migration_remove;
7499 cls_method_handle_t h_old_snapshots_list;
7500 cls_method_handle_t h_old_snapshot_add;
7501 cls_method_handle_t h_old_snapshot_remove;
7502 cls_method_handle_t h_old_snapshot_rename;
7503 cls_method_handle_t h_mirror_uuid_get;
7504 cls_method_handle_t h_mirror_uuid_set;
7505 cls_method_handle_t h_mirror_mode_get;
7506 cls_method_handle_t h_mirror_mode_set;
7507 cls_method_handle_t h_mirror_peer_list;
7508 cls_method_handle_t h_mirror_peer_add;
7509 cls_method_handle_t h_mirror_peer_remove;
7510 cls_method_handle_t h_mirror_peer_set_client;
7511 cls_method_handle_t h_mirror_peer_set_cluster;
7512 cls_method_handle_t h_mirror_image_list;
7513 cls_method_handle_t h_mirror_image_get_image_id;
7514 cls_method_handle_t h_mirror_image_get;
7515 cls_method_handle_t h_mirror_image_set;
7516 cls_method_handle_t h_mirror_image_remove;
7517 cls_method_handle_t h_mirror_image_status_set;
7518 cls_method_handle_t h_mirror_image_status_remove;
7519 cls_method_handle_t h_mirror_image_status_get;
7520 cls_method_handle_t h_mirror_image_status_list;
7521 cls_method_handle_t h_mirror_image_status_get_summary;
7522 cls_method_handle_t h_mirror_image_status_remove_down;
7523 cls_method_handle_t h_mirror_image_instance_get;
7524 cls_method_handle_t h_mirror_image_instance_list;
7525 cls_method_handle_t h_mirror_instances_list;
7526 cls_method_handle_t h_mirror_instances_add;
7527 cls_method_handle_t h_mirror_instances_remove;
7528 cls_method_handle_t h_mirror_image_map_list;
7529 cls_method_handle_t h_mirror_image_map_update;
7530 cls_method_handle_t h_mirror_image_map_remove;
7531 cls_method_handle_t h_group_dir_list;
7532 cls_method_handle_t h_group_dir_add;
7533 cls_method_handle_t h_group_dir_remove;
7534 cls_method_handle_t h_group_dir_rename;
7535 cls_method_handle_t h_group_image_remove;
7536 cls_method_handle_t h_group_image_list;
7537 cls_method_handle_t h_group_image_set;
7538 cls_method_handle_t h_image_group_add;
7539 cls_method_handle_t h_image_group_remove;
7540 cls_method_handle_t h_image_group_get;
7541 cls_method_handle_t h_group_snap_set;
7542 cls_method_handle_t h_group_snap_remove;
7543 cls_method_handle_t h_group_snap_get_by_id;
7544 cls_method_handle_t h_group_snap_list;
7545 cls_method_handle_t h_trash_add;
7546 cls_method_handle_t h_trash_remove;
7547 cls_method_handle_t h_trash_list;
7548 cls_method_handle_t h_trash_get;
7549 cls_method_handle_t h_trash_state_set;
7550 cls_method_handle_t h_namespace_add;
7551 cls_method_handle_t h_namespace_remove;
7552 cls_method_handle_t h_namespace_list;
7553 cls_method_handle_t h_copyup;
7554 cls_method_handle_t h_assert_snapc_seq;
7555 cls_method_handle_t h_sparsify;
7556
7557 cls_register("rbd", &h_class);
7558 cls_register_cxx_method(h_class, "create",
7559 CLS_METHOD_RD | CLS_METHOD_WR,
7560 create, &h_create);
7561 cls_register_cxx_method(h_class, "get_features",
7562 CLS_METHOD_RD,
7563 get_features, &h_get_features);
7564 cls_register_cxx_method(h_class, "set_features",
7565 CLS_METHOD_RD | CLS_METHOD_WR,
7566 set_features, &h_set_features);
7567 cls_register_cxx_method(h_class, "get_size",
7568 CLS_METHOD_RD,
7569 get_size, &h_get_size);
7570 cls_register_cxx_method(h_class, "set_size",
7571 CLS_METHOD_RD | CLS_METHOD_WR,
7572 set_size, &h_set_size);
7573 cls_register_cxx_method(h_class, "get_snapcontext",
7574 CLS_METHOD_RD,
7575 get_snapcontext, &h_get_snapcontext);
7576 cls_register_cxx_method(h_class, "get_object_prefix",
7577 CLS_METHOD_RD,
7578 get_object_prefix, &h_get_object_prefix);
7579 cls_register_cxx_method(h_class, "get_data_pool", CLS_METHOD_RD,
7580 get_data_pool, &h_get_data_pool);
7581 cls_register_cxx_method(h_class, "get_snapshot_name",
7582 CLS_METHOD_RD,
7583 get_snapshot_name, &h_get_snapshot_name);
7584 cls_register_cxx_method(h_class, "get_snapshot_timestamp",
7585 CLS_METHOD_RD,
7586 get_snapshot_timestamp, &h_get_snapshot_timestamp);
7587 cls_register_cxx_method(h_class, "snapshot_get",
7588 CLS_METHOD_RD,
7589 snapshot_get, &h_snapshot_get);
7590 cls_register_cxx_method(h_class, "snapshot_add",
7591 CLS_METHOD_RD | CLS_METHOD_WR,
7592 snapshot_add, &h_snapshot_add);
7593 cls_register_cxx_method(h_class, "snapshot_remove",
7594 CLS_METHOD_RD | CLS_METHOD_WR,
7595 snapshot_remove, &h_snapshot_remove);
7596 cls_register_cxx_method(h_class, "snapshot_rename",
7597 CLS_METHOD_RD | CLS_METHOD_WR,
7598 snapshot_rename, &h_snapshot_rename);
7599 cls_register_cxx_method(h_class, "snapshot_trash_add",
7600 CLS_METHOD_RD | CLS_METHOD_WR,
7601 snapshot_trash_add, &h_snapshot_trash_add);
7602 cls_register_cxx_method(h_class, "get_all_features",
7603 CLS_METHOD_RD,
7604 get_all_features, &h_get_all_features);
7605
7606 // NOTE: deprecate v1 parent APIs after mimic EOLed
7607 cls_register_cxx_method(h_class, "get_parent",
7608 CLS_METHOD_RD,
7609 get_parent, &h_get_parent);
7610 cls_register_cxx_method(h_class, "set_parent",
7611 CLS_METHOD_RD | CLS_METHOD_WR,
7612 set_parent, &h_set_parent);
7613 cls_register_cxx_method(h_class, "remove_parent",
7614 CLS_METHOD_RD | CLS_METHOD_WR,
7615 remove_parent, &h_remove_parent);
7616
7617 cls_register_cxx_method(h_class, "parent_get",
7618 CLS_METHOD_RD, parent_get, &h_parent_get);
7619 cls_register_cxx_method(h_class, "parent_overlap_get",
7620 CLS_METHOD_RD, parent_overlap_get,
7621 &h_parent_overlap_get);
7622 cls_register_cxx_method(h_class, "parent_attach",
7623 CLS_METHOD_RD | CLS_METHOD_WR,
7624 parent_attach, &h_parent_attach);
7625 cls_register_cxx_method(h_class, "parent_detach",
7626 CLS_METHOD_RD | CLS_METHOD_WR,
7627 parent_detach, &h_parent_detach);
7628
7629 cls_register_cxx_method(h_class, "set_protection_status",
7630 CLS_METHOD_RD | CLS_METHOD_WR,
7631 set_protection_status, &h_set_protection_status);
7632 cls_register_cxx_method(h_class, "get_protection_status",
7633 CLS_METHOD_RD,
7634 get_protection_status, &h_get_protection_status);
7635 cls_register_cxx_method(h_class, "get_stripe_unit_count",
7636 CLS_METHOD_RD,
7637 get_stripe_unit_count, &h_get_stripe_unit_count);
7638 cls_register_cxx_method(h_class, "set_stripe_unit_count",
7639 CLS_METHOD_RD | CLS_METHOD_WR,
7640 set_stripe_unit_count, &h_set_stripe_unit_count);
7641 cls_register_cxx_method(h_class, "get_create_timestamp",
7642 CLS_METHOD_RD,
7643 get_create_timestamp, &h_get_create_timestamp);
7644 cls_register_cxx_method(h_class, "get_access_timestamp",
7645 CLS_METHOD_RD,
7646 get_access_timestamp, &h_get_access_timestamp);
7647 cls_register_cxx_method(h_class, "get_modify_timestamp",
7648 CLS_METHOD_RD,
7649 get_modify_timestamp, &h_get_modify_timestamp);
7650 cls_register_cxx_method(h_class, "get_flags",
7651 CLS_METHOD_RD,
7652 get_flags, &h_get_flags);
7653 cls_register_cxx_method(h_class, "set_flags",
7654 CLS_METHOD_RD | CLS_METHOD_WR,
7655 set_flags, &h_set_flags);
7656 cls_register_cxx_method(h_class, "op_features_get", CLS_METHOD_RD,
7657 op_features_get, &h_op_features_get);
7658 cls_register_cxx_method(h_class, "op_features_set",
7659 CLS_METHOD_RD | CLS_METHOD_WR,
7660 op_features_set, &h_op_features_set);
7661 cls_register_cxx_method(h_class, "metadata_list",
7662 CLS_METHOD_RD,
7663 metadata_list, &h_metadata_list);
7664 cls_register_cxx_method(h_class, "metadata_set",
7665 CLS_METHOD_RD | CLS_METHOD_WR,
7666 metadata_set, &h_metadata_set);
7667 cls_register_cxx_method(h_class, "metadata_remove",
7668 CLS_METHOD_RD | CLS_METHOD_WR,
7669 metadata_remove, &h_metadata_remove);
7670 cls_register_cxx_method(h_class, "metadata_get",
7671 CLS_METHOD_RD,
7672 metadata_get, &h_metadata_get);
7673 cls_register_cxx_method(h_class, "snapshot_get_limit",
7674 CLS_METHOD_RD,
7675 snapshot_get_limit, &h_snapshot_get_limit);
7676 cls_register_cxx_method(h_class, "snapshot_set_limit",
7677 CLS_METHOD_RD | CLS_METHOD_WR,
7678 snapshot_set_limit, &h_snapshot_set_limit);
7679 cls_register_cxx_method(h_class, "child_attach",
7680 CLS_METHOD_RD | CLS_METHOD_WR,
7681 child_attach, &h_child_attach);
7682 cls_register_cxx_method(h_class, "child_detach",
7683 CLS_METHOD_RD | CLS_METHOD_WR,
7684 child_detach, &h_child_detach);
7685 cls_register_cxx_method(h_class, "children_list",
7686 CLS_METHOD_RD,
7687 children_list, &h_children_list);
7688 cls_register_cxx_method(h_class, "migration_set",
7689 CLS_METHOD_RD | CLS_METHOD_WR,
7690 migration_set, &h_migration_set);
7691 cls_register_cxx_method(h_class, "migration_set_state",
7692 CLS_METHOD_RD | CLS_METHOD_WR,
7693 migration_set_state, &h_migration_set_state);
7694 cls_register_cxx_method(h_class, "migration_get",
7695 CLS_METHOD_RD,
7696 migration_get, &h_migration_get);
7697 cls_register_cxx_method(h_class, "migration_remove",
7698 CLS_METHOD_RD | CLS_METHOD_WR,
7699 migration_remove, &h_migration_remove);
7700
7701 cls_register_cxx_method(h_class, "set_modify_timestamp",
7702 CLS_METHOD_RD | CLS_METHOD_WR,
7703 set_modify_timestamp, &h_set_modify_timestamp);
7704
7705 cls_register_cxx_method(h_class, "set_access_timestamp",
7706 CLS_METHOD_RD | CLS_METHOD_WR,
7707 set_access_timestamp, &h_set_access_timestamp);
7708
7709 /* methods for the rbd_children object */
7710 cls_register_cxx_method(h_class, "add_child",
7711 CLS_METHOD_RD | CLS_METHOD_WR,
7712 add_child, &h_add_child);
7713 cls_register_cxx_method(h_class, "remove_child",
7714 CLS_METHOD_RD | CLS_METHOD_WR,
7715 remove_child, &h_remove_child);
7716 cls_register_cxx_method(h_class, "get_children",
7717 CLS_METHOD_RD,
7718 get_children, &h_get_children);
7719
7720 /* methods for the rbd_id.$image_name objects */
7721 cls_register_cxx_method(h_class, "get_id",
7722 CLS_METHOD_RD,
7723 get_id, &h_get_id);
7724 cls_register_cxx_method(h_class, "set_id",
7725 CLS_METHOD_RD | CLS_METHOD_WR,
7726 set_id, &h_set_id);
7727
7728 /* methods for the rbd_directory object */
7729 cls_register_cxx_method(h_class, "dir_get_id",
7730 CLS_METHOD_RD,
7731 dir_get_id, &h_dir_get_id);
7732 cls_register_cxx_method(h_class, "dir_get_name",
7733 CLS_METHOD_RD,
7734 dir_get_name, &h_dir_get_name);
7735 cls_register_cxx_method(h_class, "dir_list",
7736 CLS_METHOD_RD,
7737 dir_list, &h_dir_list);
7738 cls_register_cxx_method(h_class, "dir_add_image",
7739 CLS_METHOD_RD | CLS_METHOD_WR,
7740 dir_add_image, &h_dir_add_image);
7741 cls_register_cxx_method(h_class, "dir_remove_image",
7742 CLS_METHOD_RD | CLS_METHOD_WR,
7743 dir_remove_image, &h_dir_remove_image);
7744 cls_register_cxx_method(h_class, "dir_rename_image",
7745 CLS_METHOD_RD | CLS_METHOD_WR,
7746 dir_rename_image, &h_dir_rename_image);
7747 cls_register_cxx_method(h_class, "dir_state_assert", CLS_METHOD_RD,
7748 dir_state_assert, &h_dir_state_assert);
7749 cls_register_cxx_method(h_class, "dir_state_set",
7750 CLS_METHOD_RD | CLS_METHOD_WR,
7751 dir_state_set, &h_dir_state_set);
7752
7753 /* methods for the rbd_object_map.$image_id object */
7754 cls_register_cxx_method(h_class, "object_map_load",
7755 CLS_METHOD_RD,
7756 object_map_load, &h_object_map_load);
7757 cls_register_cxx_method(h_class, "object_map_save",
7758 CLS_METHOD_RD | CLS_METHOD_WR,
7759 object_map_save, &h_object_map_save);
7760 cls_register_cxx_method(h_class, "object_map_resize",
7761 CLS_METHOD_RD | CLS_METHOD_WR,
7762 object_map_resize, &h_object_map_resize);
7763 cls_register_cxx_method(h_class, "object_map_update",
7764 CLS_METHOD_RD | CLS_METHOD_WR,
7765 object_map_update, &h_object_map_update);
7766 cls_register_cxx_method(h_class, "object_map_snap_add",
7767 CLS_METHOD_RD | CLS_METHOD_WR,
7768 object_map_snap_add, &h_object_map_snap_add);
7769 cls_register_cxx_method(h_class, "object_map_snap_remove",
7770 CLS_METHOD_RD | CLS_METHOD_WR,
7771 object_map_snap_remove, &h_object_map_snap_remove);
7772
7773 /* methods for the old format */
7774 cls_register_cxx_method(h_class, "snap_list",
7775 CLS_METHOD_RD,
7776 old_snapshots_list, &h_old_snapshots_list);
7777 cls_register_cxx_method(h_class, "snap_add",
7778 CLS_METHOD_RD | CLS_METHOD_WR,
7779 old_snapshot_add, &h_old_snapshot_add);
7780 cls_register_cxx_method(h_class, "snap_remove",
7781 CLS_METHOD_RD | CLS_METHOD_WR,
7782 old_snapshot_remove, &h_old_snapshot_remove);
7783 cls_register_cxx_method(h_class, "snap_rename",
7784 CLS_METHOD_RD | CLS_METHOD_WR,
7785 old_snapshot_rename, &h_old_snapshot_rename);
7786
7787 /* methods for the rbd_mirroring object */
7788 cls_register_cxx_method(h_class, "mirror_uuid_get", CLS_METHOD_RD,
7789 mirror_uuid_get, &h_mirror_uuid_get);
7790 cls_register_cxx_method(h_class, "mirror_uuid_set",
7791 CLS_METHOD_RD | CLS_METHOD_WR,
7792 mirror_uuid_set, &h_mirror_uuid_set);
7793 cls_register_cxx_method(h_class, "mirror_mode_get", CLS_METHOD_RD,
7794 mirror_mode_get, &h_mirror_mode_get);
7795 cls_register_cxx_method(h_class, "mirror_mode_set",
7796 CLS_METHOD_RD | CLS_METHOD_WR,
7797 mirror_mode_set, &h_mirror_mode_set);
7798 cls_register_cxx_method(h_class, "mirror_peer_list", CLS_METHOD_RD,
7799 mirror_peer_list, &h_mirror_peer_list);
7800 cls_register_cxx_method(h_class, "mirror_peer_add",
7801 CLS_METHOD_RD | CLS_METHOD_WR,
7802 mirror_peer_add, &h_mirror_peer_add);
7803 cls_register_cxx_method(h_class, "mirror_peer_remove",
7804 CLS_METHOD_RD | CLS_METHOD_WR,
7805 mirror_peer_remove, &h_mirror_peer_remove);
7806 cls_register_cxx_method(h_class, "mirror_peer_set_client",
7807 CLS_METHOD_RD | CLS_METHOD_WR,
7808 mirror_peer_set_client, &h_mirror_peer_set_client);
7809 cls_register_cxx_method(h_class, "mirror_peer_set_cluster",
7810 CLS_METHOD_RD | CLS_METHOD_WR,
7811 mirror_peer_set_cluster, &h_mirror_peer_set_cluster);
7812 cls_register_cxx_method(h_class, "mirror_image_list", CLS_METHOD_RD,
7813 mirror_image_list, &h_mirror_image_list);
7814 cls_register_cxx_method(h_class, "mirror_image_get_image_id", CLS_METHOD_RD,
7815 mirror_image_get_image_id,
7816 &h_mirror_image_get_image_id);
7817 cls_register_cxx_method(h_class, "mirror_image_get", CLS_METHOD_RD,
7818 mirror_image_get, &h_mirror_image_get);
7819 cls_register_cxx_method(h_class, "mirror_image_set",
7820 CLS_METHOD_RD | CLS_METHOD_WR,
7821 mirror_image_set, &h_mirror_image_set);
7822 cls_register_cxx_method(h_class, "mirror_image_remove",
7823 CLS_METHOD_RD | CLS_METHOD_WR,
7824 mirror_image_remove, &h_mirror_image_remove);
7825 cls_register_cxx_method(h_class, "mirror_image_status_set",
7826 CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE,
7827 mirror_image_status_set, &h_mirror_image_status_set);
7828 cls_register_cxx_method(h_class, "mirror_image_status_remove",
7829 CLS_METHOD_RD | CLS_METHOD_WR,
7830 mirror_image_status_remove,
7831 &h_mirror_image_status_remove);
7832 cls_register_cxx_method(h_class, "mirror_image_status_get", CLS_METHOD_RD,
7833 mirror_image_status_get, &h_mirror_image_status_get);
7834 cls_register_cxx_method(h_class, "mirror_image_status_list", CLS_METHOD_RD,
7835 mirror_image_status_list,
7836 &h_mirror_image_status_list);
7837 cls_register_cxx_method(h_class, "mirror_image_status_get_summary",
7838 CLS_METHOD_RD, mirror_image_status_get_summary,
7839 &h_mirror_image_status_get_summary);
7840 cls_register_cxx_method(h_class, "mirror_image_status_remove_down",
7841 CLS_METHOD_RD | CLS_METHOD_WR,
7842 mirror_image_status_remove_down,
7843 &h_mirror_image_status_remove_down);
7844 cls_register_cxx_method(h_class, "mirror_image_instance_get", CLS_METHOD_RD,
7845 mirror_image_instance_get,
7846 &h_mirror_image_instance_get);
7847 cls_register_cxx_method(h_class, "mirror_image_instance_list", CLS_METHOD_RD,
7848 mirror_image_instance_list,
7849 &h_mirror_image_instance_list);
7850 cls_register_cxx_method(h_class, "mirror_instances_list", CLS_METHOD_RD,
7851 mirror_instances_list, &h_mirror_instances_list);
7852 cls_register_cxx_method(h_class, "mirror_instances_add",
7853 CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE,
7854 mirror_instances_add, &h_mirror_instances_add);
7855 cls_register_cxx_method(h_class, "mirror_instances_remove",
7856 CLS_METHOD_RD | CLS_METHOD_WR,
7857 mirror_instances_remove,
7858 &h_mirror_instances_remove);
7859 cls_register_cxx_method(h_class, "mirror_image_map_list",
7860 CLS_METHOD_RD, mirror_image_map_list,
7861 &h_mirror_image_map_list);
7862 cls_register_cxx_method(h_class, "mirror_image_map_update",
7863 CLS_METHOD_WR, mirror_image_map_update,
7864 &h_mirror_image_map_update);
7865 cls_register_cxx_method(h_class, "mirror_image_map_remove",
7866 CLS_METHOD_WR, mirror_image_map_remove,
7867 &h_mirror_image_map_remove);
7868
7869 /* methods for the groups feature */
7870 cls_register_cxx_method(h_class, "group_dir_list",
7871 CLS_METHOD_RD,
7872 group_dir_list, &h_group_dir_list);
7873 cls_register_cxx_method(h_class, "group_dir_add",
7874 CLS_METHOD_RD | CLS_METHOD_WR,
7875 group_dir_add, &h_group_dir_add);
7876 cls_register_cxx_method(h_class, "group_dir_remove",
7877 CLS_METHOD_RD | CLS_METHOD_WR,
7878 group_dir_remove, &h_group_dir_remove);
7879 cls_register_cxx_method(h_class, "group_dir_rename",
7880 CLS_METHOD_RD | CLS_METHOD_WR,
7881 group_dir_rename, &h_group_dir_rename);
7882 cls_register_cxx_method(h_class, "group_image_remove",
7883 CLS_METHOD_RD | CLS_METHOD_WR,
7884 group_image_remove, &h_group_image_remove);
7885 cls_register_cxx_method(h_class, "group_image_list",
7886 CLS_METHOD_RD,
7887 group_image_list, &h_group_image_list);
7888 cls_register_cxx_method(h_class, "group_image_set",
7889 CLS_METHOD_RD | CLS_METHOD_WR,
7890 group_image_set, &h_group_image_set);
7891 cls_register_cxx_method(h_class, "image_group_add",
7892 CLS_METHOD_RD | CLS_METHOD_WR,
7893 image_group_add, &h_image_group_add);
7894 cls_register_cxx_method(h_class, "image_group_remove",
7895 CLS_METHOD_RD | CLS_METHOD_WR,
7896 image_group_remove, &h_image_group_remove);
7897 cls_register_cxx_method(h_class, "image_group_get",
7898 CLS_METHOD_RD,
7899 image_group_get, &h_image_group_get);
7900 cls_register_cxx_method(h_class, "group_snap_set",
7901 CLS_METHOD_RD | CLS_METHOD_WR,
7902 group_snap_set, &h_group_snap_set);
7903 cls_register_cxx_method(h_class, "group_snap_remove",
7904 CLS_METHOD_RD | CLS_METHOD_WR,
7905 group_snap_remove, &h_group_snap_remove);
7906 cls_register_cxx_method(h_class, "group_snap_get_by_id",
7907 CLS_METHOD_RD,
7908 group_snap_get_by_id, &h_group_snap_get_by_id);
7909 cls_register_cxx_method(h_class, "group_snap_list",
7910 CLS_METHOD_RD,
7911 group_snap_list, &h_group_snap_list);
7912
7913 /* rbd_trash object methods */
7914 cls_register_cxx_method(h_class, "trash_add",
7915 CLS_METHOD_RD | CLS_METHOD_WR,
7916 trash_add, &h_trash_add);
7917 cls_register_cxx_method(h_class, "trash_remove",
7918 CLS_METHOD_RD | CLS_METHOD_WR,
7919 trash_remove, &h_trash_remove);
7920 cls_register_cxx_method(h_class, "trash_list",
7921 CLS_METHOD_RD,
7922 trash_list, &h_trash_list);
7923 cls_register_cxx_method(h_class, "trash_get",
7924 CLS_METHOD_RD,
7925 trash_get, &h_trash_get);
7926 cls_register_cxx_method(h_class, "trash_state_set",
7927 CLS_METHOD_RD | CLS_METHOD_WR,
7928 trash_state_set, &h_trash_state_set);
7929
7930 /* rbd_namespace object methods */
7931 cls_register_cxx_method(h_class, "namespace_add",
7932 CLS_METHOD_RD | CLS_METHOD_WR,
7933 namespace_add, &h_namespace_add);
7934 cls_register_cxx_method(h_class, "namespace_remove",
7935 CLS_METHOD_RD | CLS_METHOD_WR,
7936 namespace_remove, &h_namespace_remove);
7937 cls_register_cxx_method(h_class, "namespace_list", CLS_METHOD_RD,
7938 namespace_list, &h_namespace_list);
7939
7940 /* data object methods */
7941 cls_register_cxx_method(h_class, "copyup",
7942 CLS_METHOD_RD | CLS_METHOD_WR,
7943 copyup, &h_copyup);
7944 cls_register_cxx_method(h_class, "assert_snapc_seq",
7945 CLS_METHOD_RD | CLS_METHOD_WR,
7946 assert_snapc_seq,
7947 &h_assert_snapc_seq);
7948 cls_register_cxx_method(h_class, "sparsify",
7949 CLS_METHOD_RD | CLS_METHOD_WR,
7950 sparsify, &h_sparsify);
7951 }