1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	
4    	#include "include/compat.h"
5    	#include "BootstrapRequest.h"
6    	#include "CloseImageRequest.h"
7    	#include "CreateImageRequest.h"
8    	#include "IsPrimaryRequest.h"
9    	#include "OpenImageRequest.h"
10   	#include "OpenLocalImageRequest.h"
11   	#include "common/debug.h"
12   	#include "common/dout.h"
13   	#include "common/errno.h"
14   	#include "common/WorkQueue.h"
15   	#include "cls/rbd/cls_rbd_client.h"
16   	#include "journal/Journaler.h"
17   	#include "librbd/ImageCtx.h"
18   	#include "librbd/ImageState.h"
19   	#include "librbd/internal.h"
20   	#include "librbd/Journal.h"
21   	#include "librbd/Utils.h"
22   	#include "librbd/journal/Types.h"
23   	#include "tools/rbd_mirror/ProgressContext.h"
24   	#include "tools/rbd_mirror/ImageSync.h"
25   	#include "tools/rbd_mirror/Threads.h"
26   	
27   	#define dout_context g_ceph_context
28   	#define dout_subsys ceph_subsys_rbd_mirror
29   	#undef dout_prefix
30   	#define dout_prefix *_dout << "rbd::mirror::image_replayer::BootstrapRequest: " \
31   	                           << this << " " << __func__ << ": "
32   	
33   	namespace rbd {
34   	namespace mirror {
35   	namespace image_replayer {
36   	
37   	using librbd::util::create_context_callback;
38   	using librbd::util::create_rados_callback;
39   	using librbd::util::unique_lock_name;
40   	
41   	template <typename I>
42   	BootstrapRequest<I>::BootstrapRequest(
43   	        Threads<I>* threads,
44   	        librados::IoCtx &local_io_ctx,
45   	        librados::IoCtx &remote_io_ctx,
46   	        InstanceWatcher<I> *instance_watcher,
47   	        I **local_image_ctx,
48   	        const std::string &local_image_id,
49   	        const std::string &remote_image_id,
50   	        const std::string &global_image_id,
51   	        const std::string &local_mirror_uuid,
52   	        const std::string &remote_mirror_uuid,
53   	        Journaler *journaler,
54   	        cls::journal::ClientState *client_state,
55   	        MirrorPeerClientMeta *client_meta,
56   	        Context *on_finish,
57   	        bool *do_resync,
58   	        rbd::mirror::ProgressContext *progress_ctx)
59   	  : BaseRequest("rbd::mirror::image_replayer::BootstrapRequest",
60   			reinterpret_cast<CephContext*>(local_io_ctx.cct()), on_finish),
61   	    m_threads(threads), m_local_io_ctx(local_io_ctx),
62   	    m_remote_io_ctx(remote_io_ctx), m_instance_watcher(instance_watcher),
63   	    m_local_image_ctx(local_image_ctx), m_local_image_id(local_image_id),
64   	    m_remote_image_id(remote_image_id), m_global_image_id(global_image_id),
65   	    m_local_mirror_uuid(local_mirror_uuid),
66   	    m_remote_mirror_uuid(remote_mirror_uuid), m_journaler(journaler),
67   	    m_client_state(client_state), m_client_meta(client_meta),
68   	    m_progress_ctx(progress_ctx), m_do_resync(do_resync),
69   	    m_lock(ceph::make_mutex(unique_lock_name("BootstrapRequest::m_lock", this))) {
70   	  dout(10) << dendl;
71   	}
72   	
73   	template <typename I>
(1) Event exn_spec_violation: An exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE" is thrown but the throw list "throw()" doesn't allow it to be thrown. This will cause a call to unexpected() which usually calls terminate().
Also see events: [fun_call_w_exception]
74   	BootstrapRequest<I>::~BootstrapRequest() {
(2) Event fun_call_w_exception: Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details]
Also see events: [exn_spec_violation]
75   	  ceph_assert(m_remote_image_ctx == nullptr);
76   	}
77   	
78   	template <typename I>
79   	bool BootstrapRequest<I>::is_syncing() const {
80   	  std::lock_guard locker{m_lock};
81   	  return (m_image_sync != nullptr);
82   	}
83   	
84   	template <typename I>
85   	void BootstrapRequest<I>::send() {
86   	  *m_do_resync = false;
87   	
88   	  get_remote_tag_class();
89   	}
90   	
91   	template <typename I>
92   	void BootstrapRequest<I>::cancel() {
93   	  dout(10) << dendl;
94   	
95   	  std::lock_guard locker{m_lock};
96   	  m_canceled = true;
97   	
98   	  if (m_image_sync != nullptr) {
99   	    m_image_sync->cancel();
100  	  }
101  	}
102  	
103  	template <typename I>
104  	void BootstrapRequest<I>::get_remote_tag_class() {
105  	  dout(15) << dendl;
106  	
107  	  update_progress("GET_REMOTE_TAG_CLASS");
108  	
109  	  Context *ctx = create_context_callback<
110  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_get_remote_tag_class>(
111  	      this);
112  	  m_journaler->get_client(librbd::Journal<>::IMAGE_CLIENT_ID, &m_client, ctx);
113  	}
114  	
115  	template <typename I>
116  	void BootstrapRequest<I>::handle_get_remote_tag_class(int r) {
117  	  dout(15) << "r=" << r << dendl;
118  	
119  	  if (r < 0) {
120  	    derr << "failed to retrieve remote client: " << cpp_strerror(r) << dendl;
121  	    finish(r);
122  	    return;
123  	  }
124  	
125  	  librbd::journal::ClientData client_data;
126  	  auto it = m_client.data.cbegin();
127  	  try {
128  	    decode(client_data, it);
129  	  } catch (const buffer::error &err) {
130  	    derr << "failed to decode remote client meta data: " << err.what()
131  	         << dendl;
132  	    finish(-EBADMSG);
133  	    return;
134  	  }
135  	
136  	  librbd::journal::ImageClientMeta *client_meta =
137  	    boost::get<librbd::journal::ImageClientMeta>(&client_data.client_meta);
138  	  if (client_meta == nullptr) {
139  	    derr << "unknown remote client registration" << dendl;
140  	    finish(-EINVAL);
141  	    return;
142  	  }
143  	
144  	  m_remote_tag_class = client_meta->tag_class;
145  	  dout(10) << "remote tag class=" << m_remote_tag_class << dendl;
146  	
147  	  open_remote_image();
148  	}
149  	
150  	template <typename I>
151  	void BootstrapRequest<I>::open_remote_image() {
152  	  dout(15) << "remote_image_id=" << m_remote_image_id << dendl;
153  	
154  	  update_progress("OPEN_REMOTE_IMAGE");
155  	
156  	  Context *ctx = create_context_callback<
157  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_open_remote_image>(
158  	      this);
159  	  OpenImageRequest<I> *request = OpenImageRequest<I>::create(
160  	    m_remote_io_ctx, &m_remote_image_ctx, m_remote_image_id, false,
161  	    ctx);
162  	  request->send();
163  	}
164  	
165  	template <typename I>
166  	void BootstrapRequest<I>::handle_open_remote_image(int r) {
167  	  dout(15) << "r=" << r << dendl;
168  	
169  	  if (r < 0) {
170  	    derr << "failed to open remote image: " << cpp_strerror(r) << dendl;
171  	    ceph_assert(m_remote_image_ctx == nullptr);
172  	    finish(r);
173  	    return;
174  	  }
175  	
176  	  is_primary();
177  	}
178  	
179  	template <typename I>
180  	void BootstrapRequest<I>::is_primary() {
181  	  dout(15) << dendl;
182  	
183  	  update_progress("OPEN_REMOTE_IMAGE");
184  	
185  	  Context *ctx = create_context_callback<
186  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_is_primary>(
187  	      this);
188  	  IsPrimaryRequest<I> *request = IsPrimaryRequest<I>::create(m_remote_image_ctx,
189  	                                                             &m_primary, ctx);
190  	  request->send();
191  	}
192  	
193  	template <typename I>
194  	void BootstrapRequest<I>::handle_is_primary(int r) {
195  	  dout(15) << "r=" << r << dendl;
196  	
197  	  if (r == -ENOENT) {
198  	    dout(5) << "remote image is not mirrored" << dendl;
199  	    m_ret_val = -EREMOTEIO;
200  	    close_remote_image();
201  	    return;
202  	  } else if (r < 0) {
203  	    derr << "error querying remote image primary status: " << cpp_strerror(r)
204  	         << dendl;
205  	    m_ret_val = r;
206  	    close_remote_image();
207  	    return;
208  	  }
209  	
210  	  if (!m_primary) {
211  	    if (m_local_image_id.empty()) {
212  	      // no local image and remote isn't primary -- don't sync it
213  	      dout(5) << "remote image is not primary -- not syncing"
214  	              << dendl;
215  	      m_ret_val = -EREMOTEIO;
216  	      close_remote_image();
217  	      return;
218  	    } else if (m_client_meta->state !=
219  	                 librbd::journal::MIRROR_PEER_STATE_REPLAYING) {
220  	      // ensure we attempt to re-sync to remote if it's re-promoted
221  	      dout(5) << "remote image is not primary -- sync interrupted"
222  	              << dendl;
223  	      m_ret_val = -EREMOTEIO;
224  	      update_client_state();
225  	      return;
226  	    }
227  	  }
228  	
229  	  if (!m_client_meta->image_id.empty()) {
230  	    // have an image id -- use that to open the image since a deletion (resync)
231  	    // will leave the old image id registered in the peer
232  	    m_local_image_id = m_client_meta->image_id;
233  	  }
234  	
235  	  if (m_local_image_id.empty()) {
236  	    // prepare to create local image
237  	    update_client_image();
238  	    return;
239  	  }
240  	
241  	  open_local_image();
242  	}
243  	
244  	template <typename I>
245  	void BootstrapRequest<I>::update_client_state() {
246  	  dout(15) << dendl;
247  	  update_progress("UPDATE_CLIENT_STATE");
248  	
249  	  librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
250  	  client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
251  	
252  	  librbd::journal::ClientData client_data(client_meta);
253  	  bufferlist data_bl;
254  	  encode(client_data, data_bl);
255  	
256  	  Context *ctx = create_context_callback<
257  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_update_client_state>(
258  	      this);
259  	  m_journaler->update_client(data_bl, ctx);
260  	}
261  	
262  	template <typename I>
263  	void BootstrapRequest<I>::handle_update_client_state(int r) {
264  	  dout(15) << "r=" << r << dendl;
265  	  if (r < 0) {
266  	    derr << "failed to update client: " << cpp_strerror(r) << dendl;
267  	  } else {
268  	    m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
269  	  }
270  	
271  	  close_remote_image();
272  	}
273  	
274  	template <typename I>
275  	void BootstrapRequest<I>::open_local_image() {
276  	  dout(15) << "local_image_id=" << m_local_image_id << dendl;
277  	
278  	  update_progress("OPEN_LOCAL_IMAGE");
279  	
280  	  Context *ctx = create_context_callback<
281  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_open_local_image>(
282  	      this);
283  	  OpenLocalImageRequest<I> *request = OpenLocalImageRequest<I>::create(
284  	    m_local_io_ctx, m_local_image_ctx, m_local_image_id, m_threads->work_queue,
285  	    ctx);
286  	  request->send();
287  	}
288  	
289  	template <typename I>
290  	void BootstrapRequest<I>::handle_open_local_image(int r) {
291  	  dout(15) << "r=" << r << dendl;
292  	
293  	  if (r == -ENOENT) {
294  	    ceph_assert(*m_local_image_ctx == nullptr);
295  	    dout(10) << "local image missing" << dendl;
296  	    unregister_client();
297  	    return;
298  	  } else if (r == -EREMOTEIO) {
299  	    ceph_assert(*m_local_image_ctx == nullptr);
300  	    dout(10) << "local image is primary -- skipping image replay" << dendl;
301  	    m_ret_val = r;
302  	    close_remote_image();
303  	    return;
304  	  } else if (r < 0) {
305  	    ceph_assert(*m_local_image_ctx == nullptr);
306  	    derr << "failed to open local image: " << cpp_strerror(r) << dendl;
307  	    m_ret_val = r;
308  	    close_remote_image();
309  	    return;
310  	  }
311  	
312  	  I *local_image_ctx = (*m_local_image_ctx);
313  	  {
314  	    local_image_ctx->image_lock.lock_shared();
315  	    if (local_image_ctx->journal == nullptr) {
316  	      local_image_ctx->image_lock.unlock_shared();
317  	
318  	      derr << "local image does not support journaling" << dendl;
319  	      m_ret_val = -EINVAL;
320  	      close_local_image();
321  	      return;
322  	    }
323  	
324  	    r = (*m_local_image_ctx)->journal->is_resync_requested(m_do_resync);
325  	    if (r < 0) {
326  	      local_image_ctx->image_lock.unlock_shared();
327  	
328  	      derr << "failed to check if a resync was requested" << dendl;
329  	      m_ret_val = r;
330  	      close_local_image();
331  	      return;
332  	    }
333  	
334  	    m_local_tag_tid = local_image_ctx->journal->get_tag_tid();
335  	    m_local_tag_data = local_image_ctx->journal->get_tag_data();
336  	    dout(10) << "local tag=" << m_local_tag_tid << ", "
337  	             << "local tag data=" << m_local_tag_data << dendl;
338  	    local_image_ctx->image_lock.unlock_shared();
339  	  }
340  	
341  	  if (m_local_tag_data.mirror_uuid != m_remote_mirror_uuid && !m_primary) {
342  	    // if the local mirror is not linked to the (now) non-primary image,
343  	    // stop the replay. Otherwise, we ignore that the remote is non-primary
344  	    // so that we can replay the demotion
345  	    dout(5) << "remote image is not primary -- skipping image replay"
346  	            << dendl;
347  	    m_ret_val = -EREMOTEIO;
348  	    close_local_image();
349  	    return;
350  	  }
351  	
352  	  if (*m_do_resync) {
353  	    close_remote_image();
354  	    return;
355  	  }
356  	
357  	  if (*m_client_state == cls::journal::CLIENT_STATE_DISCONNECTED) {
358  	    dout(10) << "client flagged disconnected -- skipping bootstrap" << dendl;
359  	    // The caller is expected to detect disconnect initializing remote journal.
360  	    m_ret_val = 0;
361  	    close_remote_image();
362  	    return;
363  	  }
364  	
365  	  get_remote_tags();
366  	}
367  	
368  	template <typename I>
369  	void BootstrapRequest<I>::unregister_client() {
370  	  dout(15) << dendl;
371  	  update_progress("UNREGISTER_CLIENT");
372  	
373  	  m_local_image_id = "";
374  	  Context *ctx = create_context_callback<
375  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_unregister_client>(
376  	      this);
377  	  m_journaler->unregister_client(ctx);
378  	}
379  	
380  	template <typename I>
381  	void BootstrapRequest<I>::handle_unregister_client(int r) {
382  	  dout(15) << "r=" << r << dendl;
383  	  if (r < 0) {
384  	    derr << "failed to unregister with remote journal: " << cpp_strerror(r)
385  	         << dendl;
386  	    m_ret_val = r;
387  	    close_remote_image();
388  	    return;
389  	  }
390  	
391  	  *m_client_meta = librbd::journal::MirrorPeerClientMeta("");
392  	  register_client();
393  	}
394  	
395  	template <typename I>
396  	void BootstrapRequest<I>::register_client() {
397  	  dout(15) << dendl;
398  	
399  	  update_progress("REGISTER_CLIENT");
400  	
401  	  ceph_assert(m_local_image_id.empty());
402  	  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
403  	  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
404  	
405  	  librbd::journal::ClientData client_data{mirror_peer_client_meta};
406  	  bufferlist client_data_bl;
407  	  encode(client_data, client_data_bl);
408  	
409  	  Context *ctx = create_context_callback<
410  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_register_client>(
411  	      this);
412  	  m_journaler->register_client(client_data_bl, ctx);
413  	}
414  	
415  	template <typename I>
416  	void BootstrapRequest<I>::handle_register_client(int r) {
417  	  dout(15) << "r=" << r << dendl;
418  	
419  	  if (r < 0) {
420  	    derr << "failed to register with remote journal: " << cpp_strerror(r)
421  	         << dendl;
422  	    m_ret_val = r;
423  	    close_remote_image();
424  	    return;
425  	  }
426  	
427  	  *m_client_state = cls::journal::CLIENT_STATE_CONNECTED;
428  	  *m_client_meta = librbd::journal::MirrorPeerClientMeta();
429  	  m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
430  	
431  	  is_primary();
432  	}
433  	
434  	template <typename I>
435  	void BootstrapRequest<I>::update_client_image() {
436  	  ceph_assert(m_local_image_id.empty());
437  	  assert(m_local_image_id.empty());
438  	  m_local_image_id = librbd::util::generate_image_id<I>(m_local_io_ctx);
439  	
440  	  dout(15) << "local_image_id=" << m_local_image_id << dendl;
441  	  update_progress("UPDATE_CLIENT_IMAGE");
442  	
443  	  librbd::journal::MirrorPeerClientMeta client_meta{m_local_image_id};
444  	  client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
445  	
446  	  librbd::journal::ClientData client_data(client_meta);
447  	  bufferlist data_bl;
448  	  encode(client_data, data_bl);
449  	
450  	  Context *ctx = create_context_callback<
451  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_update_client_image>(
452  	      this);
453  	  m_journaler->update_client(data_bl, ctx);
454  	}
455  	
456  	template <typename I>
457  	void BootstrapRequest<I>::handle_update_client_image(int r) {
458  	  dout(15) << "r=" << r << dendl;
459  	
460  	  if (r < 0) {
461  	    derr << "failed to update client: " << cpp_strerror(r) << dendl;
462  	    m_ret_val = r;
463  	    close_remote_image();
464  	    return;
465  	  }
466  	
467  	  if (m_canceled) {
468  	    dout(10) << "request canceled" << dendl;
469  	    m_ret_val = -ECANCELED;
470  	    close_remote_image();
471  	    return;
472  	  }
473  	
474  	  *m_client_meta = {m_local_image_id};
475  	  m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
476  	  create_local_image();
477  	}
478  	
479  	template <typename I>
480  	void BootstrapRequest<I>::create_local_image() {
481  	  dout(15) << "local_image_id=" << m_local_image_id << dendl;
482  	  update_progress("CREATE_LOCAL_IMAGE");
483  	
484  	  m_remote_image_ctx->image_lock.lock_shared();
485  	  std::string image_name = m_remote_image_ctx->name;
486  	  m_remote_image_ctx->image_lock.unlock_shared();
487  	
488  	  Context *ctx = create_context_callback<
489  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_create_local_image>(
490  	      this);
491  	  CreateImageRequest<I> *request = CreateImageRequest<I>::create(
492  	    m_threads, m_local_io_ctx, m_global_image_id, m_remote_mirror_uuid,
493  	    image_name, m_local_image_id, m_remote_image_ctx, ctx);
494  	  request->send();
495  	}
496  	
497  	template <typename I>
498  	void BootstrapRequest<I>::handle_create_local_image(int r) {
499  	  dout(15) << "r=" << r << dendl;
500  	
501  	  if (r == -EBADF) {
502  	    dout(5) << "image id " << m_local_image_id << " already in-use" << dendl;
503  	    m_local_image_id = "";
504  	    update_client_image();
505  	    return;
506  	  } else if (r < 0) {
507  	    if (r == -ENOENT) {
508  	      dout(10) << "parent image does not exist" << dendl;
509  	    } else {
510  	      derr << "failed to create local image: " << cpp_strerror(r) << dendl;
511  	    }
512  	    m_ret_val = r;
513  	    close_remote_image();
514  	    return;
515  	  }
516  	
517  	  open_local_image();
518  	}
519  	
520  	template <typename I>
521  	void BootstrapRequest<I>::get_remote_tags() {
522  	  if (m_client_meta->state == librbd::journal::MIRROR_PEER_STATE_SYNCING) {
523  	    // optimization -- no need to compare remote tags if we just created
524  	    // the image locally or sync was interrupted
525  	    image_sync();
526  	    return;
527  	  }
528  	
529  	  dout(15) << dendl;
530  	  update_progress("GET_REMOTE_TAGS");
531  	
532  	  Context *ctx = create_context_callback<
533  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_get_remote_tags>(this);
534  	  m_journaler->get_tags(m_remote_tag_class, &m_remote_tags, ctx);
535  	}
536  	
537  	template <typename I>
538  	void BootstrapRequest<I>::handle_get_remote_tags(int r) {
539  	  dout(15) << "r=" << r << dendl;
540  	
541  	  if (r < 0) {
542  	    derr << "failed to retrieve remote tags: " << cpp_strerror(r) << dendl;
543  	    m_ret_val = r;
544  	    close_local_image();
545  	    return;
546  	  }
547  	
548  	  if (m_canceled) {
549  	    dout(10) << "request canceled" << dendl;
550  	    m_ret_val = -ECANCELED;
551  	    close_local_image();
552  	    return;
553  	  }
554  	
555  	  // At this point, the local image was existing, non-primary, and replaying;
556  	  // and the remote image is primary.  Attempt to link the local image's most
557  	  // recent tag to the remote image's tag chain.
558  	  bool remote_tag_data_valid = false;
559  	  librbd::journal::TagData remote_tag_data;
560  	  boost::optional<uint64_t> remote_orphan_tag_tid =
561  	    boost::make_optional<uint64_t>(false, 0U);
562  	  bool reconnect_orphan = false;
563  	
564  	  // decode the remote tags
565  	  for (auto &remote_tag : m_remote_tags) {
566  	    if (m_local_tag_data.predecessor.commit_valid &&
567  	        m_local_tag_data.predecessor.mirror_uuid == m_remote_mirror_uuid &&
568  	        m_local_tag_data.predecessor.tag_tid > remote_tag.tid) {
569  	      dout(15) << "skipping processed predecessor remote tag "
570  	               << remote_tag.tid << dendl;
571  	      continue;
572  	    }
573  	
574  	    try {
575  	      auto it = remote_tag.data.cbegin();
576  	      decode(remote_tag_data, it);
577  	      remote_tag_data_valid = true;
578  	    } catch (const buffer::error &err) {
579  	      derr << "failed to decode remote tag " << remote_tag.tid << ": "
580  	           << err.what() << dendl;
581  	      m_ret_val = -EBADMSG;
582  	      close_local_image();
583  	      return;
584  	    }
585  	
586  	    dout(10) << "decoded remote tag " << remote_tag.tid << ": "
587  	             << remote_tag_data << dendl;
588  	
589  	    if (!m_local_tag_data.predecessor.commit_valid) {
590  	      // newly synced local image (no predecessor) replays from the first tag
591  	      if (remote_tag_data.mirror_uuid != librbd::Journal<>::LOCAL_MIRROR_UUID) {
592  	        dout(15) << "skipping non-primary remote tag" << dendl;
593  	        continue;
594  	      }
595  	
596  	      dout(10) << "using initial primary remote tag" << dendl;
597  	      break;
598  	    }
599  	
600  	    if (m_local_tag_data.mirror_uuid == librbd::Journal<>::ORPHAN_MIRROR_UUID) {
601  	      // demotion last available local epoch
602  	
603  	      if (remote_tag_data.mirror_uuid == m_local_tag_data.mirror_uuid &&
604  	          remote_tag_data.predecessor.commit_valid &&
605  	          remote_tag_data.predecessor.tag_tid ==
606  	            m_local_tag_data.predecessor.tag_tid) {
607  	        // demotion matches remote epoch
608  	
609  	        if (remote_tag_data.predecessor.mirror_uuid == m_local_mirror_uuid &&
610  	            m_local_tag_data.predecessor.mirror_uuid ==
611  	              librbd::Journal<>::LOCAL_MIRROR_UUID) {
612  	          // local demoted and remote has matching event
613  	          dout(15) << "found matching local demotion tag" << dendl;
614  	          remote_orphan_tag_tid = remote_tag.tid;
615  	          continue;
616  	        }
617  	
618  	        if (m_local_tag_data.predecessor.mirror_uuid == m_remote_mirror_uuid &&
619  	            remote_tag_data.predecessor.mirror_uuid ==
620  	              librbd::Journal<>::LOCAL_MIRROR_UUID) {
621  	          // remote demoted and local has matching event
622  	          dout(15) << "found matching remote demotion tag" << dendl;
623  	          remote_orphan_tag_tid = remote_tag.tid;
624  	          continue;
625  	        }
626  	      }
627  	
628  	      if (remote_tag_data.mirror_uuid == librbd::Journal<>::LOCAL_MIRROR_UUID &&
629  	          remote_tag_data.predecessor.mirror_uuid == librbd::Journal<>::ORPHAN_MIRROR_UUID &&
630  	          remote_tag_data.predecessor.commit_valid && remote_orphan_tag_tid &&
631  	          remote_tag_data.predecessor.tag_tid == *remote_orphan_tag_tid) {
632  	        // remote promotion tag chained to remote/local demotion tag
633  	        dout(15) << "found chained remote promotion tag" << dendl;
634  	        reconnect_orphan = true;
635  	        break;
636  	      }
637  	
638  	      // promotion must follow demotion
639  	      remote_orphan_tag_tid = boost::none;
640  	    }
641  	  }
642  	
643  	  if (remote_tag_data_valid &&
644  	      m_local_tag_data.mirror_uuid == m_remote_mirror_uuid) {
645  	    dout(10) << "local image is in clean replay state" << dendl;
646  	  } else if (reconnect_orphan) {
647  	    dout(10) << "remote image was demoted/promoted" << dendl;
648  	  } else {
649  	    derr << "split-brain detected -- skipping image replay" << dendl;
650  	    m_ret_val = -EEXIST;
651  	    close_local_image();
652  	    return;
653  	  }
654  	
655  	  image_sync();
656  	}
657  	
658  	template <typename I>
659  	void BootstrapRequest<I>::image_sync() {
660  	  if (m_client_meta->state == librbd::journal::MIRROR_PEER_STATE_REPLAYING) {
661  	    // clean replay state -- no image sync required
662  	    close_remote_image();
663  	    return;
664  	  }
665  	
666  	  {
667  	    std::unique_lock locker{m_lock};
668  	    if (m_canceled) {
669  	      m_ret_val = -ECANCELED;
670  	    } else {
671  	      dout(15) << dendl;
672  	      ceph_assert(m_image_sync == nullptr);
673  	
674  	      Context *ctx = create_context_callback<
675  	        BootstrapRequest<I>, &BootstrapRequest<I>::handle_image_sync>(this);
676  	      m_image_sync = ImageSync<I>::create(
677  	          *m_local_image_ctx, m_remote_image_ctx, m_threads->timer,
678  	          &m_threads->timer_lock, m_local_mirror_uuid, m_journaler,
679  	          m_client_meta, m_threads->work_queue, m_instance_watcher, ctx,
680  	          m_progress_ctx);
681  	
682  	      m_image_sync->get();
683  	
684  	      locker.unlock();
685  	      update_progress("IMAGE_SYNC");
686  	      locker.lock();
687  	
688  	      m_image_sync->send();
689  	      return;
690  	    }
691  	  }
692  	
693  	  dout(10) << "request canceled" << dendl;
694  	  close_remote_image();
695  	}
696  	
697  	template <typename I>
698  	void BootstrapRequest<I>::handle_image_sync(int r) {
699  	  dout(15) << "r=" << r << dendl;
700  	
701  	  {
702  	    std::lock_guard locker{m_lock};
703  	    m_image_sync->put();
704  	    m_image_sync = nullptr;
705  	
706  	    if (m_canceled) {
707  	      dout(10) << "request canceled" << dendl;
708  	      m_ret_val = -ECANCELED;
709  	    }
710  	
711  	    if (r < 0) {
712  	      derr << "failed to sync remote image: " << cpp_strerror(r) << dendl;
713  	      m_ret_val = r;
714  	    }
715  	  }
716  	
717  	  close_remote_image();
718  	}
719  	
720  	template <typename I>
721  	void BootstrapRequest<I>::close_local_image() {
722  	  dout(15) << dendl;
723  	
724  	  update_progress("CLOSE_LOCAL_IMAGE");
725  	
726  	  Context *ctx = create_context_callback<
727  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_close_local_image>(
728  	      this);
729  	  CloseImageRequest<I> *request = CloseImageRequest<I>::create(
730  	    m_local_image_ctx, ctx);
731  	  request->send();
732  	}
733  	
734  	template <typename I>
735  	void BootstrapRequest<I>::handle_close_local_image(int r) {
736  	  dout(15) << "r=" << r << dendl;
737  	
738  	  if (r < 0) {
739  	    derr << "error encountered closing local image: " << cpp_strerror(r)
740  	         << dendl;
741  	  }
742  	
743  	  close_remote_image();
744  	}
745  	
746  	template <typename I>
747  	void BootstrapRequest<I>::close_remote_image() {
748  	  dout(15) << dendl;
749  	
750  	  update_progress("CLOSE_REMOTE_IMAGE");
751  	
752  	  Context *ctx = create_context_callback<
753  	    BootstrapRequest<I>, &BootstrapRequest<I>::handle_close_remote_image>(
754  	      this);
755  	  CloseImageRequest<I> *request = CloseImageRequest<I>::create(
756  	    &m_remote_image_ctx, ctx);
757  	  request->send();
758  	}
759  	
760  	template <typename I>
761  	void BootstrapRequest<I>::handle_close_remote_image(int r) {
762  	  dout(15) << "r=" << r << dendl;
763  	
764  	  if (r < 0) {
765  	    derr << "error encountered closing remote image: " << cpp_strerror(r)
766  	         << dendl;
767  	  }
768  	
769  	  finish(m_ret_val);
770  	}
771  	
772  	template <typename I>
773  	void BootstrapRequest<I>::update_progress(const std::string &description) {
774  	  dout(15) << description << dendl;
775  	
776  	  if (m_progress_ctx) {
777  	    m_progress_ctx->update_progress(description);
778  	  }
779  	}
780  	
781  	} // namespace image_replayer
782  	} // namespace mirror
783  	} // namespace rbd
784  	
785  	template class rbd::mirror::image_replayer::BootstrapRequest<librbd::ImageCtx>;
786