fork: add kernel_clone_args flag to not dup/clone files
authorMike Christie <michael.christie@oracle.com>
Fri, 10 Mar 2023 22:03:27 +0000 (16:03 -0600)
committerChristian Brauner (Microsoft) <brauner@kernel.org>
Sun, 12 Mar 2023 09:54:43 +0000 (10:54 +0100)
Each vhost device gets a thread that is used to perform IO and management
operations. Instead of a thread that is accessing a device, the thread is
part of the device, so when it creates a thread using a helper based on
copy_process we can't dup or clone the parent's files/FDS because it
would do an extra increment on ourself.

Later, when we do:

Qemu process exits:
        do_exit -> exit_files -> put_files_struct -> close_files

we would leak the device's resources because of that extra refcount
on the fd or file_struct.

This patch adds a no_files option so these worker threads can prevent
taking an extra refcount on themselves.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
Acked-by: Christian Brauner <brauner@kernel.org>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner (Microsoft) <brauner@kernel.org>
include/linux/sched/task.h
kernel/fork.c

index 2950e83..4f81604 100644 (file)
@@ -28,6 +28,7 @@ struct kernel_clone_args {
        u32 kthread:1;
        u32 io_thread:1;
        u32 user_worker:1;
+       u32 no_files:1;
        unsigned long stack;
        unsigned long stack_size;
        unsigned long tls;
index fb8ec19..f8d530f 100644 (file)
@@ -1627,7 +1627,8 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
        return 0;
 }
 
-static int copy_files(unsigned long clone_flags, struct task_struct *tsk)
+static int copy_files(unsigned long clone_flags, struct task_struct *tsk,
+                     int no_files)
 {
        struct files_struct *oldf, *newf;
        int error = 0;
@@ -1639,6 +1640,11 @@ static int copy_files(unsigned long clone_flags, struct task_struct *tsk)
        if (!oldf)
                goto out;
 
+       if (no_files) {
+               tsk->files = NULL;
+               goto out;
+       }
+
        if (clone_flags & CLONE_FILES) {
                atomic_inc(&oldf->count);
                goto out;
@@ -2259,7 +2265,7 @@ static __latent_entropy struct task_struct *copy_process(
        retval = copy_semundo(clone_flags, p);
        if (retval)
                goto bad_fork_cleanup_security;
-       retval = copy_files(clone_flags, p);
+       retval = copy_files(clone_flags, p, args->no_files);
        if (retval)
                goto bad_fork_cleanup_semundo;
        retval = copy_fs(clone_flags, p);