[Devel] [PATCH RHEL10 COMMIT] ve/sunrpc: Implement a per-ve sunrpc killer

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jun 15 20:34:24 MSK 2026


The commit is pushed to "branch-rh10-6.12.0-211.16.1.12.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-211.16.1.12.1.vz10
------>
commit 0ed374bd0965f8bd1afc3fc199398eb836aeff8c
Author: Vladimir Riabchun <vladimir.riabchun at virtuozzo.com>
Date:   Mon Jun 15 19:26:25 2026 +0200

    ve/sunrpc: Implement a per-ve sunrpc killer
    
    We currently have  /proc/<pid>/net/rpc/kill-tasks feature for
    aborting pending RPC tasks. To fast-stop container, we need
    to abort all RPC tasks, so we must iterate over all VE PIDs.
    
    There are several problems with this approach:
    1. In real life with cgroups-v2 we just process container
       init PID, all other network namespaces are ignored.
    2. There is a risk of breaking unrelated NFS connections if a PID,
       that was a container process, is reused while we are
       stopping container.
    3. This may be slow - container might have a lot of processes
       and a few network namespaces.
    
    To fix this all, create a per-ve interface for aborting
    RPC requests in all VE network namespaces.
    
    https://virtuozzo.atlassian.net/browse/VSTOR-126316
    
    Feature: nfs/nfsd: containerization
    Signed-off-by: Vladimir Riabchun <vladimir.riabchun at virtuozzo.com>
    Reviewed-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 include/linux/sunrpc/clnt.h |  1 +
 include/linux/ve.h          |  4 ++++
 kernel/ve/ve.c              | 46 +++++++++++++++++++++++++++++++++++++++++++++
 net/sunrpc/clnt.c           |  3 ++-
 net/sunrpc/sunrpc_syms.c    |  3 +++
 5 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 7c6e9413db96c..0c4c582a1f1c3 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -257,6 +257,7 @@ void		rpc_clnt_probe_trunked_xprts(struct rpc_clnt *,
 
 const char *rpc_proc_name(const struct rpc_task *task);
 
+void rpc_set_kill_net(struct net *net, bool new_value);
 int rpc_task_kill_proc_init(struct net *net);
 void rpc_task_kill_proc_fini(struct net *net);
 
diff --git a/include/linux/ve.h b/include/linux/ve.h
index b46899a447d15..7c5515548ad23 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -251,6 +251,8 @@ extern bool is_ve_init_net(const struct net *net);
 
 void ve_setup_task(struct task_struct *p, struct ve_struct *ve);
 
+void ve_set_rpc_kill_fn(void (*fn)(struct net *, bool));
+
 static inline struct vdso_image *ve_get_vdso_32(struct ve_struct *ve)
 {
 	return ve->vdso_32;
@@ -357,6 +359,8 @@ static inline int vz_security_protocol_check(struct net *net, int protocol) { re
 
 static inline void ve_setup_task(struct task_struct *p, struct ve_struct *ve) { }
 
+static inline void ve_set_rpc_kill_fn(void (*fn)(struct net *, bool)) { }
+
 static inline struct vdso_image *ve_get_vdso_32(struct ve_struct *ve)
 {
 	return (struct vdso_image *)&vdso_image_32;
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 231c0300e929d..7485ee4ad009a 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -96,6 +96,8 @@ EXPORT_SYMBOL(nr_ve);
 
 static DEFINE_IDR(ve_idr);
 
+static void (__rcu *rpc_kill_net_fn)(struct net *, bool);
+
 struct ve_struct *get_ve(struct ve_struct *ve)
 {
 	if (ve)
@@ -1474,6 +1476,45 @@ static ssize_t ve_write_ctty(struct kernfs_open_file *of, char *buf,
 	return ret;
 }
 
+void ve_set_rpc_kill_fn(void (*fn)(struct net *, bool))
+{
+	rcu_assign_pointer(rpc_kill_net_fn, fn);
+	/*
+	 * ve_rpc_kill_write might be using old function.
+	 * rpc_set_kill_net -> NULL is dangerous, block sunrpc exit while we use
+	 * functions from this module.
+	 */
+	if (!fn)
+		synchronize_rcu();
+}
+EXPORT_SYMBOL(ve_set_rpc_kill_fn);
+
+static int ve_rpc_kill_write(struct cgroup_subsys_state *css,
+				 struct cftype *cft, u64 val)
+{
+	struct net *net;
+	struct ve_struct *ve = css_to_ve(css);
+	void (*fn)(struct net *net, bool);
+
+	guard(rwsem_read)(&net_rwsem);	/* for_each_net protection */
+	guard(rcu)();			/* Begin rpc_kill_net_fn usage section */
+
+	fn = rcu_dereference(rpc_kill_net_fn);
+	if (!fn) {
+		pr_info_ratelimited("SUNRPC module is not loaded.\n");
+		return 0;
+	}
+
+	for_each_net(net) {
+		if (net->owner_ve != ve)
+			continue;
+		/* rpc_set_kill_net is atomic. */
+		fn(net, val);
+	}
+
+	return 0;
+}
+
 static struct cftype ve_cftypes[] = {
 
 	{
@@ -1569,6 +1610,11 @@ static struct cftype ve_cftypes[] = {
 		.flags			= CFTYPE_ONLY_ON_ROOT,
 		.write			= ve_write_ctty,
 	},
+	{
+		.name			= "rpc_kill",
+		.flags			= CFTYPE_NOT_ON_ROOT,
+		.write_u64		= ve_rpc_kill_write,
+	},
 	{ }
 };
 
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index d794a4af01bcd..4d52ea3eb17c6 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -3433,8 +3433,9 @@ rpc_clnt_swap_deactivate(struct rpc_clnt *clnt)
 EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate);
 #endif /* CONFIG_SUNRPC_SWAP */
 
-static void rpc_set_kill_net(struct net *net, bool new_value)
+void rpc_set_kill_net(struct net *net, bool new_value)
 {
+	/* Note: function must be atomic, used under RCU read-lock. */
 	struct rpc_clnt *clnt;
 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 	if (sn->kill_tasks == new_value)
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index bab6cab294052..7e957b482fde7 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -13,6 +13,7 @@
 #include <linux/uio.h>
 #include <linux/unistd.h>
 #include <linux/init.h>
+#include <linux/ve.h>
 
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/clnt.h>
@@ -114,6 +115,7 @@ init_sunrpc(void)
 #endif
 	svc_init_xprt_sock();	/* svc sock transport */
 	init_socket_xprt();	/* clnt sock transport */
+	ve_set_rpc_kill_fn(rpc_set_kill_net);
 	return 0;
 
 out5:
@@ -131,6 +133,7 @@ init_sunrpc(void)
 static void __exit
 cleanup_sunrpc(void)
 {
+	ve_set_rpc_kill_fn(NULL);
 	rpc_sysfs_exit();
 	rpc_cleanup_clids();
 	xprt_cleanup_ids();


More information about the Devel mailing list