[PATCH RFC 5/5] sched: use kfree_nolock() instead of kfree_rcu()

From: Vlastimil Babka (SUSE)

Date: Fri Aug 07 2026 - 10:00:43 EST


In set_cpus_allowed_force() we use kfree_rcu() because kfree() is unsafe
under p->pi_lock.

With kfree_nolock() now being able to free arbitrary kmalloc() objects,
we can switch to kfree_nolock() and avoid the unnecessary rcu grace
period delay. Only in some cases the freeing might be deferred to
irq_work().

Signed-off-by: Vlastimil Babka (SUSE) <vbabka@xxxxxxxxxx>
---
kernel/sched/core.c | 9 ++-------
kernel/sched/sched.h | 7 +------
2 files changed, 3 insertions(+), 13 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 96226707c2f6..d2929e4e23f1 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2807,20 +2807,15 @@ void set_cpus_allowed_force(struct task_struct *p, const struct cpumask *new_mas
.user_mask = NULL,
.flags = SCA_USER, /* clear the user requested mask */
};
- union cpumask_rcuhead {
- cpumask_t cpumask;
- struct rcu_head rcu;
- };

scoped_guard (__task_rq_lock, p)
do_set_cpus_allowed(p, &ac);

/*
* Because this is called with p->pi_lock held, it is not possible
- * to use kfree() here (when PREEMPT_RT=y), therefore punt to using
- * kfree_rcu().
+ * to use kfree() here (when PREEMPT_RT=y), thus use kfree_nolock()
*/
- kfree_rcu((union cpumask_rcuhead *)ac.user_mask, rcu);
+ kfree_nolock(ac.user_mask);
}

int dup_user_cpus_ptr(struct task_struct *dst, struct task_struct *src,
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 56acf502ba26..6a8d0578e963 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -2886,12 +2886,7 @@ static inline bool task_allowed_on_cpu(struct task_struct *p, int cpu)

static inline cpumask_t *alloc_user_cpus_ptr(int node)
{
- /*
- * See set_cpus_allowed_force() above for the rcu_head usage.
- */
- int size = max_t(int, cpumask_size(), sizeof(struct rcu_head));
-
- return kmalloc_node(size, GFP_KERNEL, node);
+ return kmalloc_node(cpumask_size(), GFP_KERNEL, node);
}

static inline struct task_struct *get_push_task(struct rq *rq)

--
2.55.0