]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc
update sources to v12.1.0
[ceph.git] / ceph / src / tools / rbd_mirror / image_sync / SnapshotCopyRequest.cc
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"
9 #include "librbd/ExclusiveLock.h"
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
20 namespace rbd {
21 namespace mirror {
22 namespace image_sync {
23
24 namespace {
25
26 template <typename I>
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(),
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
43 using librbd::util::create_context_callback;
44 using librbd::util::unique_lock_name;
45
46 template <typename I>
47 SnapshotCopyRequest<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
69 template <typename I>
70 void 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
89 template <typename I>
90 void SnapshotCopyRequest<I>::cancel() {
91 Mutex::Locker locker(m_lock);
92
93 dout(20) << dendl;
94 m_canceled = true;
95 }
96
97 template <typename I>
98 void 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
173 auto finish_op_ctx = start_local_op();
174 if (finish_op_ctx == nullptr) {
175 derr << ": lost exclusive lock" << dendl;
176 finish(-EROFS);
177 return;
178 }
179
180 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
181 handle_snap_unprotect(r);
182 finish_op_ctx->complete(0);
183 });
184 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
185 m_local_image_ctx->operations->execute_snap_unprotect(
186 cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx);
187 }
188
189 template <typename I>
190 void SnapshotCopyRequest<I>::handle_snap_unprotect(int r) {
191 dout(20) << ": r=" << r << dendl;
192
193 if (r < 0) {
194 derr << ": failed to unprotect snapshot '" << m_snap_name << "': "
195 << cpp_strerror(r) << dendl;
196 finish(r);
197 return;
198 }
199 if (handle_cancellation())
200 {
201 return;
202 }
203
204 send_snap_unprotect();
205 }
206
207 template <typename I>
208 void SnapshotCopyRequest<I>::send_snap_remove() {
209 SnapIdSet::iterator snap_id_it = m_local_snap_ids.begin();
210 if (m_prev_snap_id != CEPH_NOSNAP) {
211 snap_id_it = m_local_snap_ids.upper_bound(m_prev_snap_id);
212 }
213
214 for (; snap_id_it != m_local_snap_ids.end(); ++snap_id_it) {
215 librados::snap_t local_snap_id = *snap_id_it;
216
217 cls::rbd::SnapshotNamespace snap_namespace;
218 m_local_image_ctx->snap_lock.get_read();
219 int r = m_local_image_ctx->get_snap_namespace(local_snap_id,
220 &snap_namespace);
221 m_local_image_ctx->snap_lock.put_read();
222 if (r < 0) {
223 derr << ": failed to retrieve local snap namespace: " << m_snap_name
224 << dendl;
225 finish(r);
226 return;
227 }
228
229 if (boost::get<cls::rbd::UserSnapshotNamespace>(&snap_namespace) ==
230 nullptr) {
231 continue;
232 }
233
234 // if the local snapshot isn't in our mapping table, remove it
235 auto snap_seq_it = std::find_if(
236 m_snap_seqs.begin(), m_snap_seqs.end(),
237 [local_snap_id](const SnapSeqs::value_type& pair) {
238 return pair.second == local_snap_id;
239 });
240
241 if (snap_seq_it == m_snap_seqs.end()) {
242 break;
243 }
244 }
245
246 if (snap_id_it == m_local_snap_ids.end()) {
247 // no local snapshots to delete
248 m_prev_snap_id = CEPH_NOSNAP;
249 send_snap_create();
250 return;
251 }
252
253 m_prev_snap_id = *snap_id_it;
254 m_snap_name = get_snapshot_name(m_local_image_ctx, m_prev_snap_id);
255
256 dout(20) << ": "
257 << "snap_name=" << m_snap_name << ", "
258 << "snap_id=" << m_prev_snap_id << dendl;
259
260 auto finish_op_ctx = start_local_op();
261 if (finish_op_ctx == nullptr) {
262 derr << ": lost exclusive lock" << dendl;
263 finish(-EROFS);
264 return;
265 }
266
267 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
268 handle_snap_remove(r);
269 finish_op_ctx->complete(0);
270 });
271 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
272 m_local_image_ctx->operations->execute_snap_remove(
273 cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx);
274 }
275
276 template <typename I>
277 void SnapshotCopyRequest<I>::handle_snap_remove(int r) {
278 dout(20) << ": r=" << r << dendl;
279
280 if (r < 0) {
281 derr << ": failed to remove snapshot '" << m_snap_name << "': "
282 << cpp_strerror(r) << dendl;
283 finish(r);
284 return;
285 }
286 if (handle_cancellation())
287 {
288 return;
289 }
290
291 send_snap_remove();
292 }
293
294 template <typename I>
295 void SnapshotCopyRequest<I>::send_snap_create() {
296 SnapIdSet::iterator snap_id_it = m_remote_snap_ids.begin();
297 if (m_prev_snap_id != CEPH_NOSNAP) {
298 snap_id_it = m_remote_snap_ids.upper_bound(m_prev_snap_id);
299 }
300
301 for (; snap_id_it != m_remote_snap_ids.end(); ++snap_id_it) {
302 librados::snap_t remote_snap_id = *snap_id_it;
303
304 cls::rbd::SnapshotNamespace snap_namespace;
305 m_remote_image_ctx->snap_lock.get_read();
306 int r = m_remote_image_ctx->get_snap_namespace(remote_snap_id, &snap_namespace);
307 m_remote_image_ctx->snap_lock.put_read();
308 if (r < 0) {
309 derr << ": failed to retrieve remote snap namespace: " << m_snap_name
310 << dendl;
311 finish(r);
312 return;
313 }
314
315 // if the remote snapshot isn't in our mapping table, create it
316 if (m_snap_seqs.find(remote_snap_id) == m_snap_seqs.end() &&
317 boost::get<cls::rbd::UserSnapshotNamespace>(&snap_namespace) != nullptr) {
318 break;
319 }
320 }
321
322 if (snap_id_it == m_remote_snap_ids.end()) {
323 // no remote snapshots to create
324 m_prev_snap_id = CEPH_NOSNAP;
325 send_snap_protect();
326 return;
327 }
328
329 m_prev_snap_id = *snap_id_it;
330 m_snap_name = get_snapshot_name(m_remote_image_ctx, m_prev_snap_id);
331
332 m_remote_image_ctx->snap_lock.get_read();
333 auto snap_info_it = m_remote_image_ctx->snap_info.find(m_prev_snap_id);
334 if (snap_info_it == m_remote_image_ctx->snap_info.end()) {
335 m_remote_image_ctx->snap_lock.put_read();
336 derr << ": failed to retrieve remote snap info: " << m_snap_name
337 << dendl;
338 finish(-ENOENT);
339 return;
340 }
341
342 uint64_t size = snap_info_it->second.size;
343 m_snap_namespace = snap_info_it->second.snap_namespace;
344 librbd::ParentSpec parent_spec;
345 uint64_t parent_overlap = 0;
346 if (snap_info_it->second.parent.spec.pool_id != -1) {
347 parent_spec = m_local_parent_spec;
348 parent_overlap = snap_info_it->second.parent.overlap;
349 }
350 m_remote_image_ctx->snap_lock.put_read();
351
352
353 dout(20) << ": "
354 << "snap_name=" << m_snap_name << ", "
355 << "snap_id=" << m_prev_snap_id << ", "
356 << "size=" << size << ", "
357 << "parent_info=["
358 << "pool_id=" << parent_spec.pool_id << ", "
359 << "image_id=" << parent_spec.image_id << ", "
360 << "snap_id=" << parent_spec.snap_id << ", "
361 << "overlap=" << parent_overlap << "]" << dendl;
362
363 Context *finish_op_ctx = start_local_op();
364 if (finish_op_ctx == nullptr) {
365 derr << ": lost exclusive lock" << dendl;
366 finish(-EROFS);
367 return;
368 }
369
370 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
371 handle_snap_create(r);
372 finish_op_ctx->complete(0);
373 });
374 SnapshotCreateRequest<I> *req = SnapshotCreateRequest<I>::create(
375 m_local_image_ctx, m_snap_name, m_snap_namespace, size, parent_spec,
376 parent_overlap, ctx);
377 req->send();
378 }
379
380 template <typename I>
381 void SnapshotCopyRequest<I>::handle_snap_create(int r) {
382 dout(20) << ": r=" << r << dendl;
383
384 if (r < 0) {
385 derr << ": failed to create snapshot '" << m_snap_name << "': "
386 << cpp_strerror(r) << dendl;
387 finish(r);
388 return;
389 }
390 if (handle_cancellation())
391 {
392 return;
393 }
394
395 assert(m_prev_snap_id != CEPH_NOSNAP);
396
397 auto snap_it = m_local_image_ctx->snap_ids.find({cls::rbd::UserSnapshotNamespace(),
398 m_snap_name});
399 assert(snap_it != m_local_image_ctx->snap_ids.end());
400 librados::snap_t local_snap_id = snap_it->second;
401
402 dout(20) << ": mapping remote snap id " << m_prev_snap_id << " to "
403 << local_snap_id << dendl;
404 m_snap_seqs[m_prev_snap_id] = local_snap_id;
405
406 send_snap_create();
407 }
408
409 template <typename I>
410 void SnapshotCopyRequest<I>::send_snap_protect() {
411 SnapIdSet::iterator snap_id_it = m_remote_snap_ids.begin();
412 if (m_prev_snap_id != CEPH_NOSNAP) {
413 snap_id_it = m_remote_snap_ids.upper_bound(m_prev_snap_id);
414 }
415
416 for (; snap_id_it != m_remote_snap_ids.end(); ++snap_id_it) {
417 librados::snap_t remote_snap_id = *snap_id_it;
418
419 m_remote_image_ctx->snap_lock.get_read();
420
421 bool remote_protected;
422 int r = m_remote_image_ctx->is_snap_protected(remote_snap_id,
423 &remote_protected);
424 if (r < 0) {
425 derr << ": failed to retrieve remote snap protect status: "
426 << cpp_strerror(r) << dendl;
427 m_remote_image_ctx->snap_lock.put_read();
428 finish(r);
429 return;
430 }
431 m_remote_image_ctx->snap_lock.put_read();
432
433 if (!remote_protected) {
434 // snap is not protected -- check next snap
435 continue;
436 }
437
438 // if local snapshot is not protected, protect it
439 auto snap_seq_it = m_snap_seqs.find(remote_snap_id);
440 assert(snap_seq_it != m_snap_seqs.end());
441
442 m_local_image_ctx->snap_lock.get_read();
443 bool local_protected;
444 r = m_local_image_ctx->is_snap_protected(snap_seq_it->second,
445 &local_protected);
446 if (r < 0) {
447 derr << ": failed to retrieve local snap protect status: "
448 << cpp_strerror(r) << dendl;
449 m_local_image_ctx->snap_lock.put_read();
450 finish(r);
451 return;
452 }
453 m_local_image_ctx->snap_lock.put_read();
454
455 if (!local_protected) {
456 break;
457 }
458 }
459
460 if (snap_id_it == m_remote_snap_ids.end()) {
461 // no local snapshots to protect
462 m_prev_snap_id = CEPH_NOSNAP;
463 send_update_client();
464 return;
465 }
466
467 m_prev_snap_id = *snap_id_it;
468 m_snap_name = get_snapshot_name(m_remote_image_ctx, m_prev_snap_id);
469
470 dout(20) << ": "
471 << "snap_name=" << m_snap_name << ", "
472 << "snap_id=" << m_prev_snap_id << dendl;
473
474 auto finish_op_ctx = start_local_op();
475 if (finish_op_ctx == nullptr) {
476 derr << ": lost exclusive lock" << dendl;
477 finish(-EROFS);
478 return;
479 }
480
481 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
482 handle_snap_protect(r);
483 finish_op_ctx->complete(0);
484 });
485 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
486 m_local_image_ctx->operations->execute_snap_protect(
487 cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx);
488 }
489
490 template <typename I>
491 void SnapshotCopyRequest<I>::handle_snap_protect(int r) {
492 dout(20) << ": r=" << r << dendl;
493
494 if (r < 0) {
495 derr << ": failed to protect snapshot '" << m_snap_name << "': "
496 << cpp_strerror(r) << dendl;
497 finish(r);
498 return;
499 }
500 if (handle_cancellation())
501 {
502 return;
503 }
504
505 send_snap_protect();
506 }
507
508 template <typename I>
509 void SnapshotCopyRequest<I>::send_update_client() {
510 dout(20) << dendl;
511
512 compute_snap_map();
513
514 librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
515 client_meta.snap_seqs = m_snap_seqs;
516
517 librbd::journal::ClientData client_data(client_meta);
518 bufferlist data_bl;
519 ::encode(client_data, data_bl);
520
521 Context *ctx = create_context_callback<
522 SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_update_client>(
523 this);
524 m_journaler->update_client(data_bl, ctx);
525 }
526
527 template <typename I>
528 void SnapshotCopyRequest<I>::handle_update_client(int r) {
529 dout(20) << ": r=" << r << dendl;
530
531 if (r < 0) {
532 derr << ": failed to update client data: " << cpp_strerror(r)
533 << dendl;
534 finish(r);
535 return;
536 }
537 if (handle_cancellation())
538 {
539 return;
540 }
541
542 m_client_meta->snap_seqs = m_snap_seqs;
543
544 finish(0);
545 }
546
547 template <typename I>
548 bool SnapshotCopyRequest<I>::handle_cancellation() {
549 {
550 Mutex::Locker locker(m_lock);
551 if (!m_canceled) {
552 return false;
553 }
554 }
555 dout(10) << ": snapshot copy canceled" << dendl;
556 finish(-ECANCELED);
557 return true;
558 }
559
560 template <typename I>
561 void SnapshotCopyRequest<I>::error(int r) {
562 dout(20) << ": r=" << r << dendl;
563
564 m_work_queue->queue(new FunctionContext([this, r](int r1) { finish(r); }));
565 }
566
567 template <typename I>
568 void SnapshotCopyRequest<I>::compute_snap_map() {
569 SnapIds local_snap_ids;
570 for (auto &pair : m_snap_seqs) {
571 local_snap_ids.reserve(1 + local_snap_ids.size());
572 local_snap_ids.insert(local_snap_ids.begin(), pair.second);
573 m_snap_map->insert(std::make_pair(pair.first, local_snap_ids));
574 }
575 }
576
577 template <typename I>
578 int SnapshotCopyRequest<I>::validate_parent(I *image_ctx,
579 librbd::ParentSpec *spec) {
580 RWLock::RLocker owner_locker(image_ctx->owner_lock);
581 RWLock::RLocker snap_locker(image_ctx->snap_lock);
582
583 // ensure remote image's parent specs are still consistent
584 *spec = image_ctx->parent_md.spec;
585 for (auto &snap_info_pair : image_ctx->snap_info) {
586 auto &parent_spec = snap_info_pair.second.parent.spec;
587 if (parent_spec.pool_id == -1) {
588 continue;
589 } else if (spec->pool_id == -1) {
590 *spec = parent_spec;
591 continue;
592 }
593
594 if (*spec != parent_spec) {
595 return -EINVAL;
596 }
597 }
598 return 0;
599 }
600
601 template <typename I>
602 Context *SnapshotCopyRequest<I>::start_local_op() {
603 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
604 if (m_local_image_ctx->exclusive_lock == nullptr) {
605 return nullptr;
606 }
607 return m_local_image_ctx->exclusive_lock->start_op();
608 }
609
610 } // namespace image_sync
611 } // namespace mirror
612 } // namespace rbd
613
614 template class rbd::mirror::image_sync::SnapshotCopyRequest<librbd::ImageCtx>;