git: c21b080f3dc2 - main - cpuset: Fix sched_[g|s]etaffinity() for better compatibility with Linux.

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

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

commit c21b080f3dc2f5e91ada608d4385b7ed6538ba9b
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2023-01-29 13:17:33 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2023-01-29 13:17:33 +0000

    cpuset: Fix sched_[g|s]etaffinity() for better compatibility with Linux.
    
    Under Linux to sched_[g|s]etaffinity() functions the value returned from a call
    to gettid(2) (thread id) can be passed in the argument pid. Specifying pid as 0
    will set the attribute for the calling thread, and passing the value returned
    from a call to getpid(2) (process id) will set the attribute for the main thread
    of the thread group.
    
    Native cpuset(2) family of system calls has "which" argument to determine how
    the value of id argument is interpreted, i.e., CPU_WHICH_TID is used to pass
    a thread id and CPU_WHICH_PID - to pass a process id.
    
    For now native sched_[g|s]etaffinity() implementation is wrong as uses "which"
    CPU_WHICH_PID to pass both (process and thread id) to the kernel. To fix this
    adding a new "which" CPU_WHICH_TIDPID intended to handle both id's.
    
    Reviewed by:            kib
    Differential Revision:  https://reviews.freebsd.org/D38209
    MFC after:              1 week
---
 lib/libc/gen/sched_getaffinity.c |  2 +-
 lib/libc/gen/sched_setaffinity.c |  2 +-
 lib/libc/sys/cpuset.2            |  4 +++-
 sys/kern/kern_cpuset.c           | 42 +++++++++++++++++++++++++++++++++++++++-
 sys/sys/cpuset.h                 |  1 +
 5 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/lib/libc/gen/sched_getaffinity.c b/lib/libc/gen/sched_getaffinity.c
index ed304c111985..95145a1eb019 100644
--- a/lib/libc/gen/sched_getaffinity.c
+++ b/lib/libc/gen/sched_getaffinity.c
@@ -35,7 +35,7 @@ sched_getaffinity(pid_t pid, size_t cpusetsz, cpuset_t *cpuset)
 {
 	int error;
 
-	error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+	error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TIDPID,
 	    pid == 0 ? -1 : pid, cpusetsz, cpuset);
 	if (error == -1 && errno == ERANGE)
 		errno = EINVAL;
diff --git a/lib/libc/gen/sched_setaffinity.c b/lib/libc/gen/sched_setaffinity.c
index 0052521cd081..36ed0f45d417 100644
--- a/lib/libc/gen/sched_setaffinity.c
+++ b/lib/libc/gen/sched_setaffinity.c
@@ -58,7 +58,7 @@ sched_setaffinity(pid_t pid, size_t cpusetsz, const cpuset_t *cpuset)
 			if (cpu > mp_maxid)
 				CPU_CLR(cpu, &c);
 	}
-	error = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
+	error = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TIDPID,
 	    pid == 0 ? -1 : pid, sizeof(cpuset_t), &c);
 	if (error == -1 && errno == EDEADLK)
 		errno = EINVAL;
diff --git a/lib/libc/sys/cpuset.2 b/lib/libc/sys/cpuset.2
index 8b17f537e7fa..854fc89bc232 100644
--- a/lib/libc/sys/cpuset.2
+++ b/lib/libc/sys/cpuset.2
@@ -26,7 +26,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 3, 2017
+.Dd January 29, 2023
 .Dt CPUSET 2
 .Os
 .Sh NAME
@@ -100,6 +100,7 @@ argument may have the following values:
 .Bl -column CPU_WHICH_INTRHANDLER -offset indent
 .It Dv CPU_WHICH_TID Ta "id is lwpid_t (thread id)"
 .It Dv CPU_WHICH_PID Ta "id is pid_t (process id)"
+.It Dv CPU_WHICH_TIDPID Ta "id is either a thread or process id"
 .It Dv CPU_WHICH_JAIL Ta "id is jid (jail id)"
 .It Dv CPU_WHICH_CPUSET Ta "id is a cpusetid_t (cpuset id)"
 .It Dv CPU_WHICH_IRQ Ta "id is an irq number"
@@ -115,6 +116,7 @@ of '-1' may be used with a
 of
 .Dv CPU_WHICH_TID ,
 .Dv CPU_WHICH_PID ,
+.Dv CPU_WHICH_TIDPID ,
 or
 .Dv CPU_WHICH_CPUSET
 to mean the current thread, process, or current thread's
diff --git a/sys/kern/kern_cpuset.c b/sys/kern/kern_cpuset.c
index 6dfe22b66689..ba0a15b86e01 100644
--- a/sys/kern/kern_cpuset.c
+++ b/sys/kern/kern_cpuset.c
@@ -927,6 +927,22 @@ cpuset_which(cpuwhich_t which, id_t id, struct proc **pp, struct thread **tdp,
 			return (ESRCH);
 		p = td->td_proc;
 		break;
+	case CPU_WHICH_TIDPID:
+		if (id == -1) {
+			PROC_LOCK(curproc);
+			td = curthread;
+			p = curproc;
+		} else if (id > PID_MAX) {
+			td = tdfind(id, -1);
+			if (td == NULL)
+				return (ESRCH);
+			p = td->td_proc;
+		} else {
+			p = pfind(id);
+			if (p == NULL)
+				return (ESRCH);
+		}
+		break;
 	case CPU_WHICH_CPUSET:
 		if (id == -1) {
 			thread_lock(curthread);
@@ -1739,7 +1755,11 @@ cpuset_check_capabilities(struct thread *td, cpulevel_t level, cpuwhich_t which,
 	if (IN_CAPABILITY_MODE(td)) {
 		if (level != CPU_LEVEL_WHICH)
 			return (ECAPMODE);
-		if (which != CPU_WHICH_TID && which != CPU_WHICH_PID)
+		if (which != CPU_WHICH_TID && which != CPU_WHICH_PID &&
+		    which != CPU_WHICH_TIDPID)
+			return (ECAPMODE);
+		if (id != -1 && which == CPU_WHICH_TIDPID &&
+		    id != td->td_tid && id != td->td_proc->p_pid)
 			return (ECAPMODE);
 		if (id != -1 &&
 		    !(which == CPU_WHICH_TID && id == td->td_tid) &&
@@ -1986,6 +2006,19 @@ kern_cpuset_getaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which,
 				thread_unlock(ttd);
 			}
 			break;
+		case CPU_WHICH_TIDPID:
+			if (id > PID_MAX || id == -1) {
+				thread_lock(ttd);
+				CPU_COPY(&ttd->td_cpuset->cs_mask, mask);
+				thread_unlock(ttd);
+				break;
+			}
+			FOREACH_THREAD_IN_PROC(p, ttd) {
+				thread_lock(ttd);
+				CPU_OR(mask, mask, &ttd->td_cpuset->cs_mask);
+				thread_unlock(ttd);
+			}
+			break;
 		case CPU_WHICH_CPUSET:
 		case CPU_WHICH_JAIL:
 			CPU_COPY(&set->cs_mask, mask);
@@ -2135,6 +2168,13 @@ kern_cpuset_setaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which,
 		case CPU_WHICH_PID:
 			error = cpuset_setproc(id, NULL, mask, NULL, false);
 			break;
+		case CPU_WHICH_TIDPID:
+			if (id > PID_MAX || id == -1)
+				error = cpuset_setthread(id, mask);
+			else
+				error = cpuset_setproc(id, NULL, mask, NULL,
+				    false);
+			break;
 		case CPU_WHICH_CPUSET:
 		case CPU_WHICH_JAIL:
 			error = cpuset_which(which, id, &p, &ttd, &set);
diff --git a/sys/sys/cpuset.h b/sys/sys/cpuset.h
index f8fc36b99aa7..55e1ec5def0c 100644
--- a/sys/sys/cpuset.h
+++ b/sys/sys/cpuset.h
@@ -109,6 +109,7 @@
 #define	CPU_WHICH_DOMAIN	6	/* Specifies a NUMA domain id. */
 #define	CPU_WHICH_INTRHANDLER	7	/* Specifies an irq # (not ithread). */
 #define	CPU_WHICH_ITHREAD	8	/* Specifies an irq's ithread. */
+#define	CPU_WHICH_TIDPID	9	/* Specifies a process or thread id. */
 
 /*
  * Reserved cpuset identifiers.