git: aae23170c8b5 - main - libutil: Move cpuset(1) domain policy parsing code into libutil
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 27 Jul 2025 16:32:15 UTC
The branch main has been updated by bnovkov:
URL: https://cgit.FreeBSD.org/src/commit/?id=aae23170c8b5ac320dbf9c5f6cec05bea0b4b62f
commit aae23170c8b5ac320dbf9c5f6cec05bea0b4b62f
Author: Bojan Novković <bnovkov@FreeBSD.org>
AuthorDate: 2024-09-08 15:51:46 +0000
Commit: Bojan Novković <bnovkov@FreeBSD.org>
CommitDate: 2025-07-27 16:31:48 +0000
libutil: Move cpuset(1) domain policy parsing code into libutil
cpuset(1) implements a domainset(9) policy parser that is used to
translate a <policy>:<domain_list> string into a domainset_t mask
and a valid domainset policy. This change moves the domainset parsing
code into a new cpuset.c function - 'domainset_parselist'.
The existing cpuset.c code was refactored into a generalized list
parsing function which is now used to parse both CPU sets and domain
sets. This is the same approach used in cpuset(1).
Reviewed by: markj, ziaee (manpages)
Differential Revision: https://reviews.freebsd.org/D46607
---
bin/cpuset/Makefile | 2 +-
bin/cpuset/cpuset.c | 153 +-------------------------------------------------
lib/libutil/Makefile | 1 +
lib/libutil/cpuset.3 | 51 ++++++++++++++---
lib/libutil/cpuset.c | 98 ++++++++++++++++++++++++++++----
lib/libutil/libutil.h | 8 ++-
6 files changed, 140 insertions(+), 173 deletions(-)
diff --git a/bin/cpuset/Makefile b/bin/cpuset/Makefile
index d6f58db62901..639dd9812171 100644
--- a/bin/cpuset/Makefile
+++ b/bin/cpuset/Makefile
@@ -1,6 +1,6 @@
PROG= cpuset
-LIBADD= jail
+LIBADD= jail util
SYMLINKS+= ../..${BINDIR}/cpuset /usr/bin/cpuset
diff --git a/bin/cpuset/cpuset.c b/bin/cpuset/cpuset.c
index 82ffcaeec252..7416e100a3c6 100644
--- a/bin/cpuset/cpuset.c
+++ b/bin/cpuset/cpuset.c
@@ -43,6 +43,7 @@
#include <err.h>
#include <errno.h>
#include <jail.h>
+#include <libutil.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -69,154 +70,6 @@ static cpuwhich_t which;
static void usage(void) __dead2;
-struct numa_policy {
- const char *name;
- int policy;
-};
-
-static struct numa_policy policies[] = {
- { "round-robin", DOMAINSET_POLICY_ROUNDROBIN },
- { "rr", DOMAINSET_POLICY_ROUNDROBIN },
- { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH },
- { "ft", DOMAINSET_POLICY_FIRSTTOUCH },
- { "prefer", DOMAINSET_POLICY_PREFER },
- { "interleave", DOMAINSET_POLICY_INTERLEAVE},
- { "il", DOMAINSET_POLICY_INTERLEAVE},
- { NULL, DOMAINSET_POLICY_INVALID }
-};
-
-static void printset(struct bitset *mask, int size);
-
-static void
-parselist(char *list, struct bitset *mask, int size)
-{
- enum { NONE, NUM, DASH } state;
- int lastnum;
- int curnum;
- char *l;
-
- state = NONE;
- curnum = lastnum = 0;
- for (l = list; *l != '\0';) {
- if (isdigit(*l)) {
- curnum = atoi(l);
- if (curnum >= size)
- errx(EXIT_FAILURE,
- "List entry %d exceeds maximum of %d",
- curnum, size - 1);
- while (isdigit(*l))
- l++;
- switch (state) {
- case NONE:
- lastnum = curnum;
- state = NUM;
- break;
- case DASH:
- for (; lastnum <= curnum; lastnum++)
- BIT_SET(size, lastnum, mask);
- state = NONE;
- break;
- case NUM:
- default:
- goto parserr;
- }
- continue;
- }
- switch (*l) {
- case ',':
- switch (state) {
- case NONE:
- break;
- case NUM:
- BIT_SET(size, curnum, mask);
- state = NONE;
- break;
- case DASH:
- goto parserr;
- break;
- }
- break;
- case '-':
- if (state != NUM)
- goto parserr;
- state = DASH;
- break;
- default:
- goto parserr;
- }
- l++;
- }
- switch (state) {
- case NONE:
- break;
- case NUM:
- BIT_SET(size, curnum, mask);
- break;
- case DASH:
- goto parserr;
- }
- return;
-parserr:
- errx(EXIT_FAILURE, "Malformed list %s", list);
-}
-
-static void
-parsecpulist(char *list, cpuset_t *mask)
-{
-
- if (strcasecmp(list, "all") == 0) {
- if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
- sizeof(*mask), mask) != 0)
- err(EXIT_FAILURE, "getaffinity");
- return;
- }
- parselist(list, (struct bitset *)mask, CPU_SETSIZE);
-}
-
-/*
- * permissively parse policy:domain list
- * allow:
- * round-robin:0-4 explicit
- * round-robin:all explicit root domains
- * 0-4 implicit root policy
- * round-robin implicit root domains
- * all explicit root domains and implicit policy
- */
-static void
-parsedomainlist(char *list, domainset_t *mask, int *policyp)
-{
- domainset_t rootmask;
- struct numa_policy *policy;
- char *l;
- int p;
-
- /*
- * Use the rootset's policy as the default for unspecified policies.
- */
- if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
- sizeof(rootmask), &rootmask, &p) != 0)
- err(EXIT_FAILURE, "getdomain");
-
- l = list;
- for (policy = &policies[0]; policy->name != NULL; policy++) {
- if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) {
- p = policy->policy;
- l += strlen(policy->name);
- if (*l != ':' && *l != '\0')
- errx(EXIT_FAILURE, "Malformed list %s", list);
- if (*l == ':')
- l++;
- break;
- }
- }
- *policyp = p;
- if (strcasecmp(l, "all") == 0 || *l == '\0') {
- DOMAINSET_COPY(&rootmask, mask);
- return;
- }
- parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE);
-}
-
static void
printset(struct bitset *mask, int size)
{
@@ -327,11 +180,11 @@ main(int argc, char *argv[])
break;
case 'l':
lflag = 1;
- parsecpulist(optarg, &mask);
+ cpuset_parselist(optarg, &mask);
break;
case 'n':
nflag = 1;
- parsedomainlist(optarg, &domains, &policy);
+ domainset_parselist(optarg, &domains, &policy);
break;
case 'p':
pflag = 1;
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile
index 0639745d08fc..2d92c5ba1916 100644
--- a/lib/libutil/Makefile
+++ b/lib/libutil/Makefile
@@ -38,6 +38,7 @@ MAN+= cpuset.3 expand_number.3 flopen.3 fparseln.3 ftime.3 getlocalbase.3 \
property.3 pty.3 quotafile.3 realhostname.3 realhostname_sa.3 \
_secure_path.3 trimdomain.3 uucplock.3 pw_util.3
MAN+= login.conf.5
+MLINKS+=cpuset.3 domainset_parselist.3
MLINKS+=flopen.3 flopenat.3
MLINKS+=kld.3 kld_isloaded.3 kld.3 kld_load.3
MLINKS+=login_auth.3 auth_cat.3 login_auth.3 auth_checknologin.3
diff --git a/lib/libutil/cpuset.3 b/lib/libutil/cpuset.3
index be29d5309ef0..47dffd209ee6 100644
--- a/lib/libutil/cpuset.3
+++ b/lib/libutil/cpuset.3
@@ -22,21 +22,22 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 31, 2017
+.Dd June 24, 2025
.Dt CPUSET 3
.Os
.Sh NAME
-.Nm cpuset_parselist
-.Nd utility functions for
-.Xr cpuset 2
-handling
+.Nm cpuset_parselist ,
+.Nm domainset_parselist
+.Nd utility functions for cpuset(2) handling
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In sys/cpuset.h
.In libutil.h
.Ft int
-.Fn cpuset_parselist "const char *cpu-list" "cpuset_t *mask"
+.Fn cpuset_parselist "const char *cpu_list" "cpuset_t *mask"
+.Ft int
+.Fn domainset_parselist "const char *domain_policy" "domainset_t *domain_mask" "int *policyp"
.Sh DESCRIPTION
The
.Fn cpuset_parselist
@@ -52,6 +53,27 @@ numbers.
A special list of
.Dq all
may be specified in which case the list includes all CPUs from the root set.
+.Pp
+The
+.Fn domainset_parselist
+function parses a
+.Xr domainset 9
+memory domain allocation policy
+specified by
+.Va domain_policy
+filling the
+.Va domain_mask
+and the
+.Va policyp .
+A valid
+.Va domain_policy
+is formatted as
+.Ar policy:domain-list .
+See the
+.Ar -n
+flag in
+.Xr cpuset 1
+for a list of valid domain policies.
.Sh RETURN VALUES
Return values can be the following
.Bl -tag -width Er
@@ -60,19 +82,30 @@ The parsing was successful
.It Dv CPUSET_PARSE_ERROR
The
.Va cpu-list
+or
+.Va domain-policy
format is invalid
.It Dv CPUSET_PARSE_GETAFFINITY
The
.Xr cpuset_getaffinity 2
call has failed
.It Dv CPUSET_PARSE_INVALID_CPU
-The number of supported CPUs has been exceeded.
+The number of supported CPUs or NUMA domains has been exceeded.
The maximum number being
-.Va CPU_SETSIZE .
+.Va CPU_SETSIZE
+and
+.Va DOMAINSET_SETSIZE
+respectively.
+.It Dv CPUSET_PARSE_GETDOMAIN
+The
+.Xr cpuset_getdomain 2
+call has failed
.El
.Sh SEE ALSO
.Xr cpuset 1 ,
.Xr cpuset 2 ,
-.Xr cpuset 9
+.Xr numa 4 ,
+.Xr cpuset 9 ,
+.Xr domainset 9
.Sh AUTHORS
.An Jeffrey Roberson Aq Mt jeff@FreeBSD.org
diff --git a/lib/libutil/cpuset.c b/lib/libutil/cpuset.c
index 3c374bfa6cac..d4840af7e175 100644
--- a/lib/libutil/cpuset.c
+++ b/lib/libutil/cpuset.c
@@ -27,34 +27,48 @@
* SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
+#define _WANT_FREEBSD_BITSET
+
#include <sys/types.h>
#include <sys/cpuset.h>
+#include <sys/domainset.h>
#include <stdlib.h>
#include <string.h>
#include <libutil.h>
#include <ctype.h>
-int
-cpuset_parselist(const char *list, cpuset_t *mask)
+struct numa_policy {
+ const char *name;
+ int policy;
+};
+
+static const struct numa_policy policies[] = {
+ { "round-robin", DOMAINSET_POLICY_ROUNDROBIN },
+ { "rr", DOMAINSET_POLICY_ROUNDROBIN },
+ { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH },
+ { "ft", DOMAINSET_POLICY_FIRSTTOUCH },
+ { "prefer", DOMAINSET_POLICY_PREFER },
+ { "interleave", DOMAINSET_POLICY_INTERLEAVE},
+ { "il", DOMAINSET_POLICY_INTERLEAVE},
+ { NULL, DOMAINSET_POLICY_INVALID }
+};
+
+static int
+parselist(const char *list, struct bitset *mask, int size)
{
enum { NONE, NUM, DASH } state;
int lastnum;
int curnum;
const char *l;
- if (strcasecmp(list, "all") == 0) {
- if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
- sizeof(*mask), mask) != 0)
- return (CPUSET_PARSE_GETAFFINITY);
- return (CPUSET_PARSE_OK);
- }
state = NONE;
curnum = lastnum = 0;
for (l = list; *l != '\0';) {
if (isdigit(*l)) {
curnum = atoi(l);
- if (curnum > CPU_SETSIZE)
+ if (curnum >= size)
return (CPUSET_PARSE_INVALID_CPU);
while (isdigit(*l))
l++;
@@ -65,7 +79,7 @@ cpuset_parselist(const char *list, cpuset_t *mask)
break;
case DASH:
for (; lastnum <= curnum; lastnum++)
- CPU_SET(lastnum, mask);
+ BIT_SET(size, lastnum, mask);
state = NONE;
break;
case NUM:
@@ -80,7 +94,7 @@ cpuset_parselist(const char *list, cpuset_t *mask)
case NONE:
break;
case NUM:
- CPU_SET(curnum, mask);
+ BIT_SET(size, curnum, mask);
state = NONE;
break;
case DASH:
@@ -102,7 +116,7 @@ cpuset_parselist(const char *list, cpuset_t *mask)
case NONE:
break;
case NUM:
- CPU_SET(curnum, mask);
+ BIT_SET(size, curnum, mask);
break;
case DASH:
goto parserr;
@@ -111,3 +125,63 @@ cpuset_parselist(const char *list, cpuset_t *mask)
parserr:
return (CPUSET_PARSE_ERROR);
}
+
+/*
+ * permissively parse policy:domain list
+ * allow:
+ * round-robin:0-4 explicit
+ * round-robin:all explicit root domains
+ * 0-4 implicit root policy
+ * round-robin implicit root domains
+ * all explicit root domains and implicit policy
+ */
+int
+domainset_parselist(const char *list, domainset_t *mask, int *policyp)
+{
+ domainset_t rootmask;
+ const struct numa_policy *policy;
+ const char *l;
+ int p;
+
+ /*
+ * Use the rootset's policy as the default for unspecified policies.
+ */
+ if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
+ sizeof(rootmask), &rootmask, &p) != 0)
+ return (CPUSET_PARSE_GETDOMAIN);
+
+ if (list == NULL || strcasecmp(list, "all") == 0 || *list == '\0') {
+ *policyp = p;
+ DOMAINSET_COPY(&rootmask, mask);
+ return (CPUSET_PARSE_OK);
+ }
+
+ l = list;
+ for (policy = &policies[0]; policy->name != NULL; policy++) {
+ if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) {
+ p = policy->policy;
+ l += strlen(policy->name);
+ if (*l != ':' && *l != '\0')
+ return (CPUSET_PARSE_ERROR);
+ if (*l == ':')
+ l++;
+ break;
+ }
+ }
+ *policyp = p;
+
+ return (parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE));
+}
+
+int
+cpuset_parselist(const char *list, cpuset_t *mask)
+{
+ if (strcasecmp(list, "all") == 0) {
+ if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
+ sizeof(*mask), mask) != 0)
+ return (CPUSET_PARSE_GETAFFINITY);
+ return (CPUSET_PARSE_OK);
+ }
+
+ return (parselist(list, (struct bitset *)mask, CPU_SETSIZE));
+}
diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h
index 919855184caf..7d8bfdf67fac 100644
--- a/lib/libutil/libutil.h
+++ b/lib/libutil/libutil.h
@@ -213,7 +213,13 @@ int cpuset_parselist(const char *list, cpuset_t *mask);
#define CPUSET_PARSE_OK 0
#define CPUSET_PARSE_GETAFFINITY -1
#define CPUSET_PARSE_ERROR -2
-#define CPUSET_PARSE_INVALID_CPU -3
+#define CPUSET_PARSE_OUT_OF_RANGE -3
+#define CPUSET_PARSE_GETDOMAIN -4
+#define CPUSET_PARSE_INVALID_CPU CPUSET_PARSE_OUT_OF_RANGE /* backwards compat */
+#endif
+
+#ifdef _SYS_DOMAINSET_H_
+int domainset_parselist(const char *list, domainset_t *mask, int *policyp);
#endif
__END_DECLS