1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "SnapshotCopyRequest.h"
5 #include "SnapshotCreateRequest.h"
6 #include "common/errno.h"
7 #include "common/WorkQueue.h"
8 #include "journal/Journaler.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/Operations.h"
11 #include "librbd/Utils.h"
12 #include "librbd/journal/Types.h"
14 #define dout_context g_ceph_context
15 #define dout_subsys ceph_subsys_rbd_mirror
17 #define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCopyRequest: " \
18 << this << " " << __func__
22 namespace image_sync
{
27 const std::string
&get_snapshot_name(I
*image_ctx
, librados::snap_t snap_id
) {
28 auto snap_it
= std::find_if(image_ctx
->snap_ids
.begin(),
29 image_ctx
->snap_ids
.end(),
32 std::pair
<cls::rbd::SnapshotNamespace
,
34 librados::snap_t
> &pair
) {
35 return pair
.second
== snap_id
;
37 assert(snap_it
!= image_ctx
->snap_ids
.end());
38 return snap_it
->first
.second
;
41 } // anonymous namespace
43 using librbd::util::create_context_callback
;
44 using librbd::util::unique_lock_name
;
47 SnapshotCopyRequest
<I
>::SnapshotCopyRequest(I
*local_image_ctx
,
51 librbd::journal::MirrorPeerClientMeta
*meta
,
52 ContextWQ
*work_queue
,
54 : BaseRequest("rbd::mirror::image_sync::SnapshotCopyRequest",
55 local_image_ctx
->cct
, on_finish
),
56 m_local_image_ctx(local_image_ctx
), m_remote_image_ctx(remote_image_ctx
),
57 m_snap_map(snap_map
), m_journaler(journaler
), m_client_meta(meta
),
58 m_work_queue(work_queue
), m_snap_seqs(meta
->snap_seqs
),
59 m_lock(unique_lock_name("SnapshotCopyRequest::m_lock", this)) {
62 // snap ids ordered from oldest to newest
63 m_remote_snap_ids
.insert(remote_image_ctx
->snaps
.begin(),
64 remote_image_ctx
->snaps
.end());
65 m_local_snap_ids
.insert(local_image_ctx
->snaps
.begin(),
66 local_image_ctx
->snaps
.end());
70 void SnapshotCopyRequest
<I
>::send() {
71 librbd::ParentSpec remote_parent_spec
;
72 int r
= validate_parent(m_remote_image_ctx
, &remote_parent_spec
);
74 derr
<< ": remote image parent spec mismatch" << dendl
;
79 r
= validate_parent(m_local_image_ctx
, &m_local_parent_spec
);
81 derr
<< ": local image parent spec mismatch" << dendl
;
86 send_snap_unprotect();
90 void SnapshotCopyRequest
<I
>::cancel() {
91 Mutex::Locker
locker(m_lock
);
98 void SnapshotCopyRequest
<I
>::send_snap_unprotect() {
100 SnapIdSet::iterator snap_id_it
= m_local_snap_ids
.begin();
101 if (m_prev_snap_id
!= CEPH_NOSNAP
) {
102 snap_id_it
= m_local_snap_ids
.upper_bound(m_prev_snap_id
);
105 for (; snap_id_it
!= m_local_snap_ids
.end(); ++snap_id_it
) {
106 librados::snap_t local_snap_id
= *snap_id_it
;
108 m_local_image_ctx
->snap_lock
.get_read();
110 bool local_unprotected
;
111 int r
= m_local_image_ctx
->is_snap_unprotected(local_snap_id
,
114 derr
<< ": failed to retrieve local snap unprotect status: "
115 << cpp_strerror(r
) << dendl
;
116 m_local_image_ctx
->snap_lock
.put_read();
120 m_local_image_ctx
->snap_lock
.put_read();
122 if (local_unprotected
) {
123 // snap is already unprotected -- check next snap
127 // if local snapshot is protected and (1) it isn't in our mapping
128 // table, or (2) the remote snapshot isn't protected, unprotect it
129 auto snap_seq_it
= std::find_if(
130 m_snap_seqs
.begin(), m_snap_seqs
.end(),
131 [local_snap_id
](const SnapSeqs::value_type
& pair
) {
132 return pair
.second
== local_snap_id
;
135 if (snap_seq_it
!= m_snap_seqs
.end()) {
136 m_remote_image_ctx
->snap_lock
.get_read();
137 bool remote_unprotected
;
138 r
= m_remote_image_ctx
->is_snap_unprotected(snap_seq_it
->first
,
139 &remote_unprotected
);
141 derr
<< ": failed to retrieve remote snap unprotect status: "
142 << cpp_strerror(r
) << dendl
;
143 m_remote_image_ctx
->snap_lock
.put_read();
147 m_remote_image_ctx
->snap_lock
.put_read();
149 if (remote_unprotected
) {
150 // remote is unprotected -- unprotect local snap
154 // remote snapshot doesn't exist -- unprotect local snap
159 if (snap_id_it
== m_local_snap_ids
.end()) {
160 // no local snapshots to unprotect
161 m_prev_snap_id
= CEPH_NOSNAP
;
166 m_prev_snap_id
= *snap_id_it
;
167 m_snap_name
= get_snapshot_name(m_local_image_ctx
, m_prev_snap_id
);
170 << "snap_name=" << m_snap_name
<< ", "
171 << "snap_id=" << m_prev_snap_id
<< dendl
;
174 auto finish_op_ctx
= start_local_op(&r
);
175 if (finish_op_ctx
== nullptr) {
176 derr
<< ": lost exclusive lock" << dendl
;
181 auto ctx
= new FunctionContext([this, finish_op_ctx
](int r
) {
182 handle_snap_unprotect(r
);
183 finish_op_ctx
->complete(0);
185 RWLock::RLocker
owner_locker(m_local_image_ctx
->owner_lock
);
186 m_local_image_ctx
->operations
->execute_snap_unprotect(
187 cls::rbd::UserSnapshotNamespace(), m_snap_name
.c_str(), ctx
);
190 template <typename I
>
191 void SnapshotCopyRequest
<I
>::handle_snap_unprotect(int r
) {
192 dout(20) << ": r=" << r
<< dendl
;
195 derr
<< ": failed to unprotect snapshot '" << m_snap_name
<< "': "
196 << cpp_strerror(r
) << dendl
;
200 if (handle_cancellation())
205 send_snap_unprotect();
208 template <typename I
>
209 void SnapshotCopyRequest
<I
>::send_snap_remove() {
210 SnapIdSet::iterator snap_id_it
= m_local_snap_ids
.begin();
211 if (m_prev_snap_id
!= CEPH_NOSNAP
) {
212 snap_id_it
= m_local_snap_ids
.upper_bound(m_prev_snap_id
);
215 for (; snap_id_it
!= m_local_snap_ids
.end(); ++snap_id_it
) {
216 librados::snap_t local_snap_id
= *snap_id_it
;
218 cls::rbd::SnapshotNamespace snap_namespace
;
219 m_local_image_ctx
->snap_lock
.get_read();
220 int r
= m_local_image_ctx
->get_snap_namespace(local_snap_id
,
222 m_local_image_ctx
->snap_lock
.put_read();
224 derr
<< ": failed to retrieve local snap namespace: " << m_snap_name
230 if (boost::get
<cls::rbd::UserSnapshotNamespace
>(&snap_namespace
) ==
235 // if the local snapshot isn't in our mapping table, remove it
236 auto snap_seq_it
= std::find_if(
237 m_snap_seqs
.begin(), m_snap_seqs
.end(),
238 [local_snap_id
](const SnapSeqs::value_type
& pair
) {
239 return pair
.second
== local_snap_id
;
242 if (snap_seq_it
== m_snap_seqs
.end()) {
247 if (snap_id_it
== m_local_snap_ids
.end()) {
248 // no local snapshots to delete
249 m_prev_snap_id
= CEPH_NOSNAP
;
254 m_prev_snap_id
= *snap_id_it
;
255 m_snap_name
= get_snapshot_name(m_local_image_ctx
, m_prev_snap_id
);
258 << "snap_name=" << m_snap_name
<< ", "
259 << "snap_id=" << m_prev_snap_id
<< dendl
;
262 auto finish_op_ctx
= start_local_op(&r
);
263 if (finish_op_ctx
== nullptr) {
264 derr
<< ": lost exclusive lock" << dendl
;
269 auto ctx
= new FunctionContext([this, finish_op_ctx
](int r
) {
270 handle_snap_remove(r
);
271 finish_op_ctx
->complete(0);
273 RWLock::RLocker
owner_locker(m_local_image_ctx
->owner_lock
);
274 m_local_image_ctx
->operations
->execute_snap_remove(
275 cls::rbd::UserSnapshotNamespace(), m_snap_name
.c_str(), ctx
);
278 template <typename I
>
279 void SnapshotCopyRequest
<I
>::handle_snap_remove(int r
) {
280 dout(20) << ": r=" << r
<< dendl
;
283 derr
<< ": failed to remove snapshot '" << m_snap_name
<< "': "
284 << cpp_strerror(r
) << dendl
;
288 if (handle_cancellation())
296 template <typename I
>
297 void SnapshotCopyRequest
<I
>::send_snap_create() {
298 SnapIdSet::iterator snap_id_it
= m_remote_snap_ids
.begin();
299 if (m_prev_snap_id
!= CEPH_NOSNAP
) {
300 snap_id_it
= m_remote_snap_ids
.upper_bound(m_prev_snap_id
);
303 for (; snap_id_it
!= m_remote_snap_ids
.end(); ++snap_id_it
) {
304 librados::snap_t remote_snap_id
= *snap_id_it
;
306 cls::rbd::SnapshotNamespace snap_namespace
;
307 m_remote_image_ctx
->snap_lock
.get_read();
308 int r
= m_remote_image_ctx
->get_snap_namespace(remote_snap_id
, &snap_namespace
);
309 m_remote_image_ctx
->snap_lock
.put_read();
311 derr
<< ": failed to retrieve remote snap namespace: " << m_snap_name
317 // if the remote snapshot isn't in our mapping table, create it
318 if (m_snap_seqs
.find(remote_snap_id
) == m_snap_seqs
.end() &&
319 boost::get
<cls::rbd::UserSnapshotNamespace
>(&snap_namespace
) != nullptr) {
324 if (snap_id_it
== m_remote_snap_ids
.end()) {
325 // no remote snapshots to create
326 m_prev_snap_id
= CEPH_NOSNAP
;
331 m_prev_snap_id
= *snap_id_it
;
332 m_snap_name
= get_snapshot_name(m_remote_image_ctx
, m_prev_snap_id
);
334 m_remote_image_ctx
->snap_lock
.get_read();
335 auto snap_info_it
= m_remote_image_ctx
->snap_info
.find(m_prev_snap_id
);
336 if (snap_info_it
== m_remote_image_ctx
->snap_info
.end()) {
337 m_remote_image_ctx
->snap_lock
.put_read();
338 derr
<< ": failed to retrieve remote snap info: " << m_snap_name
344 uint64_t size
= snap_info_it
->second
.size
;
345 m_snap_namespace
= snap_info_it
->second
.snap_namespace
;
346 librbd::ParentSpec parent_spec
;
347 uint64_t parent_overlap
= 0;
348 if (snap_info_it
->second
.parent
.spec
.pool_id
!= -1) {
349 parent_spec
= m_local_parent_spec
;
350 parent_overlap
= snap_info_it
->second
.parent
.overlap
;
352 m_remote_image_ctx
->snap_lock
.put_read();
356 << "snap_name=" << m_snap_name
<< ", "
357 << "snap_id=" << m_prev_snap_id
<< ", "
358 << "size=" << size
<< ", "
360 << "pool_id=" << parent_spec
.pool_id
<< ", "
361 << "image_id=" << parent_spec
.image_id
<< ", "
362 << "snap_id=" << parent_spec
.snap_id
<< ", "
363 << "overlap=" << parent_overlap
<< "]" << dendl
;
366 Context
*finish_op_ctx
= start_local_op(&r
);
367 if (finish_op_ctx
== nullptr) {
368 derr
<< ": lost exclusive lock" << dendl
;
373 auto ctx
= new FunctionContext([this, finish_op_ctx
](int r
) {
374 handle_snap_create(r
);
375 finish_op_ctx
->complete(0);
377 SnapshotCreateRequest
<I
> *req
= SnapshotCreateRequest
<I
>::create(
378 m_local_image_ctx
, m_snap_name
, m_snap_namespace
, size
, parent_spec
,
379 parent_overlap
, ctx
);
383 template <typename I
>
384 void SnapshotCopyRequest
<I
>::handle_snap_create(int r
) {
385 dout(20) << ": r=" << r
<< dendl
;
388 derr
<< ": failed to create snapshot '" << m_snap_name
<< "': "
389 << cpp_strerror(r
) << dendl
;
393 if (handle_cancellation())
398 assert(m_prev_snap_id
!= CEPH_NOSNAP
);
400 auto snap_it
= m_local_image_ctx
->snap_ids
.find({cls::rbd::UserSnapshotNamespace(),
402 assert(snap_it
!= m_local_image_ctx
->snap_ids
.end());
403 librados::snap_t local_snap_id
= snap_it
->second
;
405 dout(20) << ": mapping remote snap id " << m_prev_snap_id
<< " to "
406 << local_snap_id
<< dendl
;
407 m_snap_seqs
[m_prev_snap_id
] = local_snap_id
;
412 template <typename I
>
413 void SnapshotCopyRequest
<I
>::send_snap_protect() {
414 SnapIdSet::iterator snap_id_it
= m_remote_snap_ids
.begin();
415 if (m_prev_snap_id
!= CEPH_NOSNAP
) {
416 snap_id_it
= m_remote_snap_ids
.upper_bound(m_prev_snap_id
);
419 for (; snap_id_it
!= m_remote_snap_ids
.end(); ++snap_id_it
) {
420 librados::snap_t remote_snap_id
= *snap_id_it
;
422 m_remote_image_ctx
->snap_lock
.get_read();
424 bool remote_protected
;
425 int r
= m_remote_image_ctx
->is_snap_protected(remote_snap_id
,
428 derr
<< ": failed to retrieve remote snap protect status: "
429 << cpp_strerror(r
) << dendl
;
430 m_remote_image_ctx
->snap_lock
.put_read();
434 m_remote_image_ctx
->snap_lock
.put_read();
436 if (!remote_protected
) {
437 // snap is not protected -- check next snap
441 // if local snapshot is not protected, protect it
442 auto snap_seq_it
= m_snap_seqs
.find(remote_snap_id
);
443 assert(snap_seq_it
!= m_snap_seqs
.end());
445 m_local_image_ctx
->snap_lock
.get_read();
446 bool local_protected
;
447 r
= m_local_image_ctx
->is_snap_protected(snap_seq_it
->second
,
450 derr
<< ": failed to retrieve local snap protect status: "
451 << cpp_strerror(r
) << dendl
;
452 m_local_image_ctx
->snap_lock
.put_read();
456 m_local_image_ctx
->snap_lock
.put_read();
458 if (!local_protected
) {
463 if (snap_id_it
== m_remote_snap_ids
.end()) {
464 // no local snapshots to protect
465 m_prev_snap_id
= CEPH_NOSNAP
;
466 send_update_client();
470 m_prev_snap_id
= *snap_id_it
;
471 m_snap_name
= get_snapshot_name(m_remote_image_ctx
, m_prev_snap_id
);
474 << "snap_name=" << m_snap_name
<< ", "
475 << "snap_id=" << m_prev_snap_id
<< dendl
;
478 auto finish_op_ctx
= start_local_op(&r
);
479 if (finish_op_ctx
== nullptr) {
480 derr
<< ": lost exclusive lock" << dendl
;
485 auto ctx
= new FunctionContext([this, finish_op_ctx
](int r
) {
486 handle_snap_protect(r
);
487 finish_op_ctx
->complete(0);
489 RWLock::RLocker
owner_locker(m_local_image_ctx
->owner_lock
);
490 m_local_image_ctx
->operations
->execute_snap_protect(
491 cls::rbd::UserSnapshotNamespace(), m_snap_name
.c_str(), ctx
);
494 template <typename I
>
495 void SnapshotCopyRequest
<I
>::handle_snap_protect(int r
) {
496 dout(20) << ": r=" << r
<< dendl
;
499 derr
<< ": failed to protect snapshot '" << m_snap_name
<< "': "
500 << cpp_strerror(r
) << dendl
;
504 if (handle_cancellation())
512 template <typename I
>
513 void SnapshotCopyRequest
<I
>::send_update_client() {
518 librbd::journal::MirrorPeerClientMeta
client_meta(*m_client_meta
);
519 client_meta
.snap_seqs
= m_snap_seqs
;
521 librbd::journal::ClientData
client_data(client_meta
);
523 ::encode(client_data
, data_bl
);
525 Context
*ctx
= create_context_callback
<
526 SnapshotCopyRequest
<I
>, &SnapshotCopyRequest
<I
>::handle_update_client
>(
528 m_journaler
->update_client(data_bl
, ctx
);
531 template <typename I
>
532 void SnapshotCopyRequest
<I
>::handle_update_client(int r
) {
533 dout(20) << ": r=" << r
<< dendl
;
536 derr
<< ": failed to update client data: " << cpp_strerror(r
)
541 if (handle_cancellation())
546 m_client_meta
->snap_seqs
= m_snap_seqs
;
551 template <typename I
>
552 bool SnapshotCopyRequest
<I
>::handle_cancellation() {
554 Mutex::Locker
locker(m_lock
);
559 dout(10) << ": snapshot copy canceled" << dendl
;
564 template <typename I
>
565 void SnapshotCopyRequest
<I
>::error(int r
) {
566 dout(20) << ": r=" << r
<< dendl
;
568 m_work_queue
->queue(new FunctionContext([this, r
](int r1
) { finish(r
); }));
571 template <typename I
>
572 void SnapshotCopyRequest
<I
>::compute_snap_map() {
573 SnapIds local_snap_ids
;
574 for (auto &pair
: m_snap_seqs
) {
575 local_snap_ids
.reserve(1 + local_snap_ids
.size());
576 local_snap_ids
.insert(local_snap_ids
.begin(), pair
.second
);
577 m_snap_map
->insert(std::make_pair(pair
.first
, local_snap_ids
));
581 template <typename I
>
582 int SnapshotCopyRequest
<I
>::validate_parent(I
*image_ctx
,
583 librbd::ParentSpec
*spec
) {
584 RWLock::RLocker
owner_locker(image_ctx
->owner_lock
);
585 RWLock::RLocker
snap_locker(image_ctx
->snap_lock
);
587 // ensure remote image's parent specs are still consistent
588 *spec
= image_ctx
->parent_md
.spec
;
589 for (auto &snap_info_pair
: image_ctx
->snap_info
) {
590 auto &parent_spec
= snap_info_pair
.second
.parent
.spec
;
591 if (parent_spec
.pool_id
== -1) {
593 } else if (spec
->pool_id
== -1) {
598 if (*spec
!= parent_spec
) {
605 template <typename I
>
606 Context
*SnapshotCopyRequest
<I
>::start_local_op(int *r
) {
607 RWLock::RLocker
owner_locker(m_local_image_ctx
->owner_lock
);
608 if (m_local_image_ctx
->exclusive_lock
== nullptr) {
612 return m_local_image_ctx
->exclusive_lock
->start_op(r
);
615 } // namespace image_sync
616 } // namespace mirror
619 template class rbd::mirror::image_sync::SnapshotCopyRequest
<librbd::ImageCtx
>;