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/Operations.h"
10 #include "librbd/Utils.h"
11 #include "librbd/journal/Types.h"
13 #define dout_context g_ceph_context
14 #define dout_subsys ceph_subsys_rbd_mirror
16 #define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCopyRequest: " \
17 << this << " " << __func__
21 namespace image_sync
{
26 const std::string
&get_snapshot_name(I
*image_ctx
, librados::snap_t snap_id
) {
27 auto snap_it
= std::find_if(image_ctx
->snap_ids
.begin(),
28 image_ctx
->snap_ids
.end(),
31 std::pair
<cls::rbd::SnapshotNamespace
,
33 librados::snap_t
> &pair
) {
34 return pair
.second
== snap_id
;
36 assert(snap_it
!= image_ctx
->snap_ids
.end());
37 return snap_it
->first
.second
;
40 } // anonymous namespace
42 using librbd::util::create_context_callback
;
43 using librbd::util::unique_lock_name
;
46 SnapshotCopyRequest
<I
>::SnapshotCopyRequest(I
*local_image_ctx
,
50 librbd::journal::MirrorPeerClientMeta
*meta
,
51 ContextWQ
*work_queue
,
53 : BaseRequest("rbd::mirror::image_sync::SnapshotCopyRequest",
54 local_image_ctx
->cct
, on_finish
),
55 m_local_image_ctx(local_image_ctx
), m_remote_image_ctx(remote_image_ctx
),
56 m_snap_map(snap_map
), m_journaler(journaler
), m_client_meta(meta
),
57 m_work_queue(work_queue
), m_snap_seqs(meta
->snap_seqs
),
58 m_lock(unique_lock_name("SnapshotCopyRequest::m_lock", this)) {
61 // snap ids ordered from oldest to newest
62 m_remote_snap_ids
.insert(remote_image_ctx
->snaps
.begin(),
63 remote_image_ctx
->snaps
.end());
64 m_local_snap_ids
.insert(local_image_ctx
->snaps
.begin(),
65 local_image_ctx
->snaps
.end());
69 void SnapshotCopyRequest
<I
>::send() {
70 librbd::ParentSpec remote_parent_spec
;
71 int r
= validate_parent(m_remote_image_ctx
, &remote_parent_spec
);
73 derr
<< ": remote image parent spec mismatch" << dendl
;
78 r
= validate_parent(m_local_image_ctx
, &m_local_parent_spec
);
80 derr
<< ": local image parent spec mismatch" << dendl
;
85 send_snap_unprotect();
89 void SnapshotCopyRequest
<I
>::cancel() {
90 Mutex::Locker
locker(m_lock
);
97 void SnapshotCopyRequest
<I
>::send_snap_unprotect() {
99 SnapIdSet::iterator snap_id_it
= m_local_snap_ids
.begin();
100 if (m_prev_snap_id
!= CEPH_NOSNAP
) {
101 snap_id_it
= m_local_snap_ids
.upper_bound(m_prev_snap_id
);
104 for (; snap_id_it
!= m_local_snap_ids
.end(); ++snap_id_it
) {
105 librados::snap_t local_snap_id
= *snap_id_it
;
107 m_local_image_ctx
->snap_lock
.get_read();
109 bool local_unprotected
;
110 int r
= m_local_image_ctx
->is_snap_unprotected(local_snap_id
,
113 derr
<< ": failed to retrieve local snap unprotect status: "
114 << cpp_strerror(r
) << dendl
;
115 m_local_image_ctx
->snap_lock
.put_read();
119 m_local_image_ctx
->snap_lock
.put_read();
121 if (local_unprotected
) {
122 // snap is already unprotected -- check next snap
126 // if local snapshot is protected and (1) it isn't in our mapping
127 // table, or (2) the remote snapshot isn't protected, unprotect it
128 auto snap_seq_it
= std::find_if(
129 m_snap_seqs
.begin(), m_snap_seqs
.end(),
130 [local_snap_id
](const SnapSeqs::value_type
& pair
) {
131 return pair
.second
== local_snap_id
;
134 if (snap_seq_it
!= m_snap_seqs
.end()) {
135 m_remote_image_ctx
->snap_lock
.get_read();
136 bool remote_unprotected
;
137 r
= m_remote_image_ctx
->is_snap_unprotected(snap_seq_it
->first
,
138 &remote_unprotected
);
140 derr
<< ": failed to retrieve remote snap unprotect status: "
141 << cpp_strerror(r
) << dendl
;
142 m_remote_image_ctx
->snap_lock
.put_read();
146 m_remote_image_ctx
->snap_lock
.put_read();
148 if (remote_unprotected
) {
149 // remote is unprotected -- unprotect local snap
153 // remote snapshot doesn't exist -- unprotect local snap
158 if (snap_id_it
== m_local_snap_ids
.end()) {
159 // no local snapshots to unprotect
160 m_prev_snap_id
= CEPH_NOSNAP
;
165 m_prev_snap_id
= *snap_id_it
;
166 m_snap_name
= get_snapshot_name(m_local_image_ctx
, m_prev_snap_id
);
169 << "snap_name=" << m_snap_name
<< ", "
170 << "snap_id=" << m_prev_snap_id
<< dendl
;
172 Context
*ctx
= create_context_callback
<
173 SnapshotCopyRequest
<I
>, &SnapshotCopyRequest
<I
>::handle_snap_unprotect
>(
175 RWLock::RLocker
owner_locker(m_local_image_ctx
->owner_lock
);
176 m_local_image_ctx
->operations
->execute_snap_unprotect(cls::rbd::UserSnapshotNamespace(),
181 template <typename I
>
182 void SnapshotCopyRequest
<I
>::handle_snap_unprotect(int r
) {
183 dout(20) << ": r=" << r
<< dendl
;
186 derr
<< ": failed to unprotect snapshot '" << m_snap_name
<< "': "
187 << cpp_strerror(r
) << dendl
;
191 if (handle_cancellation())
196 send_snap_unprotect();
199 template <typename I
>
200 void SnapshotCopyRequest
<I
>::send_snap_remove() {
201 SnapIdSet::iterator snap_id_it
= m_local_snap_ids
.begin();
202 if (m_prev_snap_id
!= CEPH_NOSNAP
) {
203 snap_id_it
= m_local_snap_ids
.upper_bound(m_prev_snap_id
);
206 for (; snap_id_it
!= m_local_snap_ids
.end(); ++snap_id_it
) {
207 librados::snap_t local_snap_id
= *snap_id_it
;
209 cls::rbd::SnapshotNamespace snap_namespace
;
210 m_local_image_ctx
->snap_lock
.get_read();
211 int r
= m_local_image_ctx
->get_snap_namespace(local_snap_id
, &snap_namespace
);
212 m_local_image_ctx
->snap_lock
.put_read();
214 derr
<< ": failed to retrieve local snap namespace: " << m_snap_name
220 if (boost::get
<cls::rbd::UserSnapshotNamespace
>(&snap_namespace
) == nullptr) {
224 // if the local snapshot isn't in our mapping table, remove it
225 auto snap_seq_it
= std::find_if(
226 m_snap_seqs
.begin(), m_snap_seqs
.end(),
227 [local_snap_id
](const SnapSeqs::value_type
& pair
) {
228 return pair
.second
== local_snap_id
;
231 if (snap_seq_it
== m_snap_seqs
.end()) {
236 if (snap_id_it
== m_local_snap_ids
.end()) {
237 // no local snapshots to delete
238 m_prev_snap_id
= CEPH_NOSNAP
;
243 m_prev_snap_id
= *snap_id_it
;
244 m_snap_name
= get_snapshot_name(m_local_image_ctx
, m_prev_snap_id
);
247 << "snap_name=" << m_snap_name
<< ", "
248 << "snap_id=" << m_prev_snap_id
<< dendl
;
250 Context
*ctx
= create_context_callback
<
251 SnapshotCopyRequest
<I
>, &SnapshotCopyRequest
<I
>::handle_snap_remove
>(
253 RWLock::RLocker
owner_locker(m_local_image_ctx
->owner_lock
);
254 m_local_image_ctx
->operations
->execute_snap_remove(cls::rbd::UserSnapshotNamespace(),
259 template <typename I
>
260 void SnapshotCopyRequest
<I
>::handle_snap_remove(int r
) {
261 dout(20) << ": r=" << r
<< dendl
;
264 derr
<< ": failed to remove snapshot '" << m_snap_name
<< "': "
265 << cpp_strerror(r
) << dendl
;
269 if (handle_cancellation())
277 template <typename I
>
278 void SnapshotCopyRequest
<I
>::send_snap_create() {
279 SnapIdSet::iterator snap_id_it
= m_remote_snap_ids
.begin();
280 if (m_prev_snap_id
!= CEPH_NOSNAP
) {
281 snap_id_it
= m_remote_snap_ids
.upper_bound(m_prev_snap_id
);
284 for (; snap_id_it
!= m_remote_snap_ids
.end(); ++snap_id_it
) {
285 librados::snap_t remote_snap_id
= *snap_id_it
;
287 cls::rbd::SnapshotNamespace snap_namespace
;
288 m_remote_image_ctx
->snap_lock
.get_read();
289 int r
= m_remote_image_ctx
->get_snap_namespace(remote_snap_id
, &snap_namespace
);
290 m_remote_image_ctx
->snap_lock
.put_read();
292 derr
<< ": failed to retrieve remote snap namespace: " << m_snap_name
298 // if the remote snapshot isn't in our mapping table, create it
299 if (m_snap_seqs
.find(remote_snap_id
) == m_snap_seqs
.end() &&
300 boost::get
<cls::rbd::UserSnapshotNamespace
>(&snap_namespace
) != nullptr) {
305 if (snap_id_it
== m_remote_snap_ids
.end()) {
306 // no remote snapshots to create
307 m_prev_snap_id
= CEPH_NOSNAP
;
312 m_prev_snap_id
= *snap_id_it
;
313 m_snap_name
= get_snapshot_name(m_remote_image_ctx
, m_prev_snap_id
);
315 m_remote_image_ctx
->snap_lock
.get_read();
316 auto snap_info_it
= m_remote_image_ctx
->snap_info
.find(m_prev_snap_id
);
317 if (snap_info_it
== m_remote_image_ctx
->snap_info
.end()) {
318 m_remote_image_ctx
->snap_lock
.put_read();
319 derr
<< ": failed to retrieve remote snap info: " << m_snap_name
325 uint64_t size
= snap_info_it
->second
.size
;
326 m_snap_namespace
= snap_info_it
->second
.snap_namespace
;
327 librbd::ParentSpec parent_spec
;
328 uint64_t parent_overlap
= 0;
329 if (snap_info_it
->second
.parent
.spec
.pool_id
!= -1) {
330 parent_spec
= m_local_parent_spec
;
331 parent_overlap
= snap_info_it
->second
.parent
.overlap
;
333 m_remote_image_ctx
->snap_lock
.put_read();
337 << "snap_name=" << m_snap_name
<< ", "
338 << "snap_id=" << m_prev_snap_id
<< ", "
339 << "size=" << size
<< ", "
341 << "pool_id=" << parent_spec
.pool_id
<< ", "
342 << "image_id=" << parent_spec
.image_id
<< ", "
343 << "snap_id=" << parent_spec
.snap_id
<< ", "
344 << "overlap=" << parent_overlap
<< "]" << dendl
;
346 Context
*ctx
= create_context_callback
<
347 SnapshotCopyRequest
<I
>, &SnapshotCopyRequest
<I
>::handle_snap_create
>(
349 SnapshotCreateRequest
<I
> *req
= SnapshotCreateRequest
<I
>::create(
350 m_local_image_ctx
, m_snap_name
, m_snap_namespace
, size
, parent_spec
, parent_overlap
, ctx
);
354 template <typename I
>
355 void SnapshotCopyRequest
<I
>::handle_snap_create(int r
) {
356 dout(20) << ": r=" << r
<< dendl
;
359 derr
<< ": failed to create snapshot '" << m_snap_name
<< "': "
360 << cpp_strerror(r
) << dendl
;
364 if (handle_cancellation())
369 assert(m_prev_snap_id
!= CEPH_NOSNAP
);
371 auto snap_it
= m_local_image_ctx
->snap_ids
.find({cls::rbd::UserSnapshotNamespace(),
373 assert(snap_it
!= m_local_image_ctx
->snap_ids
.end());
374 librados::snap_t local_snap_id
= snap_it
->second
;
376 dout(20) << ": mapping remote snap id " << m_prev_snap_id
<< " to "
377 << local_snap_id
<< dendl
;
378 m_snap_seqs
[m_prev_snap_id
] = local_snap_id
;
383 template <typename I
>
384 void SnapshotCopyRequest
<I
>::send_snap_protect() {
385 SnapIdSet::iterator snap_id_it
= m_remote_snap_ids
.begin();
386 if (m_prev_snap_id
!= CEPH_NOSNAP
) {
387 snap_id_it
= m_remote_snap_ids
.upper_bound(m_prev_snap_id
);
390 for (; snap_id_it
!= m_remote_snap_ids
.end(); ++snap_id_it
) {
391 librados::snap_t remote_snap_id
= *snap_id_it
;
393 m_remote_image_ctx
->snap_lock
.get_read();
395 bool remote_protected
;
396 int r
= m_remote_image_ctx
->is_snap_protected(remote_snap_id
,
399 derr
<< ": failed to retrieve remote snap protect status: "
400 << cpp_strerror(r
) << dendl
;
401 m_remote_image_ctx
->snap_lock
.put_read();
405 m_remote_image_ctx
->snap_lock
.put_read();
407 if (!remote_protected
) {
408 // snap is not protected -- check next snap
412 // if local snapshot is not protected, protect it
413 auto snap_seq_it
= m_snap_seqs
.find(remote_snap_id
);
414 assert(snap_seq_it
!= m_snap_seqs
.end());
416 m_local_image_ctx
->snap_lock
.get_read();
417 bool local_protected
;
418 r
= m_local_image_ctx
->is_snap_protected(snap_seq_it
->second
,
421 derr
<< ": failed to retrieve local snap protect status: "
422 << cpp_strerror(r
) << dendl
;
423 m_local_image_ctx
->snap_lock
.put_read();
427 m_local_image_ctx
->snap_lock
.put_read();
429 if (!local_protected
) {
434 if (snap_id_it
== m_remote_snap_ids
.end()) {
435 // no local snapshots to protect
436 m_prev_snap_id
= CEPH_NOSNAP
;
437 send_update_client();
441 m_prev_snap_id
= *snap_id_it
;
442 m_snap_name
= get_snapshot_name(m_remote_image_ctx
, m_prev_snap_id
);
445 << "snap_name=" << m_snap_name
<< ", "
446 << "snap_id=" << m_prev_snap_id
<< dendl
;
448 Context
*ctx
= create_context_callback
<
449 SnapshotCopyRequest
<I
>, &SnapshotCopyRequest
<I
>::handle_snap_protect
>(
451 RWLock::RLocker
owner_locker(m_local_image_ctx
->owner_lock
);
452 m_local_image_ctx
->operations
->execute_snap_protect(cls::rbd::UserSnapshotNamespace(),
457 template <typename I
>
458 void SnapshotCopyRequest
<I
>::handle_snap_protect(int r
) {
459 dout(20) << ": r=" << r
<< dendl
;
462 derr
<< ": failed to protect snapshot '" << m_snap_name
<< "': "
463 << cpp_strerror(r
) << dendl
;
467 if (handle_cancellation())
475 template <typename I
>
476 void SnapshotCopyRequest
<I
>::send_update_client() {
481 librbd::journal::MirrorPeerClientMeta
client_meta(*m_client_meta
);
482 client_meta
.snap_seqs
= m_snap_seqs
;
484 librbd::journal::ClientData
client_data(client_meta
);
486 ::encode(client_data
, data_bl
);
488 Context
*ctx
= create_context_callback
<
489 SnapshotCopyRequest
<I
>, &SnapshotCopyRequest
<I
>::handle_update_client
>(
491 m_journaler
->update_client(data_bl
, ctx
);
494 template <typename I
>
495 void SnapshotCopyRequest
<I
>::handle_update_client(int r
) {
496 dout(20) << ": r=" << r
<< dendl
;
499 derr
<< ": failed to update client data: " << cpp_strerror(r
)
504 if (handle_cancellation())
509 m_client_meta
->snap_seqs
= m_snap_seqs
;
514 template <typename I
>
515 bool SnapshotCopyRequest
<I
>::handle_cancellation() {
517 Mutex::Locker
locker(m_lock
);
522 dout(10) << ": snapshot copy canceled" << dendl
;
527 template <typename I
>
528 void SnapshotCopyRequest
<I
>::error(int r
) {
529 dout(20) << ": r=" << r
<< dendl
;
531 m_work_queue
->queue(new FunctionContext([this, r
](int r1
) { finish(r
); }));
534 template <typename I
>
535 void SnapshotCopyRequest
<I
>::compute_snap_map() {
536 SnapIds local_snap_ids
;
537 for (auto &pair
: m_snap_seqs
) {
538 local_snap_ids
.reserve(1 + local_snap_ids
.size());
539 local_snap_ids
.insert(local_snap_ids
.begin(), pair
.second
);
540 m_snap_map
->insert(std::make_pair(pair
.first
, local_snap_ids
));
544 template <typename I
>
545 int SnapshotCopyRequest
<I
>::validate_parent(I
*image_ctx
,
546 librbd::ParentSpec
*spec
) {
547 RWLock::RLocker
owner_locker(image_ctx
->owner_lock
);
548 RWLock::RLocker
snap_locker(image_ctx
->snap_lock
);
550 // ensure remote image's parent specs are still consistent
551 *spec
= image_ctx
->parent_md
.spec
;
552 for (auto &snap_info_pair
: image_ctx
->snap_info
) {
553 auto &parent_spec
= snap_info_pair
.second
.parent
.spec
;
554 if (parent_spec
.pool_id
== -1) {
556 } else if (spec
->pool_id
== -1) {
561 if (*spec
!= parent_spec
) {
568 } // namespace image_sync
569 } // namespace mirror
572 template class rbd::mirror::image_sync::SnapshotCopyRequest
<librbd::ImageCtx
>;