]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc
update sources to 12.2.10
[ceph.git] / ceph / src / tools / rbd_mirror / image_sync / SnapshotCopyRequest.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "SnapshotCopyRequest.h"
5#include "SnapshotCreateRequest.h"
6#include "common/errno.h"
7#include "common/WorkQueue.h"
8#include "journal/Journaler.h"
31f18b77 9#include "librbd/ExclusiveLock.h"
7c673cae
FG
10#include "librbd/Operations.h"
11#include "librbd/Utils.h"
12#include "librbd/journal/Types.h"
13
14#define dout_context g_ceph_context
15#define dout_subsys ceph_subsys_rbd_mirror
16#undef dout_prefix
17#define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCopyRequest: " \
18 << this << " " << __func__
19
20namespace rbd {
21namespace mirror {
22namespace image_sync {
23
24namespace {
25
26template <typename I>
27const 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(),
30 [snap_id](
31 const std::pair<
32 std::pair<cls::rbd::SnapshotNamespace,
33 std::string>,
34 librados::snap_t> &pair) {
35 return pair.second == snap_id;
36 });
37 assert(snap_it != image_ctx->snap_ids.end());
38 return snap_it->first.second;
39}
40
41} // anonymous namespace
42
43using librbd::util::create_context_callback;
44using librbd::util::unique_lock_name;
45
46template <typename I>
47SnapshotCopyRequest<I>::SnapshotCopyRequest(I *local_image_ctx,
48 I *remote_image_ctx,
49 SnapMap *snap_map,
50 Journaler *journaler,
51 librbd::journal::MirrorPeerClientMeta *meta,
52 ContextWQ *work_queue,
53 Context *on_finish)
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)) {
60 m_snap_map->clear();
61
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());
67}
68
69template <typename I>
70void SnapshotCopyRequest<I>::send() {
71 librbd::ParentSpec remote_parent_spec;
72 int r = validate_parent(m_remote_image_ctx, &remote_parent_spec);
73 if (r < 0) {
74 derr << ": remote image parent spec mismatch" << dendl;
75 error(r);
76 return;
77 }
78
79 r = validate_parent(m_local_image_ctx, &m_local_parent_spec);
80 if (r < 0) {
81 derr << ": local image parent spec mismatch" << dendl;
82 error(r);
83 return;
84 }
85
86 send_snap_unprotect();
87}
88
89template <typename I>
90void SnapshotCopyRequest<I>::cancel() {
91 Mutex::Locker locker(m_lock);
92
93 dout(20) << dendl;
94 m_canceled = true;
95}
96
97template <typename I>
98void SnapshotCopyRequest<I>::send_snap_unprotect() {
99
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);
103 }
104
105 for (; snap_id_it != m_local_snap_ids.end(); ++snap_id_it) {
106 librados::snap_t local_snap_id = *snap_id_it;
107
108 m_local_image_ctx->snap_lock.get_read();
109
110 bool local_unprotected;
111 int r = m_local_image_ctx->is_snap_unprotected(local_snap_id,
112 &local_unprotected);
113 if (r < 0) {
114 derr << ": failed to retrieve local snap unprotect status: "
115 << cpp_strerror(r) << dendl;
116 m_local_image_ctx->snap_lock.put_read();
117 finish(r);
118 return;
119 }
120 m_local_image_ctx->snap_lock.put_read();
121
122 if (local_unprotected) {
123 // snap is already unprotected -- check next snap
124 continue;
125 }
126
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;
133 });
134
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);
140 if (r < 0) {
141 derr << ": failed to retrieve remote snap unprotect status: "
142 << cpp_strerror(r) << dendl;
143 m_remote_image_ctx->snap_lock.put_read();
144 finish(r);
145 return;
146 }
147 m_remote_image_ctx->snap_lock.put_read();
148
149 if (remote_unprotected) {
150 // remote is unprotected -- unprotect local snap
151 break;
152 }
153 } else {
154 // remote snapshot doesn't exist -- unprotect local snap
155 break;
156 }
157 }
158
159 if (snap_id_it == m_local_snap_ids.end()) {
160 // no local snapshots to unprotect
161 m_prev_snap_id = CEPH_NOSNAP;
162 send_snap_remove();
163 return;
164 }
165
166 m_prev_snap_id = *snap_id_it;
167 m_snap_name = get_snapshot_name(m_local_image_ctx, m_prev_snap_id);
168
169 dout(20) << ": "
170 << "snap_name=" << m_snap_name << ", "
171 << "snap_id=" << m_prev_snap_id << dendl;
172
91327a77
AA
173 int r;
174 auto finish_op_ctx = start_local_op(&r);
31f18b77
FG
175 if (finish_op_ctx == nullptr) {
176 derr << ": lost exclusive lock" << dendl;
91327a77 177 finish(r);
31f18b77
FG
178 return;
179 }
180
181 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
182 handle_snap_unprotect(r);
183 finish_op_ctx->complete(0);
184 });
7c673cae 185 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
31f18b77
FG
186 m_local_image_ctx->operations->execute_snap_unprotect(
187 cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx);
7c673cae
FG
188}
189
190template <typename I>
191void SnapshotCopyRequest<I>::handle_snap_unprotect(int r) {
192 dout(20) << ": r=" << r << dendl;
193
194 if (r < 0) {
195 derr << ": failed to unprotect snapshot '" << m_snap_name << "': "
196 << cpp_strerror(r) << dendl;
197 finish(r);
198 return;
199 }
200 if (handle_cancellation())
201 {
202 return;
203 }
204
205 send_snap_unprotect();
206}
207
208template <typename I>
209void 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);
213 }
214
215 for (; snap_id_it != m_local_snap_ids.end(); ++snap_id_it) {
216 librados::snap_t local_snap_id = *snap_id_it;
217
218 cls::rbd::SnapshotNamespace snap_namespace;
219 m_local_image_ctx->snap_lock.get_read();
31f18b77
FG
220 int r = m_local_image_ctx->get_snap_namespace(local_snap_id,
221 &snap_namespace);
7c673cae
FG
222 m_local_image_ctx->snap_lock.put_read();
223 if (r < 0) {
224 derr << ": failed to retrieve local snap namespace: " << m_snap_name
225 << dendl;
226 finish(r);
227 return;
228 }
229
31f18b77
FG
230 if (boost::get<cls::rbd::UserSnapshotNamespace>(&snap_namespace) ==
231 nullptr) {
7c673cae
FG
232 continue;
233 }
234
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;
240 });
241
242 if (snap_seq_it == m_snap_seqs.end()) {
243 break;
244 }
245 }
246
247 if (snap_id_it == m_local_snap_ids.end()) {
248 // no local snapshots to delete
249 m_prev_snap_id = CEPH_NOSNAP;
250 send_snap_create();
251 return;
252 }
253
254 m_prev_snap_id = *snap_id_it;
255 m_snap_name = get_snapshot_name(m_local_image_ctx, m_prev_snap_id);
256
257 dout(20) << ": "
258 << "snap_name=" << m_snap_name << ", "
259 << "snap_id=" << m_prev_snap_id << dendl;
260
91327a77
AA
261 int r;
262 auto finish_op_ctx = start_local_op(&r);
31f18b77
FG
263 if (finish_op_ctx == nullptr) {
264 derr << ": lost exclusive lock" << dendl;
91327a77 265 finish(r);
31f18b77
FG
266 return;
267 }
268
269 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
270 handle_snap_remove(r);
271 finish_op_ctx->complete(0);
272 });
7c673cae 273 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
31f18b77
FG
274 m_local_image_ctx->operations->execute_snap_remove(
275 cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx);
7c673cae
FG
276}
277
278template <typename I>
279void SnapshotCopyRequest<I>::handle_snap_remove(int r) {
280 dout(20) << ": r=" << r << dendl;
281
282 if (r < 0) {
283 derr << ": failed to remove snapshot '" << m_snap_name << "': "
284 << cpp_strerror(r) << dendl;
285 finish(r);
286 return;
287 }
288 if (handle_cancellation())
289 {
290 return;
291 }
292
293 send_snap_remove();
294}
295
296template <typename I>
297void 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);
301 }
302
303 for (; snap_id_it != m_remote_snap_ids.end(); ++snap_id_it) {
304 librados::snap_t remote_snap_id = *snap_id_it;
305
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();
310 if (r < 0) {
311 derr << ": failed to retrieve remote snap namespace: " << m_snap_name
312 << dendl;
313 finish(r);
314 return;
315 }
316
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) {
320 break;
321 }
322 }
323
324 if (snap_id_it == m_remote_snap_ids.end()) {
325 // no remote snapshots to create
326 m_prev_snap_id = CEPH_NOSNAP;
327 send_snap_protect();
328 return;
329 }
330
331 m_prev_snap_id = *snap_id_it;
332 m_snap_name = get_snapshot_name(m_remote_image_ctx, m_prev_snap_id);
333
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
339 << dendl;
340 finish(-ENOENT);
341 return;
342 }
343
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;
351 }
352 m_remote_image_ctx->snap_lock.put_read();
353
354
355 dout(20) << ": "
356 << "snap_name=" << m_snap_name << ", "
357 << "snap_id=" << m_prev_snap_id << ", "
358 << "size=" << size << ", "
359 << "parent_info=["
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;
364
91327a77
AA
365 int r;
366 Context *finish_op_ctx = start_local_op(&r);
31f18b77
FG
367 if (finish_op_ctx == nullptr) {
368 derr << ": lost exclusive lock" << dendl;
91327a77 369 finish(r);
31f18b77
FG
370 return;
371 }
372
373 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
374 handle_snap_create(r);
375 finish_op_ctx->complete(0);
376 });
7c673cae 377 SnapshotCreateRequest<I> *req = SnapshotCreateRequest<I>::create(
31f18b77
FG
378 m_local_image_ctx, m_snap_name, m_snap_namespace, size, parent_spec,
379 parent_overlap, ctx);
7c673cae
FG
380 req->send();
381}
382
383template <typename I>
384void SnapshotCopyRequest<I>::handle_snap_create(int r) {
385 dout(20) << ": r=" << r << dendl;
386
387 if (r < 0) {
388 derr << ": failed to create snapshot '" << m_snap_name << "': "
389 << cpp_strerror(r) << dendl;
390 finish(r);
391 return;
392 }
393 if (handle_cancellation())
394 {
395 return;
396 }
397
398 assert(m_prev_snap_id != CEPH_NOSNAP);
399
400 auto snap_it = m_local_image_ctx->snap_ids.find({cls::rbd::UserSnapshotNamespace(),
401 m_snap_name});
402 assert(snap_it != m_local_image_ctx->snap_ids.end());
403 librados::snap_t local_snap_id = snap_it->second;
404
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;
408
409 send_snap_create();
410}
411
412template <typename I>
413void 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);
417 }
418
419 for (; snap_id_it != m_remote_snap_ids.end(); ++snap_id_it) {
420 librados::snap_t remote_snap_id = *snap_id_it;
421
422 m_remote_image_ctx->snap_lock.get_read();
423
424 bool remote_protected;
425 int r = m_remote_image_ctx->is_snap_protected(remote_snap_id,
426 &remote_protected);
427 if (r < 0) {
428 derr << ": failed to retrieve remote snap protect status: "
429 << cpp_strerror(r) << dendl;
430 m_remote_image_ctx->snap_lock.put_read();
431 finish(r);
432 return;
433 }
434 m_remote_image_ctx->snap_lock.put_read();
435
436 if (!remote_protected) {
437 // snap is not protected -- check next snap
438 continue;
439 }
440
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());
444
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,
448 &local_protected);
449 if (r < 0) {
450 derr << ": failed to retrieve local snap protect status: "
451 << cpp_strerror(r) << dendl;
452 m_local_image_ctx->snap_lock.put_read();
453 finish(r);
454 return;
455 }
456 m_local_image_ctx->snap_lock.put_read();
457
458 if (!local_protected) {
459 break;
460 }
461 }
462
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();
467 return;
468 }
469
470 m_prev_snap_id = *snap_id_it;
471 m_snap_name = get_snapshot_name(m_remote_image_ctx, m_prev_snap_id);
472
473 dout(20) << ": "
474 << "snap_name=" << m_snap_name << ", "
475 << "snap_id=" << m_prev_snap_id << dendl;
476
91327a77
AA
477 int r;
478 auto finish_op_ctx = start_local_op(&r);
31f18b77
FG
479 if (finish_op_ctx == nullptr) {
480 derr << ": lost exclusive lock" << dendl;
91327a77 481 finish(r);
31f18b77
FG
482 return;
483 }
484
485 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
486 handle_snap_protect(r);
487 finish_op_ctx->complete(0);
488 });
7c673cae 489 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
31f18b77
FG
490 m_local_image_ctx->operations->execute_snap_protect(
491 cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx);
7c673cae
FG
492}
493
494template <typename I>
495void SnapshotCopyRequest<I>::handle_snap_protect(int r) {
496 dout(20) << ": r=" << r << dendl;
497
498 if (r < 0) {
499 derr << ": failed to protect snapshot '" << m_snap_name << "': "
500 << cpp_strerror(r) << dendl;
501 finish(r);
502 return;
503 }
504 if (handle_cancellation())
505 {
506 return;
507 }
508
509 send_snap_protect();
510}
511
512template <typename I>
513void SnapshotCopyRequest<I>::send_update_client() {
514 dout(20) << dendl;
515
516 compute_snap_map();
517
518 librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
519 client_meta.snap_seqs = m_snap_seqs;
520
521 librbd::journal::ClientData client_data(client_meta);
522 bufferlist data_bl;
523 ::encode(client_data, data_bl);
524
525 Context *ctx = create_context_callback<
526 SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_update_client>(
527 this);
528 m_journaler->update_client(data_bl, ctx);
529}
530
531template <typename I>
532void SnapshotCopyRequest<I>::handle_update_client(int r) {
533 dout(20) << ": r=" << r << dendl;
534
535 if (r < 0) {
536 derr << ": failed to update client data: " << cpp_strerror(r)
537 << dendl;
538 finish(r);
539 return;
540 }
541 if (handle_cancellation())
542 {
543 return;
544 }
545
546 m_client_meta->snap_seqs = m_snap_seqs;
547
548 finish(0);
549}
550
551template <typename I>
552bool SnapshotCopyRequest<I>::handle_cancellation() {
553 {
554 Mutex::Locker locker(m_lock);
555 if (!m_canceled) {
556 return false;
557 }
558 }
559 dout(10) << ": snapshot copy canceled" << dendl;
560 finish(-ECANCELED);
561 return true;
562}
563
564template <typename I>
565void SnapshotCopyRequest<I>::error(int r) {
566 dout(20) << ": r=" << r << dendl;
567
568 m_work_queue->queue(new FunctionContext([this, r](int r1) { finish(r); }));
569}
570
571template <typename I>
572void 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));
578 }
579}
580
581template <typename I>
582int 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);
586
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) {
592 continue;
593 } else if (spec->pool_id == -1) {
594 *spec = parent_spec;
595 continue;
596 }
597
598 if (*spec != parent_spec) {
599 return -EINVAL;
600 }
601 }
602 return 0;
603}
604
31f18b77 605template <typename I>
91327a77 606Context *SnapshotCopyRequest<I>::start_local_op(int *r) {
31f18b77
FG
607 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
608 if (m_local_image_ctx->exclusive_lock == nullptr) {
91327a77 609 *r = -EROFS;
31f18b77
FG
610 return nullptr;
611 }
91327a77 612 return m_local_image_ctx->exclusive_lock->start_op(r);
31f18b77
FG
613}
614
7c673cae
FG
615} // namespace image_sync
616} // namespace mirror
617} // namespace rbd
618
619template class rbd::mirror::image_sync::SnapshotCopyRequest<librbd::ImageCtx>;