[Devel] [PATCH VZ10] proc connector: pin task VE for the exit event notification

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Thu Aug 13 19:41:54 MSK 2026


Reviewed-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>

On 8/13/26 13:13, Vasileios Almpanis wrote:
> The exit event is reported after exit_notify(), so the parent might have
> been woken up and reaped the exiting task via wait() -> release_task()
> -> exit_ve_namespace(), which resets tsk->task_ve to ve0. If that wins
> the race against the exiting task then the event will only be delivered
> to the host VE listeners and the in-VE listeners will be skipped. For a
> task inside a container this means the listener never receives an exit
> event.
> 
> The issue is caught by the LTP suite_kernel_misc.exec.cn_pec_sh test:
> pec_listener terminates upon receiving the exit event of the pid given
> via -p. When the lost exit event is a child's one, the test fails:
> 
>   cn_pec 3 TFAIL: Event was not detected by the event listener:
>                   exit pid: 58388 exit_code: 0 exit_signal: 17
> 
> and when it is the event generator's own exit event, the listener
> polls the netlink socket forever and the test hangs until the LTP
> timeout kills it (~8h on coverage kernels):
> 
> 22:51:37 cn_pec 2 TINFO: Testing exec event (nevents=10)
> 07:11:37 Test timed out, sending SIGTERM!
> 
> The race was captured using kprobes on the connector send path:
>   p:cnp/pexit proc_exit_connector task=$arg1:x64
>   p:cnp/vexit exit_ve_namespace task=$arg1:x64
>   p:cnp/pevcve proc_event_connector_ve what=$arg3:u32
>   r:cnp/cnsend cn_netlink_send_mult_ve ret=$retval:s64
> 
> A normal exit looks like:
>   pexit -> pevcve(ve) -> cnsend ret=0 -> pevcve(ve0)
> 
> The lost event (task 0xffff89a506d73980 is the exiting child, reaped by
> its parent pid 465820 in between):
> 
>  465831 [001] pexit: (proc_exit_connector) task=0xffff89a506d73980
>  465820 [002] vexit: (exit_ve_namespace) task=0xffff89a506d73980
>  465831 [001] pevcve: (proc_event_connector_ve) what=2147483648
> 
> Only one proc_event_connector_ve() call fires (ve0, no listeners) and
> cn_netlink_send_mult_ve() is never reached: the event is dropped.
> 
> This is the same race window that commit c565cc211694 ("proc
> connector: report proper pid/tgid of an exited process") closed for
> the task pid/tgid, but nothing pins the VE.
> 
> Reproducer (fails within ~50 iterations in a CT on a coverage kernel):
> 
>   cd /opt/ltp/testcases/bin/
>   export PATH=$PATH:/opt/ltp/testcases/bin
>   for i in $(seq 1 1024); do cn_pec.sh >/dev/null 2>&1 || break; done
> 
> Solve this the same way. Pin the VE in do_exit() before exit_notify()
> is called and use it in proc_exit_connector() instead of re-reading
> task->task_ve.
> 
> https://virtuozzo.atlassian.net/browse/VSTOR-140421
> Fixes: 95fa2f096b72 ("ve: Introduce VE namespace")
> Signed-off-by: Vasileios Almpanis <vasileios.almpanis at virtuozzo.com>
> 
> Feature: ve: ve generic structures
> ---
>  drivers/connector/cn_proc.c | 10 ++++++++--
>  include/linux/cn_proc.h     |  7 +++++--
>  kernel/exit.c               |  5 ++++-
>  3 files changed, 17 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
> index d41c8aca1866..cd75f1820914 100644
> --- a/drivers/connector/cn_proc.c
> +++ b/drivers/connector/cn_proc.c
> @@ -362,9 +362,15 @@ static bool fill_exit_event(struct proc_event *ev, struct ve_struct *ve,
>  	return true;
>  }
>  
> -void proc_exit_connector(struct task_struct *task, struct pids *pids)
> +void proc_exit_connector(struct task_struct *task, struct pids *pids,
> +			 struct ve_struct *ve)
>  {
> -	proc_event_connector(task, PROC_EVENT_EXIT, (long)pids, fill_exit_event);
> +	if (!ve_is_super(ve))
> +		proc_event_connector_ve(task, ve, PROC_EVENT_EXIT, (long)pids,
> +					fill_exit_event);
> +
> +	proc_event_connector_ve(task, get_ve0(), PROC_EVENT_EXIT, (long)pids,
> +				fill_exit_event);
>  }
>  
>  /*
> diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h
> index 9701c13d82df..0e545774aa81 100644
> --- a/include/linux/cn_proc.h
> +++ b/include/linux/cn_proc.h
> @@ -17,6 +17,7 @@
>  #ifndef CN_PROC_H
>  #define CN_PROC_H
>  
> +#include <linux/ve.h>
>  #include <uapi/linux/cn_proc.h>
>  
>  /*
> @@ -36,7 +37,8 @@ void proc_sid_connector(struct task_struct *task);
>  void proc_ptrace_connector(struct task_struct *task, int which_id);
>  void proc_comm_connector(struct task_struct *task);
>  void proc_coredump_connector(struct task_struct *task);
> -void proc_exit_connector(struct task_struct *task, struct pids *pids);
> +void proc_exit_connector(struct task_struct *task, struct pids *pids,
> +			 struct ve_struct *ve);
>  #else
>  static inline void proc_fork_connector(struct task_struct *task)
>  {}
> @@ -61,7 +63,8 @@ static inline void proc_ptrace_connector(struct task_struct *task,
>  static inline void proc_coredump_connector(struct task_struct *task)
>  {}
>  
> -static inline void proc_exit_connector(struct task_struct *task, struct pids *pids)
> +static inline void proc_exit_connector(struct task_struct *task, struct pids *pids,
> +				       struct ve_struct *ve)
>  {}
>  #endif	/* CONFIG_PROC_EVENTS */
>  #endif	/* CN_PROC_H */
> diff --git a/kernel/exit.c b/kernel/exit.c
> index 448a734270a7..94d9bddae2b8 100644
> --- a/kernel/exit.c
> +++ b/kernel/exit.c
> @@ -936,6 +936,7 @@ void __noreturn do_exit(long code)
>  	struct task_struct *tsk = current;
>  	int group_dead;
>  	struct pids pids;
> +	struct ve_struct *ve;
>  
>  	WARN_ON(irqs_disabled());
>  
> @@ -1021,8 +1022,10 @@ void __noreturn do_exit(long code)
>  	exit_tasks_rcu_start();
>  	pids.pid = get_pid(task_pid(tsk));
>  	pids.tgid = get_pid(task_tgid(tsk));
> +	ve = get_task_ve(tsk);
>  	exit_notify(tsk, group_dead);
> -	proc_exit_connector(tsk, &pids);
> +	proc_exit_connector(tsk, &pids, ve);
> +	put_ve(ve);
>  	put_pid(pids.tgid);
>  	put_pid(pids.pid);
>  	mpol_put_task_policy(tsk);
> 
> ---
> base-commit: 209f11f2c454a88761fb8f0a820fa22b6feae720
> change-id: 20260813-connectors-3571be4ae57b
> 

-- 
Best regards, Pavel Tikhomirov
Senior Software Developer, Virtuozzo.



More information about the Devel mailing list