FAILED: patch "[PATCH] fork: release the files of a failed fork after" failed to apply to 6.1-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x 296a98c1fa50778c3b31eebed1a3f903f9684349
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026102801-oaf-percolate-96a4@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 296a98c1fa50778c3b31eebed1a3f903f9684349 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Mon, 21 Sep 2026 15:44:56 +0200
Subject: [PATCH] fork: release the files of a failed fork after
sched_cancel_fork()
Reorder copy_process() cleanup so sched_fork() taking scx_fork_rwsem scx_pre_fork() is safe and isn't held around exiting files. Right now, a fork that fails while another thread closed the bpf link fd will deadlock against its own read side. It also blocks every fork on the system:
copy_process() holds scx_fork_rwsem for read
exit_files()
close_files()
filp_close_sync()
bpf_scx_unreg()
kthread_flush_work() waits for the disable work
scx_root_disable()
percpu_down_write(&scx_fork_rwsem)
Simply release the child's files after sched_cancel_fork() dropped the lock. The task starts out as a copy of its parent so p->files points to the parent's table until copy_files() replaces it. exit_files() must not run for a fork that failed before that. Clear p->files up front so exit_files() is a no-op for those and make copy_files() set it explicitly for CLONE_FILES.
kernel/fork.c +6 -3
@@ -1676,6 +1676,7 @@ static int copy_files(u64 clone_flags, struct task_struct *tsk,if (clone_flags &CLONE_FILES ) {atomic_inc (&oldf->count); + tsk->files = oldf;return 0 ; }
@@ -2199,6 +2200,8 @@ __latent_entropy struct task_struct *copy_process(INIT_LIST_HEAD (&p->sibling);rcu_copy_process (p); p->vfork_done =NULL ; +/* Set by copy_files(), exit_files() on the error path skips NULL. */ + p->files =NULL ;spin_lock_init (&p->alloc_lock);init_sigpending (&p->pending);
@@ -2300,7 +2303,7 @@ __latent_entropy struct task_struct *copy_process( goto bad_fork_cleanup_semundo; retval =copy_fs (clone_flags, p, args->umh);if (retval) - goto bad_fork_cleanup_files; + goto bad_fork_cleanup_semundo; retval =copy_sighand (clone_flags, p);if (retval) goto bad_fork_cleanup_fs;
@@ -2613,8 +2616,6 @@ __latent_entropy struct task_struct *copy_process(__cleanup_sighand (p->sighand); bad_fork_cleanup_fs:exit_fs (p);/* blocking */ -bad_fork_cleanup_files: -exit_files (p);/* blocking */ bad_fork_cleanup_semundo:exit_sem (p); bad_fork_cleanup_security:
@@ -2625,6 +2626,8 @@ __latent_entropy struct task_struct *copy_process(perf_event_free_task (p); bad_fork_sched_cancel_fork:sched_cancel_fork (p); +/* ->release() of a file may need scx_fork_rwsem for write. */ +exit_files (p);/* blocking */ bad_fork_cleanup_policy:lockdep_free_task (p);#ifdef CONFIG_NUMA
Sasha Levin
maintainerPATCH 1/2 sched: Allow sched_cgroup_fork() to fail and introduce sched_cancel_fork()
From: Tejun Heo <[email protected]>
[ Upstream commit 304b3f2bc07ba7c74a1ebc7917a8f0549e6b8d54 ]
A new BPF extensible sched_class will need more control over the forking process. It wants to be able to fail from sched_cgroup_fork() after the new task's sched_task_group is initialized so that the loaded BPF program can prepare the task with its cgroup association is established and reject fork if e.g. allocation fails.
Allow sched_cgroup_fork() to fail by making it return int instead of void and adding sched_cancel_fork() to undo sched_fork() in the error path.
sched_cgroup_fork() doesn't fail yet and this patch shouldn't cause any behavior changes.
v2: Patch description updated to detail the expected use.
Stable-dep-of: 296a98c1fa50 ("fork: release the files of a failed fork after sched_cancel_fork()")
--- include/linux/sched/task.h | 3 ++- kernel/fork.c | 15 ++++++++++----- kernel/sched/core.c | 8 +++++++- 3 files changed, 19 insertions(+), 7 deletions(-)
include/linux/sched/task.h +2 -1
@@ -59,7 +59,8 @@ extern asmlinkage void schedule_tail(struct task_struct *prev);extern void init_idle (struct task_struct *idle,int cpu);extern int sched_fork (unsigned long clone_flags,struct task_struct *p); -extern void sched_cgroup_fork (struct task_struct *p,struct kernel_clone_args *kargs); +extern int sched_cgroup_fork (struct task_struct *p,struct kernel_clone_args *kargs); +extern void sched_cancel_fork (struct task_struct *p);extern void sched_post_fork (struct task_struct *p);extern void sched_dead (struct task_struct *p);
kernel/fork.c +10 -5
@@ -2335,7 +2335,7 @@ static __latent_entropy struct task_struct *copy_process( retval =perf_event_init_task (p, clone_flags);if (retval) - goto bad_fork_cleanup_policy; + goto bad_fork_sched_cancel_fork; retval =audit_alloc (p);if (retval) goto bad_fork_cleanup_perf;
@@ -2468,7 +2468,9 @@ static __latent_entropy struct task_struct *copy_process(* cgroup specific, it unconditionally needs to place the task on a * runqueue. */ -sched_cgroup_fork (p, args); + retval =sched_cgroup_fork (p, args); +if (retval) + goto bad_fork_cancel_cgroup;/* * From this point on we must avoid any synchronous user-space
@@ -2514,13 +2516,13 @@ static __latent_entropy struct task_struct *copy_process(/* Don't start children in a dying pid namespace */ if (unlikely (!(ns_of_pid (pid)->pid_allocated &PIDNS_ADDING ))) { retval = -ENOMEM ; - goto bad_fork_cancel_cgroup; + goto bad_fork_core_free; }/* Let kill terminate clone/fork in the middle */ if (fatal_signal_pending (current)) { retval = -EINTR ; - goto bad_fork_cancel_cgroup; + goto bad_fork_core_free; }/* No more failure paths after this point. */
@@ -2595,10 +2597,11 @@ static __latent_entropy struct task_struct *copy_process(return p; -bad_fork_cancel_cgroup: +bad_fork_core_free:sched_core_free (p);spin_unlock (¤t->sighand->siglock);write_unlock_irq (&tasklist_lock); +bad_fork_cancel_cgroup:cgroup_cancel_fork (p, args); bad_fork_put_pidfd:if (clone_flags &CLONE_PIDFD ) {
@@ -2637,6 +2640,8 @@ static __latent_entropy struct task_struct *copy_process(audit_free (p); bad_fork_cleanup_perf:perf_event_free_task (p); +bad_fork_sched_cancel_fork: +sched_cancel_fork (p); bad_fork_cleanup_policy:lockdep_free_task (p);#ifdef CONFIG_NUMA
kernel/sched/core.c +7 -1
@@ -4670,7 +4670,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)return 0 ; } -void sched_cgroup_fork (struct task_struct *p,struct kernel_clone_args *kargs) +int sched_cgroup_fork (struct task_struct *p,struct kernel_clone_args *kargs) {unsigned long flags;
@@ -4697,6 +4697,12 @@ void sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs)if (p->sched_class->task_fork) p->sched_class->task_fork (p);raw_spin_unlock_irqrestore (&p->pi_lock, flags); + +return 0 ; +} + +void sched_cancel_fork (struct task_struct *p) +{ }void sched_post_fork (struct task_struct *p)
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 fork: release the files of a failed fork after sched_cancel_fork()
From: Christian Brauner <[email protected]>
[ Upstream commit 296a98c1fa50778c3b31eebed1a3f903f9684349 ]
Reorder copy_process() cleanup so sched_fork() taking scx_fork_rwsem scx_pre_fork() is safe and isn't held around exiting files. Right now, a fork that fails while another thread closed the bpf link fd will deadlock against its own read side. It also blocks every fork on the system:
copy_process() holds scx_fork_rwsem for read
exit_files()
close_files()
filp_close_sync()
bpf_scx_unreg()
kthread_flush_work() waits for the disable work
scx_root_disable()
percpu_down_write(&scx_fork_rwsem)
Simply release the child's files after sched_cancel_fork() dropped the lock. The task starts out as a copy of its parent so p->files points to the parent's table until copy_files() replaces it. exit_files() must not run for a fork that failed before that. Clear p->files up front so exit_files() is a no-op for those and make copy_files() set it explicitly for CLONE_FILES.
--- kernel/fork.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
kernel/fork.c +6 -3
@@ -1645,6 +1645,7 @@ static int copy_files(unsigned long clone_flags, struct task_struct *tsk)if (clone_flags &CLONE_FILES ) {atomic_inc (&oldf->count); + tsk->files = oldf;return 0 ; }
@@ -2250,6 +2251,8 @@ static __latent_entropy struct task_struct *copy_process(INIT_LIST_HEAD (&p->sibling);rcu_copy_process (p); p->vfork_done =NULL ; +/* Set by copy_files(), exit_files() on the error path skips NULL. */ + p->files =NULL ;spin_lock_init (&p->alloc_lock);init_sigpending (&p->pending);
@@ -2352,7 +2355,7 @@ static __latent_entropy struct task_struct *copy_process( goto bad_fork_cleanup_semundo; retval =copy_fs (clone_flags, p);if (retval) - goto bad_fork_cleanup_files; + goto bad_fork_cleanup_semundo; retval =copy_sighand (clone_flags, p);if (retval) goto bad_fork_cleanup_fs;
@@ -2630,8 +2633,6 @@ static __latent_entropy struct task_struct *copy_process(__cleanup_sighand (p->sighand); bad_fork_cleanup_fs:exit_fs (p);/* blocking */ -bad_fork_cleanup_files: -exit_files (p);/* blocking */ bad_fork_cleanup_semundo:exit_sem (p); bad_fork_cleanup_security:
@@ -2642,6 +2643,8 @@ static __latent_entropy struct task_struct *copy_process(perf_event_free_task (p); bad_fork_sched_cancel_fork:sched_cancel_fork (p); +/* ->release() of a file may need scx_fork_rwsem for write. */ +exit_files (p);/* blocking */ bad_fork_cleanup_policy:lockdep_free_task (p);#ifdef CONFIG_NUMA
Signature · 1 line
2.53.0