[Devel] [PATCH VZ10 v3 2/2] ve/sunrpc: Implement a per-ve sunrpc killer

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jun 15 20:33:22 MSK 2026


● Here's what I changed (both folded into commit 2, ve/sunrpc: Implement a per-ve sunrpc killer):

  1. include/linux/ve.h - fixed the !CONFIG_VE stub signature
  -static inline void ve_set_rpc_kill_fn(void (*fn)(struct net *)) { }
  +static inline void ve_set_rpc_kill_fn(void (*fn)(struct net *, bool)) { }
  The stub was missing the bool parameter, so it didn't match the real prototype void ve_set_rpc_kill_fn(void (*fn)(struct
  net *, bool)). With CONFIG_VE=n, init_sunrpc() passes rpc_set_kill_net (a void(struct net *, bool)) into a void(*)(struct
  net *) parameter - an incompatible-function-pointer-type error. Builds with CONFIG_VE=y (our case) never hit this path, so
  it didn't break our build, but it's a real defect in the stub.

  2. kernel/ve/ve.c - fixed a stale name in a comment
  - * rpc_kill_tasks -> NULL is dangerous, block sunrpc exit while we use
  + * rpc_set_kill_net -> NULL is dangerous, block sunrpc exit while we use
  The comment inside ve_set_rpc_kill_fn() referred to rpc_kill_tasks, which no longer exists - patch 1 renamed it to
  rpc_set_kill_net. Comment-only, no logic change.

  Both edits modified already-added lines, so the diffstat is unchanged (5 files, +56/-1), and the author (Vladimir
  Riabchun) is preserved.

--
Best regards,

Konstantin Khorenko,
Virtuozzo Linux Kernel Team

On 6/5/26 20:33, Vladimir Riabchun wrote:
> 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: improve kill-tasks
> Signed-off-by: Vladimir Riabchun <vladimir.riabchun 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 0133aeba248a..18cd2a043fb9 100644
> --- a/include/linux/sunrpc/clnt.h
> +++ b/include/linux/sunrpc/clnt.h
> @@ -253,6 +253,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 224acf012821..25c2dbef03f1 100644
> --- a/include/linux/ve.h
> +++ b/include/linux/ve.h
> @@ -279,6 +279,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));
> +
>  #else	/* CONFIG_VE */
>  #include <linux/init_task.h>
>  #define get_ve(ve)	((void)(ve), NULL)
> @@ -336,6 +338,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 *)) { }
> +
>  #endif	/* CONFIG_VE */
>  
>  struct seq_file;
> diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
> index 198c82f010cc..8e9473c4742d 100644
> --- a/kernel/ve/ve.c
> +++ b/kernel/ve/ve.c
> @@ -113,6 +113,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)
> @@ -1713,6 +1715,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_kill_tasks -> 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[] = {
>  
>  	{
> @@ -1808,6 +1849,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 0b7f69eb910d..dd3b22596b64 100644
> --- a/net/sunrpc/clnt.c
> +++ b/net/sunrpc/clnt.c
> @@ -3406,8 +3406,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 bab6cab29405..7e957b482fde 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