One thread might try to drop a bnode while another does a lookup and
retakes a ref:
1- drop bnode ref (-> 0)
2- take bnode_set lock, do lookup
2- take bnode ref (-> 1)
2- drop lock
1- take bnode_set lock
1- remove from set
1- drop lock
Fix this race by rechecking the ref count while we are holding the lock.
Signed-off-by: Sage Weil <sage@redhat.com>
{
if (--nref == 0) {
dout(20) << __func__ << " removing self from set " << bnode_set << dendl;
- bnode_set->remove(this);
- delete this;
+ if (bnode_set->remove(this)) {
+ delete this;
+ } else {
+ dout(20) << __func__ << " lost race to remove myself from set" << dendl;
+ }
}
}
std::lock_guard<std::mutex> l(lock);
uset.insert(*b);
}
- void remove(Bnode *b) {
+ bool remove(Bnode *b) {
std::lock_guard<std::mutex> l(lock);
- uset.erase(*b);
+ if (b->nref == 0) {
+ uset.erase(*b);
+ return true;
+ }
+ return false;
}
};