]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: new mirroring snapshot namespace
authorMykola Golub <mgolub@suse.com>
Mon, 2 Sep 2019 07:48:30 +0000 (08:48 +0100)
committerMykola Golub <mgolub@suse.com>
Fri, 6 Dec 2019 11:57:43 +0000 (11:57 +0000)
Signed-off-by: Mykola Golub <mgolub@suse.com>
src/cls/rbd/cls_rbd_types.cc
src/cls/rbd/cls_rbd_types.h
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/api/Snapshot.cc
src/librbd/api/Snapshot.h
src/librbd/librbd.cc
src/pybind/rbd/rbd.pyx
src/tools/rbd/action/Snap.cc

index 6a8c1c476a500bc6b44305656a44adbe55eddbd5..cfdde40dd7287c84e130d2387df0cec3081c956b 100644 (file)
@@ -684,6 +684,50 @@ void TrashSnapshotNamespace::dump(Formatter *f) const {
     << original_snapshot_namespace_type;
 }
 
+void MirrorPrimarySnapshotNamespace::encode(bufferlist& bl) const {
+  using ceph::encode;
+  encode(demoted, bl);
+  encode(mirror_peers, bl);
+}
+
+void MirrorPrimarySnapshotNamespace::decode(bufferlist::const_iterator& it) {
+  using ceph::decode;
+  decode(demoted, it);
+  decode(mirror_peers, it);
+}
+
+void MirrorPrimarySnapshotNamespace::dump(Formatter *f) const {
+  f->dump_bool("demoted", demoted);
+  f->open_array_section("mirror_peers");
+  for (auto &peer : mirror_peers) {
+    f->dump_string("mirror_peer", peer);
+  }
+  f->close_section();
+}
+
+void MirrorNonPrimarySnapshotNamespace::encode(bufferlist& bl) const {
+  using ceph::encode;
+  encode(primary_mirror_uuid, bl);
+  encode(primary_snap_id, bl);
+  encode(copied, bl);
+  encode(copy_progress, bl);
+}
+
+void MirrorNonPrimarySnapshotNamespace::decode(bufferlist::const_iterator& it) {
+  using ceph::decode;
+  decode(primary_mirror_uuid, it);
+  decode(primary_snap_id, it);
+  decode(copied, it);
+  decode(copy_progress, it);
+}
+
+void MirrorNonPrimarySnapshotNamespace::dump(Formatter *f) const {
+  f->dump_string("primary_mirror_uuid", primary_mirror_uuid);
+  f->dump_unsigned("primary_snap_id", primary_snap_id);
+  f->dump_bool("copied", copied);
+  f->dump_unsigned("copy_progress", copy_progress);
+}
+
 class EncodeSnapshotNamespaceVisitor : public boost::static_visitor<void> {
 public:
   explicit EncodeSnapshotNamespaceVisitor(bufferlist &bl) : m_bl(bl) {
@@ -787,6 +831,12 @@ void SnapshotInfo::generate_test_instances(std::list<SnapshotInfo*> &o) {
                                TrashSnapshotNamespace{
                                  SNAPSHOT_NAMESPACE_TYPE_USER, "snap1"},
                                "12345", 123, {123456, 0}, 429));
+  o.push_back(new SnapshotInfo(1ULL,
+                               MirrorPrimarySnapshotNamespace{true, {"1", "2"}},
+                               "snap1", 123, {123456, 0}, 12));
+  o.push_back(new SnapshotInfo(1ULL,
+                               MirrorNonPrimarySnapshotNamespace{"uuid", 111},
+                               "snap1", 123, {123456, 0}, 12));
 }
 
 void SnapshotNamespace::encode(bufferlist& bl) const {
@@ -810,6 +860,12 @@ void SnapshotNamespace::decode(bufferlist::const_iterator &p)
     case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH:
       *this = TrashSnapshotNamespace();
       break;
+    case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_MIRROR_PRIMARY:
+      *this = MirrorPrimarySnapshotNamespace();
+      break;
+    case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_MIRROR_NON_PRIMARY:
+      *this = MirrorNonPrimarySnapshotNamespace();
+      break;
     default:
       *this = UnknownSnapshotNamespace();
       break;
@@ -830,6 +886,9 @@ void SnapshotNamespace::generate_test_instances(std::list<SnapshotNamespace*> &o
   o.push_back(new SnapshotNamespace(GroupSnapshotNamespace(5, "1018643c9869",
                                                            "33352be8933c")));
   o.push_back(new SnapshotNamespace(TrashSnapshotNamespace()));
+  o.push_back(new SnapshotNamespace(MirrorPrimarySnapshotNamespace(true,
+                                                                   {"uuid"})));
+  o.push_back(new SnapshotNamespace(MirrorNonPrimarySnapshotNamespace("", 0)));
 }
 
 std::ostream& operator<<(std::ostream& os, const SnapshotNamespaceType& type) {
@@ -843,6 +902,12 @@ std::ostream& operator<<(std::ostream& os, const SnapshotNamespaceType& type) {
   case SNAPSHOT_NAMESPACE_TYPE_TRASH:
     os << "trash";
     break;
+  case SNAPSHOT_NAMESPACE_TYPE_MIRROR_PRIMARY:
+    os << "mirror_primary";
+    break;
+  case SNAPSHOT_NAMESPACE_TYPE_MIRROR_NON_PRIMARY:
+    os << "mirror_non_primary";
+    break;
   default:
     os << "unknown";
     break;
@@ -871,6 +936,26 @@ std::ostream& operator<<(std::ostream& os, const TrashSnapshotNamespace& ns) {
   return os;
 }
 
+std::ostream& operator<<(std::ostream& os,
+                         const MirrorPrimarySnapshotNamespace& ns) {
+  os << "[" << SNAPSHOT_NAMESPACE_TYPE_MIRROR_PRIMARY << " "
+     << "demoted=" << ns.demoted << ", "
+     << "mirror_peers=" << ns.mirror_peers
+     << "]";
+  return os;
+}
+
+std::ostream& operator<<(std::ostream& os,
+                         const MirrorNonPrimarySnapshotNamespace& ns) {
+  os << "[" << SNAPSHOT_NAMESPACE_TYPE_MIRROR_NON_PRIMARY << " "
+     << "primary_mirror_uuid=" << ns.primary_mirror_uuid << ", "
+     << "primary_snap_id=" << ns.primary_snap_id << ", "
+     << "copied=" << ns.copied << ", "
+     << "copy_progress=" << ns.copy_progress
+     << "]";
+  return os;
+}
+
 std::ostream& operator<<(std::ostream& os, const UnknownSnapshotNamespace& ns) {
   os << "[unknown]";
   return os;
index 3e5c400de35ed021c3c3eeac2379fa9a78f794f5..d4da0bd13e7fdbad3a0ff1ca58967b4e65144974 100644 (file)
@@ -405,9 +405,11 @@ struct GroupSpec {
 WRITE_CLASS_ENCODER(GroupSpec);
 
 enum SnapshotNamespaceType {
-  SNAPSHOT_NAMESPACE_TYPE_USER  = 0,
-  SNAPSHOT_NAMESPACE_TYPE_GROUP = 1,
-  SNAPSHOT_NAMESPACE_TYPE_TRASH = 2
+  SNAPSHOT_NAMESPACE_TYPE_USER               = 0,
+  SNAPSHOT_NAMESPACE_TYPE_GROUP              = 1,
+  SNAPSHOT_NAMESPACE_TYPE_TRASH              = 2,
+  SNAPSHOT_NAMESPACE_TYPE_MIRROR_PRIMARY     = 3,
+  SNAPSHOT_NAMESPACE_TYPE_MIRROR_NON_PRIMARY = 4,
 };
 
 struct UserSnapshotNamespace {
@@ -495,6 +497,80 @@ struct TrashSnapshotNamespace {
   }
 };
 
+struct MirrorPrimarySnapshotNamespace {
+  static const SnapshotNamespaceType SNAPSHOT_NAMESPACE_TYPE =
+    SNAPSHOT_NAMESPACE_TYPE_MIRROR_PRIMARY;
+
+  bool demoted = false;
+  std::set<std::string> mirror_peers;
+
+  MirrorPrimarySnapshotNamespace() {
+  }
+  MirrorPrimarySnapshotNamespace(bool demoted,
+                                 const std::set<std::string> &mirror_peers)
+    : demoted(demoted), mirror_peers(mirror_peers) {
+  }
+
+  void encode(bufferlist& bl) const;
+  void decode(bufferlist::const_iterator& it);
+
+  void dump(Formatter *f) const;
+
+  inline bool operator==(const MirrorPrimarySnapshotNamespace& mpsn) const {
+    return demoted == mpsn.demoted &&
+           mirror_peer_uuids == mpsn.mirror_peer_uuids;
+  }
+
+  inline bool operator<(const MirrorPrimarySnapshotNamespace& mpsn) const {
+    if (demoted != mpsn.demoted) {
+      return demoted < mpsn.demoted;
+    }
+    return mirror_peer_uuids < mpsn.mirror_peer_uuids;
+  }
+};
+
+struct MirrorNonPrimarySnapshotNamespace {
+  static const SnapshotNamespaceType SNAPSHOT_NAMESPACE_TYPE =
+    SNAPSHOT_NAMESPACE_TYPE_MIRROR_NON_PRIMARY;
+
+  std::string primary_mirror_uuid;
+  snapid_t primary_snap_id = CEPH_NOSNAP;
+  bool copied = false;
+  uint64_t copy_progress = 0;
+
+  MirrorNonPrimarySnapshotNamespace() {
+  }
+  MirrorNonPrimarySnapshotNamespace(const std::string &primary_mirror_uuid,
+                                    snapid_t primary_snap_id)
+    : primary_mirror_uuid(primary_mirror_uuid),
+      primary_snap_id(primary_snap_id) {
+  }
+
+  void encode(bufferlist& bl) const;
+  void decode(bufferlist::const_iterator& it);
+
+  void dump(Formatter *f) const;
+
+  inline bool operator==(const MirrorNonPrimarySnapshotNamespace& mnsn) const {
+    return primary_mirror_uuid == mnsn.primary_mirror_uuid &&
+           primary_snap_id == mnsn.primary_snap_id && copied == mnsn.copied &&
+           last_copied_object_number == mnsn.last_copied_object_number;
+  }
+
+  inline bool operator<(const MirrorNonPrimarySnapshotNamespace& mnsn) const {
+    if (primary_mirror_uuid != mnsn.primary_mirror_uuid) {
+      return primary_mirror_uuid < mnsn.primary_mirror_uuid;
+    }
+    if (primary_snap_id != mnsn.primary_snap_id) {
+      return primary_snap_id < mnsn.primary_snap_id;
+    }
+    if (copied != mnsn.copied) {
+      return copied < mnsn.copied;
+    }
+    return last_copied_object_number < mnsn.last_copied_object_number;
+  }
+};
+
 struct UnknownSnapshotNamespace {
   static const SnapshotNamespaceType SNAPSHOT_NAMESPACE_TYPE =
     static_cast<SnapshotNamespaceType>(-1);
@@ -518,11 +594,17 @@ std::ostream& operator<<(std::ostream& os, const SnapshotNamespaceType& type);
 std::ostream& operator<<(std::ostream& os, const UserSnapshotNamespace& ns);
 std::ostream& operator<<(std::ostream& os, const GroupSnapshotNamespace& ns);
 std::ostream& operator<<(std::ostream& os, const TrashSnapshotNamespace& ns);
+std::ostream& operator<<(std::ostream& os,
+                         const MirrorPrimarySnapshotNamespace& ns);
+std::ostream& operator<<(std::ostream& os,
+                         const MirrorNonPrimarySnapshotNamespace& ns);
 std::ostream& operator<<(std::ostream& os, const UnknownSnapshotNamespace& ns);
 
 typedef boost::variant<UserSnapshotNamespace,
                        GroupSnapshotNamespace,
                        TrashSnapshotNamespace,
+                       MirrorPrimarySnapshotNamespace,
+                       MirrorNonPrimarySnapshotNamespace,
                        UnknownSnapshotNamespace> SnapshotNamespaceVariant;
 
 struct SnapshotNamespace : public SnapshotNamespaceVariant {
index 23ac772406bd59e2212b273b542929a39ed4b021..bcb215acdeece6585283969c16bf06fdc3acbecd 100644 (file)
@@ -75,9 +75,11 @@ typedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void *ptr);
 typedef void (*rbd_update_callback_t)(void *arg);
 
 typedef enum {
-  RBD_SNAP_NAMESPACE_TYPE_USER  = 0,
-  RBD_SNAP_NAMESPACE_TYPE_GROUP = 1,
-  RBD_SNAP_NAMESPACE_TYPE_TRASH = 2
+  RBD_SNAP_NAMESPACE_TYPE_USER               = 0,
+  RBD_SNAP_NAMESPACE_TYPE_GROUP              = 1,
+  RBD_SNAP_NAMESPACE_TYPE_TRASH              = 2,
+  RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY     = 3,
+  RBD_SNAP_NAMESPACE_TYPE_MIRROR_NON_PRIMARY = 4,
 } rbd_snap_namespace_type_t;
 
 typedef struct {
@@ -247,6 +249,19 @@ typedef struct {
   char *group_snap_name;
 } rbd_snap_group_namespace_t;
 
+typedef struct {
+  bool demoted;
+  size_t mirror_peers_count;
+  char *mirror_peers;
+} rbd_snap_mirror_primary_namespace_t;
+
+typedef struct {
+  char *primary_mirror_uuid;
+  uint64_t primary_snap_id;
+  bool copied;
+  uint64_t copy_progress;
+} rbd_snap_mirror_non_primary_namespace_t;
+
 typedef enum {
   RBD_LOCK_MODE_EXCLUSIVE = 0,
   RBD_LOCK_MODE_SHARED = 1,
@@ -825,6 +840,18 @@ CEPH_RBD_API int rbd_snap_get_trash_namespace(rbd_image_t image,
                                               uint64_t snap_id,
                                               char* original_name,
                                               size_t max_length);
+CEPH_RBD_API int rbd_snap_get_mirror_primary_namespace(
+    rbd_image_t image, uint64_t snap_id,
+    rbd_snap_mirror_primary_namespace_t *mirror_snap, size_t mirror_snap_size);
+CEPH_RBD_API int rbd_snap_mirror_primary_namespace_cleanup(
+    rbd_snap_mirror_primary_namespace_t *mirror_snap, size_t mirror_snap_size);
+CEPH_RBD_API int rbd_snap_get_mirror_non_primary_namespace(
+    rbd_image_t image, uint64_t snap_id,
+    rbd_snap_mirror_non_primary_namespace_t *mirror_snap,
+    size_t mirror_snap_size);
+CEPH_RBD_API int rbd_snap_mirror_non_primary_namespace_cleanup(
+    rbd_snap_mirror_non_primary_namespace_t *mirror_snap,
+    size_t mirror_snap_size);
 
 CEPH_RBD_API int rbd_flatten(rbd_image_t image);
 
index 825a94e5f256da8077474a5a3824bc97f7dc6b48..5511bad38a9bb439a00f2089eba4d4f0f95a98c2 100644 (file)
@@ -73,6 +73,18 @@ namespace librbd {
     std::string group_snap_name;
   } snap_group_namespace_t;
 
+  typedef struct {
+    bool demoted;
+    std::set<std::string> mirror_peers;
+  } snap_mirror_primary_namespace_t;
+
+  typedef struct {
+    std::string primary_mirror_uuid;
+    uint64_t primary_snap_id;
+    bool copied;
+    uint64_t copy_progress;
+  } snap_mirror_non_primary_namespace_t;
+
   typedef struct {
     std::string client;
     std::string cookie;
@@ -602,6 +614,12 @@ public:
                                snap_group_namespace_t *group_namespace,
                                size_t snap_group_namespace_size);
   int snap_get_trash_namespace(uint64_t snap_id, std::string* original_name);
+  int snap_get_mirror_primary_namespace(
+      uint64_t snap_id, snap_mirror_primary_namespace_t *mirror_namespace,
+      size_t snap_mirror_namespace_size);
+  int snap_get_mirror_non_primary_namespace(
+      uint64_t snap_id, snap_mirror_non_primary_namespace_t *mirror_namespace,
+      size_t snap_mirror_namespace_size);
 
   /* I/O */
   ssize_t read(uint64_t ofs, size_t len, ceph::bufferlist& bl);
index 2219d8f1a66d5abb917f88eb0147d2f9611d4fc8..75864bae59395e47d5c84c923c884c876b735126 100644 (file)
@@ -95,6 +95,51 @@ public:
   }
 };
 
+class GetMirrorPrimaryVisitor : public boost::static_visitor<int> {
+public:
+  snap_mirror_primary_namespace_t *mirror_snap;
+
+  explicit GetMirrorPrimaryVisitor(snap_mirror_primary_namespace_t *mirror_snap)
+    : mirror_snap(mirror_snap) {
+  }
+
+  template <typename T>
+  inline int operator()(const T&) const {
+    return -EINVAL;
+  }
+
+  inline int operator()(
+      const cls::rbd::MirrorPrimarySnapshotNamespace& snap_namespace) {
+    mirror_snap->demoted = snap_namespace.demoted;
+    mirror_snap->mirror_peers = snap_namespace.mirror_peers;
+    return 0;
+  }
+};
+
+class GetMirrorNonPrimaryVisitor : public boost::static_visitor<int> {
+public:
+  snap_mirror_non_primary_namespace_t *mirror_snap;
+
+  explicit GetMirrorNonPrimaryVisitor(
+      snap_mirror_non_primary_namespace_t *mirror_snap)
+    : mirror_snap(mirror_snap) {
+  }
+
+  template <typename T>
+  inline int operator()(const T&) const {
+    return -EINVAL;
+  }
+
+  inline int operator()(
+      const cls::rbd::MirrorNonPrimarySnapshotNamespace& snap_namespace) {
+    mirror_snap->primary_mirror_uuid = snap_namespace.primary_mirror_uuid;
+    mirror_snap->primary_snap_id = snap_namespace.primary_snap_id;
+    mirror_snap->copied = snap_namespace.copied;
+    mirror_snap->copy_progress = snap_namespace.copy_progress;
+    return 0;
+  }
+};
+
 } // anonymous namespace
 
 template <typename I>
@@ -143,6 +188,53 @@ int Snapshot<I>::get_trash_namespace(I *ictx, uint64_t snap_id,
   return 0;
 }
 
+template <typename I>
+int Snapshot<I>::get_mirror_primary_namespace(
+    I *ictx, uint64_t snap_id, snap_mirror_primary_namespace_t *mirror_snap) {
+  int r = ictx->state->refresh_if_required();
+  if (r < 0) {
+    return r;
+  }
+
+  std::shared_lock image_locker{ictx->image_lock};
+  auto snap_info = ictx->get_snap_info(snap_id);
+  if (snap_info == nullptr) {
+    return -ENOENT;
+  }
+
+  auto gmv = GetMirrorPrimaryVisitor(mirror_snap);
+  r = boost::apply_visitor(gmv, snap_info->snap_namespace);
+  if (r < 0) {
+    return r;
+  }
+
+  return 0;
+}
+
+template <typename I>
+int Snapshot<I>::get_mirror_non_primary_namespace(
+    I *ictx, uint64_t snap_id,
+    snap_mirror_non_primary_namespace_t *mirror_snap) {
+  int r = ictx->state->refresh_if_required();
+  if (r < 0) {
+    return r;
+  }
+
+  std::shared_lock image_locker{ictx->image_lock};
+  auto snap_info = ictx->get_snap_info(snap_id);
+  if (snap_info == nullptr) {
+    return -ENOENT;
+  }
+
+  auto gmv = GetMirrorNonPrimaryVisitor(mirror_snap);
+  r = boost::apply_visitor(gmv, snap_info->snap_namespace);
+  if (r < 0) {
+    return r;
+  }
+
+  return 0;
+}
+
 template <typename I>
 int Snapshot<I>::get_namespace_type(I *ictx, uint64_t snap_id,
                                 snap_namespace_type_t *namespace_type) {
index 8a6696578ac19677603578e03e1f600ab85c2a66..c00aaf85cf414c772c025f1b63cea996c5050ec1 100644 (file)
@@ -22,6 +22,14 @@ struct Snapshot {
   static int get_trash_namespace(ImageCtxT *ictx, uint64_t snap_id,
                                  std::string *original_name);
 
+  static int get_mirror_primary_namespace(
+      ImageCtxT *ictx, uint64_t snap_id,
+      snap_mirror_primary_namespace_t *mirror_snap);
+
+  static int get_mirror_non_primary_namespace(
+      ImageCtxT *ictx, uint64_t snap_id,
+      snap_mirror_non_primary_namespace_t *mirror_snap);
+
   static int get_namespace_type(ImageCtxT *ictx, uint64_t snap_id,
                                snap_namespace_type_t *namespace_type);
 
index 5e729893f83ac10bc586e51d0086be3aded7f082..75a854a768e5ede266d6b2e71e99bd34486a471c 100644 (file)
@@ -2333,6 +2333,34 @@ namespace librbd {
                                                         original_name);
   }
 
+  int Image::snap_get_mirror_primary_namespace(
+      uint64_t snap_id, snap_mirror_primary_namespace_t *mirror_snap,
+      size_t mirror_snap_size) {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+
+    if (mirror_snap_size != sizeof(snap_mirror_primary_namespace_t)) {
+      return -ERANGE;
+    }
+
+    int r = librbd::api::Snapshot<>::get_mirror_primary_namespace(
+        ictx, snap_id, mirror_snap);
+    return r;
+  }
+
+  int Image::snap_get_mirror_non_primary_namespace(
+      uint64_t snap_id, snap_mirror_non_primary_namespace_t *mirror_snap,
+      size_t mirror_snap_size) {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+
+    if (mirror_snap_size != sizeof(snap_mirror_non_primary_namespace_t)) {
+      return -ERANGE;
+    }
+
+    int r = librbd::api::Snapshot<>::get_mirror_non_primary_namespace(
+        ictx, snap_id, mirror_snap);
+    return r;
+  }
+
   int Image::snap_set_limit(uint64_t limit)
   {
     ImageCtx *ictx = (ImageCtx *)ctx;
@@ -6812,6 +6840,88 @@ extern "C" int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
   strcpy(original_name, cpp_original_name.c_str());
   return 0;
 }
+
+extern "C" int rbd_snap_get_mirror_primary_namespace(
+    rbd_image_t image, uint64_t snap_id,
+    rbd_snap_mirror_primary_namespace_t *mirror_snap,
+    size_t mirror_snap_size) {
+  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+
+  if (mirror_snap_size != sizeof(rbd_snap_mirror_primary_namespace_t)) {
+    return -ERANGE;
+  }
+
+  librbd::snap_mirror_primary_namespace_t mirror_namespace;
+  int r = librbd::api::Snapshot<>::get_mirror_primary_namespace(
+      ictx, snap_id, &mirror_namespace);
+  if (r < 0) {
+    return r;
+  }
+
+  mirror_snap->demoted = mirror_namespace.demoted;
+  mirror_snap->mirror_peers_count = mirror_namespace.mirror_peers.size();
+  size_t len = 0;
+  for (auto &peer : mirror_namespace.mirror_peers) {
+    len += peer.size() + 1;
+  }
+  mirror_snap->mirror_peers = (char *)malloc(len);
+  char *p = mirror_snap->mirror_peers;
+  for (auto &peer : mirror_namespace.mirror_peers) {
+    strncpy(p, peer.c_str(), peer.size() + 1);
+    p += peer.size() + 1;
+  }
+
+  return 0;
+}
+
+extern "C" int rbd_snap_mirror_primary_namespace_cleanup(
+    rbd_snap_mirror_primary_namespace_t *mirror_snap,
+    size_t mirror_snap_size) {
+  if (mirror_snap_size != sizeof(rbd_snap_mirror_primary_namespace_t)) {
+    return -ERANGE;
+  }
+
+  free(mirror_snap->mirror_peers);
+  return 0;
+}
+
+extern "C" int rbd_snap_get_mirror_non_primary_namespace(
+    rbd_image_t image, uint64_t snap_id,
+    rbd_snap_mirror_non_primary_namespace_t *mirror_snap,
+    size_t mirror_snap_size) {
+  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+
+  if (mirror_snap_size != sizeof(rbd_snap_mirror_non_primary_namespace_t)) {
+    return -ERANGE;
+  }
+
+  librbd::snap_mirror_non_primary_namespace_t mirror_namespace;
+  int r = librbd::api::Snapshot<>::get_mirror_non_primary_namespace(
+      ictx, snap_id, &mirror_namespace);
+  if (r < 0) {
+    return r;
+  }
+
+  mirror_snap->primary_mirror_uuid =
+      strdup(mirror_namespace.primary_mirror_uuid.c_str());
+  mirror_snap->primary_snap_id = mirror_namespace.primary_snap_id;
+  mirror_snap->copied = mirror_namespace.copied;
+  mirror_snap->copy_progress = mirror_namespace.copy_progress;
+
+  return 0;
+}
+
+extern "C" int rbd_snap_mirror_non_primary_namespace_cleanup(
+    rbd_snap_mirror_non_primary_namespace_t *mirror_snap,
+    size_t mirror_snap_size) {
+  if (mirror_snap_size != sizeof(rbd_snap_mirror_non_primary_namespace_t)) {
+    return -ERANGE;
+  }
+
+  free(mirror_snap->primary_mirror_uuid);
+  return 0;
+}
+
 extern "C" int rbd_watchers_list(rbd_image_t image,
                                 rbd_image_watcher_t *watchers,
                                 size_t *max_watchers) {
index a3355b8dcf6142493e6d49cb9e73e5542c74b1b8..7d835336f53080c0d041df49a3cc1878b2c9e082 100644 (file)
@@ -127,6 +127,17 @@ cdef extern from "rbd/librbd.h" nogil:
         char *group_name
         char *group_snap_name
 
+    ctypedef struct rbd_snap_mirror_primary_namespace_t:
+        bint demoted
+        size_t mirror_peers_count
+        char *mirror_peers
+
+    ctypedef struct rbd_snap_mirror_non_primary_namespace_t:
+        char *primary_mirror_uuid
+        uint64_t primary_snap_id
+        bint copied
+        uint64_t copy_progress
+
     ctypedef struct rbd_group_info_t:
         char *name
         int64_t pool
@@ -147,6 +158,8 @@ cdef extern from "rbd/librbd.h" nogil:
         _RBD_SNAP_NAMESPACE_TYPE_USER "RBD_SNAP_NAMESPACE_TYPE_USER"
         _RBD_SNAP_NAMESPACE_TYPE_GROUP "RBD_SNAP_NAMESPACE_TYPE_GROUP"
         _RBD_SNAP_NAMESPACE_TYPE_TRASH "RBD_SNAP_NAMESPACE_TYPE_TRASH"
+        _RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY "RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY"
+        _RBD_SNAP_NAMESPACE_TYPE_MIRROR_NON_PRIMARY "RBD_SNAP_NAMESPACE_TYPE_MIRROR_NON_PRIMARY"
 
     ctypedef struct rbd_snap_spec_t:
         uint64_t id
@@ -504,6 +517,20 @@ cdef extern from "rbd/librbd.h" nogil:
                                           size_t snap_group_namespace_size)
     int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
                                      char *original_name, size_t max_length)
+    int rbd_snap_get_mirror_primary_namespace(
+        rbd_image_t image, uint64_t snap_id,
+        rbd_snap_mirror_primary_namespace_t *mirror_ns,
+        size_t snap_mirror_primary_namespace_size)
+    void rbd_snap_mirror_primary_namespace_cleanup(
+        rbd_snap_mirror_primary_namespace_t *mirror_ns,
+        size_t snap_mirror_primary_namespace_size)
+    int rbd_snap_get_mirror_non_primary_namespace(
+        rbd_image_t image, uint64_t snap_id,
+        rbd_snap_mirror_non_primary_namespace_t *mirror_ns,
+        size_t snap_mirror_non_primary_namespace_size)
+    void rbd_snap_mirror_non_primary_namespace_cleanup(
+        rbd_snap_mirror_non_primary_namespace_t *mirror_ns,
+        size_t snap_mirror_non_primary_namespace_size)
 
     int rbd_flatten_with_progress(rbd_image_t image, librbd_progress_fn_t cb,
                                   void *cbdata)
@@ -715,6 +742,8 @@ RBD_IMAGE_OPTION_DATA_POOL = _RBD_IMAGE_OPTION_DATA_POOL
 RBD_SNAP_NAMESPACE_TYPE_USER = _RBD_SNAP_NAMESPACE_TYPE_USER
 RBD_SNAP_NAMESPACE_TYPE_GROUP = _RBD_SNAP_NAMESPACE_TYPE_GROUP
 RBD_SNAP_NAMESPACE_TYPE_TRASH = _RBD_SNAP_NAMESPACE_TYPE_TRASH
+RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY = _RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY
+RBD_SNAP_NAMESPACE_TYPE_MIRROR_NON_PRIMARY = _RBD_SNAP_NAMESPACE_TYPE_MIRROR_NON_PRIMARY
 
 RBD_GROUP_IMAGE_STATE_ATTACHED = _RBD_GROUP_IMAGE_STATE_ATTACHED
 RBD_GROUP_IMAGE_STATE_INCOMPLETE = _RBD_GROUP_IMAGE_STATE_INCOMPLETE
@@ -5041,6 +5070,78 @@ written." % (self.name, ret, length))
         finally:
             free(_name)
 
+    def snap_get_mirror_primary_namespace(self, snap_id):
+        """
+        get the mirror primary namespace details.
+        :param snap_id: the snapshot id of the mirror snapshot
+        :type key: int
+        :returns: dict - contains the following keys:
+
+            * ``demoted`` (bool) - True if snapshot is in demoted state
+
+            * ``mirror_peers`` (list) - mirror peer uuids
+        """
+        cdef:
+            rbd_snap_mirror_primary_namespace_t sn
+            uint64_t _snap_id = snap_id
+        with nogil:
+            ret = rbd_snap_get_mirror_primary_namespace(
+                self.image, _snap_id, &sn,
+                sizeof(rbd_snap_mirror_primary_namespace_t))
+        if ret != 0:
+            raise make_ex(ret, 'error getting snapshot mirror primary '
+                               'namespace for image: %s, snap_id: %d' %
+                               (self.name, snap_id))
+        peers = []
+        p = sn.mirror_peers
+        for i in range(sn.mirror_peers_count):
+            peer = decode_cstr(p)
+            peers.append(peer)
+            p += len(peer) + 1
+        info = {
+                'demoted' : sn.demoted,
+                'mirror_peers' : peers,
+            }
+        rbd_snap_mirror_primary_namespace_cleanup(
+            &sn, sizeof(rbd_snap_mirror_primary_namespace_t))
+        return info
+
+    def snap_get_mirror_non_primary_namespace(self, snap_id):
+        """
+        get the mirror non-primary namespace details.
+        :param snap_id: the snapshot id of the mirror snapshot
+        :type key: int
+        :returns: dict - contains the following keys:
+
+            * ``primary_mirror_uuid`` (str) - primary mirror uuid
+
+            * ``primary_snap_id`` (int) - primary snapshot Id
+
+            * ``copied`` (bool) - True if snapsho is copied
+
+           *  ``copy_progress`` (int) - copy progress
+        """
+        cdef:
+            rbd_snap_mirror_non_primary_namespace_t sn
+            uint64_t _snap_id = snap_id
+        with nogil:
+            ret = rbd_snap_get_mirror_non_primary_namespace(
+                self.image, _snap_id, &sn,
+                sizeof(rbd_snap_mirror_non_primary_namespace_t))
+        if ret != 0:
+            raise make_ex(ret, 'error getting snapshot mirror non-primary '
+                               'namespace for image: %s, snap_id: %d' %
+                               (self.name, snap_id))
+        info = {
+                'primary_mirror_uuid' : decode_cstr(sn.primary_mirror_uuid),
+                'primary_snap_id' : sn.primary_snap_id,
+                'copied' : sn.copied,
+                'copy_progress' : sn.copy_progress,
+            }
+        rbd_snap_mirror_non_primary_namespace_cleanup(
+            &sn, sizeof(rbd_snap_mirror_non_primary_namespace_t))
+        return info
+
 
 cdef class ImageIterator(object):
     """
@@ -5222,6 +5323,10 @@ cdef class SnapIterator(object):
     * ``group`` (dict) - optional for group namespace snapshots
 
     * ``trash`` (dict) - optional for trash namespace snapshots
+
+    * ``mirror_primary`` (dict) - optional for mirror primary namespace snapshots
+
+    * ``mirror_non_primary`` (dict) - optional for mirror non-primary namespace snapshots
     """
 
     cdef rbd_snap_info_t *snaps
@@ -5264,6 +5369,20 @@ cdef class SnapIterator(object):
                 except:
                     trash = None
                 s['trash'] = trash
+            elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY:
+                try:
+                    mirror = self.image.snap_get_mirror_primary_namespace(
+                        self.snaps[i].id)
+                except:
+                    mirror = None
+                s['mirror_primary'] = mirror
+            elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_MIRROR_NON_PRIMARY:
+                try:
+                    mirror = self.image.snap_get_mirror_non_primary_namespace(
+                        self.snaps[i].id)
+                except:
+                    mirror = None
+                    s['mirror_non_primary'] = mirror
             yield s
 
     def __dealloc__(self):
index c652ce1c2fef0769375819ce3f11bc3ff932ed5e..b2e6b665c6e8d92f6383fd0e28749ad91f7ec21a 100644 (file)
@@ -34,11 +34,18 @@ int do_list_snaps(librbd::Image& image, Formatter *f, bool all_snaps, librados::
     return r;
   }
 
+  librbd::image_info_t info;
   if (!all_snaps) {
     snaps.erase(remove_if(snaps.begin(),
                           snaps.end(),
                           boost::bind(utils::is_not_user_snap_namespace, &image, _1)),
                 snaps.end());
+  } else if (!f) {
+    r = image.stat(info, sizeof(info));
+    if (r < 0) {
+      std::cerr << "rbd: unable to get image info" << std::endl;
+      return r;
+    }
   }
 
   if (f) {
@@ -88,18 +95,34 @@ int do_list_snaps(librbd::Image& image, Formatter *f, bool all_snaps, librados::
     case RBD_SNAP_NAMESPACE_TYPE_TRASH:
       snap_namespace_name = "trash";
       break;
+    case RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY:
+      snap_namespace_name = "mirror_primary";
+      break;
+    case RBD_SNAP_NAMESPACE_TYPE_MIRROR_NON_PRIMARY:
+      snap_namespace_name = "mirror_non_primary";
+      break;
     }
 
     int get_trash_res = -ENOENT;
     std::string trash_original_name;
     int get_group_res = -ENOENT;
     librbd::snap_group_namespace_t group_snap;
+    int get_mirror_primary_res = -ENOENT;
+    librbd::snap_mirror_primary_namespace_t mirror_primary_snap;
+    int get_mirror_non_primary_res = -ENOENT;
+    librbd::snap_mirror_non_primary_namespace_t mirror_non_primary_snap;
     if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_GROUP) {
       get_group_res = image.snap_get_group_namespace(s->id, &group_snap,
                                                      sizeof(group_snap));
     } else if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_TRASH) {
       get_trash_res = image.snap_get_trash_namespace(
         s->id, &trash_original_name);
+    } else if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY) {
+      get_mirror_primary_res = image.snap_get_mirror_primary_namespace(
+        s->id, &mirror_primary_snap, sizeof(mirror_primary_snap));
+    } else if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_MIRROR_NON_PRIMARY) {
+      get_mirror_non_primary_res = image.snap_get_mirror_non_primary_namespace(
+        s->id, &mirror_non_primary_snap, sizeof(mirror_non_primary_snap));
     }
 
     std::string protected_str = "";
@@ -120,17 +143,32 @@ int do_list_snaps(librbd::Image& image, Formatter *f, bool all_snaps, librados::
       f->dump_string("protected", protected_str);
       f->dump_string("timestamp", tt_str);
       if (all_snaps) {
-       f->open_object_section("namespace");
+        f->open_object_section("namespace");
         f->dump_string("type", snap_namespace_name);
-       if (get_group_res == 0) {
-         std::string pool_name = pool_map[group_snap.group_pool];
-         f->dump_string("pool", pool_name);
-         f->dump_string("group", group_snap.group_name);
-         f->dump_string("group snap", group_snap.group_snap_name);
-       } else if (get_trash_res == 0) {
+        if (get_group_res == 0) {
+          std::string pool_name = pool_map[group_snap.group_pool];
+          f->dump_string("pool", pool_name);
+          f->dump_string("group", group_snap.group_name);
+          f->dump_string("group snap", group_snap.group_snap_name);
+        } else if (get_trash_res == 0) {
           f->dump_string("original_name", trash_original_name);
+        } else if (get_mirror_primary_res == 0) {
+          f->dump_bool("demoted", mirror_primary_snap.demoted);
+          f->open_array_section("mirror_peer_uuids");
+          for (auto &uuid : mirror_primary_snap.mirror_peer_uuids) {
+            f->dump_string("peer_uuid", uuid);
+          }
+          f->close_section();
+        } else if (get_mirror_non_primary_res == 0) {
+          f->dump_string("primary_mirror_uuid",
+                         mirror_non_primary_snap.primary_mirror_uuid);
+          f->dump_unsigned("primary_snap_id",
+                           mirror_non_primary_snap.primary_snap_id);
+          f->dump_bool("copied", mirror_non_primary_snap.copied);
+          f->dump_unsigned("last_copied_object_number",
+                           mirror_non_primary_snap.last_copied_object_number);
         }
-       f->close_section();
+        f->close_section();
       }
       f->close_section();
     } else {
@@ -138,19 +176,37 @@ int do_list_snaps(librbd::Image& image, Formatter *f, bool all_snaps, librados::
       t << s->id << s->name << stringify(byte_u_t(s->size)) << protected_str << tt_str;
 
       if (all_snaps) {
-       ostringstream oss;
+        ostringstream oss;
         oss << snap_namespace_name;
 
         if (get_group_res == 0) {
-         std::string pool_name = pool_map[group_snap.group_pool];
-         oss << " (" << pool_name << "/"
-                     << group_snap.group_name << "@"
-                     << group_snap.group_snap_name << ")";
+          std::string pool_name = pool_map[group_snap.group_pool];
+          oss << " (" << pool_name << "/"
+                      << group_snap.group_name << "@"
+                      << group_snap.group_snap_name << ")";
         } else if (get_trash_res == 0) {
           oss << " (" << trash_original_name << ")";
+        } else if (get_mirror_primary_res == 0) {
+          oss << " (" << (mirror_primary_snap.demoted ? "demoted " : "")
+                      << "peer_uuids:[" << mirror_primary_snap.mirror_peer_uuids
+                      << "])";
+        } else if (get_mirror_non_primary_res == 0) {
+          oss << " (" << mirror_non_primary_snap.primary_mirror_uuid << ":"
+              << mirror_non_primary_snap.primary_snap_id << " ";
+          if (!mirror_non_primary_snap.copied) {
+            if (info.num_objs > 0) {
+              auto progress = std::min<uint64_t>(
+                100, 100 * mirror_non_primary_snap.last_copied_object_number /
+                           info.num_objs);
+              oss << progress << "%";
+            } else {
+              oss << "not ";
+            }
+          }
+          oss << " copied)";
         }
 
-       t << oss.str();
+        t << oss.str();
       }
       t << TextTable::endrow;
     }