git: bb5f10e51bd5 - main - linux: implement sched_getattr()

From: Enji Cooper <ngie_at_FreeBSD.org>
Date: Mon, 05 Oct 2026 22:49:29 UTC
The branch main has been updated by ngie:

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

commit bb5f10e51bd53771f1a438f36f554256fcbd7d08
Author:     Enji Cooper <ngie@FreeBSD.org>
AuthorDate: 2026-10-05 22:48:22 +0000
Commit:     Enji Cooper <ngie@FreeBSD.org>
CommitDate: 2026-10-05 22:49:09 +0000

    linux: implement sched_getattr()
    
    This change adds the necessary glue to translate Linux scheduler policy
    and priority from FreeBSD so this information is available to Linux
    applications.
    
    This unbreaks using the Linux version of Chromium on FreeBSD.
    
    This change was originally submitted via [freebsd/freebsd-src#2370][github-pr].
    
    MFC after:      2 weeks
    PR:     297468
    Co-Authored-By: Enji Cooper <ngie@FreeBSD.org>
    Signed-off-by:  Joao Bonifacio <joaoboni017@gmail.com>
    
    [github-pr]: https://github.com/freebsd/freebsd-src/pull/2370
    
    Differential Revision:  https://reviews.freebsd.org/D60214
---
 sys/compat/linux/linux_dummy.c |  1 -
 sys/compat/linux/linux_misc.c  | 89 ++++++++++++++++++++++++++++++++++++++++++
 sys/compat/linux/linux_misc.h  | 19 ++++++++-
 3 files changed, 106 insertions(+), 3 deletions(-)

diff --git a/sys/compat/linux/linux_dummy.c b/sys/compat/linux/linux_dummy.c
index dfb1c90e9abf..873e2cef3879 100644
--- a/sys/compat/linux/linux_dummy.c
+++ b/sys/compat/linux/linux_dummy.c
@@ -97,7 +97,6 @@ DUMMY(process_vm_writev);
 /* Linux 3.8: */
 DUMMY(finit_module);
 DUMMY(sched_setattr);
-DUMMY(sched_getattr);
 /* Linux 3.18: */
 DUMMY(bpf);
 /* Linux 3.19: */
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index 65c9044dd3bd..9e7f6411df17 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -29,6 +29,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #include <sys/param.h>
 #include <sys/fcntl.h>
 #include <sys/jail.h>
@@ -116,6 +117,39 @@ struct l_pselect6arg {
 	l_size_t	ss_len;
 };
 
+/**
+ * `SCHED_ATTR_SIZE_VER0` represents the size of the initial published structure.
+ *
+ * See `linux/kernel/sched/syscalls.c` for more details.
+ */
+#define LINUX_SCHED_ATTR_SIZE_VER0 48
+/**
+ * Linux struct sched_attr
+ */
+struct linux_sched_attr {
+	l_uint 		size;
+	l_uint 		sched_policy;
+	uint64_t 	sched_flags;
+	int32_t  	sched_nice;
+	l_uint 		sched_priority;
+
+	uint64_t 	sched_runtime;
+	uint64_t 	sched_deadline;
+	uint64_t 	sched_period;
+
+	l_uint 		sched_util_min;
+	l_uint 		sched_util_max;
+};
+/**
+ * `.size` must be checked at runtime as well in the syscall to match the
+ * Linux implementation.
+ *
+ * This `_Static_assert(..)` is a sanity check to ensure that the structure
+ * meets the minimum expected bar.
+ */
+_Static_assert(sizeof(struct linux_sched_attr) >= LINUX_SCHED_ATTR_SIZE_VER0,
+    "struct linux_sched_attr size");
+
 static int	linux_utimensat_lts_to_ts(struct l_timespec *,
 			struct timespec *);
 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
@@ -1350,6 +1384,61 @@ linux_sched_getscheduler(struct thread *td,
 	return (error);
 }
 
+int
+linux_sched_getattr(struct thread *td, struct linux_sched_getattr_args *args)
+{
+	struct linux_sched_attr attr;
+	struct sched_param sched_param;
+	struct thread *tdt;
+	int error, policy;
+
+	if (args->attr == NULL || args->pid < 0 || args->flags != 0 ||
+	    args->size < LINUX_SCHED_ATTR_SIZE_VER0 || args->size > PAGE_SIZE)
+		return (EINVAL);
+
+	tdt = linux_tdfind(td, args->pid, -1);
+	if (tdt == NULL)
+		return (ESRCH);
+
+	error = kern_sched_getscheduler(td, tdt, &policy);
+	if (error) {
+		PROC_UNLOCK(tdt->td_proc);
+		return (error);
+	}
+
+	error = kern_sched_getparam(td, tdt, &sched_param);
+	PROC_UNLOCK(tdt->td_proc);
+	if (error)
+		return (error);
+
+	memset(&attr, 0, sizeof(attr));
+
+	attr.size = MIN(args->size, sizeof(attr));
+
+	if (linux_map_sched_prio) {
+		switch (policy) {
+		case SCHED_OTHER:
+			sched_param.sched_priority = 0;
+			break;
+		case SCHED_FIFO:
+		case SCHED_RR:
+			/**
+			 * Map [0, RTP_PRIO_MAX - RTP_PRIO_MIN] to
+			 * [1, LINUX_MAX_RT_PRIO - 1] (rounding up).
+			 */
+			sched_param.sched_priority =
+			    (sched_param.sched_priority *
+				    (LINUX_MAX_RT_PRIO - 1) +
+				(RTP_PRIO_MAX - RTP_PRIO_MIN - 1)) /
+				(RTP_PRIO_MAX - RTP_PRIO_MIN) + 1;
+			break;
+		}
+	}
+	attr.sched_priority = sched_param.sched_priority;
+
+	return (copyout(&attr, args->attr, args->size));
+}
+
 int
 linux_sched_get_priority_max(struct thread *td,
     struct linux_sched_get_priority_max_args *args)
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
index fb77784ddea8..44dd8e06fcb7 100644
--- a/sys/compat/linux/linux_misc.h
+++ b/sys/compat/linux/linux_misc.h
@@ -109,10 +109,25 @@
 #define	__LINUX_NPXCW__		0x37f
 #endif
 
-/* Scheduling policies */
-#define	LINUX_SCHED_OTHER	0
+/**
+ * Linux scheduling policies.
+ *
+ * Ref: `linux/include/uapi/linux/sched.h`
+ */
+#define	LINUX_SCHED_NORMAL	0
+/* `SCHED_OTHER` is a legacy alias for `SCHED_NORMAL`. */
+#define	LINUX_SCHED_OTHER	LINUX_SCHED_NORMAL
 #define	LINUX_SCHED_FIFO	1
 #define	LINUX_SCHED_RR		2
+/**
+ * FreeBSD does not implement analogs for these Linux scheduling policies. This
+ * is mostly here for reference and to be self-documenting in `sched_set*()`.
+ */
+#define	LINUX_SCHED_BATCH	3
+/* LINUX_SCHED_ISO: slot reserved, but not implemented upstream. */
+#define	LINUX_SCHED_IDLE	5
+#define	LINUX_SCHED_DEADLINE	6
+#define	LINUX_SCHED_EXT		7
 
 #define	LINUX_MAX_RT_PRIO	100