]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: watcher should internally track blacklisted state
authorJason Dillaman <dillaman@redhat.com>
Thu, 6 Sep 2018 13:44:59 +0000 (09:44 -0400)
committerJason Dillaman <dillaman@redhat.com>
Wed, 19 Sep 2018 18:52:48 +0000 (14:52 -0400)
Since it will periodically attempt to re-acquire the watch,
it will know when the RADOS client has been blacklisted and
when the blacklist has been removed.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/Watcher.cc
src/librbd/Watcher.h
src/test/librbd/mock/MockImageWatcher.h
src/test/librbd/test_mock_Watcher.cc

index 8e18460757be080ea2fbfe08ce56a0bfc0f960b3..c02598983e705174627f153710a8a5ef441a2279 100644 (file)
@@ -104,9 +104,10 @@ Watcher::~Watcher() {
 void Watcher::register_watch(Context *on_finish) {
   ldout(m_cct, 10) << dendl;
 
-  RWLock::RLocker watch_locker(m_watch_lock);
+  RWLock::WLocker watch_locker(m_watch_lock);
   ceph_assert(is_unregistered(m_watch_lock));
   m_watch_state = WATCH_STATE_REGISTERING;
+  m_watch_blacklisted = false;
 
   librados::AioCompletion *aio_comp = create_rados_callback(
     new C_RegisterWatch(this, on_finish));
@@ -137,6 +138,8 @@ void Watcher::handle_register_watch(int r, Context *on_finish) {
       lderr(m_cct) << "re-registering watch after error" << dendl;
       m_watch_state = WATCH_STATE_REWATCHING;
       watch_error = true;
+    } else {
+      m_watch_blacklisted = (r == -EBLACKLISTED);
     }
   }
 
@@ -165,11 +168,13 @@ void Watcher::unregister_watch(Context *on_finish) {
       return;
     } else if (is_registered(m_watch_lock)) {
       librados::AioCompletion *aio_comp = create_rados_callback(
-                        new C_UnwatchAndFlush(m_ioctx, on_finish));
+        new C_UnwatchAndFlush(m_ioctx, on_finish));
       int r = m_ioctx.aio_unwatch(m_watch_handle, aio_comp);
       ceph_assert(r == 0);
       aio_comp->release();
+
       m_watch_handle = 0;
+      m_watch_blacklisted = false;
       return;
     }
   }
@@ -225,6 +230,9 @@ void Watcher::handle_error(uint64_t handle, int err) {
 
   if (is_registered(m_watch_lock)) {
     m_watch_state = WATCH_STATE_REWATCHING;
+    if (err == -EBLACKLISTED) {
+      m_watch_blacklisted = true;
+    }
 
     FunctionContext *ctx = new FunctionContext(
         boost::bind(&Watcher::rewatch, this));
@@ -271,12 +279,14 @@ void Watcher::handle_rewatch(int r) {
     RWLock::WLocker watch_locker(m_watch_lock);
     ceph_assert(m_watch_state == WATCH_STATE_REWATCHING);
 
+    m_watch_blacklisted = false;
     if (m_unregister_watch_ctx != nullptr) {
       ldout(m_cct, 10) << "image is closing, skip rewatch" << dendl;
       m_watch_state = WATCH_STATE_IDLE;
       std::swap(unregister_watch_ctx, m_unregister_watch_ctx);
     } else if (r  == -EBLACKLISTED) {
       lderr(m_cct) << "client blacklisted" << dendl;
+      m_watch_blacklisted = true;
     } else if (r == -ENOENT) {
       ldout(m_cct, 5) << "object does not exist" << dendl;
     } else if (r < 0) {
index 518fbdd015e555ea6804e84331eca1c8c1a3bd1a..69e87ad30ce99cc5a26f39c7ed126f7827f141a5 100644 (file)
@@ -60,6 +60,10 @@ public:
     RWLock::RLocker locker(m_watch_lock);
     return is_unregistered(m_watch_lock);
   }
+  bool is_blacklisted() const {
+    RWLock::RLocker locker(m_watch_lock);
+    return m_watch_blacklisted;
+  }
 
 protected:
   enum WatchState {
@@ -75,7 +79,10 @@ protected:
   mutable RWLock m_watch_lock;
   uint64_t m_watch_handle;
   watcher::Notifier m_notifier;
+
   WatchState m_watch_state;
+  bool m_watch_blacklisted = false;
+
   AsyncOpTracker m_async_op_tracker;
 
   bool is_registered(const RWLock&) const {
index db3fafe3558234cf86a2eb33bab5634bc728939f..c7e9427923738a0d97ba0667861a24b84a834ece 100644 (file)
@@ -13,6 +13,7 @@ namespace librbd {
 struct MockImageWatcher {
   MOCK_METHOD0(is_registered, bool());
   MOCK_METHOD0(is_unregistered, bool());
+  MOCK_METHOD0(is_blacklisted, bool());
   MOCK_METHOD0(unregister_watch, void());
   MOCK_METHOD1(flush, void(Context *));
 
index 14171856c5f1b2f9c8a474241d0ba6fef7ea0983..907f671e8771bf329e45c6a4d87abc8e913b1baf 100644 (file)
@@ -124,6 +124,7 @@ public:
         return false;
       }
     }
+    m_watch_count -= count;
     return true;
   }
 
@@ -291,22 +292,34 @@ TEST_F(TestMockWatcher, ReregisterWatchBlacklist) {
   expect_aio_watch(mock_image_ctx, 0);
   expect_aio_unwatch(mock_image_ctx, 0);
   expect_aio_watch(mock_image_ctx, -EBLACKLISTED);
-  expect_aio_watch(mock_image_ctx, 0);
+
+  C_SaferCond blacklist_ctx;
+  expect_aio_watch(mock_image_ctx, 0, [&blacklist_ctx]() {
+      blacklist_ctx.wait();
+    });
   expect_aio_unwatch(mock_image_ctx, 0);
 
   C_SaferCond register_ctx;
   mock_image_watcher.register_watch(&register_ctx);
+  ASSERT_TRUE(wait_for_watch(mock_image_ctx, 1));
   ASSERT_EQ(0, register_ctx.wait());
 
   ceph_assert(m_watch_ctx != nullptr);
   m_watch_ctx->handle_error(0, -EBLACKLISTED);
 
   // wait for recovery unwatch/watch
-  ASSERT_TRUE(wait_for_watch(mock_image_ctx, 4));
+  ASSERT_TRUE(wait_for_watch(mock_image_ctx, 2));
+
+  ASSERT_TRUE(mock_image_watcher.is_blacklisted());
+  blacklist_ctx.complete(0);
+
+  // wait for post-blacklist recovery watch
+  ASSERT_TRUE(wait_for_watch(mock_image_ctx, 1));
 
   C_SaferCond unregister_ctx;
   mock_image_watcher.unregister_watch(&unregister_ctx);
   ASSERT_EQ(0, unregister_ctx.wait());
+  ASSERT_FALSE(mock_image_watcher.is_blacklisted());
 }
 
 TEST_F(TestMockWatcher, ReregisterUnwatchPendingUnregister) {