The initial task scan runs before the first patch registers the task exit
tracepoint. A task can begin exiting after it was selected by the scan but
before the exit handler is attached. sched_process_exit runs before
exit_notify() removes the task from the task list, so the scan could then
store a pointer to the exiting task's deadline entity after its cleanup
event had already been missed.

Initialize the shard state and attach the new-task, exit, and syscall
tracepoints before the initial scan. Make the scan use the same
PF_EXITING-aware creation helper as dynamic policy changes. On failure,
detach those tracepoints before destroying the monitor storage.

Fixes: b133207deb72 ("rv: Add nomiss deadline monitor")
Signed-off-by: Li Qiang <[email protected]>
---
 kernel/trace/rv/monitors/deadline/deadline.h | 27 ++++++++++-------
 kernel/trace/rv/monitors/nomiss/nomiss.c     | 18 +++++++----
 2 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/kernel/trace/rv/monitors/deadline/deadline.h 
b/kernel/trace/rv/monitors/deadline/deadline.h
index b92480e79807..4626d6e2b218 100644
--- a/kernel/trace/rv/monitors/deadline/deadline.h
+++ b/kernel/trace/rv/monitors/deadline/deadline.h
@@ -181,6 +181,8 @@ static void deadline_storage_init(void)
        }
 }
 
+static int deadline_create_task_storage(struct task_struct *task);
+
 /*
  * Initialise monitors for all tasks and pre-allocate the storage for servers.
  * This is necessary since we don't have access to the servers here and
@@ -190,9 +192,7 @@ static void deadline_storage_init(void)
 static inline int init_storage(bool skip_tasks)
 {
        struct task_struct *g, *p;
-       int cpu;
-
-       deadline_storage_init();
+       int cpu, ret;
 
        for_each_possible_cpu(cpu) {
                if (!da_create_empty_storage(fair_server_id(cpu)))
@@ -208,25 +208,25 @@ static inline int init_storage(bool skip_tasks)
        read_lock(&tasklist_lock);
        for_each_process_thread(g, p) {
                if (p->policy == SCHED_DEADLINE) {
-                       if (!da_create_storage(EXPAND_ID_TASK(p), NULL)) {
+                       ret = deadline_create_task_storage(p);
+                       if (ret && ret != -ESRCH) {
                                read_unlock(&tasklist_lock);
-                               goto fail;
+                               return ret;
                        }
-                       atomic_inc(&deadline_storage_shard(p->pid)->users);
                }
        }
        read_unlock(&tasklist_lock);
        return 0;
 
 fail:
-       da_monitor_destroy();
        return -ENOMEM;
 }
 
-static void deadline_create_task_storage(struct task_struct *task)
+static int deadline_create_task_storage(struct task_struct *task)
 {
        struct deadline_storage_shard *shard = 
deadline_storage_shard(task->pid);
        bool created = false;
+       int ret = -ESRCH;
 
        /*
         * The temporary reference makes an in-flight creator visible to exit.
@@ -239,14 +239,21 @@ static void deadline_create_task_storage(struct 
task_struct *task)
        raw_spin_lock(&shard->lock);
        if (!(READ_ONCE(task->flags) & PF_EXITING)) {
                guard(rcu)();
-               if (!da_get_monitor(EXPAND_ID_TASK(task)) &&
-                   da_create_storage(EXPAND_ID_TASK(task), NULL))
+               if (da_get_monitor(EXPAND_ID_TASK(task))) {
+                       ret = 0;
+               } else if (da_create_storage(EXPAND_ID_TASK(task), NULL)) {
                        created = true;
+                       ret = 0;
+               } else {
+                       ret = -ENOMEM;
+               }
        }
        raw_spin_unlock(&shard->lock);
 
        if (!created)
                atomic_dec(&shard->users);
+
+       return ret;
 }
 
 static void deadline_destroy_task_storage(struct task_struct *task)
diff --git a/kernel/trace/rv/monitors/nomiss/nomiss.c 
b/kernel/trace/rv/monitors/nomiss/nomiss.c
index 2e5ee681505b..843262779a41 100644
--- a/kernel/trace/rv/monitors/nomiss/nomiss.c
+++ b/kernel/trace/rv/monitors/nomiss/nomiss.c
@@ -231,18 +231,26 @@ static int enable_nomiss(void)
        if (retval)
                return retval;
 
+       deadline_storage_init();
+       rv_attach_trace_probe("nomiss", task_newtask, handle_newtask);
+       rv_attach_trace_probe("nomiss", sched_process_exit, handle_exit);
+       if (!should_skip_syscall_handle())
+               rv_attach_trace_probe("nomiss", sys_enter, handle_sys_enter);
+
        retval = init_storage(false);
-       if (retval)
+       if (retval) {
+               rv_detach_trace_probe("nomiss", task_newtask, handle_newtask);
+               rv_detach_trace_probe("nomiss", sched_process_exit, 
handle_exit);
+               if (!should_skip_syscall_handle())
+                       rv_detach_trace_probe("nomiss", sys_enter, 
handle_sys_enter);
+               ha_monitor_destroy();
                return retval;
+       }
        rv_attach_trace_probe("nomiss", sched_dl_replenish_tp, 
handle_dl_replenish);
        rv_attach_trace_probe("nomiss", sched_dl_throttle_tp, 
handle_dl_throttle);
        rv_attach_trace_probe("nomiss", sched_dl_server_stop_tp, 
handle_dl_server_stop);
        rv_attach_trace_probe("nomiss", sched_switch, handle_sched_switch);
        rv_attach_trace_probe("nomiss", sched_wakeup, handle_sched_wakeup);
-       if (!should_skip_syscall_handle())
-               rv_attach_trace_probe("nomiss", sys_enter, handle_sys_enter);
-       rv_attach_trace_probe("nomiss", task_newtask, handle_newtask);
-       rv_attach_trace_probe("nomiss", sched_process_exit, handle_exit);
 
        return 0;
 }
-- 
2.50.1


Reply via email to