]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
os/bluestore: fix race between SharedBlobSet::lookup and SharedBlob::put 24745/head
authorSage Weil <sage@redhat.com>
Mon, 22 Oct 2018 19:38:48 +0000 (14:38 -0500)
committerNathan Cutler <ncutler@suse.com>
Wed, 24 Oct 2018 19:59:25 +0000 (21:59 +0200)
A                             B
SharedBlobSet::lookup()
  takes lock
  nref is not 0
                              SharedBlob::put()
                                --nref
returns SharedBlobRef,
  ++nref
                                takes cache lock
                                SharedBlobSet::remove
                                  takes lock
                                  removes
                                deletes SharedBlob

-> A ends up with a ref to deleted SharedBlob

Fix by verifying that nref is still zero in SharedBlobSet::remove(),
while we are holding the SharedBlobSet::lock.  The lock ensures that we
have increased the ref for the lookup before entering remove, so we can
verify that nref is still zero before removing it.  If not, we have
raced, and put() bails out and does nothing.

Fixes: http://tracker.ceph.com/issues/36526
Signed-off-by: Sage Weil <sage@redhat.com>
(cherry picked from commit 020bd7b5f38a82d9eef5e25e6f4a4dd12b066915)

Conflicts:
src/os/bluestore/BlueStore.h

src/os/bluestore/BlueStore.cc
src/os/bluestore/BlueStore.h

index 0c4fbc0bf9ea4c74f2a6d9e3e9f9a1881dcfd8d5..e3b4105e2c23e4b239560d4e9a9b7847a0f815af 100644 (file)
@@ -1677,8 +1677,10 @@ void BlueStore::SharedBlob::put()
       if (coll_snap != coll) {
        goto again;
       }
-      coll_snap->shared_blob_set.remove(this);
-
+      if (!coll_snap->shared_blob_set.remove(this, true)) {
+       // race with lookup
+       return;
+      }
       bc._clear(coll_snap->cache);
       coll_snap->cache->rm_blob();
     }
index 01e436cdcf446f091b78851b6041aa712b05ac14..216c914e35c73a51733e1bb2e1b56ba53b623ecb 100644 (file)
@@ -457,15 +457,19 @@ public:
       sb->coll = coll;
     }
 
-    void remove(SharedBlob *sb) {
+    bool remove(SharedBlob *sb, bool verify_nref_is_zero=false) {
       std::lock_guard<std::mutex> l(lock);
       ceph_assert(sb->get_parent() == this);
+      if (verify_nref_is_zero && sb->nref != 0) {
+       return false;
+      }
       // only remove if it still points to us
       auto p = sb_map.find(sb->get_sbid());
       if (p != sb_map.end() &&
          p->second == sb) {
        sb_map.erase(p);
       }
+      return true;
     }
 
     bool empty() {