[RFC PATCH 5/7] sched/cache: Allow a process to enable cache aware scheduling via prctl

From: Tim Chen

Date: Fri Aug 28 2026 - 18:26:51 EST


Add the PR_SCHED_CACHE_ENABLE and PR_SCHED_CACHE_DISABLE subops to the
PR_SCHED_CACHE prctl interface, allowing a process to turn cache aware
scheduling on or off.

int prctl(PR_SCHED_CACHE, unsigned long subop, pid_t pid,
unsigned long cookie, unsigned long type);

/* disable cache aware scheduling for this task */
prctl(PR_SCHED_CACHE, PR_SCHED_CACHE_DISABLE, 0, 0, PIDTYPE_PID);

/* enable cache aware scheduling for this task */
prctl(PR_SCHED_CACHE, PR_SCHED_CACHE_ENABLE, 0, 0, PIDTYPE_PID);

pid 0 targets the calling task; otherwise the group of the given pid is
used. Both return -ENOENT when the task has no cache scheduling group.

Co-developed-by: Chen Yu <yu.c.chen@xxxxxxxxx>
Signed-off-by: Chen Yu <yu.c.chen@xxxxxxxxx>
Signed-off-by: Tim Chen <tim.c.chen@xxxxxxxxxxxxxxx>
---
include/linux/sched.h | 1 +
include/uapi/linux/prctl.h | 4 +++-
kernel/sched/cache_sched.c | 15 +++++++++++++++
kernel/sched/fair.c | 6 ++++++
4 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 79f0079c3aa1..1529730c91a5 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2399,6 +2399,7 @@ struct sched_cache_group {
unsigned long next_scan;
unsigned long footprint;
int cpu;
+ int enabled;
refcount_t refcnt;
struct rcu_head rcu;
} ____cacheline_aligned_in_smp;
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index fed7bb028f9a..3fb31c4ab7b5 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -421,6 +421,8 @@ struct prctl_mm_map {
# define PR_SCHED_CACHE_GET 0
# define PR_SCHED_CACHE_CREATE 1
# define PR_SCHED_CACHE_SHARE_FROM 2
-# define PR_SCHED_CACHE_MAX 3
+# define PR_SCHED_CACHE_DISABLE 3
+# define PR_SCHED_CACHE_ENABLE 4
+# define PR_SCHED_CACHE_MAX 5

#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sched/cache_sched.c b/kernel/sched/cache_sched.c
index d1932f0c5ee8..c4ec6c553cca 100644
--- a/kernel/sched/cache_sched.c
+++ b/kernel/sched/cache_sched.c
@@ -60,6 +60,7 @@ static void sched_cache_group_init(struct sched_cache_group *grp,
grp->next_scan = jiffies;
grp->nr_running_avg = 0;
grp->footprint = 0;
+ grp->enabled = 1;
refcount_set(&grp->refcnt, 1);
/*
* The update to grp->pcpu_sched should not be reordered
@@ -261,6 +262,20 @@ int sched_cache_prctl(int option, unsigned long arg2, unsigned long arg3,
}

switch (arg2) {
+ case PR_SCHED_CACHE_DISABLE:
+ case PR_SCHED_CACHE_ENABLE:
+ /*
+ * Setting a single task is OK, because the sched_cache_group is
+ * shared by multiple tasks, setting one equals to setting all.
+ */
+ grp = task_cache_group_get(dst);
+ if (!grp) {
+ err = -ENOENT;
+ goto out_task;
+ }
+ WRITE_ONCE(grp->enabled, arg2 == PR_SCHED_CACHE_ENABLE);
+
+ goto out_group;
case PR_SCHED_CACHE_GET: {
unsigned long id = 0;

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d422b62ba987..e7c8b031946c 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -1652,6 +1652,9 @@ static int get_pref_llc(struct task_struct *p, struct sched_cache_group *grp)
if (!grp)
return -1;

+ if (!READ_ONCE(grp->enabled))
+ return -1;
+
mm_sched_cpu = READ_ONCE(grp->cpu);
if (mm_sched_cpu != -1) {
mm_sched_llc = llc_id(mm_sched_cpu);
@@ -1743,6 +1746,9 @@ static void task_tick_cache(struct rq *rq, struct task_struct *p)
!grp->pcpu_sched)
return;

+ if (!READ_ONCE(grp->enabled))
+ return;
+
epoch = rq->cpu_epoch;
/* avoid moving backwards */
if (time_after_eq(grp->epoch, epoch))
--
2.32.0