Page MenuHomeFreeBSD

D34849.id105431.diff
No OneTemporary

D34849.id105431.diff

Index: lib/libc/gen/sched_getaffinity.c
===================================================================
--- lib/libc/gen/sched_getaffinity.c
+++ lib/libc/gen/sched_getaffinity.c
@@ -33,24 +33,15 @@
int
sched_getaffinity(pid_t pid, size_t cpusetsz, cpuset_t *cpuset)
{
- /*
- * Be more Linux-compatible:
- * - return EINVAL in passed size is less than size of cpuset_t
- * in advance, instead of ERANGE from the syscall
- * - if passed size is larger than the size of cpuset_t, be
- * permissive by claming it back to sizeof(cpuset_t) and
- * zeroing the rest.
- */
- if (cpusetsz < sizeof(cpuset_t)) {
+ int error;
+
+ error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+ pid == 0 ? -1 : pid, cpusetsz, cpuset);
+ if (error == -1 && errno == ERANGE)
errno = EINVAL;
- return (-1);
- }
- if (cpusetsz > sizeof(cpuset_t)) {
- memset((char *)cpuset + sizeof(cpuset_t), 0,
- cpusetsz - sizeof(cpuset_t));
- cpusetsz = sizeof(cpuset_t);
- }
+ if (error == 0)
+ return (cpusetsz < sizeof(cpuset_t) ? cpusetsz :
+ sizeof(cpuset_t));
- return (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
- pid == 0 ? -1 : pid, cpusetsz, cpuset));
+ return (error);
}
Index: lib/libc/gen/sched_setaffinity.c
===================================================================
--- lib/libc/gen/sched_setaffinity.c
+++ lib/libc/gen/sched_setaffinity.c
@@ -33,18 +33,10 @@
int
sched_setaffinity(pid_t pid, size_t cpusetsz, const cpuset_t *cpuset)
{
- cpuset_t c;
int error;
- if (cpusetsz > sizeof(cpuset_t)) {
- errno = EINVAL;
- return (-1);
- } else {
- memset(&c, 0, sizeof(c));
- memcpy(&c, cpuset, cpusetsz);
- }
error = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
- pid == 0 ? -1 : pid, sizeof(cpuset_t), &c);
+ pid == 0 ? -1 : pid, cpusetsz, cpuset);
if (error == -1 && errno == EDEADLK)
errno = EINVAL;
Index: lib/libc/sys/cpuset_getaffinity.2
===================================================================
--- lib/libc/sys/cpuset_getaffinity.2
+++ lib/libc/sys/cpuset_getaffinity.2
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 23, 2017
+.Dd April 26, 2022
.Dt CPUSET_GETAFFINITY 2
.Os
.Sh NAME
@@ -71,14 +71,15 @@
are composed using the
.Dv CPU_SET
macros.
-The kernel tolerates large sets as long as all CPUs specified
-in the set exist.
-Sets smaller than the kernel uses generate an error on calls to
+If the user-supplied mask is not large enough to fit all of CPUs
+that are currently physically on the system
.Fn cpuset_getaffinity
-even if the result set would fit within the user supplied set.
+fails with
+.Er ERANGE .
Calls to
.Fn cpuset_setaffinity
-tolerate small sets with no restrictions.
+tolerate masks of any size with no restrictions. The kernel uses a
+significant part of the mask, no large than the size of the kernel cpuset_t.
.Pp
The supplied mask should have a size of
.Fa setsize
@@ -144,7 +145,7 @@
.It Bq Er ERANGE
The
.Fa cpusetsize
-was either preposterously large or smaller than the kernel set size.
+was smaller than needed to fit all active CPUs.
.It Bq Er EPERM
The calling process did not have the credentials required to complete the
operation.
Index: share/man/man3/pthread_attr_affinity_np.3
===================================================================
--- share/man/man3/pthread_attr_affinity_np.3
+++ share/man/man3/pthread_attr_affinity_np.3
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 12, 2021
+.Dd April 26, 2022
.Dt PTHREAD_ATTR_AFFINITY_NP 3
.Os
.Sh NAME
@@ -51,14 +51,15 @@
are composed using the
.Dv CPU_SET
macros.
-The kernel tolerates large sets as long as all CPUs specified
-in the set exist.
-Sets smaller than the kernel uses generate an error on calls to
-.Fn pthread_attr_getaffinity_np
-even if the result set would fit within the user supplied set.
+If the user-supplied mask is not large enough to fit all of CPUs
+that are currently physically on the system
+.Fn cpuset_getaffinity
+fails with
+.Er ERANGE .
Calls to
-.Fn pthread_attr_setaffinity_np
-tolerate small sets with no restrictions.
+.Fn cpuset_setaffinity
+tolerate masks of any size with no restrictions. The kernel uses a
+significant part of the mask, no large than the size of the kernel cpuset_t.
.Pp
The supplied mask should have a size of
.Fa cpusetsize
Index: sys/kern/kern_cpuset.c
===================================================================
--- sys/kern/kern_cpuset.c
+++ sys/kern/kern_cpuset.c
@@ -118,6 +118,9 @@
* getaffinity call using (CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, ...).
*/
+_Static_assert(CPU_SETSIZE <= howmany(PAGE_SIZE, NBBY),
+ "CPU_SETSIZE");
+
LIST_HEAD(domainlist, domainset);
struct domainset __read_mostly domainset_firsttouch;
struct domainset __read_mostly domainset_fixed[MAXMEMDOM];
@@ -1896,13 +1899,13 @@
int error;
size_t size;
- if (cpusetsize < sizeof(cpuset_t) || cpusetsize > CPU_MAXSIZE / NBBY)
+ if (cpusetsize < howmany(smp_cpus, NBBY))
return (ERANGE);
error = cpuset_check_capabilities(td, level, which, id);
if (error != 0)
return (error);
- size = cpusetsize;
- mask = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
+ size = min(cpusetsize, sizeof(cpuset_t));
+ mask = malloc(sizeof(cpuset_t), M_TEMP, M_WAITOK | M_ZERO);
error = cpuset_which(which, id, &p, &ttd, &set);
if (error)
goto out;
@@ -2006,26 +2009,27 @@
struct proc *p;
cpuset_t *mask;
int error;
+ size_t loadsize, factsize;
- if (cpusetsize < sizeof(cpuset_t) || cpusetsize > CPU_MAXSIZE / NBBY)
- return (ERANGE);
error = cpuset_check_capabilities(td, level, which, id);
if (error != 0)
return (error);
- mask = malloc(cpusetsize, M_TEMP, M_WAITOK | M_ZERO);
- error = copyin(maskp, mask, cpusetsize);
+ loadsize = min(cpusetsize, sizeof(cpuset_t));
+ mask = malloc(sizeof(cpuset_t), M_TEMP, M_WAITOK | M_ZERO);
+ error = copyin(maskp, mask, loadsize);
if (error)
goto out;
+ factsize = howmany(smp_cpus, NBBY);
/*
* Verify that no high bits are set.
*/
- if (cpusetsize > sizeof(cpuset_t)) {
+ if (loadsize > factsize) {
char *end;
char *cp;
end = cp = (char *)&mask->__bits;
- end += cpusetsize;
- cp += sizeof(cpuset_t);
+ end += loadsize;
+ cp += factsize;
while (cp != end)
if (*cp++ != 0) {
error = EINVAL;
Index: tests/sys/kern/Makefile
===================================================================
--- tests/sys/kern/Makefile
+++ tests/sys/kern/Makefile
@@ -26,6 +26,7 @@
ATF_TESTS_C+= ptrace_test
TEST_METADATA.ptrace_test+= timeout="15"
ATF_TESTS_C+= reaper
+ATF_TESTS_C+= sched_affinity
ATF_TESTS_C+= sigaltstack
ATF_TESTS_C+= sigwait
.if ${MACHINE_ARCH} != "i386" && ${MACHINE_ARCH:Mpowerpc*} == ""
Index: tests/sys/kern/sched_affinity.c
===================================================================
--- /dev/null
+++ tests/sys/kern/sched_affinity.c
@@ -0,0 +1,222 @@
+/*-
+ * Copyright (c) 2022 Dmitry Chagin <dchagin@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stdint.h>
+
+#include <errno.h>
+#include <sched.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+
+static int
+support_sysconf(int name)
+{
+ int rv;
+
+ rv = sysconf(name);
+ ATF_REQUIRE(rv != -1);
+ return (rv);
+}
+
+ATF_TC_WITHOUT_HEAD(test_setinvalidcpu);
+ATF_TC_BODY(test_setinvalidcpu, tc)
+{
+ size_t cpusetsize;
+ cpuset_t *set;
+ ssize_t cpus;
+
+ cpus = support_sysconf(_SC_NPROCESSORS_CONF);
+
+ set = CPU_ALLOC(cpus + 1);
+ ATF_REQUIRE(set != NULL);
+ cpusetsize = CPU_ALLOC_SIZE(cpus + 1);
+ CPU_ZERO(set);
+ CPU_SET(cpus, set);
+ ATF_REQUIRE(sched_setaffinity(0, cpusetsize, set) == -1);
+ ATF_REQUIRE_EQ(errno, EINVAL);
+ CPU_FREE(set);
+}
+
+ATF_TC_WITHOUT_HEAD(test_setvalidcpu);
+ATF_TC_BODY(test_setvalidcpu, tc)
+{
+ size_t cpusetsize;
+ cpuset_t *set;
+ ssize_t cpus;
+ int cpu;
+
+ cpus = support_sysconf(_SC_NPROCESSORS_CONF);
+ cpu = cpus > 1 ? cpus - 1 : 0;
+
+ set = CPU_ALLOC(cpus);
+ ATF_REQUIRE(set != NULL);
+ cpusetsize = CPU_ALLOC_SIZE(cpus);
+ CPU_ZERO(set);
+ CPU_SET(cpu, set);
+ ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+ -1, cpusetsize, set) == 0);
+ ATF_REQUIRE_EQ(cpu, sched_getcpu());
+ CPU_FREE(set);
+}
+
+ATF_TC_WITHOUT_HEAD(test_setzeroset1);
+ATF_TC_BODY(test_setzeroset1, tc)
+{
+ size_t cpusetsize;
+ cpuset_t *set;
+ ssize_t cpus;
+
+ cpus = support_sysconf(_SC_NPROCESSORS_CONF);
+
+ set = CPU_ALLOC(cpus);
+ ATF_REQUIRE(set != NULL);
+ cpusetsize = CPU_ALLOC_SIZE(cpus);
+ CPU_ZERO(set);
+ ATF_REQUIRE(sched_setaffinity(0, cpusetsize, set) == -1);
+ ATF_REQUIRE_EQ(errno, EINVAL);
+ CPU_FREE(set);
+}
+
+ATF_TC_WITHOUT_HEAD(test_setzeroset2);
+ATF_TC_BODY(test_setzeroset2, tc)
+{
+ size_t cpusetsize;
+ cpuset_t *set;
+ ssize_t cpus;
+
+ cpus = support_sysconf(_SC_NPROCESSORS_CONF);
+
+ set = CPU_ALLOC(cpus);
+ ATF_REQUIRE(set != NULL);
+ cpusetsize = CPU_ALLOC_SIZE(cpus);
+ CPU_ZERO(set);
+ ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+ -1, cpusetsize, set) == -1);
+ ATF_REQUIRE_EQ(errno, EDEADLK);
+ CPU_FREE(set);
+}
+
+ATF_TC_WITHOUT_HEAD(test_setmaxsetsize);
+ATF_TC_BODY(test_setmaxsetsize, tc)
+{
+ size_t cpusetsize;
+ cpuset_t *set;
+ ssize_t cpus = INT32_MAX;
+
+ set = CPU_ALLOC(cpus);
+ ATF_REQUIRE(set != NULL);
+ cpusetsize = CPU_ALLOC_SIZE(cpus);
+ CPU_ZERO(set);
+ CPU_SET(0, set);
+ ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+ -1, cpusetsize, set) == 0);
+ CPU_FREE(set);
+}
+
+ATF_TC_WITHOUT_HEAD(test_setminsetsize);
+ATF_TC_BODY(test_setminsetsize, tc)
+{
+ size_t cpusetsize = 1;
+ int8_t set;
+ ssize_t cpus;
+
+ cpus = support_sysconf(_SC_NPROCESSORS_CONF);
+ if (cpus <= 8)
+ return;
+
+ set = 1;
+ ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+ -1, cpusetsize, (const cpuset_t *)&set) == 0);
+ set = 0;
+ ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+ -1, cpusetsize, (const cpuset_t *)&set) == -1);
+ ATF_REQUIRE_EQ(errno, EDEADLK);
+}
+
+ATF_TC_WITHOUT_HEAD(test_getminsetsize);
+ATF_TC_BODY(test_getminsetsize, tc)
+{
+ size_t cpusetsize = 1;
+ int8_t set = 0;
+ ssize_t cpus;
+
+ cpus = support_sysconf(_SC_NPROCESSORS_CONF);
+ if (cpus <= 8) {
+ /* Can't check ERANGE if cpus <= 8 */
+ ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+ -1, cpusetsize, (cpuset_t *)&set) == 0);
+ } else {
+ ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+ -1, cpusetsize, (cpuset_t *)&set) == -1);
+ ATF_REQUIRE_EQ(errno, ERANGE);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(test_getsetsize);
+ATF_TC_BODY(test_getsetsize, tc)
+{
+ size_t cpusetsize;
+ cpuset_t *set;
+ ssize_t cpus;
+
+ cpus = support_sysconf(_SC_NPROCESSORS_CONF);
+
+ set = CPU_ALLOC(cpus);
+ ATF_REQUIRE(set != NULL);
+ cpusetsize = CPU_ALLOC_SIZE(cpus);
+ CPU_ZERO(set);
+ ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+ -1, cpusetsize, set) == 0);
+ CPU_FREE(set);
+}
+
+ATF_TC_WITHOUT_HEAD(test_schedgetsetsize);
+ATF_TC_BODY(test_schedgetsetsize, tc)
+{
+ int cpusetsize;
+ cpuset_t *set;
+ ssize_t cpus;
+
+ cpus = support_sysconf(_SC_NPROCESSORS_CONF);
+
+ set = CPU_ALLOC(cpus);
+ ATF_REQUIRE(set != NULL);
+ cpusetsize = CPU_ALLOC_SIZE(cpus);
+ CPU_ZERO(set);
+ ATF_REQUIRE(sched_getaffinity(0, cpusetsize, set) == cpusetsize);
+ CPU_FREE(set);
+
+ set = CPU_ALLOC(CPU_SETSIZE);
+ ATF_REQUIRE(set != NULL);
+ cpusetsize = CPU_ALLOC_SIZE(CPU_SETSIZE);
+ CPU_ZERO(set);
+ ATF_REQUIRE(sched_getaffinity(0, cpusetsize, set) == cpusetsize);
+ CPU_FREE(set);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, test_setinvalidcpu);
+ ATF_TP_ADD_TC(tp, test_setvalidcpu);
+ ATF_TP_ADD_TC(tp, test_setzeroset1);
+ ATF_TP_ADD_TC(tp, test_setzeroset2);
+
+ ATF_TP_ADD_TC(tp, test_setminsetsize);
+ ATF_TP_ADD_TC(tp, test_setmaxsetsize);
+
+ ATF_TP_ADD_TC(tp, test_getminsetsize);
+ ATF_TP_ADD_TC(tp, test_getsetsize);
+
+ ATF_TP_ADD_TC(tp, test_schedgetsetsize);
+
+ return (atf_no_error());
+}

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 9, 3:22 AM (13 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28530926
Default Alt Text
D34849.id105431.diff (11 KB)

Event Timeline