]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: prevent race condition between resize requests 5769/head
authorJason Dillaman <dillaman@redhat.com>
Tue, 11 Aug 2015 13:26:33 +0000 (09:26 -0400)
committerLoic Dachary <ldachary@redhat.com>
Sun, 6 Sep 2015 12:09:34 +0000 (14:09 +0200)
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>
(cherry picked from commit 6ec431bac1cf9446f3af90209d193dfcf003f2c5)

src/librbd/AsyncResizeRequest.cc

index 7a4f65b43738801c666f201381b4003a2c1139e3..8ddf96726a9171fed3dd15cd91f795b43d8e6020 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();
     }
   }
 
@@ -125,14 +119,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;