1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
16 #define dout_subsys ceph_subsys_rbd
18 #define dout_prefix *_dout << "librbd::SnapshotCreateRequest: "
23 using util::create_async_context_callback
;
24 using util::create_context_callback
;
25 using util::create_rados_callback
;
28 SnapshotCreateRequest
<I
>::SnapshotCreateRequest(I
&image_ctx
,
30 const cls::rbd::SnapshotNamespace
&snap_namespace
,
31 const std::string
&snap_name
,
32 uint64_t journal_op_tid
,
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
) {
44 void SnapshotCreateRequest
<I
>::send_op() {
45 I
&image_ctx
= this->m_image_ctx
;
46 CephContext
*cct
= image_ctx
.cct
;
48 if (!image_ctx
.data_ctx
.is_valid()) {
49 lderr(cct
) << "missing data pool" << dendl
;
50 this->async_complete(-ENODEV
);
54 send_notify_quiesce();
58 void SnapshotCreateRequest
<I
>::send_notify_quiesce() {
59 if (m_skip_notify_quiesce
) {
60 send_suspend_requests();
64 I
&image_ctx
= this->m_image_ctx
;
65 CephContext
*cct
= image_ctx
.cct
;
66 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
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)));
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
;
80 if (*result
< 0 && !m_ignore_notify_quiesce_error
) {
81 lderr(cct
) << "failed to notify quiesce: " << cpp_strerror(*result
)
84 send_notify_unquiesce();
88 std::shared_lock owner_locker
{image_ctx
.owner_lock
};
89 send_suspend_requests();
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
;
99 // TODO suspend (shrink) resize to ensure consistent RBD mirror
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
;
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
));
119 CephContext
*cct
= image_ctx
.cct
;
120 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
122 image_ctx
.io_image_dispatcher
->block_writes(create_context_callback
<
123 SnapshotCreateRequest
<I
>,
124 &SnapshotCreateRequest
<I
>::handle_suspend_aio
>(this));
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
;
134 lderr(cct
) << "failed to block writes: " << cpp_strerror(*result
) << dendl
;
136 return send_notify_unquiesce();
139 m_writes_blocked
= true;
141 send_append_op_event();
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();
155 CephContext
*cct
= image_ctx
.cct
;
156 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
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
;
166 lderr(cct
) << "failed to commit journal entry: " << cpp_strerror(*result
)
169 return send_notify_unquiesce();
172 send_allocate_snap_id();
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
;
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();
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
;
197 lderr(cct
) << "failed to allocate snapshot id: " << cpp_strerror(*result
)
200 return send_notify_unquiesce();
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
;
213 std::shared_lock owner_locker
{image_ctx
.owner_lock
};
214 std::shared_lock image_locker
{image_ctx
.image_lock
};
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());
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
;
224 librados::ObjectWriteOperation op
;
225 if (image_ctx
.old_format
) {
226 cls_client::old_snapshot_add(&op
, m_snap_id
, m_snap_name
);
228 cls_client::snapshot_add(&op
, m_snap_id
, m_snap_name
, m_snap_namespace
);
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
);
237 rados_completion
->release();
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
;
246 if (*result
== -ESTALE
) {
247 send_allocate_snap_id();
249 } else if (*result
< 0) {
251 send_release_snap_id();
255 return send_create_object_map();
258 template <typename I
>
259 Context
*SnapshotCreateRequest
<I
>::send_create_object_map() {
260 I
&image_ctx
= this->m_image_ctx
;
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();
266 return send_create_image_state();
269 CephContext
*cct
= image_ctx
.cct
;
270 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
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();
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
;
287 lderr(cct
) << this << " " << __func__
<< ": failed to snapshot object map: "
288 << cpp_strerror(*result
) << dendl
;
291 update_snap_context();
292 return send_notify_unquiesce();
295 return send_create_image_state();
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
>(
303 if (mirror_ns
== nullptr || !mirror_ns
->is_primary()) {
304 update_snap_context();
305 return send_notify_unquiesce();
308 CephContext
*cct
= image_ctx
.cct
;
309 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
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));
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
;
325 update_snap_context();
327 lderr(cct
) << this << " " << __func__
<< ": failed to create image state: "
328 << cpp_strerror(*result
) << dendl
;
332 return send_notify_unquiesce();
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
;
341 ceph_assert(m_snap_id
!= CEPH_NOSNAP
);
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();
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
;
356 return send_notify_unquiesce();
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
;
364 if (m_writes_blocked
) {
365 image_ctx
.io_image_dispatcher
->unblock_writes();
368 if (m_skip_notify_quiesce
) {
369 return this->create_context_finisher(m_ret_val
);
372 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
374 image_ctx
.image_watcher
->notify_unquiesce(
375 m_request_id
, create_context_callback
<
376 SnapshotCreateRequest
<I
>,
377 &SnapshotCreateRequest
<I
>::handle_notify_unquiesce
>(this));
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
;
389 lderr(cct
) << "failed to notify unquiesce: " << cpp_strerror(*result
)
395 return this->create_context_finisher(m_ret_val
);
398 template <typename I
>
399 void SnapshotCreateRequest
<I
>::update_snap_context() {
400 I
&image_ctx
= this->m_image_ctx
;
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
) {
408 CephContext
*cct
= image_ctx
.cct
;
409 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
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());
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
,
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());
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();
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
;
446 } // namespace operation
447 } // namespace librbd
449 template class librbd::operation::SnapshotCreateRequest
<librbd::ImageCtx
>;