svn commit: r368461 - head/sys/kern
Kyle Evans
kevans at FreeBSD.org
Tue Dec 8 18:45:53 UTC 2020
Author: kevans
Date: Tue Dec 8 18:45:47 2020
New Revision: 368461
URL: https://svnweb.freebsd.org/changeset/base/368461
Log:
kern: cpuset: resolve race between cpuset_lookup/cpuset_rel
The race plays out like so between threads A and B:
1. A ref's cpuset 10
2. B does a lookup of cpuset 10, grabs the cpuset lock and searches
cpuset_ids
3. A rel's cpuset 10 and observes the last ref, waits on the cpuset lock
while B is still searching and not yet ref'd
4. B ref's cpuset 10 and drops the cpuset lock
5. A proceeds to free the cpuset out from underneath B
Resolve the race by only releasing the last reference under the cpuset lock.
Thread A now picks up the spinlock and observes that the cpuset has been
revived, returning immediately for B to deal with later.
Reported by: syzbot+92dff413e201164c796b at syzkaller.appspotmail.com
Reviewed by: markj
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D27498
Modified:
head/sys/kern/kern_cpuset.c
Modified: head/sys/kern/kern_cpuset.c
==============================================================================
--- head/sys/kern/kern_cpuset.c Tue Dec 8 18:44:06 2020 (r368460)
+++ head/sys/kern/kern_cpuset.c Tue Dec 8 18:45:47 2020 (r368461)
@@ -207,9 +207,13 @@ cpuset_rel(struct cpuset *set)
{
cpusetid_t id;
- if (refcount_release(&set->cs_ref) == 0)
+ if (refcount_release_if_not_last(&set->cs_ref))
return;
mtx_lock_spin(&cpuset_lock);
+ if (!refcount_release(&set->cs_ref)) {
+ mtx_unlock_spin(&cpuset_lock);
+ return;
+ }
LIST_REMOVE(set, cs_siblings);
id = set->cs_id;
if (id != CPUSET_INVALID)
@@ -229,9 +233,13 @@ static void
cpuset_rel_defer(struct setlist *head, struct cpuset *set)
{
- if (refcount_release(&set->cs_ref) == 0)
+ if (refcount_release_if_not_last(&set->cs_ref))
return;
mtx_lock_spin(&cpuset_lock);
+ if (!refcount_release(&set->cs_ref)) {
+ mtx_unlock_spin(&cpuset_lock);
+ return;
+ }
LIST_REMOVE(set, cs_siblings);
if (set->cs_id != CPUSET_INVALID)
LIST_REMOVE(set, cs_link);
More information about the svn-src-head
mailing list