]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/librbd/image/RemoveRequest.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / librbd / image / RemoveRequest.cc
index 10efaa677df7c235c9a1fc49e98fc6aa2c949f69..1cff51b3eae5d777f9fa62079df35e3bfeb098e0 100644 (file)
@@ -1,19 +1,19 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 // vim: ts=8 sw=2 smarttab
 
+#include "librbd/image/RemoveRequest.h"
 #include "common/dout.h"
 #include "common/errno.h"
 #include "librbd/internal.h"
 #include "librbd/ImageState.h"
 #include "librbd/Journal.h"
 #include "librbd/ObjectMap.h"
-#include "librbd/ExclusiveLock.h"
 #include "librbd/MirroringWatcher.h"
-#include "librbd/journal/DisabledPolicy.h"
+#include "librbd/image/DetachChildRequest.h"
+#include "librbd/image/PreRemoveRequest.h"
 #include "librbd/journal/RemoveRequest.h"
-#include "librbd/image/RemoveRequest.h"
-#include "librbd/operation/TrimRequest.h"
 #include "librbd/mirror/DisableRequest.h"
+#include "librbd/operation/TrimRequest.h"
 
 #define dout_subsys ceph_subsys_rbd
 #undef dout_prefix
@@ -39,9 +39,19 @@ RemoveRequest<I>::RemoveRequest(IoCtx &ioctx, const std::string &image_name,
     m_prog_ctx(prog_ctx), m_op_work_queue(op_work_queue),
     m_on_finish(on_finish) {
   m_cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
+}
 
-  m_image_ctx = I::create((m_image_id.empty() ? m_image_name : std::string()),
-                          m_image_id, nullptr, m_ioctx, false);
+template<typename I>
+RemoveRequest<I>::RemoveRequest(IoCtx &ioctx, I *image_ctx, bool force,
+                                bool from_trash_remove,
+                                ProgressContext &prog_ctx,
+                                ContextWQ *op_work_queue, Context *on_finish)
+  : m_ioctx(ioctx), m_image_name(image_ctx->name), m_image_id(image_ctx->id),
+    m_image_ctx(image_ctx), m_force(force),
+    m_from_trash_remove(from_trash_remove), m_prog_ctx(prog_ctx),
+    m_op_work_queue(op_work_queue), m_on_finish(on_finish),
+    m_cct(image_ctx->cct), m_header_oid(image_ctx->header_oid),
+    m_old_format(image_ctx->old_format), m_unknown_format(false) {
 }
 
 template<typename I>
@@ -53,13 +63,21 @@ void RemoveRequest<I>::send() {
 
 template<typename I>
 void RemoveRequest<I>::open_image() {
+  if (m_image_ctx != nullptr) {
+    pre_remove_image();
+    return;
+  }
+
+  m_image_ctx = I::create(m_image_id.empty() ? m_image_name : "", m_image_id,
+                          nullptr, m_ioctx, false);
+
   ldout(m_cct, 20) << dendl;
 
   using klass = RemoveRequest<I>;
   Context *ctx = create_context_callback<klass, &klass::handle_open_image>(
     this);
 
-  m_image_ctx->state->open(true, ctx);
+  m_image_ctx->state->open(OPEN_FLAG_SKIP_OPEN_PARENT, ctx);
 }
 
 template<typename I>
@@ -86,254 +104,28 @@ void RemoveRequest<I>::handle_open_image(int r) {
   m_old_format = m_image_ctx->old_format;
   m_unknown_format = false;
 
-  check_exclusive_lock();
-}
-
-template<typename I>
-void RemoveRequest<I>::check_exclusive_lock() {
-  ldout(m_cct, 20) << dendl;
-
-  if (m_image_ctx->exclusive_lock == nullptr) {
-    validate_image_removal();
-  } else {
-    acquire_exclusive_lock();
-  }
+  pre_remove_image();
 }
 
 template<typename I>
-void RemoveRequest<I>::acquire_exclusive_lock() {
-  ldout(m_cct, 20) << dendl;
+void RemoveRequest<I>::pre_remove_image() {
+  ldout(m_cct, 5) << dendl;
 
-  // do not attempt to open the journal when removing the image in case
-  // it's corrupt
-  if (m_image_ctx->test_features(RBD_FEATURE_JOURNALING)) {
-    RWLock::WLocker snap_locker(m_image_ctx->snap_lock);
-    m_image_ctx->set_journal_policy(new journal::DisabledPolicy());
-  }
-
-  using klass = RemoveRequest<I>;
-  if (m_force) {
-    Context *ctx = create_context_callback<
-      klass, &klass::handle_exclusive_lock_force>(this);
-    m_exclusive_lock = m_image_ctx->exclusive_lock;
-    m_exclusive_lock->shut_down(ctx);
-  } else {
-    Context *ctx = create_context_callback<
-      klass, &klass::handle_exclusive_lock>(this);
-    RWLock::WLocker owner_lock(m_image_ctx->owner_lock);
-    m_image_ctx->exclusive_lock->try_acquire_lock(ctx);
-  }
-}
-
-template<typename I>
-void RemoveRequest<I>::handle_exclusive_lock_force(int r) {
-  ldout(m_cct, 20) << "r=" << r << dendl;
-
-  delete m_exclusive_lock;
-  m_exclusive_lock = nullptr;
-
-  if (r < 0) {
-    lderr(m_cct) << "error shutting down exclusive lock: "
-                 << cpp_strerror(r) << dendl;
-    send_close_image(r);
-    return;
-  }
-
-  assert(m_image_ctx->exclusive_lock == nullptr);
-  validate_image_removal();
-}
-
-template<typename I>
-void RemoveRequest<I>::handle_exclusive_lock(int r) {
-  ldout(m_cct, 20) << "r=" << r << dendl;
-
-  if (r < 0 || !m_image_ctx->exclusive_lock->is_lock_owner()) {
-    lderr(m_cct) << "cannot obtain exclusive lock - not removing" << dendl;
-    send_close_image(-EBUSY);
-    return;
-  }
-
-  validate_image_removal();
-}
-
-template<typename I>
-void RemoveRequest<I>::validate_image_removal() {
-  ldout(m_cct, 20) << dendl;
-
-  check_image_snaps();
-}
-
-template<typename I>
-void RemoveRequest<I>::check_image_snaps() {
-  ldout(m_cct, 20) << dendl;
-
-  if (m_image_ctx->snaps.size()) {
-    lderr(m_cct) << "image has snapshots - not removing" << dendl;
-    send_close_image(-ENOTEMPTY);
-    return;
-  }
-
-  list_image_watchers();
-}
-
-template<typename I>
-void RemoveRequest<I>::list_image_watchers() {
-  ldout(m_cct, 20) << dendl;
-
-  librados::ObjectReadOperation op;
-  op.list_watchers(&m_watchers, &m_ret_val);
-
-  using klass = RemoveRequest<I>;
-  librados::AioCompletion *rados_completion =
-    create_rados_callback<klass, &klass::handle_list_image_watchers>(this);
-
-  int r = m_image_ctx->md_ctx.aio_operate(m_header_oid, rados_completion,
-                                          &op, &m_out_bl);
-  assert(r == 0);
-  rados_completion->release();
+  auto ctx = create_context_callback<
+    RemoveRequest<I>, &RemoveRequest<I>::handle_pre_remove_image>(this);
+  auto req = PreRemoveRequest<I>::create(m_image_ctx, m_force, ctx);
+  req->send();
 }
 
 template<typename I>
-void RemoveRequest<I>::handle_list_image_watchers(int r) {
-  ldout(m_cct, 20) << "r=" << r << dendl;
+void RemoveRequest<I>::handle_pre_remove_image(int r) {
+  ldout(m_cct, 5) << "r=" << r << dendl;
 
-  if (r == 0 && m_ret_val < 0) {
-    r = m_ret_val;
-  }
   if (r < 0) {
-    lderr(m_cct) << "error listing image watchers: " << cpp_strerror(r)
-                 << dendl;
-    send_close_image(r);
-    return;
-  }
-
-  get_mirror_image();
-}
-
-template<typename I>
-void RemoveRequest<I>::get_mirror_image() {
-  ldout(m_cct, 20) << dendl;
-  if ((m_watchers.empty()) ||
-      ((m_image_ctx->features & RBD_FEATURE_JOURNALING) == 0)) {
-    check_image_watchers();
-    return;
-  }
-
-  librados::ObjectReadOperation op;
-  cls_client::mirror_image_get_start(&op, m_image_id);
-
-  using klass = RemoveRequest<I>;
-  librados::AioCompletion *comp =
-    create_rados_callback<klass, &klass::handle_get_mirror_image>(this);
-  m_out_bl.clear();
-  int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
-  assert(r == 0);
-  comp->release();
-}
-
-template<typename I>
-void RemoveRequest<I>::handle_get_mirror_image(int r) {
-  ldout(m_cct, 20) << "r=" << r << dendl;
-
-  if (r == -ENOENT || r == -EOPNOTSUPP) {
-    check_image_watchers();
-    return;
-  } else if (r < 0) {
-    ldout(m_cct, 5) << "error retrieving mirror image: " << cpp_strerror(r)
-                    << dendl;
-  }
-
-  list_mirror_watchers();
-}
-
-template<typename I>
-void RemoveRequest<I>::list_mirror_watchers() {
-  ldout(m_cct, 20) << dendl;
-
-  librados::ObjectReadOperation op;
-  op.list_watchers(&m_mirror_watchers, &m_ret_val);
-
-  using klass = RemoveRequest<I>;
-  librados::AioCompletion *rados_completion =
-    create_rados_callback<klass, &klass::handle_list_mirror_watchers>(this);
-  m_out_bl.clear();
-  int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, rados_completion,
-                                          &op, &m_out_bl);
-  assert(r == 0);
-  rados_completion->release();
-}
-
-template<typename I>
-void RemoveRequest<I>::handle_list_mirror_watchers(int r) {
-  ldout(m_cct, 20) << "r=" << r << dendl;
-
-  if (r == 0 && m_ret_val < 0) {
-    r = m_ret_val;
-  }
-  if (r < 0 && r != -ENOENT) {
-    ldout(m_cct, 5) << "error listing mirror watchers: " << cpp_strerror(r)
-                    << dendl;
-  }
-
-  for (auto &watcher : m_mirror_watchers) {
-    m_watchers.remove_if([watcher] (obj_watch_t &w) {
-        return (strncmp(w.addr, watcher.addr, sizeof(w.addr)) == 0);
-      });
-  }
-
-  check_image_watchers();
-}
-
-template<typename I>
-void RemoveRequest<I>::check_image_watchers() {
-  if (m_watchers.size() > 1) {
-    lderr(m_cct) << "image has watchers - not removing" << dendl;
-    send_close_image(-EBUSY);
-    return;
-  }
-
-  check_group();
-}
-
-template<typename I>
-void RemoveRequest<I>::check_group() {
-  ldout(m_cct, 20) << dendl;
-
-  librados::ObjectReadOperation op;
-  librbd::cls_client::image_get_group_start(&op);
-
-  using klass = RemoveRequest<I>;
-  librados::AioCompletion *rados_completion = create_rados_callback<
-    klass, &klass::handle_check_group>(this);
-  m_out_bl.clear();
-  int r = m_image_ctx->md_ctx.aio_operate(m_header_oid, rados_completion, &op,
-                                          &m_out_bl);
-  assert(r == 0);
-  rados_completion->release();
-}
-
-template<typename I>
-void RemoveRequest<I>::handle_check_group(int r) {
-  ldout(m_cct, 20) << "r=" << r << dendl;
-
-  cls::rbd::GroupSpec s;
-  if (r == 0) {
-    bufferlist::iterator it = m_out_bl.begin();
-    r = librbd::cls_client::image_get_group_finish(&it, &s);
-  }
-  if (r < 0 && r != -EOPNOTSUPP) {
-    lderr(m_cct) << "error fetching group for image: "
-                 << cpp_strerror(r) << dendl;
     send_close_image(r);
     return;
   }
 
-  if (s.is_valid()) {
-    lderr(m_cct) << "image is in a group - not removing" << dendl;
-    send_close_image(-EMLINK);
-    return;
-  }
-
   trim_image();
 }
 
@@ -357,8 +149,10 @@ void RemoveRequest<I>::handle_trim_image(int r) {
   ldout(m_cct, 20) << "r=" << r << dendl;
 
   if (r < 0) {
-    lderr(m_cct) << "warning: failed to remove some object(s): "
+    lderr(m_cct) << "failed to remove some object(s): "
                  << cpp_strerror(r) << dendl;
+    send_close_image(r);
+    return;
   }
 
   if (m_old_format) {
@@ -366,42 +160,30 @@ void RemoveRequest<I>::handle_trim_image(int r) {
     return;
   }
 
-  remove_child();
+  detach_child();
 }
 
 template<typename I>
-void RemoveRequest<I>::remove_child() {
+void RemoveRequest<I>::detach_child() {
   ldout(m_cct, 20) << dendl;
 
-  m_image_ctx->parent_lock.get_read();
-  ParentInfo parent_info = m_image_ctx->parent_md;
-  m_image_ctx->parent_lock.put_read();
-
-  librados::ObjectWriteOperation op;
-  librbd::cls_client::remove_child(&op, parent_info.spec, m_image_id);
-
-  using klass = RemoveRequest<I>;
-  librados::AioCompletion *rados_completion =
-    create_rados_callback<klass, &klass::handle_remove_child>(this);
-  int r = m_image_ctx->md_ctx.aio_operate(RBD_CHILDREN, rados_completion, &op);
-  assert(r == 0);
-  rados_completion->release();
+  auto ctx = create_context_callback<
+    RemoveRequest<I>, &RemoveRequest<I>::handle_detach_child>(this);
+  auto req = DetachChildRequest<I>::create(*m_image_ctx, ctx);
+  req->send();
 }
 
 template<typename I>
-void RemoveRequest<I>::handle_remove_child(int r) {
+void RemoveRequest<I>::handle_detach_child(int r) {
   ldout(m_cct, 20) << "r=" << r << dendl;
 
-  if (r == -ENOENT) {
-    r = 0;
-  } else if (r < 0) {
-    lderr(m_cct) << "error removing child from children list: "
+  if (r < 0) {
+    lderr(m_cct) << "failed to detach child from parent: "
                  << cpp_strerror(r) << dendl;
     send_close_image(r);
     return;
   }
 
-
   send_disable_mirror();
 }
 
@@ -472,7 +254,7 @@ void RemoveRequest<I>::remove_header() {
   librados::AioCompletion *rados_completion =
     create_rados_callback<klass, &klass::handle_remove_header>(this);
   int r = m_ioctx.aio_remove(m_header_oid, rados_completion);
-  assert(r == 0);
+  ceph_assert(r == 0);
   rados_completion->release();
 }
 
@@ -500,7 +282,7 @@ void RemoveRequest<I>::remove_header_v2() {
   librados::AioCompletion *rados_completion =
     create_rados_callback<klass, &klass::handle_remove_header_v2>(this);
   int r = m_ioctx.aio_remove(m_header_oid, rados_completion);
-  assert(r == 0);
+  ceph_assert(r == 0);
   rados_completion->release();
 }
 
@@ -557,7 +339,7 @@ void RemoveRequest<I>::send_object_map_remove() {
   int r = ObjectMap<>::aio_remove(m_ioctx,
                                  m_image_id,
                                   rados_completion);
-  assert(r == 0);
+  ceph_assert(r == 0);
   rados_completion->release();
 }
 
@@ -588,7 +370,7 @@ void RemoveRequest<I>::mirror_image_remove() {
   librados::AioCompletion *rados_completion =
     create_rados_callback<klass, &klass::handle_mirror_image_remove>(this);
   int r = m_ioctx.aio_operate(RBD_MIRRORING, rados_completion, &op);
-  assert(r == 0);
+  ceph_assert(r == 0);
   rados_completion->release();
 }
 
@@ -685,7 +467,7 @@ void RemoveRequest<I>::dir_get_image_id() {
     create_rados_callback<klass, &klass::handle_dir_get_image_id>(this);
   m_out_bl.clear();
   int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
-  assert(r == 0);
+  ceph_assert(r == 0);
   rados_completion->release();
 }
 
@@ -701,7 +483,7 @@ void RemoveRequest<I>::handle_dir_get_image_id(int r) {
   }
 
   if (r == 0) {
-    bufferlist::iterator iter = m_out_bl.begin();
+    auto iter = m_out_bl.cbegin();
     r = librbd::cls_client::dir_get_id_finish(&iter, &m_image_id);
     if (r < 0) {
       finish(r);
@@ -724,7 +506,7 @@ void RemoveRequest<I>::dir_get_image_name() {
     create_rados_callback<klass, &klass::handle_dir_get_image_name>(this);
   m_out_bl.clear();
   int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
-  assert(r == 0);
+  ceph_assert(r == 0);
   rados_completion->release();
 }
 
@@ -740,7 +522,7 @@ void RemoveRequest<I>::handle_dir_get_image_name(int r) {
   }
 
   if (r == 0) {
-    bufferlist::iterator iter = m_out_bl.begin();
+    auto iter = m_out_bl.cbegin();
     r = librbd::cls_client::dir_get_name_finish(&iter, &m_image_name);
     if (r < 0) {
       finish(r);
@@ -759,7 +541,7 @@ void RemoveRequest<I>::remove_id_object() {
   librados::AioCompletion *rados_completion =
     create_rados_callback<klass, &klass::handle_remove_id_object>(this);
   int r = m_ioctx.aio_remove(util::id_obj_name(m_image_name), rados_completion);
-  assert(r == 0);
+  ceph_assert(r == 0);
   rados_completion->release();
 }
 
@@ -788,7 +570,7 @@ void RemoveRequest<I>::dir_remove_image() {
   librados::AioCompletion *rados_completion =
     create_rados_callback<klass, &klass::handle_dir_remove_image>(this);
   int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op);
-  assert(r == 0);
+  ceph_assert(r == 0);
   rados_completion->release();
 }