]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/image/PreRemoveRequest.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / librbd / image / PreRemoveRequest.cc
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"
10 #include "librbd/image/ListWatchersRequest.h"
11 #include "librbd/journal/DisabledPolicy.h"
12 #include "librbd/operation/SnapshotRemoveRequest.h"
13
14 #define dout_subsys ceph_subsys_rbd
15 #undef dout_prefix
16 #define dout_prefix *_dout << "librbd::image::PreRemoveRequest: " << this \
17 << " " << __func__ << ": "
18
19 namespace librbd {
20 namespace image {
21
22 namespace {
23
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:
29 return true;
30 default:
31 return false;
32 }
33 }
34
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:
40 return true;
41 default:
42 return false;
43 }
44 }
45
46 } // anonymous namespace
47
48 using util::create_context_callback;
49 using util::create_rados_callback;
50
51 template <typename I>
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"
56 << dendl;
57 finish(-EROFS);
58 return;
59 }
60
61 acquire_exclusive_lock();
62 }
63
64 template <typename I>
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();
69 return;
70 }
71
72 auto cct = m_image_ctx->cct;
73 ldout(cct, 5) << dendl;
74
75 // do not attempt to open the journal when removing the image in case
76 // it's corrupt
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());
80 }
81
82 m_exclusive_lock = m_image_ctx->exclusive_lock;
83
84 auto ctx = create_context_callback<
85 PreRemoveRequest<I>,
86 &PreRemoveRequest<I>::handle_exclusive_lock>(this, m_exclusive_lock);
87 m_exclusive_lock->acquire_lock(ctx);
88 }
89
90 template <typename I>
91 void PreRemoveRequest<I>::handle_exclusive_lock(int r) {
92 auto cct = m_image_ctx->cct;
93 ldout(cct, 5) << "r=" << r << dendl;
94
95 if (r < 0 || !m_image_ctx->exclusive_lock->is_lock_owner()) {
96 if (!m_force) {
97 lderr(cct) << "cannot obtain exclusive lock - not removing" << dendl;
98 finish(-EBUSY);
99 } else {
100 ldout(cct, 5) << "cannot obtain exclusive lock - "
101 << "proceeding due to force flag set" << dendl;
102 shut_down_exclusive_lock();
103 }
104 return;
105 }
106
107 validate_image_removal();
108 }
109
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();
115 return;
116 }
117
118 auto cct = m_image_ctx->cct;
119 ldout(cct, 5) << dendl;
120
121 auto ctx = create_context_callback<
122 PreRemoveRequest<I>,
123 &PreRemoveRequest<I>::handle_shut_down_exclusive_lock>(this);
124
125 m_exclusive_lock = m_image_ctx->exclusive_lock;
126 m_exclusive_lock->shut_down(ctx);
127 }
128
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;
133
134 m_exclusive_lock->put();
135 m_exclusive_lock = nullptr;
136
137 if (r < 0) {
138 lderr(cct) << "error shutting down exclusive lock: " << cpp_strerror(r)
139 << dendl;
140 finish(r);
141 return;
142 }
143
144 ceph_assert(m_image_ctx->exclusive_lock == nullptr);
145 validate_image_removal();
146 }
147
148 template <typename I>
149 void PreRemoveRequest<I>::validate_image_removal() {
150 auto cct = m_image_ctx->cct;
151 ldout(cct, 5) << dendl;
152
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;
156 finish(-EBUSY);
157 return;
158 }
159
160 check_image_snaps();
161 }
162
163 template <typename I>
164 void PreRemoveRequest<I>::check_image_snaps() {
165 auto cct = m_image_ctx->cct;
166 ldout(cct, 5) << dendl;
167
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();
174
175 ldout(cct, 5) << "image has snapshots - not removing" << dendl;
176 finish(-ENOTEMPTY);
177 return;
178 }
179 }
180 m_image_ctx->image_lock.unlock_shared();
181
182 list_image_watchers();
183 }
184
185 template <typename I>
186 void PreRemoveRequest<I>::list_image_watchers() {
187 auto cct = m_image_ctx->cct;
188 ldout(cct, 5) << dendl;
189
190 int flags = LIST_WATCHERS_FILTER_OUT_MY_INSTANCE |
191 LIST_WATCHERS_FILTER_OUT_MIRROR_INSTANCES;
192 auto ctx = create_context_callback<
193 PreRemoveRequest<I>,
194 &PreRemoveRequest<I>::handle_list_image_watchers>(this);
195 auto req = ListWatchersRequest<I>::create(*m_image_ctx, flags, &m_watchers,
196 ctx);
197 req->send();
198 }
199
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;
204
205 if (r < 0) {
206 lderr(cct) << "error listing image watchers: " << cpp_strerror(r) << dendl;
207 finish(r);
208 return;
209 }
210
211 check_image_watchers();
212 }
213
214 template <typename I>
215 void PreRemoveRequest<I>::check_image_watchers() {
216 auto cct = m_image_ctx->cct;
217 ldout(cct, 5) << dendl;
218
219 if (!m_watchers.empty()) {
220 lderr(cct) << "image has watchers - not removing" << dendl;
221 finish(-EBUSY);
222 return;
223 }
224
225 check_group();
226 }
227
228 template <typename I>
229 void PreRemoveRequest<I>::check_group() {
230 if (m_image_ctx->old_format) {
231 finish(0);
232 return;
233 }
234
235 auto cct = m_image_ctx->cct;
236 ldout(cct, 5) << dendl;
237
238 librados::ObjectReadOperation op;
239 librbd::cls_client::image_group_get_start(&op);
240
241 auto rados_completion = create_rados_callback<
242 PreRemoveRequest<I>, &PreRemoveRequest<I>::handle_check_group>(this);
243 m_out_bl.clear();
244 int r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid,
245 rados_completion, &op, &m_out_bl);
246 ceph_assert(r == 0);
247 rados_completion->release();
248 }
249
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;
254
255 cls::rbd::GroupSpec s;
256 if (r == 0) {
257 auto it = m_out_bl.cbegin();
258 r = librbd::cls_client::image_group_get_finish(&it, &s);
259 }
260 if (r < 0 && r != -EOPNOTSUPP) {
261 lderr(cct) << "error fetching group for image: " << cpp_strerror(r)
262 << dendl;
263 finish(r);
264 return;
265 }
266
267 if (s.is_valid()) {
268 lderr(cct) << "image is in a group - not removing" << dendl;
269 finish(-EMLINK);
270 return;
271 }
272
273 remove_snapshot();
274 }
275
276 template <typename I>
277 void PreRemoveRequest<I>::remove_snapshot() {
278 if (m_snap_infos.empty()) {
279 finish(0);
280 return;
281 }
282
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;
288
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,
294 snap_id, ctx);
295 req->send();
296
297 }
298
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;
303
304 if (r == -EBUSY) {
305 ldout(cct, 5) << "skipping attached child" << dendl;
306 if (m_ret_val == 0) {
307 m_ret_val = -ECHILD;
308 }
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;
313 finish(r);
314 return;
315 }
316
317 ceph_assert(!m_snap_infos.empty());
318 m_snap_infos.erase(m_snap_infos.begin());
319
320 remove_snapshot();
321 }
322
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;
327
328 if (m_ret_val == 0) {
329 m_ret_val = r;
330 }
331
332 m_on_finish->complete(m_ret_val);
333 delete this;
334 }
335
336 } // namespace image
337 } // namespace librbd
338
339 template class librbd::image::PreRemoveRequest<librbd::ImageCtx>;