git: 01f74ccd5a0d - main - libthr: Fix pthread_attr_[g|s]etaffinity_np to match it's manual and the kernel.

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Sun, 29 Jan 2023 12:38:20 UTC
The branch main has been updated by dchagin:

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

commit 01f74ccd5a0d1a444703e931339709c7de5296b5
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2023-01-29 12:35:18 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2023-01-29 12:35:18 +0000

    libthr: Fix pthread_attr_[g|s]etaffinity_np to match it's manual and the kernel.
    
    Since f35093f8 semantics of a thread affinity functions is changed to be a
    compatible with Linux:
    
    In case of getaffinity(), the minimum cpuset_t size that the kernel permits is
    the maximum CPU id, present in the system, / NBBY bytes, the maximum size is not
    limited.
    In case of setaffinity(), the kernel does not limit the size of the user-provided
    cpuset_t, internally using only the meaningful part of the set, where the upper
    bound is the maximum CPU id, present in the system, no larger than the size of
    the kernel cpuset_t.
    
    To match pthread_attr_[g|s]etaffinity_np checks of the user-provided cpusets to
    the kernel behavior export the minimum cpuset_t size allowed by running kernel
    via new sysctl kern.sched.cpusetsizemin and use it in checks.
    
    Reviewed by:
    Differential Revision:  https://reviews.freebsd.org/D38112
    MFC after:              1 week
---
 lib/libthr/thread/thr_attr.c | 6 ++++--
 sys/kern/kern_cpuset.c       | 6 ++++++
 sys/kern/subr_smp.c          | 2 ++
 sys/sys/cpuset.h             | 1 +
 4 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/lib/libthr/thread/thr_attr.c b/lib/libthr/thread/thr_attr.c
index 6ff23aa5a3da..5a06f793f4f8 100644
--- a/lib/libthr/thread/thr_attr.c
+++ b/lib/libthr/thread/thr_attr.c
@@ -599,8 +599,10 @@ _get_kern_cpuset_size(void)
 		size_t len;
 
 		len = sizeof(kern_cpuset_size);
-		if (sysctlbyname("kern.sched.cpusetsize", &kern_cpuset_size,
-		    &len, NULL, 0))
+		if (sysctlbyname("kern.sched.cpusetsizemin", &kern_cpuset_size,
+		    &len, NULL, 0) != 0 &&
+		    sysctlbyname("kern.sched.cpusetsize", &kern_cpuset_size,
+		    &len, NULL, 0) != 0)
 			PANIC("failed to get sysctl kern.sched.cpusetsize");
 	}
 
diff --git a/sys/kern/kern_cpuset.c b/sys/kern/kern_cpuset.c
index d89be2805759..6dfe22b66689 100644
--- a/sys/kern/kern_cpuset.c
+++ b/sys/kern/kern_cpuset.c
@@ -136,11 +136,17 @@ static struct domainlist cpuset_domains;
 static struct unrhdr *cpuset_unr;
 static struct cpuset *cpuset_zero, *cpuset_default, *cpuset_kernel;
 static struct domainset *domainset0, *domainset2;
+u_int cpusetsizemin = 1;
 
 /* Return the size of cpuset_t at the kernel level */
 SYSCTL_INT(_kern_sched, OID_AUTO, cpusetsize, CTLFLAG_RD | CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, sizeof(cpuset_t), "sizeof(cpuset_t)");
 
+/* Return the minimum size of cpuset_t allowed by the kernel */
+SYSCTL_UINT(_kern_sched, OID_AUTO, cpusetsizemin,
+    CTLFLAG_RD | CTLFLAG_CAPRD, &cpusetsizemin, 0,
+    "The minimum size of cpuset_t allowed by the kernel");
+
 cpuset_t *cpuset_root;
 cpuset_t cpuset_domain[MAXMEMDOM];
 
diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c
index b9b8968c5a37..6ab71fd63695 100644
--- a/sys/kern/subr_smp.c
+++ b/sys/kern/subr_smp.c
@@ -148,6 +148,8 @@ mp_setmaxid(void *dummy)
 	KASSERT(mp_maxid >= mp_ncpus - 1,
 	    ("%s: counters out of sync: max %d, count %d", __func__,
 		mp_maxid, mp_ncpus));
+
+	cpusetsizemin = howmany(mp_maxid + 1, NBBY);
 }
 SYSINIT(cpu_mp_setmaxid, SI_SUB_TUNABLES, SI_ORDER_FIRST, mp_setmaxid, NULL);
 
diff --git a/sys/sys/cpuset.h b/sys/sys/cpuset.h
index 601da08a46a8..f8fc36b99aa7 100644
--- a/sys/sys/cpuset.h
+++ b/sys/sys/cpuset.h
@@ -120,6 +120,7 @@
 #include <sys/queue.h>
 
 LIST_HEAD(setlist, cpuset);
+extern u_int cpusetsizemin;
 
 /*
  * cpusets encapsulate cpu binding information for one or more threads.