notify(UNQUIESCE, on_finish);
}
- void quiesce_complete(int r) {
+ void quiesce_complete(uint64_t handle, int r) {
Context *on_notify = nullptr;
{
std::lock_guard locker{m_lock};
ceph_assert(m_on_notify != nullptr);
ceph_assert(m_handle_quiesce_cnt > 0);
- ceph_assert(m_blocked);
m_handle_quiesce_cnt--;
- if (m_handle_quiesce_cnt > 0) {
- // TOFO: r should be saved
- return;
+ if (r < 0) {
+ ldout(m_cct, 10) << "QuiesceWatchers::" << __func__ << ": watcher "
+ << handle << " failed" << dendl;
+ m_failed_watchers.insert(handle);
+ m_ret_val = r;
}
- if (r < 0) {
- // TODO: fix for multiple watchers case
- m_blocked = false;
+ if (m_handle_quiesce_cnt > 0) {
+ return;
}
std::swap(on_notify, m_on_notify);
+ r = m_ret_val;
}
on_notify->complete(r);
std::list<Context *> m_pending_notify;
std::map<uint64_t, Context*> m_pending_unregister;
uint64_t m_handle_quiesce_cnt = 0;
+ std::set<uint64_t> m_failed_watchers;
bool m_blocked = false;
+ int m_ret_val = 0;
void notify(EventType event_type, Context *on_finish) {
ceph_assert(ceph_mutex_is_locked(m_lock));
Context *ctx = nullptr;
if (event_type == QUIESCE) {
ceph_assert(!m_blocked);
+ ceph_assert(m_handle_quiesce_cnt == 0);
+
m_blocked = true;
+ m_handle_quiesce_cnt = m_watchers.size();
+ m_failed_watchers.clear();
+ m_ret_val = 0;
} else {
ceph_assert(event_type == UNQUIESCE);
ceph_assert(m_blocked);
auto gather_ctx = new C_Gather(m_cct, ctx);
ceph_assert(m_on_notify == nullptr);
- ceph_assert(m_handle_quiesce_cnt == 0);
m_on_notify = on_finish;
- for (auto it : m_watchers) {
- send_notify(it.first, it.second, event_type, gather_ctx->new_sub());
+ for (auto &[handle, watcher] : m_watchers) {
+ send_notify(handle, watcher, event_type, gather_ctx->new_sub());
}
gather_ctx->activate();
<< handle << ", event_type=" << event_type << dendl;
switch (event_type) {
case QUIESCE:
- m_handle_quiesce_cnt++;
watcher->handle_quiesce();
break;
case UNQUIESCE:
+ {
+ std::lock_guard locker{m_lock};
+
+ if (m_failed_watchers.count(handle)) {
+ ldout(m_cct, 20) << "QuiesceWatchers::" << __func__
+ << ": skip for failed watcher" << dendl;
+ break;
+ }
+ }
watcher->handle_unquiesce();
break;
default:
}
template <typename I>
-void ImageState<I>::quiesce_complete(int r) {
+void ImageState<I>::quiesce_complete(uint64_t handle, int r) {
CephContext *cct = m_image_ctx->cct;
- ldout(cct, 20) << __func__ << ": r=" << r << dendl;
- m_quiesce_watchers->quiesce_complete(r);
+ ldout(cct, 20) << __func__ << ": handle=" << handle << " r=" << r << dendl;
+ m_quiesce_watchers->quiesce_complete(handle, r);
}
} // namespace librbd
uint64_t size = 2 << 20;
ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
- uint64_t handle1, handle2;
rbd_image_t image1, image2;
ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
}
rbd_image_t ℑ
+ uint64_t handle = 0;
size_t quiesce_count = 0;
size_t unquiesce_count = 0;
void handle_quiesce() {
ASSERT_EQ(quiesce_count, unquiesce_count);
quiesce_count++;
- rbd_quiesce_complete(image, 0);
+ rbd_quiesce_complete(image, handle, 0);
}
void handle_unquiesce() {
std::unique_lock locker(lock);
} watcher1(image1), watcher2(image2);
ASSERT_EQ(0, rbd_quiesce_watch(image1, Watcher::quiesce_cb,
- Watcher::unquiesce_cb, &watcher1, &handle1));
+ Watcher::unquiesce_cb, &watcher1,
+ &watcher1.handle));
ASSERT_EQ(0, rbd_quiesce_watch(image2, Watcher::quiesce_cb,
- Watcher::unquiesce_cb, &watcher2, &handle2));
+ Watcher::unquiesce_cb, &watcher2,
+ &watcher2.handle));
ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
ASSERT_EQ(1U, watcher1.quiesce_count);
ASSERT_EQ(2U, watcher2.quiesce_count);
ASSERT_TRUE(watcher2.wait_for_unquiesce(2U));
- ASSERT_EQ(0, rbd_quiesce_unwatch(image1, handle1));
+ ASSERT_EQ(0, rbd_quiesce_unwatch(image1, watcher1.handle));
ASSERT_EQ(0, rbd_snap_create(image1, "snap3"));
ASSERT_EQ(2U, watcher1.quiesce_count);
ASSERT_EQ(3U, watcher2.quiesce_count);
ASSERT_TRUE(watcher2.wait_for_unquiesce(3U));
- ASSERT_EQ(0, rbd_quiesce_unwatch(image2, handle2));
+ ASSERT_EQ(0, rbd_quiesce_unwatch(image2, watcher2.handle));
ASSERT_EQ(0, rbd_snap_remove(image1, "snap1"));
ASSERT_EQ(0, rbd_snap_remove(image1, "snap2"));
struct Watcher : public librbd::QuiesceWatchCtx {
librbd::Image ℑ
+ uint64_t handle = 0;
size_t quiesce_count = 0;
size_t unquiesce_count = 0;
void handle_quiesce() override {
ASSERT_EQ(quiesce_count, unquiesce_count);
quiesce_count++;
- image.quiesce_complete(0);
+ image.quiesce_complete(handle, 0);
}
void handle_unquiesce() override {
std::unique_lock locker(lock);
[this, c]() { return unquiesce_count >= c; });
}
} watcher1(image1), watcher2(image2);
- uint64_t handle1, handle2;
- ASSERT_EQ(0, image1.quiesce_watch(&watcher1, &handle1));
- ASSERT_EQ(0, image2.quiesce_watch(&watcher2, &handle2));
+ ASSERT_EQ(0, image1.quiesce_watch(&watcher1, &watcher1.handle));
+ ASSERT_EQ(0, image2.quiesce_watch(&watcher2, &watcher2.handle));
ASSERT_EQ(0, image1.snap_create("snap1"));
ASSERT_EQ(1U, watcher1.quiesce_count);
ASSERT_EQ(2U, watcher2.quiesce_count);
ASSERT_TRUE(watcher2.wait_for_unquiesce(2U));
- ASSERT_EQ(0, image1.quiesce_unwatch(handle1));
+ ASSERT_EQ(0, image1.quiesce_unwatch(watcher1.handle));
ASSERT_EQ(0, image1.snap_create("snap3"));
ASSERT_EQ(2U, watcher1.quiesce_count);
ASSERT_EQ(3U, watcher2.quiesce_count);
ASSERT_TRUE(watcher2.wait_for_unquiesce(3U));
- ASSERT_EQ(0, image2.quiesce_unwatch(handle2));
+ ASSERT_EQ(0, image2.quiesce_unwatch(watcher2.handle));
ASSERT_EQ(0, image1.snap_remove("snap1"));
ASSERT_EQ(0, image1.snap_remove("snap2"));
struct Watcher : public librbd::QuiesceWatchCtx {
librbd::Image ℑ
int r;
+ uint64_t handle;
size_t quiesce_count = 0;
size_t unquiesce_count = 0;
Watcher(librbd::Image &image, int r) : image(image), r(r) {
}
+ void reset_counters() {
+ quiesce_count = 0;
+ unquiesce_count = 0;
+ }
+
void handle_quiesce() override {
quiesce_count++;
- image.quiesce_complete(r);
+ image.quiesce_complete(handle, r);
}
void handle_unquiesce() override {
cv.notify_one();
}
- bool wait_for_unquiesce(size_t c) {
+ bool wait_for_unquiesce() {
std::unique_lock locker(lock);
return cv.wait_for(locker, seconds(60),
- [this, c]() { return unquiesce_count >= c; });
+ [this]() {
+ return quiesce_count == unquiesce_count;
+ });
}
- } watcher1(image1, -EINVAL), watcher2(image2, 0);
- uint64_t handle1, handle2;
+ } watcher10(image1, -EINVAL), watcher11(image1, 0), watcher20(image2, 0);
- ASSERT_EQ(0, image1.quiesce_watch(&watcher1, &handle1));
- ASSERT_EQ(0, image2.quiesce_watch(&watcher2, &handle2));
+ ASSERT_EQ(0, image1.quiesce_watch(&watcher10, &watcher10.handle));
+ ASSERT_EQ(0, image1.quiesce_watch(&watcher11, &watcher11.handle));
+ ASSERT_EQ(0, image2.quiesce_watch(&watcher20, &watcher20.handle));
ASSERT_EQ(-EINVAL, image1.snap_create("snap1"));
- ASSERT_LT(0U, watcher1.quiesce_count);
- ASSERT_EQ(0U, watcher1.unquiesce_count);
- ASSERT_EQ(1U, watcher2.quiesce_count);
- ASSERT_TRUE(watcher2.wait_for_unquiesce(1U));
+ ASSERT_GT(watcher10.quiesce_count, 0U);
+ ASSERT_EQ(watcher10.unquiesce_count, 0U);
+ ASSERT_GT(watcher11.quiesce_count, 0U);
+ ASSERT_TRUE(watcher11.wait_for_unquiesce());
+ ASSERT_GT(watcher20.quiesce_count, 0U);
+ ASSERT_TRUE(watcher20.wait_for_unquiesce());
PrintProgress prog_ctx;
- watcher1.quiesce_count = 0;
+ watcher10.reset_counters();
+ watcher11.reset_counters();
+ watcher20.reset_counters();
ASSERT_EQ(0, image2.snap_create2("snap2",
RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR,
prog_ctx));
- ASSERT_LT(0U, watcher1.quiesce_count);
- ASSERT_EQ(0U, watcher1.unquiesce_count);
- ASSERT_EQ(2U, watcher2.quiesce_count);
- ASSERT_TRUE(watcher2.wait_for_unquiesce(2U));
+ ASSERT_GT(watcher10.quiesce_count, 0U);
+ ASSERT_EQ(watcher10.unquiesce_count, 0U);
+ ASSERT_GT(watcher11.quiesce_count, 0U);
+ ASSERT_TRUE(watcher11.wait_for_unquiesce());
+ ASSERT_GT(watcher20.quiesce_count, 0U);
+ ASSERT_TRUE(watcher20.wait_for_unquiesce());
- ASSERT_EQ(0, image1.quiesce_unwatch(handle1));
+ ASSERT_EQ(0, image1.quiesce_unwatch(watcher10.handle));
+ watcher11.reset_counters();
+ watcher20.reset_counters();
ASSERT_EQ(0, image1.snap_create("snap3"));
- ASSERT_EQ(3U, watcher2.quiesce_count);
- ASSERT_TRUE(watcher2.wait_for_unquiesce(3U));
+ ASSERT_GT(watcher11.quiesce_count, 0U);
+ ASSERT_TRUE(watcher11.wait_for_unquiesce());
+ ASSERT_GT(watcher20.quiesce_count, 0U);
+ ASSERT_TRUE(watcher20.wait_for_unquiesce());
+
+ ASSERT_EQ(0, image1.quiesce_unwatch(watcher11.handle));
+ watcher20.reset_counters();
ASSERT_EQ(0, image2.snap_create2("snap4", RBD_SNAP_CREATE_SKIP_QUIESCE,
prog_ctx));
- ASSERT_EQ(3U, watcher2.quiesce_count);
- ASSERT_EQ(3U, watcher2.unquiesce_count);
+ ASSERT_EQ(watcher20.quiesce_count, 0U);
+ ASSERT_EQ(watcher20.unquiesce_count, 0U);
- ASSERT_EQ(0, image2.quiesce_unwatch(handle2));
+ ASSERT_EQ(0, image2.quiesce_unwatch(watcher20.handle));
ASSERT_EQ(0, image1.snap_remove("snap2"));
ASSERT_EQ(0, image1.snap_remove("snap3"));
std::cerr << "test quiesce is not long enough to time out" << std::endl;
- thread quiesce1([&image, &watcher]() {
+ thread quiesce1([&image, &watcher, handle]() {
watcher.wait_for_quiesce_count(1);
sleep(8);
- image.quiesce_complete(0);
+ image.quiesce_complete(handle, 0);
});
ASSERT_EQ(0, image.snap_create("snap1"));
std::cerr << "test quiesce is timed out" << std::endl;
bool timed_out = false;
- thread quiesce2([&image, &watcher, &timed_out]() {
+ thread quiesce2([&image, &watcher, handle, &timed_out]() {
watcher.wait_for_quiesce_count(2);
for (int i = 0; !timed_out && i < 60; i++) {
std::cerr << "waiting for timed out ... " << i << std::endl;
sleep(1);
}
- image.quiesce_complete(0);
+ image.quiesce_complete(handle, 0);
});
ASSERT_EQ(-ETIMEDOUT, image.snap_create("snap2"));
watcher.wait_for_unquiesce_count(2);
ASSERT_EQ(2U, watcher.unquiesce_count);
- thread quiesce3([&image, &watcher]() {
+ thread quiesce3([&image, handle, &watcher]() {
watcher.wait_for_quiesce_count(3);
- image.quiesce_complete(0);
+ image.quiesce_complete(handle, 0);
});
std::cerr << "test retry succeeds" << std::endl;