]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/librbd/io/CopyupRequest.cc
update sources to v12.2.3
[ceph.git] / ceph / src / librbd / io / CopyupRequest.cc
index 0f1d34f2075749a3faa8aca80d1c9e9bc9377c03..4ae6878bcc99661b10bc134ac324f9b8d09ffec0 100644 (file)
@@ -35,9 +35,9 @@ class UpdateObjectMap : public C_AsyncObjectThrottle<> {
 public:
   UpdateObjectMap(AsyncObjectThrottle<> &throttle, ImageCtx *image_ctx,
                   uint64_t object_no, const std::vector<uint64_t> *snap_ids,
-                  size_t snap_id_idx)
-    : C_AsyncObjectThrottle(throttle, *image_ctx),
-      m_object_no(object_no), m_snap_ids(*snap_ids), m_snap_id_idx(snap_id_idx)
+                  const ZTracer::Trace &trace, size_t snap_id_idx)
+    : C_AsyncObjectThrottle(throttle, *image_ctx), m_object_no(object_no),
+      m_snap_ids(*snap_ids), m_trace(trace), m_snap_id_idx(snap_id_idx)
   {
   }
 
@@ -49,7 +49,7 @@ public:
       assert(m_image_ctx.exclusive_lock->is_lock_owner());
       assert(m_image_ctx.object_map != nullptr);
       bool sent = m_image_ctx.object_map->aio_update<Context>(
-        CEPH_NOSNAP, m_object_no, OBJECT_EXISTS, {}, this);
+        CEPH_NOSNAP, m_object_no, OBJECT_EXISTS, {}, m_trace, this);
       return (sent ? 0 : 1);
     }
 
@@ -66,7 +66,7 @@ public:
     }
 
     bool sent = m_image_ctx.object_map->aio_update<Context>(
-      snap_id, m_object_no, state, {}, this);
+      snap_id, m_object_no, state, {}, m_trace, this);
     assert(sent);
     return 0;
   }
@@ -74,47 +74,53 @@ public:
 private:
   uint64_t m_object_no;
   const std::vector<uint64_t> &m_snap_ids;
+  const ZTracer::Trace &m_trace;
   size_t m_snap_id_idx;
 };
 
 } // anonymous namespace
 
-
-CopyupRequest::CopyupRequest(ImageCtx *ictx, const std::string &oid,
-                             uint64_t objectno, Extents &&image_extents)
-  : m_ictx(ictx), m_oid(oid), m_object_no(objectno),
-    m_image_extents(image_extents), m_state(STATE_READ_FROM_PARENT)
+template <typename I>
+CopyupRequest<I>::CopyupRequest(I *ictx, const std::string &oid,
+                                uint64_t objectno, Extents &&image_extents,
+                                const ZTracer::Trace &parent_trace)
+  : m_ictx(util::get_image_ctx(ictx)), m_oid(oid), m_object_no(objectno),
+    m_image_extents(image_extents),
+    m_trace(util::create_trace(*m_ictx, "copy-up", parent_trace)),
+    m_state(STATE_READ_FROM_PARENT), m_lock("CopyupRequest", false, false)
 {
   m_async_op.start_op(*m_ictx);
 }
 
-CopyupRequest::~CopyupRequest() {
+template <typename I>
+CopyupRequest<I>::~CopyupRequest() {
   assert(m_pending_requests.empty());
   m_async_op.finish_op();
 }
 
-void CopyupRequest::append_request(ObjectRequest<> *req) {
+template <typename I>
+void CopyupRequest<I>::append_request(AbstractObjectWriteRequest<I> *req) {
   ldout(m_ictx->cct, 20) << req << dendl;
   m_pending_requests.push_back(req);
 }
 
-void CopyupRequest::complete_requests(int r) {
+template <typename I>
+void CopyupRequest<I>::complete_requests(int r) {
   while (!m_pending_requests.empty()) {
-    vector<ObjectRequest<> *>::iterator it = m_pending_requests.begin();
-    ObjectRequest<> *req = *it;
+    auto it = m_pending_requests.begin();
+    auto req = *it;
     ldout(m_ictx->cct, 20) << "completing request " << req << dendl;
-    req->complete(r);
+    req->handle_copyup(r);
     m_pending_requests.erase(it);
   }
 }
 
-bool CopyupRequest::send_copyup() {
-  bool add_copyup_op = !m_copyup_data.is_zero();
+template <typename I>
+bool CopyupRequest<I>::send_copyup() {
   bool copy_on_read = m_pending_requests.empty();
-  if (!add_copyup_op && copy_on_read) {
-    // copyup empty object to prevent future CoR attempts
+  bool add_copyup_op = !m_copyup_data.is_zero();
+  if (!add_copyup_op) {
     m_copyup_data.clear();
-    add_copyup_op = true;
   }
 
   ldout(m_ictx->cct, 20) << "oid " << m_oid << dendl;
@@ -126,17 +132,15 @@ bool CopyupRequest::send_copyup() {
 
   std::vector<librados::snap_t> snaps;
 
-  if (!copy_on_read) {
-    m_pending_copyups++;
-  }
-
+  Mutex::Locker locker(m_lock);
   int r;
   if (copy_on_read || (!snapc.snaps.empty() && add_copyup_op)) {
-    assert(add_copyup_op);
-    add_copyup_op = false;
 
     librados::ObjectWriteOperation copyup_op;
     copyup_op.exec("rbd", "copyup", m_copyup_data);
+    m_copyup_data.clear();
+
+    ObjectRequest<I>::add_write_hint(*m_ictx, &copyup_op);
 
     // send only the copyup request with a blank snapshot context so that
     // all snapshots are detected from the parent for this object.  If
@@ -151,48 +155,59 @@ bool CopyupRequest::send_copyup() {
     r = rados.ioctx_create2(m_ictx->data_ctx.get_id(), m_data_ctx);
     assert(r == 0);
 
-    r = m_data_ctx.aio_operate(m_oid, comp, &copyup_op, 0, snaps);
+    r = m_data_ctx.aio_operate(
+      m_oid, comp, &copyup_op, 0, snaps,
+      (m_trace.valid() ? m_trace.get_info() : nullptr));
     assert(r == 0);
     comp->release();
   }
 
   if (!copy_on_read) {
     librados::ObjectWriteOperation write_op;
-    if (add_copyup_op) {
-      // CoW did not need to handle existing snapshots
-      write_op.exec("rbd", "copyup", m_copyup_data);
-    }
+    write_op.exec("rbd", "copyup", m_copyup_data);
 
     // merge all pending write ops into this single RADOS op
-    for (size_t i=0; i<m_pending_requests.size(); ++i) {
-      ObjectRequest<> *req = m_pending_requests[i];
+    ObjectRequest<I>::add_write_hint(*m_ictx, &write_op);
+    for (auto req : m_pending_requests) {
       ldout(m_ictx->cct, 20) << "add_copyup_ops " << req << dendl;
       req->add_copyup_ops(&write_op);
     }
-    assert(write_op.size() != 0);
+
+    m_pending_copyups++;
 
     snaps.insert(snaps.end(), snapc.snaps.begin(), snapc.snaps.end());
     librados::AioCompletion *comp = util::create_rados_callback(this);
-    r = m_ictx->data_ctx.aio_operate(m_oid, comp, &write_op);
+    r = m_ictx->data_ctx.aio_operate(
+      m_oid, comp, &write_op, snapc.seq, snaps,
+      (m_trace.valid() ? m_trace.get_info() : nullptr));
     assert(r == 0);
     comp->release();
   }
   return false;
 }
 
-bool CopyupRequest::is_copyup_required() {
-  bool noop = true;
-  for (const ObjectRequest<> *req : m_pending_requests) {
-    if (!req->is_op_payload_empty()) {
-      noop = false;
-      break;
-    }
+template <typename I>
+bool CopyupRequest<I>::is_copyup_required() {
+  bool copy_on_read = m_pending_requests.empty();
+  if (copy_on_read) {
+    // always force a copyup if CoR enabled
+    return true;
+  }
+
+  if (!m_copyup_data.is_zero()) {
+    return true;
   }
 
-  return (m_copyup_data.is_zero() && noop);
+  for (auto req : m_pending_requests) {
+    if (!req->is_empty_write_op()) {
+      return true;
+    }
+  }
+  return false;
 }
 
-void CopyupRequest::send()
+template <typename I>
+void CopyupRequest<I>::send()
 {
   m_state = STATE_READ_FROM_PARENT;
   AioCompletion *comp = AioCompletion::create_and_start(
@@ -203,10 +218,11 @@ void CopyupRequest::send()
                          << ", extents " << m_image_extents
                          << dendl;
   ImageRequest<>::aio_read(m_ictx->parent, comp, std::move(m_image_extents),
-                           ReadResult{&m_copyup_data}, 0);
+                           ReadResult{&m_copyup_data}, 0, m_trace);
 }
 
-void CopyupRequest::complete(int r)
+template <typename I>
+void CopyupRequest<I>::complete(int r)
 {
   if (should_complete(r)) {
     complete_requests(r);
@@ -214,7 +230,8 @@ void CopyupRequest::complete(int r)
   }
 }
 
-bool CopyupRequest::should_complete(int r)
+template <typename I>
+bool CopyupRequest<I>::should_complete(int r)
 {
   CephContext *cct = m_ictx->cct;
   ldout(cct, 20) << "oid " << m_oid
@@ -226,7 +243,7 @@ bool CopyupRequest::should_complete(int r)
     ldout(cct, 20) << "READ_FROM_PARENT" << dendl;
     remove_from_list();
     if (r >= 0 || r == -ENOENT) {
-      if (is_copyup_required()) {
+      if (!is_copyup_required()) {
         ldout(cct, 20) << "nop, skipping" << dendl;
         return true;
       }
@@ -246,8 +263,11 @@ bool CopyupRequest::should_complete(int r)
     return send_copyup();
 
   case STATE_COPYUP:
-    // invoked via a finisher in librados, so thread safe
-    pending_copyups = --m_pending_copyups;
+    {
+      Mutex::Locker locker(m_lock);
+      assert(m_pending_copyups > 0);
+      pending_copyups = --m_pending_copyups;
+    }
     ldout(cct, 20) << "COPYUP (" << pending_copyups << " pending)"
                    << dendl;
     if (r == -ENOENT) {
@@ -268,17 +288,18 @@ bool CopyupRequest::should_complete(int r)
   return (r < 0);
 }
 
-void CopyupRequest::remove_from_list()
+template <typename I>
+void CopyupRequest<I>::remove_from_list()
 {
   Mutex::Locker l(m_ictx->copyup_list_lock);
 
-  map<uint64_t, CopyupRequest*>::iterator it =
-    m_ictx->copyup_list.find(m_object_no);
+  auto it = m_ictx->copyup_list.find(m_object_no);
   assert(it != m_ictx->copyup_list.end());
   m_ictx->copyup_list.erase(it);
 }
 
-bool CopyupRequest::send_object_map_head() {
+template <typename I>
+bool CopyupRequest<I>::send_object_map_head() {
   CephContext *cct = m_ictx->cct;
   ldout(cct, 20) << dendl;
 
@@ -306,28 +327,26 @@ bool CopyupRequest::send_object_map_head() {
       }
 
       bool may_update = false;
-      uint8_t new_state, current_state;
+      uint8_t new_state;
+      uint8_t current_state = (*m_ictx->object_map)[m_object_no];
 
-      vector<ObjectRequest<> *>::reverse_iterator r_it = m_pending_requests.rbegin();
-      for (; r_it != m_pending_requests.rend(); ++r_it) {
-        ObjectRequest<> *req = *r_it;
-        if (!req->pre_object_map_update(&new_state)) {
-          continue;
-        }
+      auto r_it = m_pending_requests.rbegin();
+      if (r_it != m_pending_requests.rend()) {
+        auto req = *r_it;
+        new_state = req->get_pre_write_object_map_state();
 
-        current_state = (*m_ictx->object_map)[m_object_no];
         ldout(cct, 20) << req->get_op_type() << " object no "
                        << m_object_no << " current state "
                        << stringify(static_cast<uint32_t>(current_state))
                        << " new state " << stringify(static_cast<uint32_t>(new_state))
                        << dendl;
         may_update = true;
-        break;
       }
 
       if (may_update && (new_state != current_state) &&
           m_ictx->object_map->aio_update<CopyupRequest>(
-            CEPH_NOSNAP, m_object_no, new_state, current_state, this)) {
+            CEPH_NOSNAP, m_object_no, new_state, current_state, m_trace,
+            this)) {
         return false;
       }
     }
@@ -336,7 +355,8 @@ bool CopyupRequest::send_object_map_head() {
   return send_object_map();
 }
 
-bool CopyupRequest::send_object_map() {
+template <typename I>
+bool CopyupRequest<I>::send_object_map() {
   // avoid possible recursive lock attempts
   if (m_snap_ids.empty()) {
     // no object map update required
@@ -349,7 +369,7 @@ bool CopyupRequest::send_object_map() {
     RWLock::RLocker owner_locker(m_ictx->owner_lock);
     AsyncObjectThrottle<>::ContextFactory context_factory(
       boost::lambda::bind(boost::lambda::new_ptr<UpdateObjectMap>(),
-      boost::lambda::_1, m_ictx, m_object_no, &m_snap_ids,
+      boost::lambda::_1, m_ictx, m_object_no, &m_snap_ids, m_trace,
       boost::lambda::_2));
     AsyncObjectThrottle<> *throttle = new AsyncObjectThrottle<>(
       NULL, *m_ictx, context_factory, util::create_context_callback(this),
@@ -361,3 +381,5 @@ bool CopyupRequest::send_object_map() {
 
 } // namespace io
 } // namespace librbd
+
+template class librbd::io::CopyupRequest<librbd::ImageCtx>;