On Sun, Jun 22, 2014 at 11:32:23AM +0000, Alexander V. Chernikov wrote: > Author: melifaro > Date: Sun Jun 22 11:32:23 2014 > New Revision: 267716 > URL: http://svnweb.freebsd.org/changeset/base/267716 > > Log: > Permit changing cpu mask for cpu set 1 in presence of drivers > binding their threads to particular CPU. > > Changing ithread cpu mask is now performed by special cpuset_setithread(). > It creates additional cpuset root group on first bind invocation. > > No objection: jhb > Tested by: hiren > MFC after: 2 weeks > Sponsored by: Yandex LLC > > Modified: > head/sys/kern/kern_cpuset.c > head/sys/kern/kern_intr.c > head/sys/sys/cpuset.h > > Modified: head/sys/kern/kern_cpuset.c > ============================================================================== > --- head/sys/kern/kern_cpuset.c Sun Jun 22 10:00:33 2014 > (r267715) > +++ head/sys/kern/kern_cpuset.c Sun Jun 22 11:32:23 2014 > (r267716) > @@ -106,7 +106,7 @@ static uma_zone_t cpuset_zone; > static struct mtx cpuset_lock; > static struct setlist cpuset_ids; > static struct unrhdr *cpuset_unr; > -static struct cpuset *cpuset_zero; > +static struct cpuset *cpuset_zero, *cpuset_default; > > /* Return the size of cpuset_t at the kernel level */ > SYSCTL_INT(_kern_sched, OID_AUTO, cpusetsize, CTLFLAG_RD, > @@ -716,6 +716,89 @@ out: > } > > /* > + * Apply new cpumask to the ithread. > + */ > +int > +cpuset_setithread(lwpid_t id, u_char cpu) > +{ > + struct cpuset *nset, *rset; > + struct cpuset *parent, *old_set; > + struct thread *td; > + struct proc *p; > + cpusetid_t cs_id; > + cpuset_t mask; > + int error; > + > + nset = uma_zalloc(cpuset_zone, M_WAITOK); > + rset = uma_zalloc(cpuset_zone, M_WAITOK); > + > + CPU_ZERO(&mask); > + if (cpu == NOCPU) > + CPU_COPY(cpuset_root, &mask); > + else > + CPU_SET(cpu, &mask); > + > + error = cpuset_which(CPU_WHICH_TID, id, &p, &td, &old_set); > + if (((cs_id = alloc_unr(cpuset_unr)) == CPUSET_INVALID) || error != 0) Why calling alloc_unr() at all if error != 0 ?
> + goto out; > + > + thread_lock(td); > + old_set = td->td_cpuset; > + > + if (cpu == NOCPU) { > + /* > + * roll back to default set. We're not using cpuset_shadow() > + * here because we can fail CPU_SUBSET() check. This can happen > + * if default set does not contain all CPUs. > + */ > + error = _cpuset_create(nset, cpuset_default, &mask, > + CPUSET_INVALID); Why should _cpuset_create() be called under the thread_lock() taken ? > + > + goto applyset; > + } > + > + if (old_set->cs_id == 1 || (old_set->cs_id == CPUSET_INVALID && > + old_set->cs_parent->cs_id == 1)) { > + /* Default mask, we need to use new root set */ > + error = _cpuset_create(rset, cpuset_zero, > + &cpuset_zero->cs_mask, cs_id); And this one, does the call need thread_lock ? > + if (error != 0) { Wouldn't this leak thread_lock() ? > + PROC_UNLOCK(p); > + goto out; > + } > + rset->cs_flags |= CPU_SET_ROOT; > + parent = rset; > + rset = NULL; > + cs_id = CPUSET_INVALID; > + } else { > + /* Assume existing set was already allocated by previous call */ > + parent = td->td_cpuset; > + old_set = NULL; > + } > + > + error = cpuset_shadow(parent, nset, &mask); > +applyset: > + if (error == 0) { > + td->td_cpuset = nset; > + sched_affinity(td); > + nset = NULL; > + } > + thread_unlock(td); > + PROC_UNLOCK(p); > + if (old_set != NULL) > + cpuset_rel(old_set); > +out: > + if (nset != NULL) > + uma_zfree(cpuset_zone, nset); > + if (rset != NULL) > + uma_zfree(cpuset_zone, rset); > + if (cs_id != CPUSET_INVALID) > + free_unr(cpuset_unr, cs_id); > + return (error); > +} > + > + > +/* > * Creates the cpuset for thread0. We make two sets: > * > * 0 - The root set which should represent all valid processors in the > @@ -735,6 +818,7 @@ cpuset_thread0(void) > cpuset_zone = uma_zcreate("cpuset", sizeof(struct cpuset), NULL, NULL, > NULL, NULL, UMA_ALIGN_PTR, 0); > mtx_init(&cpuset_lock, "cpuset", NULL, MTX_SPIN | MTX_RECURSE); > + > /* > * Create the root system set for the whole machine. Doesn't use > * cpuset_create() due to NULL parent. > @@ -747,12 +831,15 @@ cpuset_thread0(void) > set->cs_flags = CPU_SET_ROOT; > cpuset_zero = set; > cpuset_root = &set->cs_mask; > + > /* > * Now derive a default, modifiable set from that to give out. > */ > set = uma_zalloc(cpuset_zone, M_WAITOK); > error = _cpuset_create(set, cpuset_zero, &cpuset_zero->cs_mask, 1); > KASSERT(error == 0, ("Error creating default set: %d\n", error)); > + cpuset_default = set; > + > /* > * Initialize the unit allocator. 0 and 1 are allocated above. > */ > > Modified: head/sys/kern/kern_intr.c > ============================================================================== > --- head/sys/kern/kern_intr.c Sun Jun 22 10:00:33 2014 (r267715) > +++ head/sys/kern/kern_intr.c Sun Jun 22 11:32:23 2014 (r267716) > @@ -295,7 +295,6 @@ intr_event_create(struct intr_event **ev > int > intr_event_bind(struct intr_event *ie, u_char cpu) > { > - cpuset_t mask; > lwpid_t id; > int error; > > @@ -316,14 +315,9 @@ intr_event_bind(struct intr_event *ie, u > */ > mtx_lock(&ie->ie_lock); > if (ie->ie_thread != NULL) { > - CPU_ZERO(&mask); > - if (cpu == NOCPU) > - CPU_COPY(cpuset_root, &mask); > - else > - CPU_SET(cpu, &mask); > id = ie->ie_thread->it_thread->td_tid; > mtx_unlock(&ie->ie_lock); > - error = cpuset_setthread(id, &mask); > + error = cpuset_setithread(id, cpu); > if (error) > return (error); > } else > @@ -332,14 +326,10 @@ intr_event_bind(struct intr_event *ie, u > if (error) { > mtx_lock(&ie->ie_lock); > if (ie->ie_thread != NULL) { > - CPU_ZERO(&mask); > - if (ie->ie_cpu == NOCPU) > - CPU_COPY(cpuset_root, &mask); > - else > - CPU_SET(ie->ie_cpu, &mask); > + cpu = ie->ie_cpu; > id = ie->ie_thread->it_thread->td_tid; > mtx_unlock(&ie->ie_lock); > - (void)cpuset_setthread(id, &mask); > + (void)cpuset_setithread(id, cpu); > } else > mtx_unlock(&ie->ie_lock); > return (error); > > Modified: head/sys/sys/cpuset.h > ============================================================================== > --- head/sys/sys/cpuset.h Sun Jun 22 10:00:33 2014 (r267715) > +++ head/sys/sys/cpuset.h Sun Jun 22 11:32:23 2014 (r267716) > @@ -118,6 +118,7 @@ struct cpuset *cpuset_thread0(void); > struct cpuset *cpuset_ref(struct cpuset *); > void cpuset_rel(struct cpuset *); > int cpuset_setthread(lwpid_t id, cpuset_t *); > +int cpuset_setithread(lwpid_t id, u_char cpu); > int cpuset_create_root(struct prison *, struct cpuset **); > int cpuset_setproc_update_set(struct proc *, struct cpuset *); > char *cpusetobj_strprint(char *, const cpuset_t *);
pgpELheaHe71u.pgp
Description: PGP signature