From: Sage Weil Date: Mon, 22 Oct 2018 19:38:48 +0000 (-0500) Subject: os/bluestore: fix race between SharedBlobSet::lookup and SharedBlob::put X-Git-Tag: v13.2.3~71^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=e76cea690a6f67a09f8b8174d81723b06903657b;p=ceph.git os/bluestore: fix race between SharedBlobSet::lookup and SharedBlob::put 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 (cherry picked from commit 020bd7b5f38a82d9eef5e25e6f4a4dd12b066915) Conflicts: src/os/bluestore/BlueStore.h --- diff --git a/src/os/bluestore/BlueStore.cc b/src/os/bluestore/BlueStore.cc index 0c4fbc0bf9ea..e3b4105e2c23 100644 --- a/src/os/bluestore/BlueStore.cc +++ b/src/os/bluestore/BlueStore.cc @@ -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(); } diff --git a/src/os/bluestore/BlueStore.h b/src/os/bluestore/BlueStore.h index 01e436cdcf44..216c914e35c7 100644 --- a/src/os/bluestore/BlueStore.h +++ b/src/os/bluestore/BlueStore.h @@ -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 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() {