]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/image/PreRemoveRequest.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / image / PreRemoveRequest.cc
CommitLineData
11fdf7f2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
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"
f67539c2 10#include "librbd/exclusive_lock/StandardPolicy.h"
11fdf7f2
TL
11#include "librbd/image/ListWatchersRequest.h"
12#include "librbd/journal/DisabledPolicy.h"
13#include "librbd/operation/SnapshotRemoveRequest.h"
14
15#define dout_subsys ceph_subsys_rbd
16#undef dout_prefix
17#define dout_prefix *_dout << "librbd::image::PreRemoveRequest: " << this \
18 << " " << __func__ << ": "
19
20namespace librbd {
21namespace image {
22
23namespace {
24
25bool auto_delete_snapshot(const SnapInfo& snap_info) {
26 auto snap_namespace_type = cls::rbd::get_snap_namespace_type(
27 snap_info.snap_namespace);
28 switch (snap_namespace_type) {
29 case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH:
30 return true;
31 default:
32 return false;
33 }
34}
35
9f95a23c
TL
36bool ignore_snapshot(const SnapInfo& snap_info) {
37 auto snap_namespace_type = cls::rbd::get_snap_namespace_type(
38 snap_info.snap_namespace);
39 switch (snap_namespace_type) {
40 case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_MIRROR:
41 return true;
42 default:
43 return false;
44 }
45}
46
11fdf7f2
TL
47} // anonymous namespace
48
49using util::create_context_callback;
50using util::create_rados_callback;
51
52template <typename I>
53void PreRemoveRequest<I>::send() {
54 auto cct = m_image_ctx->cct;
55 if (m_image_ctx->operations_disabled) {
56 lderr(cct) << "image operations disabled due to unsupported op features"
57 << dendl;
58 finish(-EROFS);
59 return;
60 }
61
62 acquire_exclusive_lock();
63}
64
65template <typename I>
66void PreRemoveRequest<I>::acquire_exclusive_lock() {
f67539c2
TL
67 // lock for write for set_exclusive_lock_policy()
68 std::unique_lock owner_locker{m_image_ctx->owner_lock};
11fdf7f2 69 if (m_image_ctx->exclusive_lock == nullptr) {
f67539c2 70 owner_locker.unlock();
11fdf7f2
TL
71 validate_image_removal();
72 return;
73 }
74
75 auto cct = m_image_ctx->cct;
76 ldout(cct, 5) << dendl;
77
f67539c2
TL
78 // refuse to release exclusive lock when (in the midst of) removing
79 // the image
80 m_image_ctx->set_exclusive_lock_policy(
81 new exclusive_lock::StandardPolicy<I>(m_image_ctx));
82
11fdf7f2
TL
83 // do not attempt to open the journal when removing the image in case
84 // it's corrupt
85 if (m_image_ctx->test_features(RBD_FEATURE_JOURNALING)) {
9f95a23c 86 std::unique_lock image_locker{m_image_ctx->image_lock};
11fdf7f2
TL
87 m_image_ctx->set_journal_policy(new journal::DisabledPolicy());
88 }
89
9f95a23c 90 m_exclusive_lock = m_image_ctx->exclusive_lock;
eafe8130 91
9f95a23c
TL
92 auto ctx = create_context_callback<
93 PreRemoveRequest<I>,
94 &PreRemoveRequest<I>::handle_exclusive_lock>(this, m_exclusive_lock);
95 m_exclusive_lock->acquire_lock(ctx);
11fdf7f2
TL
96}
97
98template <typename I>
99void PreRemoveRequest<I>::handle_exclusive_lock(int r) {
100 auto cct = m_image_ctx->cct;
101 ldout(cct, 5) << "r=" << r << dendl;
102
103 if (r < 0 || !m_image_ctx->exclusive_lock->is_lock_owner()) {
eafe8130
TL
104 if (!m_force) {
105 lderr(cct) << "cannot obtain exclusive lock - not removing" << dendl;
106 finish(-EBUSY);
107 } else {
108 ldout(cct, 5) << "cannot obtain exclusive lock - "
109 << "proceeding due to force flag set" << dendl;
110 shut_down_exclusive_lock();
111 }
11fdf7f2
TL
112 return;
113 }
114
115 validate_image_removal();
116}
117
118template <typename I>
eafe8130 119void PreRemoveRequest<I>::shut_down_exclusive_lock() {
f67539c2 120 std::shared_lock owner_locker{m_image_ctx->owner_lock};
eafe8130 121 if (m_image_ctx->exclusive_lock == nullptr) {
f67539c2 122 owner_locker.unlock();
eafe8130
TL
123 validate_image_removal();
124 return;
125 }
126
127 auto cct = m_image_ctx->cct;
128 ldout(cct, 5) << dendl;
129
130 auto ctx = create_context_callback<
131 PreRemoveRequest<I>,
132 &PreRemoveRequest<I>::handle_shut_down_exclusive_lock>(this);
133
134 m_exclusive_lock = m_image_ctx->exclusive_lock;
135 m_exclusive_lock->shut_down(ctx);
136}
137
138template <typename I>
139void PreRemoveRequest<I>::handle_shut_down_exclusive_lock(int r) {
11fdf7f2
TL
140 auto cct = m_image_ctx->cct;
141 ldout(cct, 5) << "r=" << r << dendl;
142
9f95a23c 143 m_exclusive_lock->put();
11fdf7f2
TL
144 m_exclusive_lock = nullptr;
145
146 if (r < 0) {
147 lderr(cct) << "error shutting down exclusive lock: " << cpp_strerror(r)
148 << dendl;
149 finish(r);
150 return;
151 }
152
153 ceph_assert(m_image_ctx->exclusive_lock == nullptr);
154 validate_image_removal();
155}
156
157template <typename I>
158void PreRemoveRequest<I>::validate_image_removal() {
159 auto cct = m_image_ctx->cct;
160 ldout(cct, 5) << dendl;
161
162 if (!m_image_ctx->ignore_migrating &&
163 m_image_ctx->test_features(RBD_FEATURE_MIGRATING)) {
164 lderr(cct) << "image in migration state - not removing" << dendl;
165 finish(-EBUSY);
166 return;
167 }
168
169 check_image_snaps();
170}
171
172template <typename I>
173void PreRemoveRequest<I>::check_image_snaps() {
174 auto cct = m_image_ctx->cct;
175 ldout(cct, 5) << dendl;
176
9f95a23c 177 m_image_ctx->image_lock.lock_shared();
11fdf7f2
TL
178 for (auto& snap_info : m_image_ctx->snap_info) {
179 if (auto_delete_snapshot(snap_info.second)) {
180 m_snap_infos.insert(snap_info);
9f95a23c
TL
181 } else if (!ignore_snapshot(snap_info.second)) {
182 m_image_ctx->image_lock.unlock_shared();
11fdf7f2 183
9f95a23c 184 ldout(cct, 5) << "image has snapshots - not removing" << dendl;
11fdf7f2
TL
185 finish(-ENOTEMPTY);
186 return;
187 }
188 }
9f95a23c 189 m_image_ctx->image_lock.unlock_shared();
11fdf7f2
TL
190
191 list_image_watchers();
192}
193
194template <typename I>
195void PreRemoveRequest<I>::list_image_watchers() {
196 auto cct = m_image_ctx->cct;
197 ldout(cct, 5) << dendl;
198
199 int flags = LIST_WATCHERS_FILTER_OUT_MY_INSTANCE |
200 LIST_WATCHERS_FILTER_OUT_MIRROR_INSTANCES;
201 auto ctx = create_context_callback<
202 PreRemoveRequest<I>,
203 &PreRemoveRequest<I>::handle_list_image_watchers>(this);
204 auto req = ListWatchersRequest<I>::create(*m_image_ctx, flags, &m_watchers,
205 ctx);
206 req->send();
207}
208
209template <typename I>
210void PreRemoveRequest<I>::handle_list_image_watchers(int r) {
211 auto cct = m_image_ctx->cct;
212 ldout(cct, 5) << "r=" << r << dendl;
213
214 if (r < 0) {
215 lderr(cct) << "error listing image watchers: " << cpp_strerror(r) << dendl;
216 finish(r);
217 return;
218 }
219
220 check_image_watchers();
221}
222
223template <typename I>
224void PreRemoveRequest<I>::check_image_watchers() {
225 auto cct = m_image_ctx->cct;
226 ldout(cct, 5) << dendl;
227
228 if (!m_watchers.empty()) {
229 lderr(cct) << "image has watchers - not removing" << dendl;
230 finish(-EBUSY);
231 return;
232 }
233
234 check_group();
235}
236
237template <typename I>
238void PreRemoveRequest<I>::check_group() {
239 if (m_image_ctx->old_format) {
240 finish(0);
241 return;
242 }
243
244 auto cct = m_image_ctx->cct;
245 ldout(cct, 5) << dendl;
246
247 librados::ObjectReadOperation op;
248 librbd::cls_client::image_group_get_start(&op);
249
250 auto rados_completion = create_rados_callback<
251 PreRemoveRequest<I>, &PreRemoveRequest<I>::handle_check_group>(this);
252 m_out_bl.clear();
253 int r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid,
254 rados_completion, &op, &m_out_bl);
255 ceph_assert(r == 0);
256 rados_completion->release();
257}
258
259template <typename I>
260void PreRemoveRequest<I>::handle_check_group(int r) {
261 auto cct = m_image_ctx->cct;
262 ldout(cct, 5) << "r=" << r << dendl;
263
264 cls::rbd::GroupSpec s;
265 if (r == 0) {
266 auto it = m_out_bl.cbegin();
267 r = librbd::cls_client::image_group_get_finish(&it, &s);
268 }
269 if (r < 0 && r != -EOPNOTSUPP) {
270 lderr(cct) << "error fetching group for image: " << cpp_strerror(r)
271 << dendl;
272 finish(r);
273 return;
274 }
275
276 if (s.is_valid()) {
277 lderr(cct) << "image is in a group - not removing" << dendl;
278 finish(-EMLINK);
279 return;
280 }
281
282 remove_snapshot();
283}
284
285template <typename I>
286void PreRemoveRequest<I>::remove_snapshot() {
287 if (m_snap_infos.empty()) {
288 finish(0);
289 return;
290 }
291
292 auto cct = m_image_ctx->cct;
293 auto snap_id = m_snap_infos.begin()->first;
294 auto& snap_info = m_snap_infos.begin()->second;
295 ldout(cct, 20) << "snap_id=" << snap_id << ", "
296 << "snap_name=" << snap_info.name << dendl;
297
9f95a23c 298 std::shared_lock owner_lock{m_image_ctx->owner_lock};
11fdf7f2
TL
299 auto ctx = create_context_callback<
300 PreRemoveRequest<I>, &PreRemoveRequest<I>::handle_remove_snapshot>(this);
301 auto req = librbd::operation::SnapshotRemoveRequest<I>::create(
302 *m_image_ctx, snap_info.snap_namespace, snap_info.name,
303 snap_id, ctx);
304 req->send();
305
306}
307
308template <typename I>
309void PreRemoveRequest<I>::handle_remove_snapshot(int r) {
310 auto cct = m_image_ctx->cct;
311 ldout(cct, 5) << "r=" << r << dendl;
312
9f95a23c
TL
313 if (r == -EBUSY) {
314 ldout(cct, 5) << "skipping attached child" << dendl;
315 if (m_ret_val == 0) {
316 m_ret_val = -ECHILD;
317 }
318 } else if (r < 0 && r != -ENOENT) {
11fdf7f2
TL
319 auto snap_id = m_snap_infos.begin()->first;
320 lderr(cct) << "failed to auto-prune snapshot " << snap_id << ": "
321 << cpp_strerror(r) << dendl;
11fdf7f2
TL
322 finish(r);
323 return;
324 }
325
326 ceph_assert(!m_snap_infos.empty());
327 m_snap_infos.erase(m_snap_infos.begin());
328
329 remove_snapshot();
330}
331
332template <typename I>
333void PreRemoveRequest<I>::finish(int r) {
334 auto cct = m_image_ctx->cct;
335 ldout(cct, 5) << "r=" << r << dendl;
336
9f95a23c
TL
337 if (m_ret_val == 0) {
338 m_ret_val = r;
339 }
340
341 m_on_finish->complete(m_ret_val);
11fdf7f2
TL
342 delete this;
343}
344
345} // namespace image
346} // namespace librbd
347
348template class librbd::image::PreRemoveRequest<librbd::ImageCtx>;