@@ -320,7 +320,7 @@ void proc_coredump_connector(struct task_struct *task)
send_msg(msg);
}
-void proc_exit_connector(struct task_struct *task)
+void proc_exit_connector(struct task_struct *task, __u32 uexit_code)
{
struct cn_msg *msg;
struct proc_event *ev;
@@ -337,7 +337,10 @@ void proc_exit_connector(struct task_struct *task)
ev->what = PROC_EVENT_EXIT;
ev->event_data.exit.process_pid = task->pid;
ev->event_data.exit.process_tgid = task->tgid;
- ev->event_data.exit.exit_code = task->exit_code;
+ if (task->exit_code == 0)
+ ev->event_data.exit.exit_code = uexit_code;
+ else
+ ev->event_data.exit.exit_code = task->exit_code;
ev->event_data.exit.exit_signal = task->exit_signal;
rcu_read_lock();
@@ -413,6 +416,10 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
if (msg->len == sizeof(*pinput)) {
pinput = (struct proc_input *)msg->data;
mc_op = pinput->mcast_op;
+ if (mc_op == PROC_CN_MCAST_NOTIFY) {
+ current->exit_code = pinput->uexit_code;
+ return;
+ }
ev_type = pinput->event_type;
} else if (msg->len == sizeof(mc_op)) {
mc_op = *((enum proc_cn_mcast_op *)msg->data);
@@ -27,7 +27,7 @@ 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);
+void proc_exit_connector(struct task_struct *task, __u32 uexit_code);
#else
static inline void proc_fork_connector(struct task_struct *task)
{}
@@ -52,7 +52,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)
+static inline void proc_exit_connector(struct task_struct *task,
+ __u32 uexit_code)
{}
#endif /* CONFIG_PROC_EVENTS */
#endif /* CN_PROC_H */
@@ -27,7 +27,8 @@
*/
enum proc_cn_mcast_op {
PROC_CN_MCAST_LISTEN = 1,
- PROC_CN_MCAST_IGNORE = 2
+ PROC_CN_MCAST_IGNORE = 2,
+ PROC_CN_MCAST_NOTIFY = 3
};
#define PROC_EVENT_ALL (PROC_EVENT_FORK | PROC_EVENT_EXEC | PROC_EVENT_UID | \
@@ -65,6 +66,7 @@ enum proc_cn_event {
struct proc_input {
enum proc_cn_mcast_op mcast_op;
enum proc_cn_event event_type;
+ __u32 uexit_code;
};
static inline enum proc_cn_event valid_event(enum proc_cn_event ev_type)
@@ -821,6 +821,7 @@ void __noreturn do_exit(long code)
{
struct task_struct *tsk = current;
int group_dead;
+ __u32 uexit_code;
WARN_ON(irqs_disabled());
@@ -863,6 +864,8 @@ void __noreturn do_exit(long code)
tty_audit_exit();
audit_free(tsk);
+ uexit_code = tsk->exit_code;
+
tsk->exit_code = code;
taskstats_exit(tsk, group_dead);
@@ -900,7 +903,7 @@ void __noreturn do_exit(long code)
exit_tasks_rcu_start();
exit_notify(tsk, group_dead);
- proc_exit_connector(tsk);
+ proc_exit_connector(tsk, uexit_code);
mpol_put_task_policy(tsk);
#ifdef CONFIG_FUTEX
if (unlikely(current->pi_state_cache))
Add a new type PROC_CN_MCAST_NOTIFY to proc connector API, which allows a thread to notify the kernel that it has exited abnormally. Thread can also send the exit status code it wants returned in the notification with it. Exiting thread can call this either when it wants to call pthread_exit() with non-zero value or from signal handler. Once kernel receives this, it saves this exit status in the thread's exit_code field of task_struct. This field is then checked when the thread actually exits, and if non-zero, it is copied to the notification to be sent. Signed-off-by: Anjali Kulkarni <anjali.k.kulkarni@oracle.com> --- drivers/connector/cn_proc.c | 11 +++++++++-- include/linux/cn_proc.h | 5 +++-- include/uapi/linux/cn_proc.h | 4 +++- kernel/exit.c | 5 ++++- 4 files changed, 19 insertions(+), 6 deletions(-)