u64 node_stamp; /* migration stamp */
unsigned long numa_contrib;
unsigned long *numa_faults;
+ struct callback_head numa_work;
#endif /* CONFIG_SCHED_NUMA */
struct rcu_head rcu;
p->numa_migrate_seq = p->mm ? p->mm->numa_scan_seq - 1 : 0;
p->numa_faults = NULL;
p->numa_task_period = sysctl_sched_numa_task_period_min;
+ p->numa_work.next = &p->numa_work;
#endif /* CONFIG_SCHED_NUMA */
}
struct task_struct *p = current;
struct mm_struct *mm = p->mm;
- WARN_ON_ONCE(p != container_of(work, struct task_struct, rcu));
+ WARN_ON_ONCE(p != container_of(work, struct task_struct, numa_work));
+ work->next = work; /* protect against double add */
/*
* Who cares about NUMA placement when they're dying.
*
*/
void task_tick_numa(struct rq *rq, struct task_struct *curr)
{
+ struct callback_head *work = &curr->numa_work;
u64 period, now;
/*
* We don't care about NUMA placement if we don't have memory.
*/
- if (!curr->mm)
+ if (!curr->mm || (curr->flags & PF_EXITING) || work->next != work)
return;
/*
curr->node_stamp = now;
if (!time_before(jiffies, curr->mm->numa_next_scan)) {
- /*
- * We can re-use curr->rcu because we checked curr->mm
- * != NULL so release_task()->call_rcu() was not called
- * yet and exit_task_work() is called before
- * exit_notify().
- */
- init_task_work(&curr->rcu, task_numa_work);
- task_work_add(curr, &curr->rcu, true);
+ init_task_work(work, task_numa_work); /* TODO: move this into sched_fork() */
+ task_work_add(curr, work, true);
}
}
}