]>
Commit | Line | Data |
---|---|---|
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 | ||
20 | namespace librbd { | |
21 | namespace image { | |
22 | ||
23 | namespace { | |
24 | ||
25 | bool 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 |
36 | bool 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 | ||
49 | using util::create_context_callback; | |
50 | using util::create_rados_callback; | |
51 | ||
52 | template <typename I> | |
53 | void 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 | ||
65 | template <typename I> | |
66 | void 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 | ||
98 | template <typename I> | |
99 | void 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 | ||
118 | template <typename I> | |
eafe8130 | 119 | void 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 | ||
138 | template <typename I> | |
139 | void 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 | ||
157 | template <typename I> | |
158 | void 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 | ||
172 | template <typename I> | |
173 | void 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 | ||
194 | template <typename I> | |
195 | void 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 | ||
209 | template <typename I> | |
210 | void 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 | ||
223 | template <typename I> | |
224 | void 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 | ||
237 | template <typename I> | |
238 | void 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 | ||
259 | template <typename I> | |
260 | void 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 | ||
285 | template <typename I> | |
286 | void 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 | ||
308 | template <typename I> | |
309 | void 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 | ||
332 | template <typename I> | |
333 | void 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 | ||
348 | template class librbd::image::PreRemoveRequest<librbd::ImageCtx>; |