Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_cpuset.c
| Show First 20 Lines • Show All 524 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* | /* | ||||
| * Are any of the domains in the mask empty? If so, silently | * Are any of the domains in the mask empty? If so, silently | ||||
| * remove them and update the domainset accordingly. If only empty | * remove them and update the domainset accordingly. If only empty | ||||
| * domains are present, we must return failure. | * domains are present, we must return failure. | ||||
| */ | */ | ||||
| static bool | bool | ||||
| domainset_empty_vm(struct domainset *domain) | domainset_empty_vm(struct domainset *domain) | ||||
| { | { | ||||
| domainset_t empty; | domainset_t empty; | ||||
| int i, j; | int i, j; | ||||
| DOMAINSET_ZERO(&empty); | DOMAINSET_ZERO(&empty); | ||||
| for (i = 0; i < vm_ndomains; i++) | for (i = 0; i < vm_ndomains; i++) | ||||
| if (VM_DOMAIN_EMPTY(i)) | if (VM_DOMAIN_EMPTY(i)) | ||||
| ▲ Show 20 Lines • Show All 1,862 Lines • ▼ Show 20 Lines | |||||
| sys_cpuset_setdomain(struct thread *td, struct cpuset_setdomain_args *uap) | sys_cpuset_setdomain(struct thread *td, struct cpuset_setdomain_args *uap) | ||||
| { | { | ||||
| return (kern_cpuset_setdomain(td, uap->level, uap->which, | return (kern_cpuset_setdomain(td, uap->level, uap->which, | ||||
| uap->id, uap->domainsetsize, uap->mask, uap->policy, ©_set)); | uap->id, uap->domainsetsize, uap->mask, uap->policy, ©_set)); | ||||
| } | } | ||||
| int | int | ||||
| kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which, | domainset_populate(struct domainset *domain, const domainset_t *mask, int policy, | ||||
| id_t id, size_t domainsetsize, const domainset_t *maskp, int policy, | size_t mask_size) | ||||
markj: Can `mask` be a pointer to const? | |||||
Done Inline ActionsIt can, done! bnovkov: It can, done! | |||||
| const struct cpuset_copy_cb *cb) | |||||
| { | { | ||||
| struct cpuset *nset; | |||||
| struct cpuset *set; | |||||
| struct thread *ttd; | |||||
| struct proc *p; | |||||
| struct domainset domain; | |||||
| domainset_t *mask; | |||||
| int error; | |||||
| if (domainsetsize < sizeof(domainset_t) || | |||||
| domainsetsize > DOMAINSET_MAXSIZE / NBBY) | |||||
| return (ERANGE); | |||||
| if (policy <= DOMAINSET_POLICY_INVALID || | if (policy <= DOMAINSET_POLICY_INVALID || | ||||
| policy > DOMAINSET_POLICY_MAX) | policy > DOMAINSET_POLICY_MAX) { | ||||
| return (EINVAL); | return (EINVAL); | ||||
| error = cpuset_check_capabilities(td, level, which, id); | } | ||||
| if (error != 0) | |||||
| return (error); | |||||
| memset(&domain, 0, sizeof(domain)); | |||||
| mask = malloc(domainsetsize, M_TEMP, M_WAITOK | M_ZERO); | |||||
| error = cb->cpuset_copyin(maskp, mask, domainsetsize); | |||||
| if (error) | |||||
| goto out; | |||||
| /* | /* | ||||
| * Verify that no high bits are set. | * Verify that no high bits are set. | ||||
| */ | */ | ||||
| if (domainsetsize > sizeof(domainset_t)) { | if (mask_size > sizeof(domainset_t)) { | ||||
| char *end; | const char *end; | ||||
| char *cp; | const char *cp; | ||||
| end = cp = (char *)&mask->__bits; | end = cp = (const char *)&mask->__bits; | ||||
| end += domainsetsize; | end += mask_size; | ||||
| cp += sizeof(domainset_t); | cp += sizeof(domainset_t); | ||||
| while (cp != end) | while (cp != end) { | ||||
| if (*cp++ != 0) { | if (*cp++ != 0) { | ||||
| error = EINVAL; | return (EINVAL); | ||||
| goto out; | |||||
| } | } | ||||
| } | } | ||||
Done Inline Actions[annoying style nitpicking] This function consistently omitted braces for single statements, but now it has a mix of both styles. Either style is ok, but it'd be nice to be consistent. markj: [annoying style nitpicking] This function consistently omitted braces for single statements… | |||||
| } | |||||
| if (DOMAINSET_EMPTY(mask)) { | if (DOMAINSET_EMPTY(mask)) { | ||||
| error = EDEADLK; | return (EDEADLK); | ||||
| goto out; | |||||
| } | } | ||||
| DOMAINSET_COPY(mask, &domain.ds_mask); | DOMAINSET_COPY(mask, &domain->ds_mask); | ||||
| domain.ds_policy = policy; | domain->ds_policy = policy; | ||||
| /* | /* | ||||
| * Sanitize the provided mask. | * Sanitize the provided mask. | ||||
| */ | */ | ||||
| if (!DOMAINSET_SUBSET(&all_domains, &domain.ds_mask)) { | if (!DOMAINSET_SUBSET(&all_domains, &domain->ds_mask)) { | ||||
| error = EINVAL; | return (EINVAL); | ||||
| goto out; | |||||
| } | } | ||||
| /* Translate preferred policy into a mask and fallback. */ | /* Translate preferred policy into a mask and fallback. */ | ||||
| if (policy == DOMAINSET_POLICY_PREFER) { | if (policy == DOMAINSET_POLICY_PREFER) { | ||||
| /* Only support a single preferred domain. */ | /* Only support a single preferred domain. */ | ||||
| if (DOMAINSET_COUNT(&domain.ds_mask) != 1) { | if (DOMAINSET_COUNT(&domain->ds_mask) != 1) { | ||||
| error = EINVAL; | return (EINVAL); | ||||
| goto out; | |||||
| } | } | ||||
| domain.ds_prefer = DOMAINSET_FFS(&domain.ds_mask) - 1; | domain->ds_prefer = DOMAINSET_FFS(&domain->ds_mask) - 1; | ||||
| /* This will be constrained by domainset_shadow(). */ | /* This will be constrained by domainset_shadow(). */ | ||||
| DOMAINSET_COPY(&all_domains, &domain.ds_mask); | DOMAINSET_COPY(&all_domains, &domain->ds_mask); | ||||
| } | } | ||||
| return (0); | |||||
| } | |||||
| int | |||||
| kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which, | |||||
| id_t id, size_t domainsetsize, const domainset_t *maskp, int policy, | |||||
| const struct cpuset_copy_cb *cb) | |||||
| { | |||||
| struct cpuset *nset; | |||||
| struct cpuset *set; | |||||
| struct thread *ttd; | |||||
| struct proc *p; | |||||
| struct domainset domain; | |||||
| domainset_t *mask; | |||||
| int error; | |||||
| error = cpuset_check_capabilities(td, level, which, id); | |||||
| if (error != 0) | |||||
| return (error); | |||||
| if (domainsetsize < sizeof(domainset_t) || | |||||
| domainsetsize > DOMAINSET_MAXSIZE / NBBY) | |||||
| return (ERANGE); | |||||
| memset(&domain, 0, sizeof(domain)); | |||||
| mask = malloc(domainsetsize, M_TEMP, M_WAITOK | M_ZERO); | |||||
| error = cb->cpuset_copyin(maskp, mask, domainsetsize); | |||||
| if (error) | |||||
| goto out; | |||||
| error = domainset_populate(&domain, mask, policy, domainsetsize); | |||||
| if (error) | |||||
| goto out; | |||||
| /* | /* | ||||
| * When given an impossible policy, fall back to interleaving | * When given an impossible policy, fall back to interleaving | ||||
| * across all domains. | * across all domains. | ||||
| */ | */ | ||||
| if (domainset_empty_vm(&domain)) | if (domainset_empty_vm(&domain)) | ||||
| domainset_copy(domainset2, &domain); | domainset_copy(domainset2, &domain); | ||||
| switch (level) { | switch (level) { | ||||
Done Inline ActionsIt feels a bit weird to include this last section here--is it appropriate for a generic helper function, or is it really a policy of the syscall layer? markj: It feels a bit weird to include this last section here--is it appropriate for a generic helper… | |||||
Done Inline ActionsHm right, it's a bit unclear where the cutoff point should be. I guess it'd be useful to give other consumers of this interface a chance to return an error when faced with an empty domainset, the only issue with this is that it would require making domainset_vm_empty (and perhaps domainset_copy) public functions. Does that sound reasonable? bnovkov: Hm right, it's a bit unclear where the cutoff point should be.
I guess it'd be useful to give… | |||||
Done Inline ActionsI think making those symbols public is fine, yes. markj: I think making those symbols public is fine, yes. | |||||
| case CPU_LEVEL_ROOT: | case CPU_LEVEL_ROOT: | ||||
| case CPU_LEVEL_CPUSET: | case CPU_LEVEL_CPUSET: | ||||
| error = cpuset_which(which, id, &p, &ttd, &set); | error = cpuset_which(which, id, &p, &ttd, &set); | ||||
| if (error) | if (error) | ||||
| break; | break; | ||||
| switch (which) { | switch (which) { | ||||
| case CPU_WHICH_TID: | case CPU_WHICH_TID: | ||||
| case CPU_WHICH_PID: | case CPU_WHICH_PID: | ||||
| ▲ Show 20 Lines • Show All 129 Lines • Show Last 20 Lines | |||||
Can mask be a pointer to const?