The branch main has been updated by bnovkov:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=cf571e08503d7401d6eb7cae077058ebf02da116

commit cf571e08503d7401d6eb7cae077058ebf02da116
Author:     Bojan Novković <bnov...@freebsd.org>
AuthorDate: 2024-09-08 16:10:53 +0000
Commit:     Bojan Novković <bnov...@freebsd.org>
CommitDate: 2025-07-27 16:31:48 +0000

    domainset(9): Split domainset validation logic into a separate function
    
    This change splits the validation and 'struct domainset'-filling logic
    from kern_cpuset_setdomain into a separate function - domainset_populate.
    This function's main use is to validate user-provided domainset(9)
    policies and populate a struct domainset before handing it off
    to domainset_create. No functional change intended.
    
    Differential Revision:  https://reviews.freebsd.org/D46608
    Reviewed by:    markj
---
 share/man/man9/domainset.9 | 16 +++++++-
 sys/kern/kern_cpuset.c     | 98 +++++++++++++++++++++++++---------------------
 sys/sys/domainset.h        | 14 +++++++
 3 files changed, 83 insertions(+), 45 deletions(-)

diff --git a/share/man/man9/domainset.9 b/share/man/man9/domainset.9
index 816ce29f04f7..702c9f83a88b 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 5d9e2f2f326b..d7eb82d5f259 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;
@@ -2409,82 +2409,92 @@ sys_cpuset_setdomain(struct thread *td, struct 
cpuset_setdomain_args *uap)
 }
 
 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)
+domainset_populate(struct domainset *domain, const domainset_t *mask, int 
policy,
+    size_t mask_size)
 {
-       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 ||
-           policy > DOMAINSET_POLICY_MAX)
+           policy > DOMAINSET_POLICY_MAX) {
                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.
         */
-       if (domainsetsize > sizeof(domainset_t)) {
-               char *end;
-               char *cp;
+       if (mask_size > sizeof(domainset_t)) {
+               const char *end;
+               const char *cp;
 
-               end = cp = (char *)&mask->__bits;
-               end += domainsetsize;
+               end = cp = (const char *)&mask->__bits;
+               end += mask_size;
                cp += sizeof(domainset_t);
-               while (cp != end)
+               while (cp != end) {
                        if (*cp++ != 0) {
-                               error = EINVAL;
-                               goto out;
+                               return (EINVAL);
                        }
+               }
        }
        if (DOMAINSET_EMPTY(mask)) {
-               error = EDEADLK;
-               goto out;
+               return (EDEADLK);
        }
-       DOMAINSET_COPY(mask, &domain.ds_mask);
-       domain.ds_policy = policy;
+       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;
+       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) {
-                       error = EINVAL;
-                       goto out;
+               if (DOMAINSET_COUNT(&domain->ds_mask) != 1) {
+                       return (EINVAL);
                }
-               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(). */
-               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
         * across all domains.
         */
        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 f98b175e9bc8..f3dc92ec6383 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

Reply via email to