]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/operation/SnapshotCreateRequest.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / librbd / operation / SnapshotCreateRequest.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 "cls/rbd/cls_rbd_types.h"
5 #include "librbd/operation/SnapshotCreateRequest.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "librbd/ExclusiveLock.h"
9 #include "librbd/ImageCtx.h"
10 #include "librbd/ImageWatcher.h"
11 #include "librbd/ObjectMap.h"
12 #include "librbd/Utils.h"
13 #include "librbd/io/ImageDispatcherInterface.h"
14 #include "librbd/mirror/snapshot/SetImageStateRequest.h"
15
16 #define dout_subsys ceph_subsys_rbd
17 #undef dout_prefix
18 #define dout_prefix *_dout << "librbd::SnapshotCreateRequest: "
19
20 namespace librbd {
21 namespace operation {
22
23 using util::create_async_context_callback;
24 using util::create_context_callback;
25 using util::create_rados_callback;
26
27 template <typename I>
28 SnapshotCreateRequest<I>::SnapshotCreateRequest(I &image_ctx,
29 Context *on_finish,
30 const cls::rbd::SnapshotNamespace &snap_namespace,
31 const std::string &snap_name,
32 uint64_t journal_op_tid,
33 uint64_t flags,
34 ProgressContext &prog_ctx)
35 : Request<I>(image_ctx, on_finish, journal_op_tid),
36 m_snap_namespace(snap_namespace), m_snap_name(snap_name),
37 m_skip_object_map(flags & SNAP_CREATE_FLAG_SKIP_OBJECT_MAP),
38 m_skip_notify_quiesce(flags & SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE),
39 m_ignore_notify_quiesce_error(flags & SNAP_CREATE_FLAG_IGNORE_NOTIFY_QUIESCE_ERROR),
40 m_prog_ctx(prog_ctx) {
41 }
42
43 template <typename I>
44 void SnapshotCreateRequest<I>::send_op() {
45 I &image_ctx = this->m_image_ctx;
46 CephContext *cct = image_ctx.cct;
47
48 if (!image_ctx.data_ctx.is_valid()) {
49 lderr(cct) << "missing data pool" << dendl;
50 this->async_complete(-ENODEV);
51 return;
52 }
53
54 send_notify_quiesce();
55 }
56
57 template <typename I>
58 void SnapshotCreateRequest<I>::send_notify_quiesce() {
59 if (m_skip_notify_quiesce) {
60 send_suspend_requests();
61 return;
62 }
63
64 I &image_ctx = this->m_image_ctx;
65 CephContext *cct = image_ctx.cct;
66 ldout(cct, 5) << this << " " << __func__ << dendl;
67
68 image_ctx.image_watcher->notify_quiesce(
69 &m_request_id, m_prog_ctx, create_async_context_callback(
70 image_ctx, create_context_callback<SnapshotCreateRequest<I>,
71 &SnapshotCreateRequest<I>::handle_notify_quiesce>(this)));
72 }
73
74 template <typename I>
75 Context *SnapshotCreateRequest<I>::handle_notify_quiesce(int *result) {
76 I &image_ctx = this->m_image_ctx;
77 CephContext *cct = image_ctx.cct;
78 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
79
80 if (*result < 0 && !m_ignore_notify_quiesce_error) {
81 lderr(cct) << "failed to notify quiesce: " << cpp_strerror(*result)
82 << dendl;
83 save_result(result);
84 send_notify_unquiesce();
85 return nullptr;
86 }
87
88 std::shared_lock owner_locker{image_ctx.owner_lock};
89 send_suspend_requests();
90 return nullptr;
91 }
92
93 template <typename I>
94 void SnapshotCreateRequest<I>::send_suspend_requests() {
95 I &image_ctx = this->m_image_ctx;
96 CephContext *cct = image_ctx.cct;
97 ldout(cct, 5) << this << " " << __func__ << dendl;
98
99 // TODO suspend (shrink) resize to ensure consistent RBD mirror
100 send_suspend_aio();
101 }
102
103 template <typename I>
104 Context *SnapshotCreateRequest<I>::handle_suspend_requests(int *result) {
105 I &image_ctx = this->m_image_ctx;
106 CephContext *cct = image_ctx.cct;
107 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
108
109 // TODO
110 send_suspend_aio();
111 return nullptr;
112 }
113
114 template <typename I>
115 void SnapshotCreateRequest<I>::send_suspend_aio() {
116 I &image_ctx = this->m_image_ctx;
117 ceph_assert(ceph_mutex_is_locked(image_ctx.owner_lock));
118
119 CephContext *cct = image_ctx.cct;
120 ldout(cct, 5) << this << " " << __func__ << dendl;
121
122 image_ctx.io_image_dispatcher->block_writes(create_context_callback<
123 SnapshotCreateRequest<I>,
124 &SnapshotCreateRequest<I>::handle_suspend_aio>(this));
125 }
126
127 template <typename I>
128 Context *SnapshotCreateRequest<I>::handle_suspend_aio(int *result) {
129 I &image_ctx = this->m_image_ctx;
130 CephContext *cct = image_ctx.cct;
131 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
132
133 if (*result < 0) {
134 lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
135 save_result(result);
136 return send_notify_unquiesce();
137 }
138
139 m_writes_blocked = true;
140
141 send_append_op_event();
142 return nullptr;
143 }
144
145 template <typename I>
146 void SnapshotCreateRequest<I>::send_append_op_event() {
147 I &image_ctx = this->m_image_ctx;
148 if (!this->template append_op_event<
149 SnapshotCreateRequest<I>,
150 &SnapshotCreateRequest<I>::handle_append_op_event>(this)) {
151 send_allocate_snap_id();
152 return;
153 }
154
155 CephContext *cct = image_ctx.cct;
156 ldout(cct, 5) << this << " " << __func__ << dendl;
157 }
158
159 template <typename I>
160 Context *SnapshotCreateRequest<I>::handle_append_op_event(int *result) {
161 I &image_ctx = this->m_image_ctx;
162 CephContext *cct = image_ctx.cct;
163 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
164
165 if (*result < 0) {
166 lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result)
167 << dendl;
168 save_result(result);
169 return send_notify_unquiesce();
170 }
171
172 send_allocate_snap_id();
173 return nullptr;
174 }
175
176 template <typename I>
177 void SnapshotCreateRequest<I>::send_allocate_snap_id() {
178 I &image_ctx = this->m_image_ctx;
179 CephContext *cct = image_ctx.cct;
180 ldout(cct, 5) << this << " " << __func__ << dendl;
181
182 librados::AioCompletion *rados_completion = create_rados_callback<
183 SnapshotCreateRequest<I>,
184 &SnapshotCreateRequest<I>::handle_allocate_snap_id>(this);
185 image_ctx.data_ctx.aio_selfmanaged_snap_create(&m_snap_id, rados_completion);
186 rados_completion->release();
187 }
188
189 template <typename I>
190 Context *SnapshotCreateRequest<I>::handle_allocate_snap_id(int *result) {
191 I &image_ctx = this->m_image_ctx;
192 CephContext *cct = image_ctx.cct;
193 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << ", "
194 << "snap_id=" << m_snap_id << dendl;
195
196 if (*result < 0) {
197 lderr(cct) << "failed to allocate snapshot id: " << cpp_strerror(*result)
198 << dendl;
199 save_result(result);
200 return send_notify_unquiesce();
201 }
202
203 send_create_snap();
204 return nullptr;
205 }
206
207 template <typename I>
208 void SnapshotCreateRequest<I>::send_create_snap() {
209 I &image_ctx = this->m_image_ctx;
210 CephContext *cct = image_ctx.cct;
211 ldout(cct, 5) << this << " " << __func__ << dendl;
212
213 std::shared_lock owner_locker{image_ctx.owner_lock};
214 std::shared_lock image_locker{image_ctx.image_lock};
215
216 // should have been canceled prior to releasing lock
217 ceph_assert(image_ctx.exclusive_lock == nullptr ||
218 image_ctx.exclusive_lock->is_lock_owner());
219
220 // save current size / parent info for creating snapshot record in ImageCtx
221 m_size = image_ctx.size;
222 m_parent_info = image_ctx.parent_md;
223
224 librados::ObjectWriteOperation op;
225 if (image_ctx.old_format) {
226 cls_client::old_snapshot_add(&op, m_snap_id, m_snap_name);
227 } else {
228 cls_client::snapshot_add(&op, m_snap_id, m_snap_name, m_snap_namespace);
229 }
230
231 librados::AioCompletion *rados_completion = create_rados_callback<
232 SnapshotCreateRequest<I>,
233 &SnapshotCreateRequest<I>::handle_create_snap>(this);
234 int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid,
235 rados_completion, &op);
236 ceph_assert(r == 0);
237 rados_completion->release();
238 }
239
240 template <typename I>
241 Context *SnapshotCreateRequest<I>::handle_create_snap(int *result) {
242 I &image_ctx = this->m_image_ctx;
243 CephContext *cct = image_ctx.cct;
244 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
245
246 if (*result == -ESTALE) {
247 send_allocate_snap_id();
248 return nullptr;
249 } else if (*result < 0) {
250 save_result(result);
251 send_release_snap_id();
252 return nullptr;
253 }
254
255 return send_create_object_map();
256 }
257
258 template <typename I>
259 Context *SnapshotCreateRequest<I>::send_create_object_map() {
260 I &image_ctx = this->m_image_ctx;
261
262 image_ctx.image_lock.lock_shared();
263 if (image_ctx.object_map == nullptr || m_skip_object_map) {
264 image_ctx.image_lock.unlock_shared();
265
266 return send_create_image_state();
267 }
268
269 CephContext *cct = image_ctx.cct;
270 ldout(cct, 5) << this << " " << __func__ << dendl;
271
272 image_ctx.object_map->snapshot_add(
273 m_snap_id, create_context_callback<
274 SnapshotCreateRequest<I>,
275 &SnapshotCreateRequest<I>::handle_create_object_map>(this));
276 image_ctx.image_lock.unlock_shared();
277 return nullptr;
278 }
279
280 template <typename I>
281 Context *SnapshotCreateRequest<I>::handle_create_object_map(int *result) {
282 I &image_ctx = this->m_image_ctx;
283 CephContext *cct = image_ctx.cct;
284 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
285
286 if (*result < 0) {
287 lderr(cct) << this << " " << __func__ << ": failed to snapshot object map: "
288 << cpp_strerror(*result) << dendl;
289
290 save_result(result);
291 update_snap_context();
292 return send_notify_unquiesce();
293 }
294
295 return send_create_image_state();
296 }
297
298 template <typename I>
299 Context *SnapshotCreateRequest<I>::send_create_image_state() {
300 I &image_ctx = this->m_image_ctx;
301 auto mirror_ns = std::get_if<cls::rbd::MirrorSnapshotNamespace>(
302 &m_snap_namespace);
303 if (mirror_ns == nullptr || !mirror_ns->is_primary()) {
304 update_snap_context();
305 return send_notify_unquiesce();
306 }
307
308 CephContext *cct = image_ctx.cct;
309 ldout(cct, 5) << this << " " << __func__ << dendl;
310
311 auto req = mirror::snapshot::SetImageStateRequest<I>::create(
312 &image_ctx, m_snap_id, create_context_callback<
313 SnapshotCreateRequest<I>,
314 &SnapshotCreateRequest<I>::handle_create_image_state>(this));
315 req->send();
316 return nullptr;
317 }
318
319 template <typename I>
320 Context *SnapshotCreateRequest<I>::handle_create_image_state(int *result) {
321 I &image_ctx = this->m_image_ctx;
322 CephContext *cct = image_ctx.cct;
323 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
324
325 update_snap_context();
326 if (*result < 0) {
327 lderr(cct) << this << " " << __func__ << ": failed to create image state: "
328 << cpp_strerror(*result) << dendl;
329 save_result(result);
330 }
331
332 return send_notify_unquiesce();
333 }
334
335 template <typename I>
336 void SnapshotCreateRequest<I>::send_release_snap_id() {
337 I &image_ctx = this->m_image_ctx;
338 CephContext *cct = image_ctx.cct;
339 ldout(cct, 5) << this << " " << __func__ << dendl;
340
341 ceph_assert(m_snap_id != CEPH_NOSNAP);
342
343 librados::AioCompletion *rados_completion = create_rados_callback<
344 SnapshotCreateRequest<I>,
345 &SnapshotCreateRequest<I>::handle_release_snap_id>(this);
346 image_ctx.data_ctx.aio_selfmanaged_snap_remove(m_snap_id, rados_completion);
347 rados_completion->release();
348 }
349
350 template <typename I>
351 Context *SnapshotCreateRequest<I>::handle_release_snap_id(int *result) {
352 I &image_ctx = this->m_image_ctx;
353 CephContext *cct = image_ctx.cct;
354 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
355
356 return send_notify_unquiesce();
357 }
358
359 template <typename I>
360 Context *SnapshotCreateRequest<I>::send_notify_unquiesce() {
361 I &image_ctx = this->m_image_ctx;
362 CephContext *cct = image_ctx.cct;
363
364 if (m_writes_blocked) {
365 image_ctx.io_image_dispatcher->unblock_writes();
366 }
367
368 if (m_skip_notify_quiesce) {
369 return this->create_context_finisher(m_ret_val);
370 }
371
372 ldout(cct, 5) << this << " " << __func__ << dendl;
373
374 image_ctx.image_watcher->notify_unquiesce(
375 m_request_id, create_context_callback<
376 SnapshotCreateRequest<I>,
377 &SnapshotCreateRequest<I>::handle_notify_unquiesce>(this));
378
379 return nullptr;
380 }
381
382 template <typename I>
383 Context *SnapshotCreateRequest<I>::handle_notify_unquiesce(int *result) {
384 I &image_ctx = this->m_image_ctx;
385 CephContext *cct = image_ctx.cct;
386 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
387
388 if (*result < 0) {
389 lderr(cct) << "failed to notify unquiesce: " << cpp_strerror(*result)
390 << dendl;
391 // ignore error
392 }
393
394 *result = m_ret_val;
395 return this->create_context_finisher(m_ret_val);
396 }
397
398 template <typename I>
399 void SnapshotCreateRequest<I>::update_snap_context() {
400 I &image_ctx = this->m_image_ctx;
401
402 std::shared_lock owner_locker{image_ctx.owner_lock};
403 std::unique_lock image_locker{image_ctx.image_lock};
404 if (image_ctx.get_snap_info(m_snap_id) != NULL) {
405 return;
406 }
407
408 CephContext *cct = image_ctx.cct;
409 ldout(cct, 5) << this << " " << __func__ << dendl;
410
411 // should have been canceled prior to releasing lock
412 ceph_assert(image_ctx.exclusive_lock == nullptr ||
413 image_ctx.exclusive_lock->is_lock_owner());
414
415 // immediately add a reference to the new snapshot
416 utime_t snap_time = ceph_clock_now();
417 image_ctx.add_snap(m_snap_namespace, m_snap_name, m_snap_id, m_size,
418 m_parent_info, RBD_PROTECTION_STATUS_UNPROTECTED,
419 0, snap_time);
420
421 // immediately start using the new snap context if we
422 // own the exclusive lock
423 std::vector<snapid_t> snaps;
424 snaps.push_back(m_snap_id);
425 snaps.insert(snaps.end(), image_ctx.snapc.snaps.begin(),
426 image_ctx.snapc.snaps.end());
427
428 image_ctx.snapc.seq = m_snap_id;
429 image_ctx.snapc.snaps.swap(snaps);
430 image_ctx.data_ctx.selfmanaged_snap_set_write_ctx(
431 image_ctx.snapc.seq, image_ctx.snaps);
432 image_ctx.rebuild_data_io_context();
433
434 if (!image_ctx.migration_info.empty()) {
435 auto it = image_ctx.migration_info.snap_map.find(CEPH_NOSNAP);
436 ceph_assert(it != image_ctx.migration_info.snap_map.end());
437 ceph_assert(!it->second.empty());
438 if (it->second[0] == CEPH_NOSNAP) {
439 ldout(cct, 5) << this << " " << __func__
440 << ": updating migration snap_map" << dendl;
441 it->second[0] = m_snap_id;
442 }
443 }
444 }
445
446 } // namespace operation
447 } // namespace librbd
448
449 template class librbd::operation::SnapshotCreateRequest<librbd::ImageCtx>;