io_uring: add task fork hook

Called when copy_process() is called to copy state to a new child.
Right now this is just a stub, but will be used shortly to properly
handle fork'ing of task based io_uring restrictions.

Reviewed-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Jens Axboe 2026-01-16 15:28:58 -07:00
parent e7f67c2be7
commit 9fd99788f3
4 changed files with 36 additions and 10 deletions

View file

@ -12,6 +12,7 @@ void __io_uring_free(struct task_struct *tsk);
void io_uring_unreg_ringfd(void);
const char *io_uring_get_opcode(u8 opcode);
bool io_is_uring_fops(struct file *file);
int __io_uring_fork(struct task_struct *tsk);
static inline void io_uring_files_cancel(void)
{
@ -25,9 +26,16 @@ static inline void io_uring_task_cancel(void)
}
static inline void io_uring_free(struct task_struct *tsk)
{
if (tsk->io_uring)
if (tsk->io_uring || tsk->io_uring_restrict)
__io_uring_free(tsk);
}
static inline int io_uring_fork(struct task_struct *tsk)
{
if (tsk->io_uring_restrict)
return __io_uring_fork(tsk);
return 0;
}
#else
static inline void io_uring_task_cancel(void)
{
@ -46,6 +54,10 @@ static inline bool io_is_uring_fops(struct file *file)
{
return false;
}
static inline int io_uring_fork(struct task_struct *tsk)
{
return 0;
}
#endif
#endif

View file

@ -1190,6 +1190,7 @@ struct task_struct {
#ifdef CONFIG_IO_URING
struct io_uring_task *io_uring;
struct io_restriction *io_uring_restrict;
#endif
/* Namespaces: */

View file

@ -54,16 +54,18 @@ void __io_uring_free(struct task_struct *tsk)
* node is stored in the xarray. Until that gets sorted out, attempt
* an iteration here and warn if any entries are found.
*/
xa_for_each(&tctx->xa, index, node) {
WARN_ON_ONCE(1);
break;
}
WARN_ON_ONCE(tctx->io_wq);
WARN_ON_ONCE(tctx->cached_refs);
if (tctx) {
xa_for_each(&tctx->xa, index, node) {
WARN_ON_ONCE(1);
break;
}
WARN_ON_ONCE(tctx->io_wq);
WARN_ON_ONCE(tctx->cached_refs);
percpu_counter_destroy(&tctx->inflight);
kfree(tctx);
tsk->io_uring = NULL;
percpu_counter_destroy(&tctx->inflight);
kfree(tctx);
tsk->io_uring = NULL;
}
}
__cold int io_uring_alloc_task_context(struct task_struct *task,
@ -351,3 +353,8 @@ int io_ringfd_unregister(struct io_ring_ctx *ctx, void __user *__arg,
return i ? i : ret;
}
int __io_uring_fork(struct task_struct *tsk)
{
return 0;
}

View file

@ -97,6 +97,7 @@
#include <linux/kasan.h>
#include <linux/scs.h>
#include <linux/io_uring.h>
#include <linux/io_uring_types.h>
#include <linux/bpf.h>
#include <linux/stackprotector.h>
#include <linux/user_events.h>
@ -2129,6 +2130,10 @@ __latent_entropy struct task_struct *copy_process(
#ifdef CONFIG_IO_URING
p->io_uring = NULL;
retval = io_uring_fork(p);
if (unlikely(retval))
goto bad_fork_cleanup_delayacct;
retval = -EAGAIN;
#endif
p->default_timer_slack_ns = current->timer_slack_ns;
@ -2525,6 +2530,7 @@ bad_fork_cleanup_policy:
mpol_put(p->mempolicy);
#endif
bad_fork_cleanup_delayacct:
io_uring_free(p);
delayacct_tsk_free(p);
bad_fork_cleanup_count:
dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);