diff --git a/share/man/man9/domainset.9 b/share/man/man9/domainset.9 index 816ce29f04f..702c9f83a88 100644 --- a/share/man/man9/domainset.9 +++ b/share/man/man9/domainset.9 @@ -22,7 +22,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd April 14, 2021 +.Dd June 24, 2025 .Dt DOMAINSET 9 .Os .Sh NAME @@ -54,6 +54,8 @@ struct domainset { .Ft struct domainset * .Fn domainset_create "const struct domainset *key" .Ft int +.Fn domainset_populate "struct domainset *domain" "domainset_t *mask" "int policy" "size_t mask_size" +.Ft int .Fn sysctl_handle_domainset "SYSCTL_HANDLER_ARGS" .Sh DESCRIPTION The @@ -137,6 +139,7 @@ These policies should be used in preference to to avoid blocking indefinitely on a .Dv M_WAITOK request. +.Pp The .Fn domainset_create function takes a partially filled in domainset as a key and returns a @@ -148,6 +151,17 @@ is an immutable type that is shared among all matching keys and must not be modified after return. .Pp The +.Fn domainset_populate +function fills a +.Vt domainset +struct using a domain mask and policy. +It is used for validating and +translating a domain mask and policy into a +.Vt domainset +struct when creating a custom domainset using +.Vt domainset_create . +.Pp +The .Fn sysctl_handle_domainset function is provided as a convenience for modifying or viewing domainsets that are not accessible via diff --git a/sys/kern/kern_cpuset.c b/sys/kern/kern_cpuset.c index 5d9e2f2f326..d7eb82d5f25 100644 --- a/sys/kern/kern_cpuset.c +++ b/sys/kern/kern_cpuset.c @@ -530,7 +530,7 @@ _domainset_create(struct domainset *domain, struct domainlist *freelist) * remove them and update the domainset accordingly. If only empty * domains are present, we must return failure. */ -static bool +bool domainset_empty_vm(struct domainset *domain) { domainset_t empty; @@ -2408,6 +2408,59 @@ sys_cpuset_setdomain(struct thread *td, struct cpuset_setdomain_args *uap) uap->id, uap->domainsetsize, uap->mask, uap->policy, ©_set)); } +int +domainset_populate(struct domainset *domain, const domainset_t *mask, int policy, + size_t mask_size) +{ + + if (policy <= DOMAINSET_POLICY_INVALID || + policy > DOMAINSET_POLICY_MAX) { + return (EINVAL); + } + + /* + * Verify that no high bits are set. + */ + if (mask_size > sizeof(domainset_t)) { + const char *end; + const char *cp; + + end = cp = (const char *)&mask->__bits; + end += mask_size; + cp += sizeof(domainset_t); + while (cp != end) { + if (*cp++ != 0) { + return (EINVAL); + } + } + } + if (DOMAINSET_EMPTY(mask)) { + return (EDEADLK); + } + DOMAINSET_COPY(mask, &domain->ds_mask); + domain->ds_policy = policy; + + /* + * Sanitize the provided mask. + */ + if (!DOMAINSET_SUBSET(&all_domains, &domain->ds_mask)) { + return (EINVAL); + } + + /* Translate preferred policy into a mask and fallback. */ + if (policy == DOMAINSET_POLICY_PREFER) { + /* Only support a single preferred domain. */ + if (DOMAINSET_COUNT(&domain->ds_mask) != 1) { + return (EINVAL); + } + domain->ds_prefer = DOMAINSET_FFS(&domain->ds_mask) - 1; + /* This will be constrained by domainset_shadow(). */ + 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, @@ -2421,62 +2474,20 @@ kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which, domainset_t *mask; int error; - if (domainsetsize < sizeof(domainset_t) || - domainsetsize > DOMAINSET_MAXSIZE / NBBY) - return (ERANGE); - if (policy <= DOMAINSET_POLICY_INVALID || - policy > DOMAINSET_POLICY_MAX) - return (EINVAL); 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; - /* - * Verify that no high bits are set. - */ - if (domainsetsize > sizeof(domainset_t)) { - char *end; - char *cp; - - end = cp = (char *)&mask->__bits; - end += domainsetsize; - cp += sizeof(domainset_t); - while (cp != end) - if (*cp++ != 0) { - error = EINVAL; - goto out; - } - } - if (DOMAINSET_EMPTY(mask)) { - error = EDEADLK; + error = domainset_populate(&domain, mask, policy, domainsetsize); + if (error) goto out; - } - DOMAINSET_COPY(mask, &domain.ds_mask); - domain.ds_policy = policy; - - /* - * Sanitize the provided mask. - */ - if (!DOMAINSET_SUBSET(&all_domains, &domain.ds_mask)) { - error = EINVAL; - goto out; - } - - /* Translate preferred policy into a mask and fallback. */ - if (policy == DOMAINSET_POLICY_PREFER) { - /* Only support a single preferred domain. */ - if (DOMAINSET_COUNT(&domain.ds_mask) != 1) { - error = EINVAL; - goto out; - } - domain.ds_prefer = DOMAINSET_FFS(&domain.ds_mask) - 1; - /* This will be constrained by domainset_shadow(). */ - DOMAINSET_COPY(&all_domains, &domain.ds_mask); - } /* * When given an impossible policy, fall back to interleaving @@ -2484,7 +2495,6 @@ kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which, */ if (domainset_empty_vm(&domain)) domainset_copy(domainset2, &domain); - switch (level) { case CPU_LEVEL_ROOT: case CPU_LEVEL_CPUSET: diff --git a/sys/sys/domainset.h b/sys/sys/domainset.h index f98b175e9bc..f3dc92ec638 100644 --- a/sys/sys/domainset.h +++ b/sys/sys/domainset.h @@ -113,6 +113,20 @@ void domainset_zero(void); * returned value will not match the key pointer. */ struct domainset *domainset_create(const struct domainset *); + +/* + * Remove empty domains from a given domainset. + * Returns 'false' if the domainset consists entirely of empty domains. + */ +bool domainset_empty_vm(struct domainset *domain); + +/* + * Validate and populate a domainset structure according to the specified + * policy and mask. + */ +int domainset_populate(struct domainset *domain, const domainset_t *mask, int policy, + size_t mask_size); + #ifdef _SYS_SYSCTL_H_ int sysctl_handle_domainset(SYSCTL_HANDLER_ARGS); #endif