]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/librbd/deep_copy/SnapshotCopyRequest.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / librbd / deep_copy / SnapshotCopyRequest.cc
index db24ca72ecf3b19fe9b3b508b562a29bd17fe8d1..8ac59308873f4ba1be3f72d24743a1d759d9b5a6 100644 (file)
@@ -45,22 +45,34 @@ using librbd::util::unique_lock_name;
 template <typename I>
 SnapshotCopyRequest<I>::SnapshotCopyRequest(I *src_image_ctx,
                                             I *dst_image_ctx,
-                                            librados::snap_t snap_id_end,
+                                            librados::snap_t src_snap_id_start,
+                                            librados::snap_t src_snap_id_end,
+                                            librados::snap_t dst_snap_id_start,
                                             bool flatten, ContextWQ *work_queue,
                                             SnapSeqs *snap_seqs,
                                             Context *on_finish)
-  : RefCountedObject(dst_image_ctx->cct, 1), m_src_image_ctx(src_image_ctx),
-    m_dst_image_ctx(dst_image_ctx), m_snap_id_end(snap_id_end),
+  : RefCountedObject(dst_image_ctx->cct), m_src_image_ctx(src_image_ctx),
+    m_dst_image_ctx(dst_image_ctx), m_src_snap_id_start(src_snap_id_start),
+    m_src_snap_id_end(src_snap_id_end), m_dst_snap_id_start(dst_snap_id_start),
     m_flatten(flatten), m_work_queue(work_queue), m_snap_seqs_result(snap_seqs),
     m_snap_seqs(*snap_seqs), m_on_finish(on_finish), m_cct(dst_image_ctx->cct),
-    m_lock(unique_lock_name("SnapshotCopyRequest::m_lock", this)) {
+    m_lock(ceph::make_mutex(unique_lock_name("SnapshotCopyRequest::m_lock", this))) {
+  ceph_assert((m_src_snap_id_start == 0 && m_dst_snap_id_start == 0) ||
+              (m_src_snap_id_start > 0 && m_dst_snap_id_start > 0));
+
   // snap ids ordered from oldest to newest
+  m_src_image_ctx->image_lock.lock_shared();
   m_src_snap_ids.insert(src_image_ctx->snaps.begin(),
                         src_image_ctx->snaps.end());
+  m_src_image_ctx->image_lock.unlock_shared();
+
+  m_dst_image_ctx->image_lock.lock_shared();
   m_dst_snap_ids.insert(dst_image_ctx->snaps.begin(),
                         dst_image_ctx->snaps.end());
-  if (m_snap_id_end != CEPH_NOSNAP) {
-    m_src_snap_ids.erase(m_src_snap_ids.upper_bound(m_snap_id_end),
+  m_dst_image_ctx->image_lock.unlock_shared();
+
+  if (m_src_snap_id_end != CEPH_NOSNAP) {
+    m_src_snap_ids.erase(m_src_snap_ids.upper_bound(m_src_snap_id_end),
                          m_src_snap_ids.end());
   }
 }
@@ -87,7 +99,7 @@ void SnapshotCopyRequest<I>::send() {
 
 template <typename I>
 void SnapshotCopyRequest<I>::cancel() {
-  Mutex::Locker locker(m_lock);
+  std::lock_guard locker{m_lock};
 
   ldout(m_cct, 20) << dendl;
   m_canceled = true;
@@ -99,23 +111,25 @@ void SnapshotCopyRequest<I>::send_snap_unprotect() {
   SnapIdSet::iterator snap_id_it = m_dst_snap_ids.begin();
   if (m_prev_snap_id != CEPH_NOSNAP) {
     snap_id_it = m_dst_snap_ids.upper_bound(m_prev_snap_id);
+  } else if (m_dst_snap_id_start > 0) {
+    snap_id_it = m_dst_snap_ids.upper_bound(m_dst_snap_id_start);
   }
 
   for (; snap_id_it != m_dst_snap_ids.end(); ++snap_id_it) {
     librados::snap_t dst_snap_id = *snap_id_it;
 
-    m_dst_image_ctx->snap_lock.get_read();
+    m_dst_image_ctx->image_lock.lock_shared();
 
     bool dst_unprotected;
     int r = m_dst_image_ctx->is_snap_unprotected(dst_snap_id, &dst_unprotected);
     if (r < 0) {
       lderr(m_cct) << "failed to retrieve destination snap unprotect status: "
            << cpp_strerror(r) << dendl;
-      m_dst_image_ctx->snap_lock.put_read();
+      m_dst_image_ctx->image_lock.unlock_shared();
       finish(r);
       return;
     }
-    m_dst_image_ctx->snap_lock.put_read();
+    m_dst_image_ctx->image_lock.unlock_shared();
 
     if (dst_unprotected) {
       // snap is already unprotected -- check next snap
@@ -131,7 +145,7 @@ void SnapshotCopyRequest<I>::send_snap_unprotect() {
       });
 
     if (snap_seq_it != m_snap_seqs.end()) {
-      m_src_image_ctx->snap_lock.get_read();
+      m_src_image_ctx->image_lock.lock_shared();
       bool src_unprotected;
       r = m_src_image_ctx->is_snap_unprotected(snap_seq_it->first,
                                                &src_unprotected);
@@ -145,11 +159,11 @@ void SnapshotCopyRequest<I>::send_snap_unprotect() {
       if (r < 0) {
         lderr(m_cct) << "failed to retrieve source snap unprotect status: "
                      << cpp_strerror(r) << dendl;
-        m_src_image_ctx->snap_lock.put_read();
+        m_src_image_ctx->image_lock.unlock_shared();
         finish(r);
         return;
       }
-      m_src_image_ctx->snap_lock.put_read();
+      m_src_image_ctx->image_lock.unlock_shared();
 
       if (src_unprotected) {
         // source is unprotected -- unprotect destination snap
@@ -182,11 +196,11 @@ void SnapshotCopyRequest<I>::send_snap_unprotect() {
     return;
   }
 
-  auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
+  auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
       handle_snap_unprotect(r);
       finish_op_ctx->complete(0);
     });
-  RWLock::RLocker owner_locker(m_dst_image_ctx->owner_lock);
+  std::shared_lock owner_locker{m_dst_image_ctx->owner_lock};
   m_dst_image_ctx->operations->execute_snap_unprotect(
     cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx);
 }
@@ -197,14 +211,14 @@ void SnapshotCopyRequest<I>::handle_snap_unprotect(int r) {
 
   if (r < 0) {
     lderr(m_cct) << "failed to unprotect snapshot '" << m_snap_name << "': "
-         << cpp_strerror(r) << dendl;
+                 << cpp_strerror(r) << dendl;
     finish(r);
     return;
   }
 
   {
     // avoid the need to refresh to delete the newly unprotected snapshot
-    RWLock::RLocker snap_locker(m_dst_image_ctx->snap_lock);
+    std::shared_lock image_locker{m_dst_image_ctx->image_lock};
     auto snap_info_it = m_dst_image_ctx->snap_info.find(m_prev_snap_id);
     if (snap_info_it != m_dst_image_ctx->snap_info.end()) {
       snap_info_it->second.protection_status =
@@ -224,15 +238,17 @@ void SnapshotCopyRequest<I>::send_snap_remove() {
   SnapIdSet::iterator snap_id_it = m_dst_snap_ids.begin();
   if (m_prev_snap_id != CEPH_NOSNAP) {
     snap_id_it = m_dst_snap_ids.upper_bound(m_prev_snap_id);
+  } else if (m_dst_snap_id_start > 0) {
+    snap_id_it = m_dst_snap_ids.upper_bound(m_dst_snap_id_start);
   }
 
   for (; snap_id_it != m_dst_snap_ids.end(); ++snap_id_it) {
     librados::snap_t dst_snap_id = *snap_id_it;
 
     cls::rbd::SnapshotNamespace snap_namespace;
-    m_dst_image_ctx->snap_lock.get_read();
+    m_dst_image_ctx->image_lock.lock_shared();
     int r = m_dst_image_ctx->get_snap_namespace(dst_snap_id, &snap_namespace);
-    m_dst_image_ctx->snap_lock.put_read();
+    m_dst_image_ctx->image_lock.unlock_shared();
     if (r < 0) {
       lderr(m_cct) << "failed to retrieve destination snap namespace: "
                    << m_snap_name << dendl;
@@ -279,11 +295,11 @@ void SnapshotCopyRequest<I>::send_snap_remove() {
     return;
   }
 
-  auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
+  auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
       handle_snap_remove(r);
       finish_op_ctx->complete(0);
     });
-  RWLock::RLocker owner_locker(m_dst_image_ctx->owner_lock);
+  std::shared_lock owner_locker{m_dst_image_ctx->owner_lock};
   m_dst_image_ctx->operations->execute_snap_remove(
     cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx);
 }
@@ -310,15 +326,17 @@ void SnapshotCopyRequest<I>::send_snap_create() {
   SnapIdSet::iterator snap_id_it = m_src_snap_ids.begin();
   if (m_prev_snap_id != CEPH_NOSNAP) {
     snap_id_it = m_src_snap_ids.upper_bound(m_prev_snap_id);
+  } else if (m_src_snap_id_start > 0) {
+    snap_id_it = m_src_snap_ids.upper_bound(m_src_snap_id_start);
   }
 
   for (; snap_id_it != m_src_snap_ids.end(); ++snap_id_it) {
     librados::snap_t src_snap_id = *snap_id_it;
 
     cls::rbd::SnapshotNamespace snap_namespace;
-    m_src_image_ctx->snap_lock.get_read();
+    m_src_image_ctx->image_lock.lock_shared();
     int r = m_src_image_ctx->get_snap_namespace(src_snap_id, &snap_namespace);
-    m_src_image_ctx->snap_lock.put_read();
+    m_src_image_ctx->image_lock.unlock_shared();
     if (r < 0) {
       lderr(m_cct) << "failed to retrieve source snap namespace: "
                    << m_snap_name << dendl;
@@ -326,10 +344,17 @@ void SnapshotCopyRequest<I>::send_snap_create() {
       return;
     }
 
-    // if the source snapshot isn't in our mapping table, create it
-    if (m_snap_seqs.find(src_snap_id) == m_snap_seqs.end() &&
-       boost::get<cls::rbd::UserSnapshotNamespace>(&snap_namespace) != nullptr) {
-      break;
+    if (m_snap_seqs.find(src_snap_id) == m_snap_seqs.end()) {
+      // the source snapshot is not in our mapping table, ...
+      if (boost::get<cls::rbd::UserSnapshotNamespace>(&snap_namespace) !=
+            nullptr) {
+        // ... create it since it's a user snapshot
+        break;
+      } else if (src_snap_id == m_src_snap_id_end) {
+        // ... map it to destination HEAD since it's not a user snapshot that we
+        // will create (e.g. MirrorSnapshotNamespace)
+        m_snap_seqs[src_snap_id] = CEPH_NOSNAP;
+      }
     }
   }
 
@@ -343,10 +368,10 @@ void SnapshotCopyRequest<I>::send_snap_create() {
   m_prev_snap_id = *snap_id_it;
   m_snap_name = get_snapshot_name(m_src_image_ctx, m_prev_snap_id);
 
-  m_src_image_ctx->snap_lock.get_read();
+  m_src_image_ctx->image_lock.lock_shared();
   auto snap_info_it = m_src_image_ctx->snap_info.find(m_prev_snap_id);
   if (snap_info_it == m_src_image_ctx->snap_info.end()) {
-    m_src_image_ctx->snap_lock.put_read();
+    m_src_image_ctx->image_lock.unlock_shared();
     lderr(m_cct) << "failed to retrieve source snap info: " << m_snap_name
                  << dendl;
     finish(-ENOENT);
@@ -361,7 +386,7 @@ void SnapshotCopyRequest<I>::send_snap_create() {
     parent_spec = m_dst_parent_spec;
     parent_overlap = snap_info_it->second.parent.overlap;
   }
-  m_src_image_ctx->snap_lock.put_read();
+  m_src_image_ctx->image_lock.unlock_shared();
 
   ldout(m_cct, 20) << "snap_name=" << m_snap_name << ", "
                    << "snap_id=" << m_prev_snap_id << ", "
@@ -380,7 +405,7 @@ void SnapshotCopyRequest<I>::send_snap_create() {
     return;
   }
 
-  auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
+  auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
       handle_snap_create(r);
       finish_op_ctx->complete(0);
     });
@@ -396,7 +421,7 @@ void SnapshotCopyRequest<I>::handle_snap_create(int r) {
 
   if (r < 0) {
     lderr(m_cct) << "failed to create snapshot '" << m_snap_name << "': "
-         << cpp_strerror(r) << dendl;
+                 << cpp_strerror(r) << dendl;
     finish(r);
     return;
   }
@@ -423,23 +448,25 @@ void SnapshotCopyRequest<I>::send_snap_protect() {
   SnapIdSet::iterator snap_id_it = m_src_snap_ids.begin();
   if (m_prev_snap_id != CEPH_NOSNAP) {
     snap_id_it = m_src_snap_ids.upper_bound(m_prev_snap_id);
+  } else if (m_src_snap_id_start > 0) {
+    snap_id_it = m_src_snap_ids.upper_bound(m_src_snap_id_start);
   }
 
   for (; snap_id_it != m_src_snap_ids.end(); ++snap_id_it) {
     librados::snap_t src_snap_id = *snap_id_it;
 
-    m_src_image_ctx->snap_lock.get_read();
+    m_src_image_ctx->image_lock.lock_shared();
 
     bool src_protected;
     int r = m_src_image_ctx->is_snap_protected(src_snap_id, &src_protected);
     if (r < 0) {
       lderr(m_cct) << "failed to retrieve source snap protect status: "
                    << cpp_strerror(r) << dendl;
-      m_src_image_ctx->snap_lock.put_read();
+      m_src_image_ctx->image_lock.unlock_shared();
       finish(r);
       return;
     }
-    m_src_image_ctx->snap_lock.put_read();
+    m_src_image_ctx->image_lock.unlock_shared();
 
     if (!src_protected) {
       // snap is not protected -- check next snap
@@ -449,18 +476,23 @@ void SnapshotCopyRequest<I>::send_snap_protect() {
     // if destination snapshot is not protected, protect it
     auto snap_seq_it = m_snap_seqs.find(src_snap_id);
     ceph_assert(snap_seq_it != m_snap_seqs.end());
+    if (snap_seq_it->second == CEPH_NOSNAP) {
+      // implies src end snapshot is mapped to a non-copyable snapshot
+      ceph_assert(src_snap_id == m_src_snap_id_end);
+      break;
+    }
 
-    m_dst_image_ctx->snap_lock.get_read();
+    m_dst_image_ctx->image_lock.lock_shared();
     bool dst_protected;
     r = m_dst_image_ctx->is_snap_protected(snap_seq_it->second, &dst_protected);
     if (r < 0) {
       lderr(m_cct) << "failed to retrieve destination snap protect status: "
                    << cpp_strerror(r) << dendl;
-      m_dst_image_ctx->snap_lock.put_read();
+      m_dst_image_ctx->image_lock.unlock_shared();
       finish(r);
       return;
     }
-    m_dst_image_ctx->snap_lock.put_read();
+    m_dst_image_ctx->image_lock.unlock_shared();
 
     if (!dst_protected) {
       break;
@@ -488,11 +520,11 @@ void SnapshotCopyRequest<I>::send_snap_protect() {
     return;
   }
 
-  auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
+  auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
       handle_snap_protect(r);
       finish_op_ctx->complete(0);
     });
-  RWLock::RLocker owner_locker(m_dst_image_ctx->owner_lock);
+  std::shared_lock owner_locker{m_dst_image_ctx->owner_lock};
   m_dst_image_ctx->operations->execute_snap_protect(
     cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx);
 }
@@ -516,7 +548,11 @@ void SnapshotCopyRequest<I>::handle_snap_protect(int r) {
 
 template <typename I>
 void SnapshotCopyRequest<I>::send_set_head() {
-  if (m_snap_id_end != CEPH_NOSNAP) {
+  auto snap_seq_it = m_snap_seqs.find(m_src_snap_id_end);
+  if (m_src_snap_id_end != CEPH_NOSNAP &&
+      (snap_seq_it == m_snap_seqs.end() ||
+       snap_seq_it->second != CEPH_NOSNAP)) {
+    // not copying to src nor dst HEAD revision
     finish(0);
     return;
   }
@@ -527,11 +563,21 @@ void SnapshotCopyRequest<I>::send_set_head() {
   cls::rbd::ParentImageSpec parent_spec;
   uint64_t parent_overlap = 0;
   {
-    RWLock::RLocker src_locker(m_src_image_ctx->snap_lock);
-    size = m_src_image_ctx->size;
-    if (!m_flatten) {
-      parent_spec = m_src_image_ctx->parent_md.spec;
-      parent_overlap = m_src_image_ctx->parent_md.overlap;
+    std::shared_lock src_locker{m_src_image_ctx->image_lock};
+    auto snap_info_it = m_src_image_ctx->snap_info.find(m_src_snap_id_end);
+    if (snap_info_it != m_src_image_ctx->snap_info.end()) {
+      auto& snap_info = snap_info_it->second;
+      size = snap_info.size;
+      if (!m_flatten && snap_info.parent.spec.pool_id != -1) {
+        parent_spec = m_dst_parent_spec;
+        parent_overlap = snap_info.parent.overlap;
+      }
+    } else {
+      size = m_src_image_ctx->size;
+      if (!m_flatten) {
+        parent_spec = m_dst_image_ctx->parent_md.spec;
+        parent_overlap = m_src_image_ctx->parent_md.overlap;
+      }
     }
   }
 
@@ -563,10 +609,9 @@ template <typename I>
 void SnapshotCopyRequest<I>::send_resize_object_map() {
   int r = 0;
 
-  if (m_snap_id_end == CEPH_NOSNAP &&
-      m_dst_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP)) {
-    RWLock::RLocker owner_locker(m_dst_image_ctx->owner_lock);
-    RWLock::RLocker snap_locker(m_dst_image_ctx->snap_lock);
+  if (m_dst_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+    std::shared_lock owner_locker{m_dst_image_ctx->owner_lock};
+    std::shared_lock image_locker{m_dst_image_ctx->image_lock};
 
     if (m_dst_image_ctx->object_map != nullptr &&
         Striper::get_num_objects(m_dst_image_ctx->layout,
@@ -577,7 +622,7 @@ void SnapshotCopyRequest<I>::send_resize_object_map() {
 
       auto finish_op_ctx = start_lock_op(m_dst_image_ctx->owner_lock, &r);
       if (finish_op_ctx != nullptr) {
-        auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
+        auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
             handle_resize_object_map(r);
             finish_op_ctx->complete(0);
           });
@@ -611,7 +656,7 @@ void SnapshotCopyRequest<I>::handle_resize_object_map(int r) {
 template <typename I>
 bool SnapshotCopyRequest<I>::handle_cancellation() {
   {
-    Mutex::Locker locker(m_lock);
+    std::lock_guard locker{m_lock};
     if (!m_canceled) {
       return false;
     }
@@ -625,14 +670,14 @@ template <typename I>
 void SnapshotCopyRequest<I>::error(int r) {
   ldout(m_cct, 20) << "r=" << r << dendl;
 
-  m_work_queue->queue(new FunctionContext([this, r](int r1) { finish(r); }));
+  m_work_queue->queue(new LambdaContext([this, r](int r1) { finish(r); }));
 }
 
 template <typename I>
 int SnapshotCopyRequest<I>::validate_parent(I *image_ctx,
                                             cls::rbd::ParentImageSpec *spec) {
-  RWLock::RLocker owner_locker(image_ctx->owner_lock);
-  RWLock::RLocker snap_locker(image_ctx->snap_lock);
+  std::shared_lock owner_locker{image_ctx->owner_lock};
+  std::shared_lock image_locker{image_ctx->image_lock};
 
   // ensure source image's parent specs are still consistent
   *spec = image_ctx->parent_md.spec;
@@ -654,15 +699,15 @@ int SnapshotCopyRequest<I>::validate_parent(I *image_ctx,
 
 template <typename I>
 Context *SnapshotCopyRequest<I>::start_lock_op(int* r) {
-  RWLock::RLocker owner_locker(m_dst_image_ctx->owner_lock);
+  std::shared_lock owner_locker{m_dst_image_ctx->owner_lock};
   return start_lock_op(m_dst_image_ctx->owner_lock, r);
 }
 
 template <typename I>
-Context *SnapshotCopyRequest<I>::start_lock_op(RWLock &owner_lock, int* r) {
-  ceph_assert(m_dst_image_ctx->owner_lock.is_locked());
+Context *SnapshotCopyRequest<I>::start_lock_op(ceph::shared_mutex &owner_lock, int* r) {
+  ceph_assert(ceph_mutex_is_locked(m_dst_image_ctx->owner_lock));
   if (m_dst_image_ctx->exclusive_lock == nullptr) {
-    return new FunctionContext([](int r) {});
+    return new LambdaContext([](int r) {});
   }
   return m_dst_image_ctx->exclusive_lock->start_op(r);
 }