From nobody Tue Jan 20 04:09:40 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4dwDP10nMcz6Nvsx for ; Tue, 20 Jan 2026 04:09:41 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4dwDP04PFyz3W2w for ; Tue, 20 Jan 2026 04:09:40 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1768882180; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=RpcPE8oxol0c82R+G1jhhkW95QdzrmRcLNN+EeONW0A=; b=QsVzvYwM3OsliWgQFjM6w0+I3HYp7TcMQKE9R1crVqOJt0yGsOCLyEZva/45gOkX51p9+d rmRAsCxCO6O/BQviqf23/18L/xGBTqNhrjle0AYA0Q8nO+3D4NUzJXlyxZYSJB3o3iaqzU /IfTX24jviPlKzpjatlDkeJVPAs2jluFU7HL1dOamDHPINaxnqWuz/WevEAjQyns2jRKOQ EnsKvOkJ9g9IgYdTrdv+rMMq1BrKrJDlmM9H5UAu8KcjTLq3z4TjgJWLq4Vof45XWTY9Vq 4F1VI7JLVSkd4iJu3ayI8qiSXymjO2WsPMq83Dv0ovDbnrErHsgY6McaPpnZDg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1768882180; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=RpcPE8oxol0c82R+G1jhhkW95QdzrmRcLNN+EeONW0A=; b=CTk6dbYqS8Xj8uJdL3oN401CY85nE3G+GmyheQXO7bp9kbZfetPGtCjCjKZOYEu7rQAxoN XdHi+D81Jtp1xUNPNTI1EqChTTw6Wi5Ypt7E6/dEOjGqPYIOXdgV7f1X8nG7bBEhm76u2J nq9ID4/WeXgPoncUEUhQI7555Wxe7LqGpO88BPfJIWr2htuoTO3OVa0vAywURtP2/i03Zg 8r3pEyOgA9eBiwGwlzB8d6mDfcbdLI2pHVvjAbq3SZQeS8t8QnTk/F8aV3mv4kRdVidQX/ PGcpmlB+bSxTCalm7XK1VDDaK1Z4BmYbynjFWObSZ1gozOatuGCSt706PxYAdQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1768882180; a=rsa-sha256; cv=none; b=fxQ+Up0hk6vNAKOKJZwAB6ECKjAZfIzc0DqUd+YESJyW4VlOC+rST8fv5/sjWoIoWimeDf mI5xp/hbgNwicK199kMKw7ZjhRia+4G9Al/ANetQpbHtH1Suzt50yE1VIqOse3iyiTIonD MPcog9eH+hIEJPPqcEf6HadZyWqGwAWXgCjHTW1cwFSr1wfa75AvVbgoBJn0pJGQW4nOlS R4BtQl63VQfM7wYOoRqZAaK0chb/NF3umZLmqL0H/CQwlxdd85ce5TlI/Q8BDo/7ZKVOWB 18q7NXF/xfApbKUNbwP1jWFmkOLLcucxij7x38/HUrKN3KHxgY50i4rcRGyDJw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4dwDP03r9Lz11xM for ; Tue, 20 Jan 2026 04:09:40 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 30ba6 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 20 Jan 2026 04:09:40 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kyle Evans Subject: git: b196a718ca0e - stable/14 - libc: report _SC_NPROCESSORS_ONLN more accurately in cpu-limited jails List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: b196a718ca0e77685b8e40aaac0911f11604d00c Auto-Submitted: auto-generated Date: Tue, 20 Jan 2026 04:09:40 +0000 Message-Id: <696f0004.30ba6.135c78fe@gitrepo.freebsd.org> The branch stable/14 has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=b196a718ca0e77685b8e40aaac0911f11604d00c commit b196a718ca0e77685b8e40aaac0911f11604d00c Author: Kyle Evans AuthorDate: 2025-10-29 16:32:30 +0000 Commit: Kyle Evans CommitDate: 2026-01-20 04:06:56 +0000 libc: report _SC_NPROCESSORS_ONLN more accurately in cpu-limited jails We don't support CPU hotplug, but we do support cpuset(8) restrictions on jails (including prison0, which uses cpuset 1). The process cannot widen its cpuset beyond its root set, so it makes sense to instead report the number of cpus enabled there rather than the total number in the system. This change is effectively a nop for the majority of systems and jails in the wild, though it does reduce the performance of this query now that we can't take advantage of AT_NCPUS being provided in the auxinfo. The implementation here is notably different than Linux, which would not take cgroups into account. They do, however, take CPU hotplug into account, so the possibility for it to diverge from (and be lower than) the # configured count to reflect what the process can actually be scheduled on doesn't really diverge in semantics. Reviewed by: kib (cherry picked from commit d617806aac1469319970e3551656e9deabb98a35) --- lib/libc/gen/sysconf.3 | 6 +- lib/libc/gen/sysconf.c | 16 ++++- lib/libc/tests/sys/cpuset_test.c | 140 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 156 insertions(+), 6 deletions(-) diff --git a/lib/libc/gen/sysconf.3 b/lib/libc/gen/sysconf.3 index 56d4c0bc5aa6..73338ae30349 100644 --- a/lib/libc/gen/sysconf.3 +++ b/lib/libc/gen/sysconf.3 @@ -27,7 +27,7 @@ .\" .\" @(#)sysconf.3 8.3 (Berkeley) 4/19/94 .\" -.Dd April 26, 2013 +.Dd August 30, 2025 .Dt SYSCONF 3 .Os .Sh NAME @@ -79,7 +79,9 @@ The maximum number of supplemental groups. .It Li _SC_NPROCESSORS_CONF The number of processors configured. .It Li _SC_NPROCESSORS_ONLN -The number of processors currently online. +The number of processors currently online, taking into account current jail +restrictions to report only the number of processors that are usable to the +process. .It Li _SC_OPEN_MAX One more than the maximum value the system may assign to a new file descriptor. .It Li _SC_PAGESIZE diff --git a/lib/libc/gen/sysconf.c b/lib/libc/gen/sysconf.c index 4b43cb48840c..fd9bc658ae40 100644 --- a/lib/libc/gen/sysconf.c +++ b/lib/libc/gen/sysconf.c @@ -73,6 +73,7 @@ long sysconf(int name) { struct rlimit rl; + cpuset_t cpus; size_t len; int mib[2], sverrno, value; long lvalue, defaultresult; @@ -580,8 +581,21 @@ yesno: return (_POSIX_IPV6); #endif - case _SC_NPROCESSORS_CONF: case _SC_NPROCESSORS_ONLN: + /* + * Consult our root set first, because our CPU availability + * may not match the total number of CPUs available on the + * system and we may have a non-uniform layout even within + * userland. In particular, each jail has a root set that can + * be constrained by its parent and processes within the jail + * cannot widen beyond those constraints, so to those processes + * it makes sense to claim the more limited count. + */ + if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, + sizeof(cpus), &cpus) == 0) + return (CPU_COUNT(&cpus)); + /* FALLTHROUGH */ + case _SC_NPROCESSORS_CONF: if (_elf_aux_info(AT_NCPUS, &value, sizeof(value)) == 0) return ((long)value); mib[0] = CTL_HW; diff --git a/lib/libc/tests/sys/cpuset_test.c b/lib/libc/tests/sys/cpuset_test.c index 53d6a8215bbc..c8ad225fadfc 100644 --- a/lib/libc/tests/sys/cpuset_test.c +++ b/lib/libc/tests/sys/cpuset_test.c @@ -34,8 +34,10 @@ #include #include +#include #include #include +#include #include #include @@ -107,6 +109,19 @@ skip_ltncpu(int ncpu, cpuset_t *mask) atf_tc_skip("Test requires %d or more cores.", ncpu); } +static void +skip_ltncpu_root(int ncpu, cpuset_t *mask) +{ + + CPU_ZERO(mask); + ATF_REQUIRE_EQ(0, cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, + -1, sizeof(*mask), mask)); + if (CPU_COUNT(mask) < ncpu) { + atf_tc_skip("Test requires cpuset root with %d or more cores.", + ncpu); + } +} + ATF_TC(newset); ATF_TC_HEAD(newset, tc) { @@ -234,9 +249,8 @@ ATF_TC_BODY(deadlk, tc) } static int -do_jail(int sock) +create_jail(void) { - struct jail_test_info info; struct iovec iov[2]; char *name; int error; @@ -250,8 +264,22 @@ do_jail(int sock) iov[1].iov_base = name; iov[1].iov_len = strlen(name) + 1; - if (jail_set(iov, 2, JAIL_CREATE | JAIL_ATTACH) < 0) + error = jail_set(iov, 2, JAIL_CREATE | JAIL_ATTACH); + free(name); + if (error < 0) return (FAILURE_JAIL); + return (0); +} + +static int +do_jail(int sock) +{ + struct jail_test_info info; + int error; + + error = create_jail(); + if (error != 0) + return (error); /* Record parameters, kick them over, then make a swift exit. */ CPU_ZERO(&info.jail_tidmask); @@ -641,6 +669,111 @@ ATF_TC_BODY(jail_attach_disjoint, tc) try_attach(jid, &smask); } +struct nproc_info { + long nproc_init; + long nproc_final; + long nproc_global; +}; + +ATF_TC(jail_nproc); +ATF_TC_HEAD(jail_nproc, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test that _SC_PROCESSORS_ONLN reflects jail cpuset constraints"); +} +ATF_TC_BODY(jail_nproc, tc) +{ + cpuset_t jmask; + struct nproc_info ninfo = { }; + int sockpair[2]; + cpusetid_t setid; + ssize_t readsz; + pid_t pid; + int fcpu, error, pfd, sock; + char okb = 0x7f, rcvb; + + skip_ltncpu_root(2, &jmask); + fcpu = CPU_FFS(&jmask) - 1; + + /* + * Just adjusting our affinity should not affect the number of + * processors considered online- we want to be sure that it's only + * adjusted if our jail's root set is. + */ + CPU_CLR(fcpu, &jmask); + error = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, + sizeof(jmask), &jmask); + ATF_REQUIRE_EQ(0, error); + ATF_REQUIRE(sysconf(_SC_NPROCESSORS_ONLN) > CPU_COUNT(&jmask)); + + ATF_REQUIRE_EQ(0, socketpair(PF_UNIX, SOCK_STREAM, 0, sockpair)); + + /* We'll wait on the procdesc, too, so we can fail faster if it dies. */ + ATF_REQUIRE((pid = pdfork(&pfd, 0)) != -1); + + if (pid == 0) { + /* First child sets up the jail. */ + sock = sockpair[SP_CHILD]; + close(sockpair[SP_PARENT]); + + error = create_jail(); + if (error != 0) + _exit(error); + + ninfo.nproc_init = sysconf(_SC_NPROCESSORS_ONLN); + + /* Signal the parent that we're jailed. */ + readsz = write(sock, &okb, sizeof(okb)); + assert(readsz == sizeof(okb)); + + /* Wait for parent to adjust our mask and signal OK. */ + readsz = read(sock, &rcvb, sizeof(rcvb)); + assert(readsz == sizeof(rcvb)); + assert(rcvb == okb); + + ninfo.nproc_final = sysconf(_SC_NPROCESSORS_ONLN); + ninfo.nproc_global = sysconf(_SC_NPROCESSORS_CONF); + readsz = write(sock, &ninfo, sizeof(ninfo)); + assert(readsz == sizeof(ninfo)); + + _exit(0); + } + + close(sockpair[SP_CHILD]); + sock = sockpair[SP_PARENT]; + + /* Wait for signal that they are jailed. */ + readsz = read(sock, &rcvb, sizeof(rcvb)); + assert(readsz == sizeof(rcvb)); + assert(rcvb == okb); + + /* Grab the cpuset id and adjust it. */ + error = cpuset_getid(CPU_LEVEL_ROOT, CPU_WHICH_PID, pid, &setid); + ATF_REQUIRE_EQ(0, error); + error = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_CPUSET, + setid, sizeof(jmask), &jmask); + ATF_REQUIRE_EQ(0, error); + + /* Signal OK to proceed. */ + readsz = write(sock, &okb, sizeof(okb)); + ATF_REQUIRE_EQ(sizeof(okb), readsz); + + /* Grab our final nproc info. */ + readsz = read(sock, &ninfo, sizeof(ninfo)); + ATF_REQUIRE_EQ(sizeof(ninfo), readsz); + + /* + * We set our own affinity to jmask, which is derived from *our* root + * set, at the beginning of the test. The jail would inherit from this + * set, so we just re-use that mask here to confirm that + * _SC_NPROCESSORS_ONLN did actually drop in response to us limiting the + * jail, and that its _SC_NPROCESSORS_CONF did not. + */ + ATF_REQUIRE_EQ(CPU_COUNT(&jmask) + 1, ninfo.nproc_init); + ATF_REQUIRE_EQ(CPU_COUNT(&jmask) + 1, ninfo.nproc_global); + ATF_REQUIRE_EQ(CPU_COUNT(&jmask), ninfo.nproc_final); +} + ATF_TC(badparent); ATF_TC_HEAD(badparent, tc) { @@ -686,6 +819,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, jail_attach_prevbase); ATF_TP_ADD_TC(tp, jail_attach_plain); ATF_TP_ADD_TC(tp, jail_attach_disjoint); + ATF_TP_ADD_TC(tp, jail_nproc); ATF_TP_ADD_TC(tp, badparent); return (atf_no_error()); }