Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 27 Jul 2025 16:32:16 GMT
From:      Bojan =?utf-8?Q?Novkovi=C4=87?= <bnovkov@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: cf571e08503d - main - domainset(9): Split domainset validation logic into a separate function
Message-ID:  <202507271632.56RGWGIG015672@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by bnovkov:

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

commit cf571e08503d7401d6eb7cae077058ebf02da116
Author:     Bojan Novković <bnovkov@FreeBSD.org>
AuthorDate: 2024-09-08 16:10:53 +0000
Commit:     Bojan Novković <bnovkov@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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202507271632.56RGWGIG015672>