From aa381ab5065541fec032b9657e381defa87a16e3 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Fri, 11 Sep 2020 15:20:45 -0400 Subject: [PATCH] librbd: ensure that thread pool lock is held when processing throttled IOs There previously was a potential race for throttled IOs to complete prior to the main worker thread finishing the processing of the blocked IO. Fixes: https://tracker.ceph.com/issues/47371 Signed-off-by: Jason Dillaman (cherry picked from commit 2d86e0935aa6f0c392df428676d9ab0a338fccae) Conflicts: src/test/librbd/io/test_mock_ImageRequestWQ.cc - in Octopus, commit 792d6c53fedc695199cc18916347c1b545fe42c2 did a global replace of Mutex to ceph::mutex, so to fix this for Nautilus, we just need to do that in test_mock_ImageRequestWQ.cc since the get_pool_lock() method is returning a Mutex instead of a ceph::mutex --- src/librbd/io/ImageRequestWQ.cc | 10 +++++---- .../librbd/io/test_mock_ImageRequestWQ.cc | 22 ++++++++++++------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/librbd/io/ImageRequestWQ.cc b/src/librbd/io/ImageRequestWQ.cc index b9c508f649d8a..7bdaf2f25a425 100644 --- a/src/librbd/io/ImageRequestWQ.cc +++ b/src/librbd/io/ImageRequestWQ.cc @@ -730,21 +730,23 @@ void ImageRequestWQ::apply_qos_limit(const uint64_t flag, } template -void ImageRequestWQ::handle_throttle_ready(int r, ImageDispatchSpec *item, uint64_t flag) { +void ImageRequestWQ::handle_throttle_ready(int r, ImageDispatchSpec *item, + uint64_t flag) { CephContext *cct = m_image_ctx.cct; ldout(cct, 15) << "r=" << r << ", " << "req=" << item << dendl; + std::lock_guard pool_locker{this->get_pool_lock()}; ceph_assert(m_io_throttled.load() > 0); item->set_throttled(flag); if (item->were_all_throttled()) { - this->requeue_back(item); + this->requeue_back(pool_locker, item); --m_io_throttled; - this->signal(); + this->signal(pool_locker); } } template -bool ImageRequestWQ::needs_throttle(ImageDispatchSpec *item) { +bool ImageRequestWQ::needs_throttle(ImageDispatchSpec *item) { uint64_t tokens = 0; uint64_t flag = 0; bool blocked = false; diff --git a/src/test/librbd/io/test_mock_ImageRequestWQ.cc b/src/test/librbd/io/test_mock_ImageRequestWQ.cc index 50daa83c777bc..7b91d68fbaddf 100644 --- a/src/test/librbd/io/test_mock_ImageRequestWQ.cc +++ b/src/test/librbd/io/test_mock_ImageRequestWQ.cc @@ -88,10 +88,10 @@ struct ThreadPool::PointerWQ ImageDispatchSpec; static PointerWQ* s_instance; - Mutex m_lock; + ceph::mutex m_lock; PointerWQ(const std::string &name, time_t, int, ThreadPool *) - : m_lock(name) { + : m_lock(ceph::make_mutex(name)) { s_instance = this; } virtual ~PointerWQ() { @@ -101,11 +101,13 @@ struct ThreadPool::PointerWQ&)); MOCK_METHOD0(process_finish, void()); MOCK_METHOD0(front, ImageDispatchSpec*()); MOCK_METHOD1(requeue_front, void(ImageDispatchSpec*)); - MOCK_METHOD1(requeue_back, void(ImageDispatchSpec*)); + MOCK_METHOD2(requeue_back, void(const std::lock_guard&, + ImageDispatchSpec*)); MOCK_METHOD0(dequeue, void*()); MOCK_METHOD1(queue, void(ImageDispatchSpec*)); @@ -113,12 +115,12 @@ struct ThreadPool::PointerWQ