]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: update AioCompletion return value before evaluating pending count 37645/head
authorJason Dillaman <dillaman@redhat.com>
Tue, 13 Oct 2020 01:34:25 +0000 (21:34 -0400)
committerJason Dillaman <dillaman@redhat.com>
Tue, 13 Oct 2020 12:34:07 +0000 (08:34 -0400)
If the pending count is decremented before the return value is updated,
there is a possibility of two ASIO threads concurrently decrementing the
pending count down from 2 -> 1 -> 0. In the second thread (the one that
performs the final decrement from 1 -> 0), it can finalize the completion
before the first thread has had a chance to update the return value.

Fixes: https://tracker.ceph.com/issues/47847
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/io/AioCompletion.cc

index 96cc0f9f7719478b77ef1da61b385a20bf96fde9..c04b80770f9998e9f9fac47941c25595d08028b1 100644 (file)
@@ -213,22 +213,22 @@ void AioCompletion::set_request_count(uint32_t count) {
 
 void AioCompletion::complete_request(ssize_t r)
 {
-  uint32_t previous_pending_count = pending_count--;
-  ceph_assert(previous_pending_count > 0);
-  auto pending_count = previous_pending_count - 1;
-
   ceph_assert(ictx != nullptr);
   CephContext *cct = ictx->cct;
 
   if (r > 0) {
     rval += r;
-  } else if (r != -EEXIST) {
+  } else if (r < 0 && r != -EEXIST) {
     // might race w/ another thread setting an error code but
     // first one wins
     int zero = 0;
     error_rval.compare_exchange_strong(zero, r);
   }
 
+  uint32_t previous_pending_count = pending_count--;
+  ceph_assert(previous_pending_count > 0);
+  auto pending_count = previous_pending_count - 1;
+
   ldout(cct, 20) << "cb=" << complete_cb << ", "
                  << "pending=" << pending_count << dendl;
   if (pending_count == 0) {