]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc
add subtree-ish sources for 12.0.3
[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/Operations.h"
10 #include "librbd/Utils.h"
11 #include "librbd/journal/Types.h"
12
13 #define dout_context g_ceph_context
14 #define dout_subsys ceph_subsys_rbd_mirror
15 #undef dout_prefix
16 #define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCopyRequest: " \
17 << this << " " << __func__
18
19 namespace rbd {
20 namespace mirror {
21 namespace image_sync {
22
23 namespace {
24
25 template <typename I>
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(),
29 [snap_id](
30 const std::pair<
31 std::pair<cls::rbd::SnapshotNamespace,
32 std::string>,
33 librados::snap_t> &pair) {
34 return pair.second == snap_id;
35 });
36 assert(snap_it != image_ctx->snap_ids.end());
37 return snap_it->first.second;
38 }
39
40 } // anonymous namespace
41
42 using librbd::util::create_context_callback;
43 using librbd::util::unique_lock_name;
44
45 template <typename I>
46 SnapshotCopyRequest<I>::SnapshotCopyRequest(I *local_image_ctx,
47 I *remote_image_ctx,
48 SnapMap *snap_map,
49 Journaler *journaler,
50 librbd::journal::MirrorPeerClientMeta *meta,
51 ContextWQ *work_queue,
52 Context *on_finish)
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)) {
59 m_snap_map->clear();
60
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());
66 }
67
68 template <typename I>
69 void SnapshotCopyRequest<I>::send() {
70 librbd::ParentSpec remote_parent_spec;
71 int r = validate_parent(m_remote_image_ctx, &remote_parent_spec);
72 if (r < 0) {
73 derr << ": remote image parent spec mismatch" << dendl;
74 error(r);
75 return;
76 }
77
78 r = validate_parent(m_local_image_ctx, &m_local_parent_spec);
79 if (r < 0) {
80 derr << ": local image parent spec mismatch" << dendl;
81 error(r);
82 return;
83 }
84
85 send_snap_unprotect();
86 }
87
88 template <typename I>
89 void SnapshotCopyRequest<I>::cancel() {
90 Mutex::Locker locker(m_lock);
91
92 dout(20) << dendl;
93 m_canceled = true;
94 }
95
96 template <typename I>
97 void SnapshotCopyRequest<I>::send_snap_unprotect() {
98
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);
102 }
103
104 for (; snap_id_it != m_local_snap_ids.end(); ++snap_id_it) {
105 librados::snap_t local_snap_id = *snap_id_it;
106
107 m_local_image_ctx->snap_lock.get_read();
108
109 bool local_unprotected;
110 int r = m_local_image_ctx->is_snap_unprotected(local_snap_id,
111 &local_unprotected);
112 if (r < 0) {
113 derr << ": failed to retrieve local snap unprotect status: "
114 << cpp_strerror(r) << dendl;
115 m_local_image_ctx->snap_lock.put_read();
116 finish(r);
117 return;
118 }
119 m_local_image_ctx->snap_lock.put_read();
120
121 if (local_unprotected) {
122 // snap is already unprotected -- check next snap
123 continue;
124 }
125
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;
132 });
133
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);
139 if (r < 0) {
140 derr << ": failed to retrieve remote snap unprotect status: "
141 << cpp_strerror(r) << dendl;
142 m_remote_image_ctx->snap_lock.put_read();
143 finish(r);
144 return;
145 }
146 m_remote_image_ctx->snap_lock.put_read();
147
148 if (remote_unprotected) {
149 // remote is unprotected -- unprotect local snap
150 break;
151 }
152 } else {
153 // remote snapshot doesn't exist -- unprotect local snap
154 break;
155 }
156 }
157
158 if (snap_id_it == m_local_snap_ids.end()) {
159 // no local snapshots to unprotect
160 m_prev_snap_id = CEPH_NOSNAP;
161 send_snap_remove();
162 return;
163 }
164
165 m_prev_snap_id = *snap_id_it;
166 m_snap_name = get_snapshot_name(m_local_image_ctx, m_prev_snap_id);
167
168 dout(20) << ": "
169 << "snap_name=" << m_snap_name << ", "
170 << "snap_id=" << m_prev_snap_id << dendl;
171
172 Context *ctx = create_context_callback<
173 SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_snap_unprotect>(
174 this);
175 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
176 m_local_image_ctx->operations->execute_snap_unprotect(cls::rbd::UserSnapshotNamespace(),
177 m_snap_name.c_str(),
178 ctx);
179 }
180
181 template <typename I>
182 void SnapshotCopyRequest<I>::handle_snap_unprotect(int r) {
183 dout(20) << ": r=" << r << dendl;
184
185 if (r < 0) {
186 derr << ": failed to unprotect snapshot '" << m_snap_name << "': "
187 << cpp_strerror(r) << dendl;
188 finish(r);
189 return;
190 }
191 if (handle_cancellation())
192 {
193 return;
194 }
195
196 send_snap_unprotect();
197 }
198
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);
204 }
205
206 for (; snap_id_it != m_local_snap_ids.end(); ++snap_id_it) {
207 librados::snap_t local_snap_id = *snap_id_it;
208
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();
213 if (r < 0) {
214 derr << ": failed to retrieve local snap namespace: " << m_snap_name
215 << dendl;
216 finish(r);
217 return;
218 }
219
220 if (boost::get<cls::rbd::UserSnapshotNamespace>(&snap_namespace) == nullptr) {
221 continue;
222 }
223
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;
229 });
230
231 if (snap_seq_it == m_snap_seqs.end()) {
232 break;
233 }
234 }
235
236 if (snap_id_it == m_local_snap_ids.end()) {
237 // no local snapshots to delete
238 m_prev_snap_id = CEPH_NOSNAP;
239 send_snap_create();
240 return;
241 }
242
243 m_prev_snap_id = *snap_id_it;
244 m_snap_name = get_snapshot_name(m_local_image_ctx, m_prev_snap_id);
245
246 dout(20) << ": "
247 << "snap_name=" << m_snap_name << ", "
248 << "snap_id=" << m_prev_snap_id << dendl;
249
250 Context *ctx = create_context_callback<
251 SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_snap_remove>(
252 this);
253 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
254 m_local_image_ctx->operations->execute_snap_remove(cls::rbd::UserSnapshotNamespace(),
255 m_snap_name.c_str(),
256 ctx);
257 }
258
259 template <typename I>
260 void SnapshotCopyRequest<I>::handle_snap_remove(int r) {
261 dout(20) << ": r=" << r << dendl;
262
263 if (r < 0) {
264 derr << ": failed to remove snapshot '" << m_snap_name << "': "
265 << cpp_strerror(r) << dendl;
266 finish(r);
267 return;
268 }
269 if (handle_cancellation())
270 {
271 return;
272 }
273
274 send_snap_remove();
275 }
276
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);
282 }
283
284 for (; snap_id_it != m_remote_snap_ids.end(); ++snap_id_it) {
285 librados::snap_t remote_snap_id = *snap_id_it;
286
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();
291 if (r < 0) {
292 derr << ": failed to retrieve remote snap namespace: " << m_snap_name
293 << dendl;
294 finish(r);
295 return;
296 }
297
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) {
301 break;
302 }
303 }
304
305 if (snap_id_it == m_remote_snap_ids.end()) {
306 // no remote snapshots to create
307 m_prev_snap_id = CEPH_NOSNAP;
308 send_snap_protect();
309 return;
310 }
311
312 m_prev_snap_id = *snap_id_it;
313 m_snap_name = get_snapshot_name(m_remote_image_ctx, m_prev_snap_id);
314
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
320 << dendl;
321 finish(-ENOENT);
322 return;
323 }
324
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;
332 }
333 m_remote_image_ctx->snap_lock.put_read();
334
335
336 dout(20) << ": "
337 << "snap_name=" << m_snap_name << ", "
338 << "snap_id=" << m_prev_snap_id << ", "
339 << "size=" << size << ", "
340 << "parent_info=["
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;
345
346 Context *ctx = create_context_callback<
347 SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_snap_create>(
348 this);
349 SnapshotCreateRequest<I> *req = SnapshotCreateRequest<I>::create(
350 m_local_image_ctx, m_snap_name, m_snap_namespace, size, parent_spec, parent_overlap, ctx);
351 req->send();
352 }
353
354 template <typename I>
355 void SnapshotCopyRequest<I>::handle_snap_create(int r) {
356 dout(20) << ": r=" << r << dendl;
357
358 if (r < 0) {
359 derr << ": failed to create snapshot '" << m_snap_name << "': "
360 << cpp_strerror(r) << dendl;
361 finish(r);
362 return;
363 }
364 if (handle_cancellation())
365 {
366 return;
367 }
368
369 assert(m_prev_snap_id != CEPH_NOSNAP);
370
371 auto snap_it = m_local_image_ctx->snap_ids.find({cls::rbd::UserSnapshotNamespace(),
372 m_snap_name});
373 assert(snap_it != m_local_image_ctx->snap_ids.end());
374 librados::snap_t local_snap_id = snap_it->second;
375
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;
379
380 send_snap_create();
381 }
382
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);
388 }
389
390 for (; snap_id_it != m_remote_snap_ids.end(); ++snap_id_it) {
391 librados::snap_t remote_snap_id = *snap_id_it;
392
393 m_remote_image_ctx->snap_lock.get_read();
394
395 bool remote_protected;
396 int r = m_remote_image_ctx->is_snap_protected(remote_snap_id,
397 &remote_protected);
398 if (r < 0) {
399 derr << ": failed to retrieve remote snap protect status: "
400 << cpp_strerror(r) << dendl;
401 m_remote_image_ctx->snap_lock.put_read();
402 finish(r);
403 return;
404 }
405 m_remote_image_ctx->snap_lock.put_read();
406
407 if (!remote_protected) {
408 // snap is not protected -- check next snap
409 continue;
410 }
411
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());
415
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,
419 &local_protected);
420 if (r < 0) {
421 derr << ": failed to retrieve local snap protect status: "
422 << cpp_strerror(r) << dendl;
423 m_local_image_ctx->snap_lock.put_read();
424 finish(r);
425 return;
426 }
427 m_local_image_ctx->snap_lock.put_read();
428
429 if (!local_protected) {
430 break;
431 }
432 }
433
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();
438 return;
439 }
440
441 m_prev_snap_id = *snap_id_it;
442 m_snap_name = get_snapshot_name(m_remote_image_ctx, m_prev_snap_id);
443
444 dout(20) << ": "
445 << "snap_name=" << m_snap_name << ", "
446 << "snap_id=" << m_prev_snap_id << dendl;
447
448 Context *ctx = create_context_callback<
449 SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_snap_protect>(
450 this);
451 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
452 m_local_image_ctx->operations->execute_snap_protect(cls::rbd::UserSnapshotNamespace(),
453 m_snap_name.c_str(),
454 ctx);
455 }
456
457 template <typename I>
458 void SnapshotCopyRequest<I>::handle_snap_protect(int r) {
459 dout(20) << ": r=" << r << dendl;
460
461 if (r < 0) {
462 derr << ": failed to protect snapshot '" << m_snap_name << "': "
463 << cpp_strerror(r) << dendl;
464 finish(r);
465 return;
466 }
467 if (handle_cancellation())
468 {
469 return;
470 }
471
472 send_snap_protect();
473 }
474
475 template <typename I>
476 void SnapshotCopyRequest<I>::send_update_client() {
477 dout(20) << dendl;
478
479 compute_snap_map();
480
481 librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
482 client_meta.snap_seqs = m_snap_seqs;
483
484 librbd::journal::ClientData client_data(client_meta);
485 bufferlist data_bl;
486 ::encode(client_data, data_bl);
487
488 Context *ctx = create_context_callback<
489 SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_update_client>(
490 this);
491 m_journaler->update_client(data_bl, ctx);
492 }
493
494 template <typename I>
495 void SnapshotCopyRequest<I>::handle_update_client(int r) {
496 dout(20) << ": r=" << r << dendl;
497
498 if (r < 0) {
499 derr << ": failed to update client data: " << cpp_strerror(r)
500 << dendl;
501 finish(r);
502 return;
503 }
504 if (handle_cancellation())
505 {
506 return;
507 }
508
509 m_client_meta->snap_seqs = m_snap_seqs;
510
511 finish(0);
512 }
513
514 template <typename I>
515 bool SnapshotCopyRequest<I>::handle_cancellation() {
516 {
517 Mutex::Locker locker(m_lock);
518 if (!m_canceled) {
519 return false;
520 }
521 }
522 dout(10) << ": snapshot copy canceled" << dendl;
523 finish(-ECANCELED);
524 return true;
525 }
526
527 template <typename I>
528 void SnapshotCopyRequest<I>::error(int r) {
529 dout(20) << ": r=" << r << dendl;
530
531 m_work_queue->queue(new FunctionContext([this, r](int r1) { finish(r); }));
532 }
533
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));
541 }
542 }
543
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);
549
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) {
555 continue;
556 } else if (spec->pool_id == -1) {
557 *spec = parent_spec;
558 continue;
559 }
560
561 if (*spec != parent_spec) {
562 return -EINVAL;
563 }
564 }
565 return 0;
566 }
567
568 } // namespace image_sync
569 } // namespace mirror
570 } // namespace rbd
571
572 template class rbd::mirror::image_sync::SnapshotCopyRequest<librbd::ImageCtx>;