]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/librbd/api/Snapshot.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / librbd / api / Snapshot.cc
index 3d29cfb263a2078a239642ffb702fc37e3bbc3be..da6c7196bc83aba938fb085e85fb6caf548ba8f6 100644 (file)
@@ -4,10 +4,12 @@
 #include "librbd/api/Snapshot.h"
 #include "cls/rbd/cls_rbd_types.h"
 #include "common/errno.h"
+#include "librbd/internal.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageState.h"
 #include "librbd/Operations.h"
 #include "librbd/Utils.h"
+#include "librbd/api/Image.h"
 #include <boost/variant.hpp>
 #include "include/Context.h"
 #include "common/Cond.h"
@@ -16,6 +18,8 @@
 #undef dout_prefix
 #define dout_prefix *_dout << "librbd::api::Snapshot: " << __func__ << ": "
 
+using librados::snap_t;
+
 namespace librbd {
 namespace api {
 
@@ -95,6 +99,32 @@ public:
   }
 };
 
+class GetMirrorVisitor : public boost::static_visitor<int> {
+public:
+  snap_mirror_namespace_t *mirror_snap;
+
+  explicit GetMirrorVisitor(snap_mirror_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::MirrorSnapshotNamespace& snap_namespace) {
+    mirror_snap->state = static_cast<snap_mirror_state_t>(snap_namespace.state);
+    mirror_snap->complete = snap_namespace.complete;
+    mirror_snap->mirror_peer_uuids = snap_namespace.mirror_peer_uuids;
+    mirror_snap->primary_mirror_uuid = snap_namespace.primary_mirror_uuid;
+    mirror_snap->primary_snap_id = snap_namespace.primary_snap_id;
+    mirror_snap->last_copied_object_number =
+      snap_namespace.last_copied_object_number;
+    return 0;
+  }
+};
+
 } // anonymous namespace
 
 template <typename I>
@@ -105,7 +135,7 @@ int Snapshot<I>::get_group_namespace(I *ictx, uint64_t snap_id,
     return r;
   }
 
-  RWLock::RLocker snap_locker(ictx->snap_lock);
+  std::shared_lock image_locker{ictx->image_lock};
   auto snap_info = ictx->get_snap_info(snap_id);
   if (snap_info == nullptr) {
     return -ENOENT;
@@ -128,7 +158,7 @@ int Snapshot<I>::get_trash_namespace(I *ictx, uint64_t snap_id,
     return r;
   }
 
-  RWLock::RLocker snap_locker(ictx->snap_lock);
+  std::shared_lock image_locker{ictx->image_lock};
   auto snap_info = ictx->get_snap_info(snap_id);
   if (snap_info == nullptr) {
     return -ENOENT;
@@ -143,6 +173,29 @@ int Snapshot<I>::get_trash_namespace(I *ictx, uint64_t snap_id,
   return 0;
 }
 
+template <typename I>
+int Snapshot<I>::get_mirror_namespace(
+    I *ictx, uint64_t snap_id, snap_mirror_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 = GetMirrorVisitor(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) {
@@ -151,7 +204,7 @@ int Snapshot<I>::get_namespace_type(I *ictx, uint64_t snap_id,
     return r;
   }
 
-  RWLock::RLocker l(ictx->snap_lock);
+  std::shared_lock l{ictx->image_lock};
   auto snap_info = ictx->get_snap_info(snap_id);
   if (snap_info == nullptr) {
     return -ENOENT;
@@ -174,7 +227,7 @@ int Snapshot<I>::remove(I *ictx, uint64_t snap_id) {
   cls::rbd::SnapshotNamespace snapshot_namespace;
   std::string snapshot_name;
   {
-    RWLock::RLocker snap_locker(ictx->snap_lock);
+    std::shared_lock image_locker{ictx->image_lock};
     auto it = ictx->snap_info.find(snap_id);
     if (it == ictx->snap_info.end()) {
       return -ENOENT;
@@ -190,6 +243,183 @@ int Snapshot<I>::remove(I *ictx, uint64_t snap_id) {
   return r;
 }
 
+template <typename I>
+int Snapshot<I>::get_name(I *ictx, uint64_t snap_id, std::string *snap_name)
+  {
+    ldout(ictx->cct, 20) << "snap_get_name " << ictx << " " << snap_id << dendl;
+
+    int r = ictx->state->refresh_if_required();
+    if (r < 0)
+      return r;
+
+    std::shared_lock image_locker{ictx->image_lock};
+    r = ictx->get_snap_name(snap_id, snap_name);
+
+    return r;
+  }
+
+template <typename I>
+int Snapshot<I>::get_id(I *ictx, const std::string& snap_name, uint64_t *snap_id)
+  {
+    ldout(ictx->cct, 20) << "snap_get_id " << ictx << " " << snap_name << dendl;
+
+    int r = ictx->state->refresh_if_required();
+    if (r < 0)
+      return r;
+
+    std::shared_lock image_locker{ictx->image_lock};
+    *snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), snap_name);
+    if (*snap_id == CEPH_NOSNAP)
+      return -ENOENT;
+
+    return 0;
+  }
+
+template <typename I>
+int Snapshot<I>::list(I *ictx, vector<snap_info_t>& snaps) {
+  ldout(ictx->cct, 20) << "snap_list " << ictx << dendl;
+
+  int r = ictx->state->refresh_if_required();
+  if (r < 0)
+    return r;
+
+  std::shared_lock l{ictx->image_lock};
+  for (auto &it : ictx->snap_info) {
+    snap_info_t info;
+    info.name = it.second.name;
+    info.id = it.first;
+    info.size = it.second.size;
+    snaps.push_back(info);
+  }
+
+  return 0;
+}
+
+template <typename I>
+int Snapshot<I>::exists(I *ictx, const cls::rbd::SnapshotNamespace& snap_namespace,
+                       const char *snap_name, bool *exists) {
+  ldout(ictx->cct, 20) << "snap_exists " << ictx << " " << snap_name << dendl;
+
+  int r = ictx->state->refresh_if_required();
+  if (r < 0)
+    return r;
+
+  std::shared_lock l{ictx->image_lock};
+  *exists = ictx->get_snap_id(snap_namespace, snap_name) != CEPH_NOSNAP;
+  return 0;
+}
+
+template <typename I>
+int Snapshot<I>::remove(I *ictx, const char *snap_name, uint32_t flags,
+                        ProgressContext& pctx) {
+  ldout(ictx->cct, 20) << "snap_remove " << ictx << " " << snap_name << " flags: " << flags << dendl;
+
+  int r = 0;
+
+  r = ictx->state->refresh_if_required();
+  if (r < 0)
+    return r;
+
+  if (flags & RBD_SNAP_REMOVE_FLATTEN) {
+     r = Image<I>::flatten_children(ictx, snap_name, pctx);
+     if (r < 0) {
+       return r;
+     }
+  }
+
+  bool protect;
+  r = is_protected(ictx, snap_name, &protect);
+  if (r < 0) {
+    return r;
+  }
+
+  if (protect && flags & RBD_SNAP_REMOVE_UNPROTECT) {
+    r = ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(), snap_name);
+    if (r < 0) {
+      lderr(ictx->cct) << "failed to unprotect snapshot: " << snap_name << dendl;
+      return r;
+    }
+
+    r = is_protected(ictx, snap_name, &protect);
+    if (r < 0) {
+      return r;
+    }
+    if (protect) {
+      lderr(ictx->cct) << "snapshot is still protected after unprotection" << dendl;
+      ceph_abort();
+    }
+  }
+
+  C_SaferCond ctx;
+  ictx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(), snap_name, &ctx);
+
+  r = ctx.wait();
+  return r;
+}
+
+template <typename I>
+int Snapshot<I>::get_timestamp(I *ictx, uint64_t snap_id, struct timespec *timestamp) {
+  auto snap_it = ictx->snap_info.find(snap_id);
+  ceph_assert(snap_it != ictx->snap_info.end());
+  utime_t time = snap_it->second.timestamp;
+  time.to_timespec(timestamp);
+  return 0;
+}
+
+template <typename I>
+int Snapshot<I>::get_limit(I *ictx, uint64_t *limit) {
+  int r = cls_client::snapshot_get_limit(&ictx->md_ctx, ictx->header_oid,
+                                         limit);
+  if (r == -EOPNOTSUPP) {
+    *limit = UINT64_MAX;
+    r = 0;
+  }
+  return r;
+}
+
+template <typename I>
+int Snapshot<I>::set_limit(I *ictx, uint64_t limit) {
+  return ictx->operations->snap_set_limit(limit);
+}
+
+template <typename I>
+int Snapshot<I>::is_protected(I *ictx, const char *snap_name, bool *protect) {
+  ldout(ictx->cct, 20) << "snap_is_protected " << ictx << " " << snap_name
+                      << dendl;
+
+  int r = ictx->state->refresh_if_required();
+  if (r < 0)
+    return r;
+
+  std::shared_lock l{ictx->image_lock};
+  snap_t snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), snap_name);
+  if (snap_id == CEPH_NOSNAP)
+    return -ENOENT;
+  bool is_unprotected;
+  r = ictx->is_snap_unprotected(snap_id, &is_unprotected);
+  // consider both PROTECTED or UNPROTECTING to be 'protected',
+  // since in either state they can't be deleted
+  *protect = !is_unprotected;
+  return r;
+}
+
+template <typename I>
+int Snapshot<I>::get_namespace(I *ictx, const char *snap_name,
+                               cls::rbd::SnapshotNamespace *snap_namespace) {
+  ldout(ictx->cct, 20) << "get_snap_namespace " << ictx << " " << snap_name
+                       << dendl;
+
+  int r = ictx->state->refresh_if_required();
+  if (r < 0)
+    return r;
+  std::shared_lock l{ictx->image_lock};
+  snap_t snap_id = ictx->get_snap_id(*snap_namespace, snap_name);
+  if (snap_id == CEPH_NOSNAP)
+    return -ENOENT;
+  r = ictx->get_snap_namespace(snap_id, snap_namespace);
+  return r;
+}
+
 } // namespace api
 } // namespace librbd