From e07e3fa3c95c74fba6540736f1687ad0ee47537c Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Sat, 28 Nov 2020 01:21:11 +0000 Subject: kern: cpuset: drop the lock to allocate domainsets Restructure the loop a little bit to make it a little more clear how it really operates: we never allocate any domains at the beginning of the first iteration, and it will run until we've satisfied the amount we need or we encounter an error. The lock is now taken outside of the loop to make stuff inside the loop easier to evaluate w.r.t. locking. This fixes it to not try and allocate any domains for the freelist under the spinlock, which would have happened before if we needed any new domains. Reported by: syzbot+6743fa07b9b7528dc561@syzkaller.appspotmail.com Reviewed by: markj MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D27371 --- sys/kern/kern_cpuset.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'sys/kern') diff --git a/sys/kern/kern_cpuset.c b/sys/kern/kern_cpuset.c index c5f4583b0d20..2429e535853e 100644 --- a/sys/kern/kern_cpuset.c +++ b/sys/kern/kern_cpuset.c @@ -794,14 +794,11 @@ cpuset_modify_domain(struct cpuset *set, struct domainset *domain) return (EPERM); domainset_freelist_init(&domains, 0); domain = domainset_create(domain); - ndomains = needed = 0; - do { - if (ndomains < needed) { - domainset_freelist_add(&domains, needed - ndomains); - ndomains = needed; - } + ndomains = 0; + + mtx_lock_spin(&cpuset_lock); + for (;;) { root = cpuset_getroot(set); - mtx_lock_spin(&cpuset_lock); dset = root->cs_domain; /* * Verify that we have access to this set of domains. @@ -826,7 +823,15 @@ cpuset_modify_domain(struct cpuset *set, struct domainset *domain) &needed, 0); if (error) goto out; - } while (ndomains < needed); + if (ndomains >= needed) + break; + + /* Dropping the lock; we'll need to re-evaluate again. */ + mtx_unlock_spin(&cpuset_lock); + domainset_freelist_add(&domains, needed - ndomains); + ndomains = needed; + mtx_lock_spin(&cpuset_lock); + } dset = set->cs_domain; cpuset_update_domain(set, domain, dset, &domains); out: -- cgit v1.2.3