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

Konstantin Khorenko khorenko at virtuozzo.com
Fri May 15 17:53:22 MSK 2026


The commit is pushed to "branch-rh10-6.12.0-55.52.1.5.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-55.52.1.5.25.vz10
------>
commit 264cb799c915abd7b01eb1d342a5d3de73006791
Author: Liu Kui <kui.liu at virtuozzo.com>
Date:   Fri Apr 24 13:44:15 2026 +0800

    fs/fuse kio: fix hung connection on vstorage-mount exit
    
    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>
    Acked-by: Alexey Kuznetsov <kuznet at virtuozzo.com>
    
    Feature: fuse: kRPC - single RPC for kernel and userspace
---
 fs/fuse/kio/pcs/pcs_krpc.c | 89 ++++++++++++++++++++++++++++++++++++----------
 fs/fuse/kio/pcs/pcs_krpc.h |  4 ++-
 2 files changed, 73 insertions(+), 20 deletions(-)

diff --git a/fs/fuse/kio/pcs/pcs_krpc.c b/fs/fuse/kio/pcs/pcs_krpc.c
index 374cbce9c3c4a..7d5a9619276df 100644
--- a/fs/fuse/kio/pcs/pcs_krpc.c
+++ b/fs/fuse/kio/pcs/pcs_krpc.c
@@ -650,7 +650,40 @@ 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(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;
@@ -683,29 +716,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;
 
-	krpcs->krpc_task = get_task_struct(tsk);
+	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->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;
+
+	wake_up_process(watcher);
 
-	return tsk;
+	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 +763,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 +1242,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 +1272,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 6a090ef66185b..427c598f01f7e 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;
 };
 


More information about the Devel mailing list