]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: prevent race condition between resize requests 5544/head
authorJason Dillaman <dillaman@redhat.com>
Tue, 11 Aug 2015 13:26:33 +0000 (09:26 -0400)
committerJason Dillaman <dillaman@redhat.com>
Tue, 11 Aug 2015 13:26:33 +0000 (09:26 -0400)
It was possible that the same resize request could be sent twice
if a completed resize op started a newly created resize op while
it was also being concurrently started by another thread.

Fixes: #12664
Backport: hammer
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/AsyncResizeRequest.cc

index bbd697f7cffe89ab2fbea2c072a365be2623b337..732e3f734f2a9db5e96f2940edb0bc16324d8d51 100644 (file)
@@ -24,21 +24,15 @@ AsyncResizeRequest::AsyncResizeRequest(ImageCtx &image_ctx, Context *on_finish,
     m_prog_ctx(prog_ctx), m_new_parent_overlap(0),
     m_xlist_item(this)
 {
-  RWLock::WLocker l(m_image_ctx.snap_lock);
-  m_image_ctx.async_resize_reqs.push_back(&m_xlist_item);
-  m_original_size = m_image_ctx.size;
-  compute_parent_overlap();
 }
 
 AsyncResizeRequest::~AsyncResizeRequest() {
   AsyncResizeRequest *next_req = NULL;
   {
-    RWLock::WLocker l(m_image_ctx.snap_lock);
+    RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
     assert(m_xlist_item.remove_myself());
     if (!m_image_ctx.async_resize_reqs.empty()) {
       next_req = m_image_ctx.async_resize_reqs.front();
-      next_req->m_original_size = m_image_ctx.size;
-      next_req->compute_parent_overlap();
     }
   }
 
@@ -123,14 +117,19 @@ bool AsyncResizeRequest::should_complete(int r) {
 
 void AsyncResizeRequest::send() {
   assert(m_image_ctx.owner_lock.is_locked());
-  {
-    RWLock::RLocker l(m_image_ctx.snap_lock);
-    assert(!m_image_ctx.async_resize_reqs.empty());
 
-    // only allow a single concurrent resize request
-    if (m_image_ctx.async_resize_reqs.front() != this) {
-      return;
+  {
+    RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
+    if (!m_xlist_item.is_on_list()) {
+      m_image_ctx.async_resize_reqs.push_back(&m_xlist_item);
+      if (m_image_ctx.async_resize_reqs.front() != this) {
+        return;
+      }
     }
+
+    assert(m_image_ctx.async_resize_reqs.front() == this);
+    m_original_size = m_image_ctx.size;
+    compute_parent_overlap();
   }
 
   CephContext *cct = m_image_ctx.cct;