]>
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 "tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.h" | |
5 | #include "common/debug.h" | |
6 | #include "common/errno.h" | |
7 | #include "librbd/ExclusiveLock.h" | |
8 | #include "librbd/ImageCtx.h" | |
9 | #include "librbd/ImageState.h" | |
10 | #include "librbd/Operations.h" | |
11 | #include "librbd/Utils.h" | |
12 | #include "librbd/journal/Policy.h" | |
13 | #include "tools/rbd_mirror/image_deleter/Types.h" | |
14 | ||
15 | #define dout_context g_ceph_context | |
16 | #define dout_subsys ceph_subsys_rbd_mirror | |
17 | #undef dout_prefix | |
18 | #define dout_prefix *_dout << "rbd::mirror::image_deleter::SnapshotPurgeRequest: " \ | |
19 | << this << " " << __func__ << ": " | |
20 | ||
21 | namespace rbd { | |
22 | namespace mirror { | |
23 | namespace image_deleter { | |
24 | ||
25 | using librbd::util::create_context_callback; | |
26 | ||
27 | template <typename I> | |
28 | void SnapshotPurgeRequest<I>::send() { | |
29 | open_image(); | |
30 | } | |
31 | ||
32 | template <typename I> | |
33 | void SnapshotPurgeRequest<I>::open_image() { | |
34 | dout(10) << dendl; | |
35 | m_image_ctx = I::create("", m_image_id, nullptr, m_io_ctx, false); | |
36 | ||
9f95a23c TL |
37 | // ensure non-primary images can be modified |
38 | m_image_ctx->read_only_mask &= ~librbd::IMAGE_READ_ONLY_FLAG_NON_PRIMARY; | |
39 | ||
11fdf7f2 | 40 | { |
9f95a23c | 41 | std::unique_lock image_locker{m_image_ctx->image_lock}; |
11fdf7f2 TL |
42 | m_image_ctx->set_journal_policy(new JournalPolicy()); |
43 | } | |
44 | ||
45 | Context *ctx = create_context_callback< | |
46 | SnapshotPurgeRequest<I>, &SnapshotPurgeRequest<I>::handle_open_image>( | |
47 | this); | |
48 | m_image_ctx->state->open(librbd::OPEN_FLAG_SKIP_OPEN_PARENT, ctx); | |
49 | } | |
50 | ||
51 | template <typename I> | |
52 | void SnapshotPurgeRequest<I>::handle_open_image(int r) { | |
53 | dout(10) << "r=" << r << dendl; | |
54 | ||
55 | if (r < 0) { | |
56 | derr << "failed to open image '" << m_image_id << "': " << cpp_strerror(r) | |
57 | << dendl; | |
58 | m_image_ctx->destroy(); | |
59 | m_image_ctx = nullptr; | |
60 | ||
61 | finish(r); | |
62 | return; | |
63 | } | |
64 | ||
65 | acquire_lock(); | |
66 | } | |
67 | ||
68 | template <typename I> | |
69 | void SnapshotPurgeRequest<I>::acquire_lock() { | |
70 | dout(10) << dendl; | |
71 | ||
9f95a23c | 72 | m_image_ctx->owner_lock.lock_shared(); |
11fdf7f2 | 73 | if (m_image_ctx->exclusive_lock == nullptr) { |
9f95a23c | 74 | m_image_ctx->owner_lock.unlock_shared(); |
11fdf7f2 | 75 | |
9f95a23c | 76 | start_snap_unprotect(); |
11fdf7f2 TL |
77 | return; |
78 | } | |
79 | ||
80 | m_image_ctx->exclusive_lock->acquire_lock(create_context_callback< | |
81 | SnapshotPurgeRequest<I>, &SnapshotPurgeRequest<I>::handle_acquire_lock>( | |
82 | this)); | |
9f95a23c | 83 | m_image_ctx->owner_lock.unlock_shared(); |
11fdf7f2 TL |
84 | } |
85 | ||
86 | template <typename I> | |
87 | void SnapshotPurgeRequest<I>::handle_acquire_lock(int r) { | |
88 | dout(10) << "r=" << r << dendl; | |
89 | ||
90 | if (r < 0) { | |
91 | derr << "failed to acquire exclusive lock: " << cpp_strerror(r) << dendl; | |
92 | m_ret_val = r; | |
93 | close_image(); | |
94 | return; | |
95 | } | |
96 | ||
9f95a23c TL |
97 | start_snap_unprotect(); |
98 | } | |
99 | ||
100 | template <typename I> | |
101 | void SnapshotPurgeRequest<I>::start_snap_unprotect() { | |
102 | dout(10) << dendl; | |
103 | ||
11fdf7f2 | 104 | { |
9f95a23c | 105 | std::shared_lock image_locker{m_image_ctx->image_lock}; |
11fdf7f2 TL |
106 | m_snaps = m_image_ctx->snaps; |
107 | } | |
108 | snap_unprotect(); | |
109 | } | |
110 | ||
111 | template <typename I> | |
112 | void SnapshotPurgeRequest<I>::snap_unprotect() { | |
113 | if (m_snaps.empty()) { | |
114 | close_image(); | |
115 | return; | |
116 | } | |
117 | ||
118 | librados::snap_t snap_id = m_snaps.back(); | |
9f95a23c | 119 | m_image_ctx->image_lock.lock_shared(); |
11fdf7f2 TL |
120 | int r = m_image_ctx->get_snap_namespace(snap_id, &m_snap_namespace); |
121 | if (r < 0) { | |
9f95a23c | 122 | m_image_ctx->image_lock.unlock_shared(); |
11fdf7f2 TL |
123 | |
124 | derr << "failed to get snap namespace: " << cpp_strerror(r) << dendl; | |
125 | m_ret_val = r; | |
126 | close_image(); | |
127 | return; | |
128 | } | |
129 | ||
130 | r = m_image_ctx->get_snap_name(snap_id, &m_snap_name); | |
131 | if (r < 0) { | |
9f95a23c | 132 | m_image_ctx->image_lock.unlock_shared(); |
11fdf7f2 TL |
133 | |
134 | derr << "failed to get snap name: " << cpp_strerror(r) << dendl; | |
135 | m_ret_val = r; | |
136 | close_image(); | |
137 | return; | |
138 | } | |
139 | ||
140 | bool is_protected; | |
141 | r = m_image_ctx->is_snap_protected(snap_id, &is_protected); | |
142 | if (r < 0) { | |
9f95a23c | 143 | m_image_ctx->image_lock.unlock_shared(); |
11fdf7f2 TL |
144 | |
145 | derr << "failed to get snap protection status: " << cpp_strerror(r) | |
146 | << dendl; | |
147 | m_ret_val = r; | |
148 | close_image(); | |
149 | return; | |
150 | } | |
9f95a23c | 151 | m_image_ctx->image_lock.unlock_shared(); |
11fdf7f2 TL |
152 | |
153 | if (!is_protected) { | |
154 | snap_remove(); | |
155 | return; | |
156 | } | |
157 | ||
158 | dout(10) << "snap_id=" << snap_id << ", " | |
159 | << "snap_namespace=" << m_snap_namespace << ", " | |
160 | << "snap_name=" << m_snap_name << dendl; | |
161 | ||
162 | auto finish_op_ctx = start_lock_op(&r); | |
163 | if (finish_op_ctx == nullptr) { | |
164 | derr << "lost exclusive lock" << dendl; | |
165 | m_ret_val = r; | |
166 | close_image(); | |
167 | return; | |
168 | } | |
169 | ||
9f95a23c | 170 | auto ctx = new LambdaContext([this, finish_op_ctx](int r) { |
11fdf7f2 TL |
171 | handle_snap_unprotect(r); |
172 | finish_op_ctx->complete(0); | |
173 | }); | |
9f95a23c | 174 | std::shared_lock owner_locker{m_image_ctx->owner_lock}; |
11fdf7f2 TL |
175 | m_image_ctx->operations->execute_snap_unprotect( |
176 | m_snap_namespace, m_snap_name.c_str(), ctx); | |
177 | } | |
178 | ||
179 | template <typename I> | |
180 | void SnapshotPurgeRequest<I>::handle_snap_unprotect(int r) { | |
181 | dout(10) << "r=" << r << dendl; | |
182 | ||
183 | if (r == -EBUSY) { | |
184 | dout(10) << "snapshot in-use" << dendl; | |
185 | m_ret_val = r; | |
186 | close_image(); | |
187 | return; | |
188 | } else if (r < 0) { | |
189 | derr << "failed to unprotect snapshot: " << cpp_strerror(r) << dendl; | |
190 | m_ret_val = r; | |
191 | close_image(); | |
192 | return; | |
193 | } | |
194 | ||
195 | { | |
196 | // avoid the need to refresh to delete the newly unprotected snapshot | |
9f95a23c | 197 | std::shared_lock image_locker{m_image_ctx->image_lock}; |
11fdf7f2 TL |
198 | librados::snap_t snap_id = m_snaps.back(); |
199 | auto snap_info_it = m_image_ctx->snap_info.find(snap_id); | |
200 | if (snap_info_it != m_image_ctx->snap_info.end()) { | |
201 | snap_info_it->second.protection_status = | |
202 | RBD_PROTECTION_STATUS_UNPROTECTED; | |
203 | } | |
204 | } | |
205 | ||
206 | snap_remove(); | |
207 | } | |
208 | ||
209 | template <typename I> | |
210 | void SnapshotPurgeRequest<I>::snap_remove() { | |
211 | librados::snap_t snap_id = m_snaps.back(); | |
212 | dout(10) << "snap_id=" << snap_id << ", " | |
213 | << "snap_namespace=" << m_snap_namespace << ", " | |
214 | << "snap_name=" << m_snap_name << dendl; | |
215 | ||
216 | int r; | |
217 | auto finish_op_ctx = start_lock_op(&r); | |
218 | if (finish_op_ctx == nullptr) { | |
219 | derr << "lost exclusive lock" << dendl; | |
220 | m_ret_val = r; | |
221 | close_image(); | |
222 | return; | |
223 | } | |
224 | ||
9f95a23c | 225 | auto ctx = new LambdaContext([this, finish_op_ctx](int r) { |
11fdf7f2 TL |
226 | handle_snap_remove(r); |
227 | finish_op_ctx->complete(0); | |
228 | }); | |
9f95a23c | 229 | std::shared_lock owner_locker{m_image_ctx->owner_lock}; |
11fdf7f2 TL |
230 | m_image_ctx->operations->execute_snap_remove( |
231 | m_snap_namespace, m_snap_name.c_str(), ctx); | |
232 | } | |
233 | ||
234 | template <typename I> | |
235 | void SnapshotPurgeRequest<I>::handle_snap_remove(int r) { | |
236 | dout(10) << "r=" << r << dendl; | |
237 | ||
238 | if (r == -EBUSY) { | |
239 | dout(10) << "snapshot in-use" << dendl; | |
240 | m_ret_val = r; | |
241 | close_image(); | |
242 | return; | |
243 | } else if (r < 0) { | |
244 | derr << "failed to remove snapshot: " << cpp_strerror(r) << dendl; | |
245 | m_ret_val = r; | |
246 | close_image(); | |
247 | return; | |
248 | } | |
249 | ||
250 | m_snaps.pop_back(); | |
251 | snap_unprotect(); | |
252 | } | |
253 | ||
254 | template <typename I> | |
255 | void SnapshotPurgeRequest<I>::close_image() { | |
256 | dout(10) << dendl; | |
257 | ||
258 | m_image_ctx->state->close(create_context_callback< | |
259 | SnapshotPurgeRequest<I>, | |
260 | &SnapshotPurgeRequest<I>::handle_close_image>(this)); | |
261 | } | |
262 | ||
263 | template <typename I> | |
264 | void SnapshotPurgeRequest<I>::handle_close_image(int r) { | |
265 | dout(10) << "r=" << r << dendl; | |
266 | ||
267 | m_image_ctx->destroy(); | |
268 | m_image_ctx = nullptr; | |
269 | ||
270 | if (r < 0) { | |
271 | derr << "failed to close: " << cpp_strerror(r) << dendl; | |
272 | finish(r); | |
273 | return; | |
274 | } | |
275 | finish(0); | |
276 | } | |
277 | ||
278 | template <typename I> | |
279 | void SnapshotPurgeRequest<I>::finish(int r) { | |
280 | if (m_ret_val < 0) { | |
281 | r = m_ret_val; | |
282 | } | |
283 | ||
284 | m_on_finish->complete(r); | |
285 | delete this; | |
286 | } | |
287 | ||
288 | template <typename I> | |
289 | Context *SnapshotPurgeRequest<I>::start_lock_op(int* r) { | |
9f95a23c TL |
290 | std::shared_lock owner_locker{m_image_ctx->owner_lock}; |
291 | if (m_image_ctx->exclusive_lock == nullptr) { | |
292 | return new LambdaContext([](int r) {}); | |
293 | } | |
11fdf7f2 TL |
294 | return m_image_ctx->exclusive_lock->start_op(r); |
295 | } | |
296 | ||
297 | } // namespace image_deleter | |
298 | } // namespace mirror | |
299 | } // namespace rbd | |
300 | ||
301 | template class rbd::mirror::image_deleter::SnapshotPurgeRequest<librbd::ImageCtx>; |