1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/image/PreRemoveRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "cls/rbd/cls_rbd_types.h"
8 #include "librbd/ExclusiveLock.h"
9 #include "librbd/Utils.h"
10 #include "librbd/image/ListWatchersRequest.h"
11 #include "librbd/journal/DisabledPolicy.h"
12 #include "librbd/operation/SnapshotRemoveRequest.h"
14 #define dout_subsys ceph_subsys_rbd
16 #define dout_prefix *_dout << "librbd::image::PreRemoveRequest: " << this \
17 << " " << __func__ << ": "
24 bool auto_delete_snapshot(const SnapInfo
& snap_info
) {
25 auto snap_namespace_type
= cls::rbd::get_snap_namespace_type(
26 snap_info
.snap_namespace
);
27 switch (snap_namespace_type
) {
28 case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
:
35 bool ignore_snapshot(const SnapInfo
& snap_info
) {
36 auto snap_namespace_type
= cls::rbd::get_snap_namespace_type(
37 snap_info
.snap_namespace
);
38 switch (snap_namespace_type
) {
39 case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_MIRROR
:
46 } // anonymous namespace
48 using util::create_context_callback
;
49 using util::create_rados_callback
;
52 void PreRemoveRequest
<I
>::send() {
53 auto cct
= m_image_ctx
->cct
;
54 if (m_image_ctx
->operations_disabled
) {
55 lderr(cct
) << "image operations disabled due to unsupported op features"
61 acquire_exclusive_lock();
65 void PreRemoveRequest
<I
>::acquire_exclusive_lock() {
66 std::shared_lock owner_lock
{m_image_ctx
->owner_lock
};
67 if (m_image_ctx
->exclusive_lock
== nullptr) {
68 validate_image_removal();
72 auto cct
= m_image_ctx
->cct
;
73 ldout(cct
, 5) << dendl
;
75 // do not attempt to open the journal when removing the image in case
77 if (m_image_ctx
->test_features(RBD_FEATURE_JOURNALING
)) {
78 std::unique_lock image_locker
{m_image_ctx
->image_lock
};
79 m_image_ctx
->set_journal_policy(new journal::DisabledPolicy());
82 m_exclusive_lock
= m_image_ctx
->exclusive_lock
;
84 auto ctx
= create_context_callback
<
86 &PreRemoveRequest
<I
>::handle_exclusive_lock
>(this, m_exclusive_lock
);
87 m_exclusive_lock
->acquire_lock(ctx
);
91 void PreRemoveRequest
<I
>::handle_exclusive_lock(int r
) {
92 auto cct
= m_image_ctx
->cct
;
93 ldout(cct
, 5) << "r=" << r
<< dendl
;
95 if (r
< 0 || !m_image_ctx
->exclusive_lock
->is_lock_owner()) {
97 lderr(cct
) << "cannot obtain exclusive lock - not removing" << dendl
;
100 ldout(cct
, 5) << "cannot obtain exclusive lock - "
101 << "proceeding due to force flag set" << dendl
;
102 shut_down_exclusive_lock();
107 validate_image_removal();
110 template <typename I
>
111 void PreRemoveRequest
<I
>::shut_down_exclusive_lock() {
112 std::shared_lock owner_lock
{m_image_ctx
->owner_lock
};
113 if (m_image_ctx
->exclusive_lock
== nullptr) {
114 validate_image_removal();
118 auto cct
= m_image_ctx
->cct
;
119 ldout(cct
, 5) << dendl
;
121 auto ctx
= create_context_callback
<
123 &PreRemoveRequest
<I
>::handle_shut_down_exclusive_lock
>(this);
125 m_exclusive_lock
= m_image_ctx
->exclusive_lock
;
126 m_exclusive_lock
->shut_down(ctx
);
129 template <typename I
>
130 void PreRemoveRequest
<I
>::handle_shut_down_exclusive_lock(int r
) {
131 auto cct
= m_image_ctx
->cct
;
132 ldout(cct
, 5) << "r=" << r
<< dendl
;
134 m_exclusive_lock
->put();
135 m_exclusive_lock
= nullptr;
138 lderr(cct
) << "error shutting down exclusive lock: " << cpp_strerror(r
)
144 ceph_assert(m_image_ctx
->exclusive_lock
== nullptr);
145 validate_image_removal();
148 template <typename I
>
149 void PreRemoveRequest
<I
>::validate_image_removal() {
150 auto cct
= m_image_ctx
->cct
;
151 ldout(cct
, 5) << dendl
;
153 if (!m_image_ctx
->ignore_migrating
&&
154 m_image_ctx
->test_features(RBD_FEATURE_MIGRATING
)) {
155 lderr(cct
) << "image in migration state - not removing" << dendl
;
163 template <typename I
>
164 void PreRemoveRequest
<I
>::check_image_snaps() {
165 auto cct
= m_image_ctx
->cct
;
166 ldout(cct
, 5) << dendl
;
168 m_image_ctx
->image_lock
.lock_shared();
169 for (auto& snap_info
: m_image_ctx
->snap_info
) {
170 if (auto_delete_snapshot(snap_info
.second
)) {
171 m_snap_infos
.insert(snap_info
);
172 } else if (!ignore_snapshot(snap_info
.second
)) {
173 m_image_ctx
->image_lock
.unlock_shared();
175 ldout(cct
, 5) << "image has snapshots - not removing" << dendl
;
180 m_image_ctx
->image_lock
.unlock_shared();
182 list_image_watchers();
185 template <typename I
>
186 void PreRemoveRequest
<I
>::list_image_watchers() {
187 auto cct
= m_image_ctx
->cct
;
188 ldout(cct
, 5) << dendl
;
190 int flags
= LIST_WATCHERS_FILTER_OUT_MY_INSTANCE
|
191 LIST_WATCHERS_FILTER_OUT_MIRROR_INSTANCES
;
192 auto ctx
= create_context_callback
<
194 &PreRemoveRequest
<I
>::handle_list_image_watchers
>(this);
195 auto req
= ListWatchersRequest
<I
>::create(*m_image_ctx
, flags
, &m_watchers
,
200 template <typename I
>
201 void PreRemoveRequest
<I
>::handle_list_image_watchers(int r
) {
202 auto cct
= m_image_ctx
->cct
;
203 ldout(cct
, 5) << "r=" << r
<< dendl
;
206 lderr(cct
) << "error listing image watchers: " << cpp_strerror(r
) << dendl
;
211 check_image_watchers();
214 template <typename I
>
215 void PreRemoveRequest
<I
>::check_image_watchers() {
216 auto cct
= m_image_ctx
->cct
;
217 ldout(cct
, 5) << dendl
;
219 if (!m_watchers
.empty()) {
220 lderr(cct
) << "image has watchers - not removing" << dendl
;
228 template <typename I
>
229 void PreRemoveRequest
<I
>::check_group() {
230 if (m_image_ctx
->old_format
) {
235 auto cct
= m_image_ctx
->cct
;
236 ldout(cct
, 5) << dendl
;
238 librados::ObjectReadOperation op
;
239 librbd::cls_client::image_group_get_start(&op
);
241 auto rados_completion
= create_rados_callback
<
242 PreRemoveRequest
<I
>, &PreRemoveRequest
<I
>::handle_check_group
>(this);
244 int r
= m_image_ctx
->md_ctx
.aio_operate(m_image_ctx
->header_oid
,
245 rados_completion
, &op
, &m_out_bl
);
247 rados_completion
->release();
250 template <typename I
>
251 void PreRemoveRequest
<I
>::handle_check_group(int r
) {
252 auto cct
= m_image_ctx
->cct
;
253 ldout(cct
, 5) << "r=" << r
<< dendl
;
255 cls::rbd::GroupSpec s
;
257 auto it
= m_out_bl
.cbegin();
258 r
= librbd::cls_client::image_group_get_finish(&it
, &s
);
260 if (r
< 0 && r
!= -EOPNOTSUPP
) {
261 lderr(cct
) << "error fetching group for image: " << cpp_strerror(r
)
268 lderr(cct
) << "image is in a group - not removing" << dendl
;
276 template <typename I
>
277 void PreRemoveRequest
<I
>::remove_snapshot() {
278 if (m_snap_infos
.empty()) {
283 auto cct
= m_image_ctx
->cct
;
284 auto snap_id
= m_snap_infos
.begin()->first
;
285 auto& snap_info
= m_snap_infos
.begin()->second
;
286 ldout(cct
, 20) << "snap_id=" << snap_id
<< ", "
287 << "snap_name=" << snap_info
.name
<< dendl
;
289 std::shared_lock owner_lock
{m_image_ctx
->owner_lock
};
290 auto ctx
= create_context_callback
<
291 PreRemoveRequest
<I
>, &PreRemoveRequest
<I
>::handle_remove_snapshot
>(this);
292 auto req
= librbd::operation::SnapshotRemoveRequest
<I
>::create(
293 *m_image_ctx
, snap_info
.snap_namespace
, snap_info
.name
,
299 template <typename I
>
300 void PreRemoveRequest
<I
>::handle_remove_snapshot(int r
) {
301 auto cct
= m_image_ctx
->cct
;
302 ldout(cct
, 5) << "r=" << r
<< dendl
;
305 ldout(cct
, 5) << "skipping attached child" << dendl
;
306 if (m_ret_val
== 0) {
309 } else if (r
< 0 && r
!= -ENOENT
) {
310 auto snap_id
= m_snap_infos
.begin()->first
;
311 lderr(cct
) << "failed to auto-prune snapshot " << snap_id
<< ": "
312 << cpp_strerror(r
) << dendl
;
317 ceph_assert(!m_snap_infos
.empty());
318 m_snap_infos
.erase(m_snap_infos
.begin());
323 template <typename I
>
324 void PreRemoveRequest
<I
>::finish(int r
) {
325 auto cct
= m_image_ctx
->cct
;
326 ldout(cct
, 5) << "r=" << r
<< dendl
;
328 if (m_ret_val
== 0) {
332 m_on_finish
->complete(m_ret_val
);
337 } // namespace librbd
339 template class librbd::image::PreRemoveRequest
<librbd::ImageCtx
>;