|
@@ -1220,8 +1220,6 @@ static void task_numa_assign(struct task_numa_env *env,
|
|
|
{
|
|
|
if (env->best_task)
|
|
|
put_task_struct(env->best_task);
|
|
|
- if (p)
|
|
|
- get_task_struct(p);
|
|
|
|
|
|
env->best_task = p;
|
|
|
env->best_imp = imp;
|
|
@@ -1289,20 +1287,30 @@ static void task_numa_compare(struct task_numa_env *env,
|
|
|
long imp = env->p->numa_group ? groupimp : taskimp;
|
|
|
long moveimp = imp;
|
|
|
int dist = env->dist;
|
|
|
+ bool assigned = false;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
|
raw_spin_lock_irq(&dst_rq->lock);
|
|
|
cur = dst_rq->curr;
|
|
|
/*
|
|
|
- * No need to move the exiting task, and this ensures that ->curr
|
|
|
- * wasn't reaped and thus get_task_struct() in task_numa_assign()
|
|
|
- * is safe under RCU read lock.
|
|
|
- * Note that rcu_read_lock() itself can't protect from the final
|
|
|
- * put_task_struct() after the last schedule().
|
|
|
+ * No need to move the exiting task or idle task.
|
|
|
*/
|
|
|
if ((cur->flags & PF_EXITING) || is_idle_task(cur))
|
|
|
cur = NULL;
|
|
|
+ else {
|
|
|
+ /*
|
|
|
+ * The task_struct must be protected here to protect the
|
|
|
+ * p->numa_faults access in the task_weight since the
|
|
|
+ * numa_faults could already be freed in the following path:
|
|
|
+ * finish_task_switch()
|
|
|
+ * --> put_task_struct()
|
|
|
+ * --> __put_task_struct()
|
|
|
+ * --> task_numa_free()
|
|
|
+ */
|
|
|
+ get_task_struct(cur);
|
|
|
+ }
|
|
|
+
|
|
|
raw_spin_unlock_irq(&dst_rq->lock);
|
|
|
|
|
|
/*
|
|
@@ -1386,6 +1394,7 @@ balance:
|
|
|
*/
|
|
|
if (!load_too_imbalanced(src_load, dst_load, env)) {
|
|
|
imp = moveimp - 1;
|
|
|
+ put_task_struct(cur);
|
|
|
cur = NULL;
|
|
|
goto assign;
|
|
|
}
|
|
@@ -1411,9 +1420,16 @@ balance:
|
|
|
env->dst_cpu = select_idle_sibling(env->p, env->dst_cpu);
|
|
|
|
|
|
assign:
|
|
|
+ assigned = true;
|
|
|
task_numa_assign(env, cur, imp);
|
|
|
unlock:
|
|
|
rcu_read_unlock();
|
|
|
+ /*
|
|
|
+ * The dst_rq->curr isn't assigned. The protection for task_struct is
|
|
|
+ * finished.
|
|
|
+ */
|
|
|
+ if (cur && !assigned)
|
|
|
+ put_task_struct(cur);
|
|
|
}
|
|
|
|
|
|
static void task_numa_find_cpu(struct task_numa_env *env,
|