[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(¤t->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