]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd-mirror: skeleton integration with service daemon API
authorJason Dillaman <dillaman@redhat.com>
Tue, 11 Jul 2017 16:44:02 +0000 (12:44 -0400)
committerJason Dillaman <dillaman@redhat.com>
Tue, 18 Jul 2017 14:28:13 +0000 (10:28 -0400)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
17 files changed:
src/test/rbd_mirror/test_ClusterWatcher.cc
src/test/rbd_mirror/test_ImageDeleter.cc
src/test/rbd_mirror/test_ImageReplayer.cc
src/test/rbd_mirror/test_mock_InstanceReplayer.cc
src/tools/rbd_mirror/CMakeLists.txt
src/tools/rbd_mirror/ClusterWatcher.cc
src/tools/rbd_mirror/ClusterWatcher.h
src/tools/rbd_mirror/ImageDeleter.cc
src/tools/rbd_mirror/ImageDeleter.h
src/tools/rbd_mirror/InstanceReplayer.cc
src/tools/rbd_mirror/InstanceReplayer.h
src/tools/rbd_mirror/Mirror.cc
src/tools/rbd_mirror/Mirror.h
src/tools/rbd_mirror/PoolReplayer.cc
src/tools/rbd_mirror/PoolReplayer.h
src/tools/rbd_mirror/ServiceDaemon.cc [new file with mode: 0644]
src/tools/rbd_mirror/ServiceDaemon.h [new file with mode: 0644]

index 2fd894c702e788b7549ab8f08b77e1a22b71aa38..61f67a5f2279b546520a01eaab7880a660734b36 100644 (file)
@@ -7,6 +7,7 @@
 #include "librbd/internal.h"
 #include "librbd/api/Mirror.h"
 #include "tools/rbd_mirror/ClusterWatcher.h"
+#include "tools/rbd_mirror/ServiceDaemon.h"
 #include "tools/rbd_mirror/types.h"
 #include "test/rbd_mirror/test_fixture.h"
 #include "test/librados/test.h"
@@ -34,7 +35,10 @@ public:
   {
     m_cluster = std::make_shared<librados::Rados>();
     EXPECT_EQ("", connect_cluster_pp(*m_cluster));
-    m_cluster_watcher.reset(new ClusterWatcher(m_cluster, m_lock));
+    m_service_daemon.reset(new rbd::mirror::ServiceDaemon<>(g_ceph_context,
+                                                            m_cluster));
+    m_cluster_watcher.reset(new ClusterWatcher(m_cluster, m_lock,
+                                               m_service_daemon.get()));
   }
 
   ~TestClusterWatcher() override {
@@ -126,8 +130,9 @@ public:
     ASSERT_EQ(m_pool_peers, m_cluster_watcher->get_pool_peers());
   }
 
-  Mutex m_lock;
   RadosRef m_cluster;
+  Mutex m_lock;
+  unique_ptr<rbd::mirror::ServiceDaemon<>> m_service_daemon;
   unique_ptr<ClusterWatcher> m_cluster_watcher;
 
   set<string> m_pools;
index 24f52574949473b579f63cb5e7fc43be3761272b..0f0b44fdb149bc7f0101fe363ce0526e56952fe0 100644 (file)
@@ -18,6 +18,7 @@
 #include "cls/rbd/cls_rbd_client.h"
 #include "tools/rbd_mirror/ImageDeleter.h"
 #include "tools/rbd_mirror/ImageReplayer.h"
+#include "tools/rbd_mirror/ServiceDaemon.h"
 #include "tools/rbd_mirror/Threads.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageState.h"
@@ -61,12 +62,15 @@ public:
 
   void SetUp() override {
     TestFixture::SetUp();
+    m_service_daemon.reset(new rbd::mirror::ServiceDaemon<>(g_ceph_context,
+                                                            _rados));
 
     librbd::api::Mirror<>::mode_set(m_local_io_ctx, RBD_MIRROR_MODE_IMAGE);
 
     m_deleter = new rbd::mirror::ImageDeleter<>(m_threads->work_queue,
                                                 m_threads->timer,
-                                                &m_threads->timer_lock);
+                                                &m_threads->timer_lock,
+                                                m_service_daemon.get());
 
     EXPECT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, 1 << 20));
     ImageCtx *ictx = new ImageCtx(m_image_name, "", "", m_local_io_ctx,
@@ -210,6 +214,7 @@ public:
 
   librbd::RBD rbd;
   std::string m_local_image_id;
+  std::unique_ptr<rbd::mirror::ServiceDaemon<>> m_service_daemon;
   rbd::mirror::ImageDeleter<> *m_deleter;
 };
 
index 9b9791c48b46c203ce91e96b9a25ee753ebcdbdc..810ebff41a7ebab00ec63f78d44d65ea3ca1a043 100644 (file)
 #include "librbd/io/ImageRequestWQ.h"
 #include "librbd/io/ReadResult.h"
 #include "tools/rbd_mirror/types.h"
+#include "tools/rbd_mirror/ImageDeleter.h"
 #include "tools/rbd_mirror/ImageReplayer.h"
 #include "tools/rbd_mirror/InstanceWatcher.h"
+#include "tools/rbd_mirror/ServiceDaemon.h"
 #include "tools/rbd_mirror/Threads.h"
-#include "tools/rbd_mirror/ImageDeleter.h"
 
 #include "test/librados/test.h"
 #include "gtest/gtest.h"
@@ -115,8 +116,11 @@ public:
     m_threads = new rbd::mirror::Threads<>(reinterpret_cast<CephContext*>(
       m_local_ioctx.cct()));
 
+    m_service_daemon.reset(new rbd::mirror::ServiceDaemon<>(g_ceph_context,
+                                                            m_local_cluster));
     m_image_deleter.reset(new rbd::mirror::ImageDeleter<>(
-      m_threads->work_queue, m_threads->timer, &m_threads->timer_lock));
+      m_threads->work_queue, m_threads->timer, &m_threads->timer_lock,
+      m_service_daemon.get()));
     m_instance_watcher = rbd::mirror::InstanceWatcher<>::create(
         m_local_ioctx, m_threads->work_queue, nullptr);
     m_instance_watcher->handle_acquire_leader();
@@ -366,6 +370,7 @@ public:
   static int _image_number;
 
   rbd::mirror::Threads<> *m_threads = nullptr;
+  unique_ptr<rbd::mirror::ServiceDaemon<>> m_service_daemon;
   std::unique_ptr<rbd::mirror::ImageDeleter<>> m_image_deleter;
   std::shared_ptr<librados::Rados> m_local_cluster;
   librados::Rados m_remote_cluster;
index f577aa47ba42a7078c3923f4c18a225f1085ca6a..9e786fc7570425b86aca0cba37c422ea0ac9fe19 100644 (file)
@@ -7,6 +7,7 @@
 #include "tools/rbd_mirror/ImageReplayer.h"
 #include "tools/rbd_mirror/InstanceWatcher.h"
 #include "tools/rbd_mirror/InstanceReplayer.h"
+#include "tools/rbd_mirror/ServiceDaemon.h"
 #include "tools/rbd_mirror/Threads.h"
 
 namespace librbd {
@@ -46,6 +47,10 @@ struct ImageDeleter<librbd::MockTestImageCtx> {
                void(int64_t, const std::string&, Context*, bool));
 };
 
+template<>
+struct ServiceDaemon<librbd::MockTestImageCtx> {
+};
+
 template<>
 struct InstanceWatcher<librbd::MockTestImageCtx> {
 };
@@ -120,6 +125,7 @@ public:
   typedef ImageReplayer<librbd::MockTestImageCtx> MockImageReplayer;
   typedef InstanceReplayer<librbd::MockTestImageCtx> MockInstanceReplayer;
   typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
+  typedef ServiceDaemon<librbd::MockTestImageCtx> MockServiceDaemon;
   typedef Threads<librbd::MockTestImageCtx> MockThreads;
 
   void SetUp() override {
@@ -147,11 +153,12 @@ public:
 };
 
 TEST_F(TestMockInstanceReplayer, AcquireReleaseImage) {
+  MockServiceDaemon mock_service_daemon;
   MockImageDeleter mock_image_deleter;
   MockInstanceWatcher mock_instance_watcher;
   MockImageReplayer mock_image_replayer;
   MockInstanceReplayer instance_replayer(
-    m_mock_threads, &mock_image_deleter,
+    m_mock_threads, &mock_service_daemon, &mock_image_deleter,
     rbd::mirror::RadosRef(new librados::Rados(m_local_io_ctx)),
     "local_mirror_uuid", m_local_io_ctx.get_id());
 
index 1a9d0fb1aab4ede856b3dbedcee2609c6b4da98e..914dfc7b80912febb24d1383f55db4fbcdd330db 100644 (file)
@@ -16,6 +16,7 @@ set(rbd_mirror_internal
   MirrorStatusWatcher.cc
   PoolReplayer.cc
   PoolWatcher.cc
+  ServiceDaemon.cc
   Threads.cc
   types.cc
   image_replayer/BootstrapRequest.cc
index 9bb96b166dd2c33ef022f45a5482f8dc158619ee..f17a5ea69280b22a02f4a6173dc0022863c013e3 100644 (file)
@@ -27,9 +27,9 @@ using librados::IoCtx;
 namespace rbd {
 namespace mirror {
 
-ClusterWatcher::ClusterWatcher(RadosRef cluster, Mutex &lock) :
-  m_lock(lock),
-  m_cluster(cluster)
+ClusterWatcher::ClusterWatcher(RadosRef cluster, Mutex &lock,
+                               ServiceDaemon<librbd::ImageCtx>* service_daemon)
+  : m_cluster(cluster), m_lock(lock), m_service_daemon(service_daemon)
 {
 }
 
index f101de07ba47b0dc26d6997454f256fb618b47c2..e49202f2c2a16f34bd0651559f856dfedb95368f 100644 (file)
 #include "include/rados/librados.hpp"
 #include "types.h"
 
+namespace librbd { struct ImageCtx; }
+
 namespace rbd {
 namespace mirror {
 
+template <typename> class ServiceDaemon;
+
 /**
  * Tracks mirroring configuration for pools in a single
  * cluster.
@@ -27,7 +31,8 @@ public:
   typedef std::map<int64_t, Peers>  PoolPeers;
   typedef std::set<std::string> PoolNames;
 
-  ClusterWatcher(RadosRef cluster, Mutex &lock);
+  ClusterWatcher(RadosRef cluster, Mutex &lock,
+                 ServiceDaemon<librbd::ImageCtx>* service_daemon);
   ~ClusterWatcher() = default;
   ClusterWatcher(const ClusterWatcher&) = delete;
   ClusterWatcher& operator=(const ClusterWatcher&) = delete;
@@ -37,8 +42,10 @@ public:
   const PoolPeers& get_pool_peers() const;
 
 private:
-  Mutex &m_lock;
   RadosRef m_cluster;
+  Mutex &m_lock;
+  ServiceDaemon<librbd::ImageCtx>* m_service_daemon;
+
   PoolPeers m_pool_peers;
 
   void read_pool_peers(PoolPeers *pool_peers, PoolNames *pool_names);
index a0047d353c4dd38d07b6fda7a21885ac5318025f..611b0c20948b026c48de62c42314704445127b3c 100644 (file)
@@ -137,9 +137,10 @@ private:
 
 template <typename I>
 ImageDeleter<I>::ImageDeleter(ContextWQ *work_queue, SafeTimer *timer,
-                              Mutex *timer_lock)
-  : m_running(true),
-    m_work_queue(work_queue),
+                              Mutex *timer_lock,
+                              ServiceDaemon<librbd::ImageCtx>* service_daemon)
+  : m_work_queue(work_queue),
+    m_service_daemon(service_daemon),
     m_delete_lock("rbd::mirror::ImageDeleter::Delete"),
     m_image_deleter_thread(this),
     m_failed_timer(timer),
index e55337680f090cee3b68bfe1b5d1b0aae281f8b6..039c7a11c03a49c483d3fd4f2cfcfc8bb65d49c5 100644 (file)
@@ -32,6 +32,8 @@ namespace librbd { struct ImageCtx; }
 namespace rbd {
 namespace mirror {
 
+template <typename> class ServiceDaemon;
+
 /**
  * Manage deletion of non-primary images.
  */
@@ -40,7 +42,8 @@ class ImageDeleter {
 public:
   static const int EISPRM = 1000;
 
-  ImageDeleter(ContextWQ *work_queue, SafeTimer *timer, Mutex *timer_lock);
+  ImageDeleter(ContextWQ *work_queue, SafeTimer *timer, Mutex *timer_lock,
+               ServiceDaemon<librbd::ImageCtx>* service_daemon);
   ~ImageDeleter();
   ImageDeleter(const ImageDeleter&) = delete;
   ImageDeleter& operator=(const ImageDeleter&) = delete;
@@ -100,9 +103,10 @@ private:
                       bool print_failure_info=false);
   };
 
-  std::atomic<unsigned> m_running { 0 };
+  std::atomic<unsigned> m_running { 1 };
 
   ContextWQ *m_work_queue;
+  ServiceDaemon<librbd::ImageCtx>* m_service_daemon;
 
   std::deque<std::unique_ptr<DeleteInfo> > m_delete_queue;
   Mutex m_delete_lock;
index 74efb295759eeeb6eb0b68e7b4b26d939660519c..5dbddc16f6c606cb3ee860f5e4888889f48572d0 100644 (file)
@@ -24,12 +24,12 @@ using librbd::util::create_context_callback;
 
 template <typename I>
 InstanceReplayer<I>::InstanceReplayer(
-    Threads<I> *threads, ImageDeleter<I>* image_deleter,
-    RadosRef local_rados, const std::string &local_mirror_uuid,
-    int64_t local_pool_id)
-  : m_threads(threads), m_image_deleter(image_deleter),
-    m_local_rados(local_rados), m_local_mirror_uuid(local_mirror_uuid),
-    m_local_pool_id(local_pool_id),
+    Threads<I> *threads, ServiceDaemon<I>* service_daemon,
+    ImageDeleter<I>* image_deleter, RadosRef local_rados,
+    const std::string &local_mirror_uuid, int64_t local_pool_id)
+  : m_threads(threads), m_service_daemon(service_daemon),
+    m_image_deleter(image_deleter), m_local_rados(local_rados),
+    m_local_mirror_uuid(local_mirror_uuid), m_local_pool_id(local_pool_id),
     m_lock("rbd::mirror::InstanceReplayer " + stringify(local_pool_id)) {
 }
 
index b704f1785cf13775df181524b25171aa7e389d70..ecd7d11f4a7cf15249a1d5cde4b686d001abb08d 100644 (file)
@@ -20,6 +20,7 @@ namespace mirror {
 template <typename> class ImageDeleter;
 template <typename> class ImageReplayer;
 template <typename> class InstanceWatcher;
+template <typename> class ServiceDaemon;
 template <typename> struct Threads;
 
 template <typename ImageCtxT = librbd::ImageCtx>
@@ -27,17 +28,19 @@ class InstanceReplayer {
 public:
   static InstanceReplayer* create(
       Threads<ImageCtxT> *threads,
+      ServiceDaemon<ImageCtxT>* service_daemon,
       ImageDeleter<ImageCtxT>* image_deleter,
       RadosRef local_rados, const std::string &local_mirror_uuid,
       int64_t local_pool_id) {
-    return new InstanceReplayer(threads, image_deleter, local_rados,
-                                local_mirror_uuid, local_pool_id);
+    return new InstanceReplayer(threads, service_daemon, image_deleter,
+                                local_rados, local_mirror_uuid, local_pool_id);
   }
   void destroy() {
     delete this;
   }
 
   InstanceReplayer(Threads<ImageCtxT> *threads,
+                   ServiceDaemon<ImageCtxT>* service_daemon,
                   ImageDeleter<ImageCtxT>* image_deleter,
                   RadosRef local_rados, const std::string &local_mirror_uuid,
                   int64_t local_pool_id);
@@ -109,6 +112,7 @@ private:
   typedef std::set<Peer> Peers;
 
   Threads<ImageCtxT> *m_threads;
+  ServiceDaemon<ImageCtxT>* m_service_daemon;
   ImageDeleter<ImageCtxT>* m_image_deleter;
   RadosRef m_local_rados;
   std::string m_local_mirror_uuid;
index 4697d37b67357623d302e86b6f9831d92a7a9831..20036be055c1a66cf6ea1b6bd9feb28fd6e56179 100644 (file)
@@ -202,6 +202,7 @@ Mirror::Mirror(CephContext *cct, const std::vector<const char*> &args) :
   m_args(args),
   m_lock("rbd::mirror::Mirror"),
   m_local(new librados::Rados()),
+  m_service_daemon(m_cct, m_local),
   m_asok_hook(new MirrorAdminSocketHook(cct, this))
 {
   cct->lookup_or_create_singleton_object<Threads<librbd::ImageCtx> >(
@@ -236,12 +237,19 @@ int Mirror::init()
     return r;
   }
 
-  m_local_cluster_watcher.reset(new ClusterWatcher(m_local, m_lock));
+  r = m_service_daemon.init();
+  if (r < 0) {
+    derr << "error registering service daemon: " << cpp_strerror(r) << dendl;
+    return r;
+  }
+
+  m_local_cluster_watcher.reset(new ClusterWatcher(m_local, m_lock,
+                                                   &m_service_daemon));
 
   m_image_deleter.reset(new ImageDeleter<>(m_threads->work_queue,
                                            m_threads->timer,
-                                           &m_threads->timer_lock));
-
+                                           &m_threads->timer_lock,
+                                           &m_service_daemon));
   return r;
 }
 
@@ -399,7 +407,8 @@ void Mirror::update_pool_replayers(const PoolPeers &pool_peers)
       if (m_pool_replayers.find(pool_peer) == m_pool_replayers.end()) {
         dout(20) << "starting pool replayer for " << peer << dendl;
         unique_ptr<PoolReplayer> pool_replayer(new PoolReplayer(
-         m_threads, m_image_deleter.get(), kv.first, peer, m_args));
+         m_threads, &m_service_daemon, m_image_deleter.get(), kv.first,
+          peer, m_args));
 
         // TODO: make async, and retry connecting within pool replayer
         int r = pool_replayer->init();
index 17d712f37d9f2de7aab505ab1210c73527c0f131..8558f82c821cc92473ee3c3ce88adea519a67c10 100644 (file)
@@ -11,6 +11,7 @@
 #include "PoolReplayer.h"
 #include "ImageDeleter.h"
 #include "types.h"
+#include "ServiceDaemon.h"
 
 #include <set>
 #include <map>
@@ -61,6 +62,7 @@ private:
   Mutex m_lock;
   Cond m_cond;
   RadosRef m_local;
+  ServiceDaemon<librbd::ImageCtx> m_service_daemon;
 
   // monitor local cluster for config changes in peers
   std::unique_ptr<ClusterWatcher> m_local_cluster_watcher;
index f63828eadce73b8e7012c2c8c17559b527f99631..ede06fae76bbea61ebb90bf4f2b665e0b7ab5571 100644 (file)
@@ -206,10 +206,12 @@ private:
 } // anonymous namespace
 
 PoolReplayer::PoolReplayer(Threads<librbd::ImageCtx> *threads,
+                           ServiceDaemon<librbd::ImageCtx>* service_daemon,
                           ImageDeleter<>* image_deleter,
                           int64_t local_pool_id, const peer_t &peer,
                           const std::vector<const char*> &args) :
   m_threads(threads),
+  m_service_daemon(service_daemon),
   m_image_deleter(image_deleter),
   m_lock(stringify("rbd::mirror::PoolReplayer ") + stringify(peer)),
   m_peer(peer),
@@ -303,9 +305,9 @@ int PoolReplayer::init()
 
   dout(20) << "connected to " << m_peer << dendl;
 
-  m_instance_replayer.reset(
-    InstanceReplayer<>::create(m_threads, m_image_deleter, m_local_rados,
-                               local_mirror_uuid, m_local_pool_id));
+  m_instance_replayer.reset(InstanceReplayer<>::create(
+    m_threads, m_service_daemon, m_image_deleter, m_local_rados,
+    local_mirror_uuid, m_local_pool_id));
   m_instance_replayer->init();
   m_instance_replayer->add_peer(m_peer.uuid, m_remote_io_ctx);
 
index 1c4170a0a0b7aaac885b54cb9762b74e5752bceb..d23b0d66a7443ef5d1c32fe609fca1b4542b5917 100644 (file)
@@ -29,9 +29,10 @@ namespace librbd { class ImageCtx; }
 namespace rbd {
 namespace mirror {
 
-template <typename> struct Threads;
 template <typename> class InstanceReplayer;
 template <typename> class InstanceWatcher;
+template <typename> class ServiceDaemon;
+template <typename> struct Threads;
 
 /**
  * Controls mirroring for a single remote cluster.
@@ -39,6 +40,7 @@ template <typename> class InstanceWatcher;
 class PoolReplayer {
 public:
   PoolReplayer(Threads<librbd::ImageCtx> *threads,
+               ServiceDaemon<librbd::ImageCtx>* service_daemon,
               ImageDeleter<>* image_deleter,
               int64_t local_pool_id, const peer_t &peer,
               const std::vector<const char*> &args);
@@ -102,6 +104,7 @@ private:
   void handle_update_leader(const std::string &leader_instance_id);
 
   Threads<librbd::ImageCtx> *m_threads;
+  ServiceDaemon<librbd::ImageCtx>* m_service_daemon;
   ImageDeleter<>* m_image_deleter;
   mutable Mutex m_lock;
   Cond m_cond;
diff --git a/src/tools/rbd_mirror/ServiceDaemon.cc b/src/tools/rbd_mirror/ServiceDaemon.cc
new file mode 100644 (file)
index 0000000..2d0ecae
--- /dev/null
@@ -0,0 +1,47 @@
+
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "tools/rbd_mirror/ServiceDaemon.h"
+#include "include/stringify.h"
+#include "common/ceph_context.h"
+#include "common/config.h"
+
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_rbd_mirror
+#undef dout_prefix
+#define dout_prefix *_dout << "rbd::mirror::ServiceDaemon: " << this << " " \
+                           << __func__ << ": "
+
+namespace rbd {
+namespace mirror {
+
+namespace {
+
+const std::string RBD_MIRROR_AUTH_ID_PREFIX("rbd-mirror.");
+
+} // anonymous namespace
+
+template <typename I>
+int ServiceDaemon<I>::init() {
+  std::string name = m_cct->_conf->name.get_id();
+  if (name.find(RBD_MIRROR_AUTH_ID_PREFIX) == 0) {
+    name = name.substr(RBD_MIRROR_AUTH_ID_PREFIX.size());
+  }
+
+  std::map<std::string, std::string> service_metadata = {
+      {"instance_id", stringify(m_rados->get_instance_id())}
+    };
+  int r = m_rados->service_daemon_register("rbd-mirror", name,
+                                           service_metadata);
+  if (r < 0) {
+    return r;
+  }
+
+  return 0;
+}
+
+} // namespace mirror
+} // namespace rbd
+
+template class rbd::mirror::ServiceDaemon<librbd::ImageCtx>;
diff --git a/src/tools/rbd_mirror/ServiceDaemon.h b/src/tools/rbd_mirror/ServiceDaemon.h
new file mode 100644 (file)
index 0000000..73c3b9b
--- /dev/null
@@ -0,0 +1,37 @@
+
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_RBD_MIRROR_SERVICE_DAEMON_H
+#define CEPH_RBD_MIRROR_SERVICE_DAEMON_H
+
+#include "tools/rbd_mirror/types.h"
+#include <string>
+
+struct CephContext;
+namespace librbd { struct ImageCtx; }
+
+namespace rbd {
+namespace mirror {
+
+template <typename ImageCtxT = librbd::ImageCtx>
+class ServiceDaemon {
+public:
+  ServiceDaemon(CephContext *cct, RadosRef rados)
+    : m_cct(cct), m_rados(rados) {
+  }
+
+  int init();
+
+private:
+  CephContext *m_cct;
+  RadosRef m_rados;
+
+};
+
+} // namespace mirror
+} // namespace rbd
+
+extern template class rbd::mirror::ServiceDaemon<librbd::ImageCtx>;
+
+#endif // CEPH_RBD_MIRROR_SERVICE_DAEMON_H