The race plays out like so between threads A and B:
- A ref's cpuset 10
- B does a lookup of cpuset 10, grabs the cpuset lock and searches cpuset_ids
- 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
- B ref's cpuset 10 and drops the cpuset lock
- 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@syzkaller.appspotmail.com