Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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>;