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/ObjectMap.h"
11 #include "librbd/Utils.h"
12 #include "librbd/io/ImageRequestWQ.h"
14 #define dout_subsys ceph_subsys_rbd
16 #define dout_prefix *_dout << "librbd::SnapshotCreateRequest: "
21 using util::create_async_context_callback
;
22 using util::create_context_callback
;
23 using util::create_rados_callback
;
26 SnapshotCreateRequest
<I
>::SnapshotCreateRequest(I
&image_ctx
,
28 const cls::rbd::SnapshotNamespace
&snap_namespace
,
29 const std::string
&snap_name
,
30 uint64_t journal_op_tid
,
32 : Request
<I
>(image_ctx
, on_finish
, journal_op_tid
),
33 m_snap_namespace(snap_namespace
), m_snap_name(snap_name
),
34 m_skip_object_map(skip_object_map
), m_ret_val(0), m_snap_id(CEPH_NOSNAP
) {
38 void SnapshotCreateRequest
<I
>::send_op() {
39 I
&image_ctx
= this->m_image_ctx
;
40 CephContext
*cct
= image_ctx
.cct
;
42 if (!image_ctx
.data_ctx
.is_valid()) {
43 lderr(cct
) << "missing data pool" << dendl
;
44 this->async_complete(-ENODEV
);
48 send_suspend_requests();
52 void SnapshotCreateRequest
<I
>::send_suspend_requests() {
53 I
&image_ctx
= this->m_image_ctx
;
54 CephContext
*cct
= image_ctx
.cct
;
55 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
57 // TODO suspend (shrink) resize to ensure consistent RBD mirror
62 Context
*SnapshotCreateRequest
<I
>::handle_suspend_requests(int *result
) {
63 I
&image_ctx
= this->m_image_ctx
;
64 CephContext
*cct
= image_ctx
.cct
;
65 ldout(cct
, 5) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
73 void SnapshotCreateRequest
<I
>::send_suspend_aio() {
74 I
&image_ctx
= this->m_image_ctx
;
75 ceph_assert(image_ctx
.owner_lock
.is_locked());
77 CephContext
*cct
= image_ctx
.cct
;
78 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
80 image_ctx
.io_work_queue
->block_writes(create_context_callback
<
81 SnapshotCreateRequest
<I
>,
82 &SnapshotCreateRequest
<I
>::handle_suspend_aio
>(this));
86 Context
*SnapshotCreateRequest
<I
>::handle_suspend_aio(int *result
) {
87 I
&image_ctx
= this->m_image_ctx
;
88 CephContext
*cct
= image_ctx
.cct
;
89 ldout(cct
, 5) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
92 lderr(cct
) << "failed to block writes: " << cpp_strerror(*result
) << dendl
;
93 image_ctx
.io_work_queue
->unblock_writes();
94 return this->create_context_finisher(*result
);
97 send_append_op_event();
101 template <typename I
>
102 void SnapshotCreateRequest
<I
>::send_append_op_event() {
103 I
&image_ctx
= this->m_image_ctx
;
104 if (!this->template append_op_event
<
105 SnapshotCreateRequest
<I
>,
106 &SnapshotCreateRequest
<I
>::handle_append_op_event
>(this)) {
107 send_allocate_snap_id();
111 CephContext
*cct
= image_ctx
.cct
;
112 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
115 template <typename I
>
116 Context
*SnapshotCreateRequest
<I
>::handle_append_op_event(int *result
) {
117 I
&image_ctx
= this->m_image_ctx
;
118 CephContext
*cct
= image_ctx
.cct
;
119 ldout(cct
, 5) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
122 image_ctx
.io_work_queue
->unblock_writes();
123 lderr(cct
) << "failed to commit journal entry: " << cpp_strerror(*result
)
125 return this->create_context_finisher(*result
);
128 send_allocate_snap_id();
132 template <typename I
>
133 void SnapshotCreateRequest
<I
>::send_allocate_snap_id() {
134 I
&image_ctx
= this->m_image_ctx
;
135 CephContext
*cct
= image_ctx
.cct
;
136 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
138 librados::AioCompletion
*rados_completion
= create_rados_callback
<
139 SnapshotCreateRequest
<I
>,
140 &SnapshotCreateRequest
<I
>::handle_allocate_snap_id
>(this);
141 image_ctx
.data_ctx
.aio_selfmanaged_snap_create(&m_snap_id
, rados_completion
);
142 rados_completion
->release();
145 template <typename I
>
146 Context
*SnapshotCreateRequest
<I
>::handle_allocate_snap_id(int *result
) {
147 I
&image_ctx
= this->m_image_ctx
;
148 CephContext
*cct
= image_ctx
.cct
;
149 ldout(cct
, 5) << this << " " << __func__
<< ": r=" << *result
<< ", "
150 << "snap_id=" << m_snap_id
<< dendl
;
154 image_ctx
.io_work_queue
->unblock_writes();
155 lderr(cct
) << "failed to allocate snapshot id: " << cpp_strerror(*result
)
157 return this->create_context_finisher(*result
);
164 template <typename I
>
165 void SnapshotCreateRequest
<I
>::send_create_snap() {
166 I
&image_ctx
= this->m_image_ctx
;
167 CephContext
*cct
= image_ctx
.cct
;
168 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
170 RWLock::RLocker
owner_locker(image_ctx
.owner_lock
);
171 RWLock::RLocker
snap_locker(image_ctx
.snap_lock
);
172 RWLock::RLocker
parent_locker(image_ctx
.parent_lock
);
174 // should have been canceled prior to releasing lock
175 ceph_assert(image_ctx
.exclusive_lock
== nullptr ||
176 image_ctx
.exclusive_lock
->is_lock_owner());
178 // save current size / parent info for creating snapshot record in ImageCtx
179 m_size
= image_ctx
.size
;
180 m_parent_info
= image_ctx
.parent_md
;
182 librados::ObjectWriteOperation op
;
183 if (image_ctx
.old_format
) {
184 cls_client::old_snapshot_add(&op
, m_snap_id
, m_snap_name
);
186 cls_client::snapshot_add(&op
, m_snap_id
, m_snap_name
, m_snap_namespace
);
189 librados::AioCompletion
*rados_completion
= create_rados_callback
<
190 SnapshotCreateRequest
<I
>,
191 &SnapshotCreateRequest
<I
>::handle_create_snap
>(this);
192 int r
= image_ctx
.md_ctx
.aio_operate(image_ctx
.header_oid
,
193 rados_completion
, &op
);
195 rados_completion
->release();
198 template <typename I
>
199 Context
*SnapshotCreateRequest
<I
>::handle_create_snap(int *result
) {
200 I
&image_ctx
= this->m_image_ctx
;
201 CephContext
*cct
= image_ctx
.cct
;
202 ldout(cct
, 5) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
204 if (*result
== -ESTALE
) {
205 send_allocate_snap_id();
207 } else if (*result
< 0) {
209 send_release_snap_id();
213 return send_create_object_map();
216 template <typename I
>
217 Context
*SnapshotCreateRequest
<I
>::send_create_object_map() {
218 I
&image_ctx
= this->m_image_ctx
;
220 image_ctx
.snap_lock
.get_read();
221 if (image_ctx
.object_map
== nullptr || m_skip_object_map
) {
222 image_ctx
.snap_lock
.put_read();
224 update_snap_context();
225 image_ctx
.io_work_queue
->unblock_writes();
226 return this->create_context_finisher(0);
229 CephContext
*cct
= image_ctx
.cct
;
230 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
233 RWLock::RLocker
object_map_lock(image_ctx
.object_map_lock
);
234 image_ctx
.object_map
->snapshot_add(
235 m_snap_id
, create_context_callback
<
236 SnapshotCreateRequest
<I
>,
237 &SnapshotCreateRequest
<I
>::handle_create_object_map
>(this));
239 image_ctx
.snap_lock
.put_read();
243 template <typename I
>
244 Context
*SnapshotCreateRequest
<I
>::handle_create_object_map(int *result
) {
245 I
&image_ctx
= this->m_image_ctx
;
246 CephContext
*cct
= image_ctx
.cct
;
247 ldout(cct
, 5) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
249 update_snap_context();
250 image_ctx
.io_work_queue
->unblock_writes();
252 lderr(cct
) << this << " " << __func__
<< ": failed to snapshot object map: "
253 << cpp_strerror(*result
) << dendl
;
254 return this->create_context_finisher(*result
);
257 return this->create_context_finisher(0);
260 template <typename I
>
261 void SnapshotCreateRequest
<I
>::send_release_snap_id() {
262 I
&image_ctx
= this->m_image_ctx
;
263 CephContext
*cct
= image_ctx
.cct
;
264 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
266 ceph_assert(m_snap_id
!= CEPH_NOSNAP
);
268 librados::AioCompletion
*rados_completion
= create_rados_callback
<
269 SnapshotCreateRequest
<I
>,
270 &SnapshotCreateRequest
<I
>::handle_release_snap_id
>(this);
271 image_ctx
.data_ctx
.aio_selfmanaged_snap_remove(m_snap_id
, rados_completion
);
272 rados_completion
->release();
275 template <typename I
>
276 Context
*SnapshotCreateRequest
<I
>::handle_release_snap_id(int *result
) {
277 I
&image_ctx
= this->m_image_ctx
;
278 CephContext
*cct
= image_ctx
.cct
;
279 ldout(cct
, 5) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
281 ceph_assert(m_ret_val
< 0);
284 image_ctx
.io_work_queue
->unblock_writes();
285 return this->create_context_finisher(m_ret_val
);
288 template <typename I
>
289 void SnapshotCreateRequest
<I
>::update_snap_context() {
290 I
&image_ctx
= this->m_image_ctx
;
292 RWLock::RLocker
owner_locker(image_ctx
.owner_lock
);
293 RWLock::WLocker
snap_locker(image_ctx
.snap_lock
);
294 if (image_ctx
.old_format
) {
298 if (image_ctx
.get_snap_info(m_snap_id
) != NULL
) {
302 CephContext
*cct
= image_ctx
.cct
;
303 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
305 // should have been canceled prior to releasing lock
306 ceph_assert(image_ctx
.exclusive_lock
== nullptr ||
307 image_ctx
.exclusive_lock
->is_lock_owner());
309 // immediately add a reference to the new snapshot
310 utime_t snap_time
= ceph_clock_now();
311 image_ctx
.add_snap(m_snap_namespace
, m_snap_name
, m_snap_id
, m_size
,
312 m_parent_info
, RBD_PROTECTION_STATUS_UNPROTECTED
,
315 // immediately start using the new snap context if we
316 // own the exclusive lock
317 std::vector
<snapid_t
> snaps
;
318 snaps
.push_back(m_snap_id
);
319 snaps
.insert(snaps
.end(), image_ctx
.snapc
.snaps
.begin(),
320 image_ctx
.snapc
.snaps
.end());
322 image_ctx
.snapc
.seq
= m_snap_id
;
323 image_ctx
.snapc
.snaps
.swap(snaps
);
324 image_ctx
.data_ctx
.selfmanaged_snap_set_write_ctx(
325 image_ctx
.snapc
.seq
, image_ctx
.snaps
);
327 if (!image_ctx
.migration_info
.empty()) {
328 auto it
= image_ctx
.migration_info
.snap_map
.find(CEPH_NOSNAP
);
329 ceph_assert(it
!= image_ctx
.migration_info
.snap_map
.end());
330 ceph_assert(!it
->second
.empty());
331 if (it
->second
[0] == CEPH_NOSNAP
) {
332 ldout(cct
, 5) << this << " " << __func__
333 << ": updating migration snap_map" << dendl
;
334 it
->second
[0] = m_snap_id
;
339 } // namespace operation
340 } // namespace librbd
342 template class librbd::operation::SnapshotCreateRequest
<librbd::ImageCtx
>;