[Devel] [PATCH VZ10 v2] fs/fuse kio: fix hung connection on vstorage-mount exit

Alexey Kuznetsov kuznet at virtuozzo.com
Fri Apr 24 13:15:43 MSK 2026


Ack

On Fri, Apr 24, 2026 at 1:56 PM Liu Kui <kui.liu at virtuozzo.com> wrote:
>
> krpc_sender kthread holds a reference to vstorage-mount's file_struct,
> preventing /dev/fuse from closing after the process exits. This leaves
> the fuse connection without proper teardown and prevents systemd from
> restarting the vstorage-fs service.
>
> Fix this by adding a krpc_watcher kthread that monitors the userspace
> vstorage-mount process via its pidfd wait queue and stops the krpc_sender
> kthread when that process exits, triggering a clean fuse connection
> teardown and allowing systemd to restart the vstorage-fs service.
>
> Related to
> https://virtuozzo.atlassian.net/browse/VSTOR-128451
>
> Signed-off-by: Liu Kui <kui.liu at virtuozzo.com>
> ---
>  fs/fuse/kio/pcs/pcs_krpc.c | 93 ++++++++++++++++++++++++++++++--------
>  fs/fuse/kio/pcs/pcs_krpc.h |  4 +-
>  2 files changed, 77 insertions(+), 20 deletions(-)
>
> diff --git a/fs/fuse/kio/pcs/pcs_krpc.c b/fs/fuse/kio/pcs/pcs_krpc.c
> index 374cbce9c3c4..8c87feb78a34 100644
> --- a/fs/fuse/kio/pcs/pcs_krpc.c
> +++ b/fs/fuse/kio/pcs/pcs_krpc.c
> @@ -650,12 +650,49 @@ static void kreq_submit(struct krpc_req *kreq)
>         }
>  }
>
> -static int krpc_threadfn(void *data)
> +static bool process_has_exited(struct pid *pid)
> +{
> +       struct task_struct *t;
> +       bool exited = false;
> +
> +       rcu_read_lock();
> +       t = pid_task(pid, PIDTYPE_TGID);
> +
> +       if (!t || READ_ONCE(t->exit_state) != 0)
> +               exited = true;
> +       rcu_read_unlock();
> +
> +       return exited;
> +}
> +
> +static int krpc_watcher_fn(void *data)
> +{
> +       struct pcs_krpc_set *krpcs = data;
> +
> +       wait_event_interruptible(krpcs->watched_pid->wait_pidfd,
> +                       process_has_exited(krpcs->watched_pid) || kthread_should_stop());
> +
> +       kthread_stop(krpcs->sender_task);
> +       put_task_struct(krpcs->sender_task);
> +       krpcs->sender_task = NULL;
> +       mmput(krpcs->mm);
> +       krpcs->mm = NULL;
> +       put_pid(krpcs->watched_pid);
> +       krpcs->watched_pid = NULL;
> +
> +       return 0;
> +}
> +
> +static int krpc_sender_fn(void *data)
>  {
>         struct pcs_krpc_set *krpcs = data;
>         struct llist_node *ll;
>         struct krpc_req *kreq, *kreq_next;
>
> +       /* a rare case when creation of the watcher kthread failed */
> +       if (!krpcs->mm)
> +               return 0;
> +
>         kthread_use_mm(krpcs->mm);
>
>         for (;;) {
> @@ -683,29 +720,45 @@ static int krpc_threadfn(void *data)
>         return 0;
>  }
>
> -static struct task_struct *pcs_krpc_task_create(struct pcs_krpc_set *krpcs)
> +static struct task_struct *krpc_task_create(struct pcs_krpc_set *krpcs)
>  {
> -       struct task_struct *tsk;
> +       struct task_struct *sender, *watcher;
>         struct mm_struct *mm;
> +       struct pid *watched_pid;
>
> -       WARN_ON_ONCE(krpcs->krpc_task);
> +       WARN_ON_ONCE(krpcs->sender_task);
>
>         mm = get_task_mm(current);
>         if (!mm)
>                 return NULL;
>
> -       tsk = kthread_create(krpc_threadfn, krpcs, "krpc_send");
> -       if (!tsk || IS_ERR(tsk)) {
> -               mmput(mm);
> -               return NULL;
> -       }
> +       sender = kthread_create(krpc_sender_fn, krpcs, "krpc_sender");
> +       if (IS_ERR(sender))
> +               goto err_sender;
> +
> +       watched_pid = get_task_pid(current, PIDTYPE_TGID);
> +
> +       watcher = kthread_create(krpc_watcher_fn, krpcs, "krpc_watcher");
> +       if (IS_ERR(watcher))
> +               goto err_watcher;
>
> -       krpcs->krpc_task = get_task_struct(tsk);
> +       krpcs->watcher_task = get_task_struct(watcher);
> +       krpcs->watched_pid = watched_pid;
> +       krpcs->sender_task = get_task_struct(sender);
>         krpcs->mm = mm;
>         atomic_inc(&current->files->count);
> -       tsk->files = current->files;
> +       sender->files = current->files;
>
> -       return tsk;
> +       wake_up_process(watcher);
> +
> +       return sender;
> +
> +err_watcher:
> +       put_pid(watched_pid);
> +       kthread_stop(sender);
> +err_sender:
> +       mmput(mm);
> +       return NULL;
>  }
>
>  static int pcs_krpc_ioctl_send_msg(struct krpc_req *kreq)
> @@ -714,9 +767,9 @@ static int pcs_krpc_ioctl_send_msg(struct krpc_req *kreq)
>         struct pcs_krpc_set *krpcs = kreq->krpc->krpcs;
>
>         if (pcs_krpc_use_thread) {
> -               tsk = krpcs->krpc_task;
> +               tsk = krpcs->sender_task;
>                 if (unlikely(!tsk))
> -                       tsk = pcs_krpc_task_create(krpcs);
> +                       tsk = krpc_task_create(krpcs);
>
>                 if (likely(tsk)) {
>                         llist_add(&kreq->llist_link, &krpcs->req_llist);
> @@ -1193,8 +1246,10 @@ void pcs_krpcset_init(struct pcs_krpc_set *krpcs)
>
>         INIT_LIST_HEAD(&krpcs->list);
>         krpcs->nkrpc = 0;
> -       krpcs->krpc_task = NULL;
> +       krpcs->sender_task = NULL;
>         krpcs->mm = NULL;
> +       krpcs->watcher_task = NULL;
> +       krpcs->watched_pid = NULL;
>         init_llist_head(&krpcs->req_llist);
>         spin_lock_init(&krpcs->lock);
>  }
> @@ -1221,10 +1276,10 @@ void pcs_krpcset_fini(struct pcs_krpc_set *krpcs)
>         }
>         spin_unlock(&krpcs->lock);
>
> -       if (krpcs->krpc_task) {
> -               kthread_stop(krpcs->krpc_task);
> -               put_task_struct(krpcs->krpc_task);
> -               mmput(krpcs->mm);
> +       if (krpcs->watcher_task) {
> +               kthread_stop(krpcs->watcher_task);
> +               put_task_struct(krpcs->watcher_task);
> +               krpcs->watcher_task = NULL;
>         }
>         BUG_ON(!list_empty(&krpcs->list));
>         BUG_ON(krpcs->nkrpc != 0);
> diff --git a/fs/fuse/kio/pcs/pcs_krpc.h b/fs/fuse/kio/pcs/pcs_krpc.h
> index 6a090ef66185..427c598f01f7 100644
> --- a/fs/fuse/kio/pcs/pcs_krpc.h
> +++ b/fs/fuse/kio/pcs/pcs_krpc.h
> @@ -37,8 +37,10 @@ struct pcs_krpc_set {
>         unsigned int                    nkrpc;
>
>         spinlock_t                      lock;
> -       struct task_struct              *krpc_task;
> +       struct task_struct              *sender_task;
>         struct mm_struct                *mm;
> +       struct task_struct              *watcher_task;
> +       struct pid                      *watched_pid;
>         struct llist_head               req_llist;
>  };
>
> --
> 2.39.5 (Apple Git-154)



More information about the Devel mailing list