Skip to content

Commit c72cbc9

Browse files
committed
Merge tag 'sched-urgent-2021-03-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull scheduler fixes from Thomas Gleixner: "A set of scheduler updates: - Prevent a NULL pointer dereference in the migration_stop_cpu() mechanims - Prevent self concurrency of affine_move_task() - Small fixes and cleanups related to task migration/affinity setting - Ensure that sync_runqueues_membarrier_state() is invoked on the current CPU when it is in the cpu mask" * tag 'sched-urgent-2021-03-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: sched/membarrier: fix missing local execution of ipi_sync_rq_state() sched: Simplify set_affinity_pending refcounts sched: Fix affine_move_task() self-concurrency sched: Optimize migration_cpu_stop() sched: Collate affine_move_task() stoppers sched: Simplify migration_cpu_stop() sched: Fix migration_cpu_stop() requeueing
2 parents 19469d2 + ce29ddc commit c72cbc9

File tree

2 files changed

+63
-67
lines changed

2 files changed

+63
-67
lines changed

kernel/sched/core.c

Lines changed: 62 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,8 +1862,13 @@ struct migration_arg {
18621862
struct set_affinity_pending *pending;
18631863
};
18641864

1865+
/*
1866+
* @refs: number of wait_for_completion()
1867+
* @stop_pending: is @stop_work in use
1868+
*/
18651869
struct set_affinity_pending {
18661870
refcount_t refs;
1871+
unsigned int stop_pending;
18671872
struct completion done;
18681873
struct cpu_stop_work stop_work;
18691874
struct migration_arg arg;
@@ -1898,8 +1903,8 @@ static struct rq *__migrate_task(struct rq *rq, struct rq_flags *rf,
18981903
*/
18991904
static int migration_cpu_stop(void *data)
19001905
{
1901-
struct set_affinity_pending *pending;
19021906
struct migration_arg *arg = data;
1907+
struct set_affinity_pending *pending = arg->pending;
19031908
struct task_struct *p = arg->task;
19041909
int dest_cpu = arg->dest_cpu;
19051910
struct rq *rq = this_rq();
@@ -1921,7 +1926,6 @@ static int migration_cpu_stop(void *data)
19211926
raw_spin_lock(&p->pi_lock);
19221927
rq_lock(rq, &rf);
19231928

1924-
pending = p->migration_pending;
19251929
/*
19261930
* If task_rq(p) != rq, it cannot be migrated here, because we're
19271931
* holding rq->lock, if p->on_rq == 0 it cannot get enqueued because
@@ -1932,21 +1936,14 @@ static int migration_cpu_stop(void *data)
19321936
goto out;
19331937

19341938
if (pending) {
1935-
p->migration_pending = NULL;
1939+
if (p->migration_pending == pending)
1940+
p->migration_pending = NULL;
19361941
complete = true;
19371942
}
19381943

1939-
/* migrate_enable() -- we must not race against SCA */
19401944
if (dest_cpu < 0) {
1941-
/*
1942-
* When this was migrate_enable() but we no longer
1943-
* have a @pending, a concurrent SCA 'fixed' things
1944-
* and we should be valid again. Nothing to do.
1945-
*/
1946-
if (!pending) {
1947-
WARN_ON_ONCE(!cpumask_test_cpu(task_cpu(p), &p->cpus_mask));
1945+
if (cpumask_test_cpu(task_cpu(p), &p->cpus_mask))
19481946
goto out;
1949-
}
19501947

19511948
dest_cpu = cpumask_any_distribute(&p->cpus_mask);
19521949
}
@@ -1956,7 +1953,14 @@ static int migration_cpu_stop(void *data)
19561953
else
19571954
p->wake_cpu = dest_cpu;
19581955

1959-
} else if (dest_cpu < 0 || pending) {
1956+
/*
1957+
* XXX __migrate_task() can fail, at which point we might end
1958+
* up running on a dodgy CPU, AFAICT this can only happen
1959+
* during CPU hotplug, at which point we'll get pushed out
1960+
* anyway, so it's probably not a big deal.
1961+
*/
1962+
1963+
} else if (pending) {
19601964
/*
19611965
* This happens when we get migrated between migrate_enable()'s
19621966
* preempt_enable() and scheduling the stopper task. At that
@@ -1971,43 +1975,32 @@ static int migration_cpu_stop(void *data)
19711975
* ->pi_lock, so the allowed mask is stable - if it got
19721976
* somewhere allowed, we're done.
19731977
*/
1974-
if (pending && cpumask_test_cpu(task_cpu(p), p->cpus_ptr)) {
1975-
p->migration_pending = NULL;
1978+
if (cpumask_test_cpu(task_cpu(p), p->cpus_ptr)) {
1979+
if (p->migration_pending == pending)
1980+
p->migration_pending = NULL;
19761981
complete = true;
19771982
goto out;
19781983
}
19791984

1980-
/*
1981-
* When this was migrate_enable() but we no longer have an
1982-
* @pending, a concurrent SCA 'fixed' things and we should be
1983-
* valid again. Nothing to do.
1984-
*/
1985-
if (!pending) {
1986-
WARN_ON_ONCE(!cpumask_test_cpu(task_cpu(p), &p->cpus_mask));
1987-
goto out;
1988-
}
1989-
19901985
/*
19911986
* When migrate_enable() hits a rq mis-match we can't reliably
19921987
* determine is_migration_disabled() and so have to chase after
19931988
* it.
19941989
*/
1990+
WARN_ON_ONCE(!pending->stop_pending);
19951991
task_rq_unlock(rq, p, &rf);
19961992
stop_one_cpu_nowait(task_cpu(p), migration_cpu_stop,
19971993
&pending->arg, &pending->stop_work);
19981994
return 0;
19991995
}
20001996
out:
1997+
if (pending)
1998+
pending->stop_pending = false;
20011999
task_rq_unlock(rq, p, &rf);
20022000

20032001
if (complete)
20042002
complete_all(&pending->done);
20052003

2006-
/* For pending->{arg,stop_work} */
2007-
pending = arg->pending;
2008-
if (pending && refcount_dec_and_test(&pending->refs))
2009-
wake_up_var(&pending->refs);
2010-
20112004
return 0;
20122005
}
20132006

@@ -2194,11 +2187,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
21942187
int dest_cpu, unsigned int flags)
21952188
{
21962189
struct set_affinity_pending my_pending = { }, *pending = NULL;
2197-
struct migration_arg arg = {
2198-
.task = p,
2199-
.dest_cpu = dest_cpu,
2200-
};
2201-
bool complete = false;
2190+
bool stop_pending, complete = false;
22022191

22032192
/* Can the task run on the task's current CPU? If so, we're done */
22042193
if (cpumask_test_cpu(task_cpu(p), &p->cpus_mask)) {
@@ -2210,12 +2199,16 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
22102199
push_task = get_task_struct(p);
22112200
}
22122201

2202+
/*
2203+
* If there are pending waiters, but no pending stop_work,
2204+
* then complete now.
2205+
*/
22132206
pending = p->migration_pending;
2214-
if (pending) {
2215-
refcount_inc(&pending->refs);
2207+
if (pending && !pending->stop_pending) {
22162208
p->migration_pending = NULL;
22172209
complete = true;
22182210
}
2211+
22192212
task_rq_unlock(rq, p, rf);
22202213

22212214
if (push_task) {
@@ -2224,7 +2217,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
22242217
}
22252218

22262219
if (complete)
2227-
goto do_complete;
2220+
complete_all(&pending->done);
22282221

22292222
return 0;
22302223
}
@@ -2235,6 +2228,12 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
22352228
/* Install the request */
22362229
refcount_set(&my_pending.refs, 1);
22372230
init_completion(&my_pending.done);
2231+
my_pending.arg = (struct migration_arg) {
2232+
.task = p,
2233+
.dest_cpu = -1, /* any */
2234+
.pending = &my_pending,
2235+
};
2236+
22382237
p->migration_pending = &my_pending;
22392238
} else {
22402239
pending = p->migration_pending;
@@ -2259,60 +2258,59 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
22592258
return -EINVAL;
22602259
}
22612260

2262-
if (flags & SCA_MIGRATE_ENABLE) {
2263-
2264-
refcount_inc(&pending->refs); /* pending->{arg,stop_work} */
2265-
p->migration_flags &= ~MDF_PUSH;
2266-
task_rq_unlock(rq, p, rf);
2267-
2268-
pending->arg = (struct migration_arg) {
2269-
.task = p,
2270-
.dest_cpu = -1,
2271-
.pending = pending,
2272-
};
2273-
2274-
stop_one_cpu_nowait(cpu_of(rq), migration_cpu_stop,
2275-
&pending->arg, &pending->stop_work);
2276-
2277-
return 0;
2278-
}
2279-
22802261
if (task_running(rq, p) || p->state == TASK_WAKING) {
22812262
/*
2282-
* Lessen races (and headaches) by delegating
2283-
* is_migration_disabled(p) checks to the stopper, which will
2284-
* run on the same CPU as said p.
2263+
* MIGRATE_ENABLE gets here because 'p == current', but for
2264+
* anything else we cannot do is_migration_disabled(), punt
2265+
* and have the stopper function handle it all race-free.
22852266
*/
2267+
stop_pending = pending->stop_pending;
2268+
if (!stop_pending)
2269+
pending->stop_pending = true;
2270+
2271+
if (flags & SCA_MIGRATE_ENABLE)
2272+
p->migration_flags &= ~MDF_PUSH;
2273+
22862274
task_rq_unlock(rq, p, rf);
2287-
stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg);
22882275

2276+
if (!stop_pending) {
2277+
stop_one_cpu_nowait(cpu_of(rq), migration_cpu_stop,
2278+
&pending->arg, &pending->stop_work);
2279+
}
2280+
2281+
if (flags & SCA_MIGRATE_ENABLE)
2282+
return 0;
22892283
} else {
22902284

22912285
if (!is_migration_disabled(p)) {
22922286
if (task_on_rq_queued(p))
22932287
rq = move_queued_task(rq, rf, p, dest_cpu);
22942288

2295-
p->migration_pending = NULL;
2296-
complete = true;
2289+
if (!pending->stop_pending) {
2290+
p->migration_pending = NULL;
2291+
complete = true;
2292+
}
22972293
}
22982294
task_rq_unlock(rq, p, rf);
22992295

2300-
do_complete:
23012296
if (complete)
23022297
complete_all(&pending->done);
23032298
}
23042299

23052300
wait_for_completion(&pending->done);
23062301

23072302
if (refcount_dec_and_test(&pending->refs))
2308-
wake_up_var(&pending->refs);
2303+
wake_up_var(&pending->refs); /* No UaF, just an address */
23092304

23102305
/*
23112306
* Block the original owner of &pending until all subsequent callers
23122307
* have seen the completion and decremented the refcount
23132308
*/
23142309
wait_var_event(&my_pending.refs, !refcount_read(&my_pending.refs));
23152310

2311+
/* ARGH */
2312+
WARN_ON_ONCE(my_pending.stop_pending);
2313+
23162314
return 0;
23172315
}
23182316

kernel/sched/membarrier.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,9 +471,7 @@ static int sync_runqueues_membarrier_state(struct mm_struct *mm)
471471
}
472472
rcu_read_unlock();
473473

474-
preempt_disable();
475-
smp_call_function_many(tmpmask, ipi_sync_rq_state, mm, 1);
476-
preempt_enable();
474+
on_each_cpu_mask(tmpmask, ipi_sync_rq_state, mm, true);
477475

478476
free_cpumask_var(tmpmask);
479477
cpus_read_unlock();

0 commit comments

Comments
 (0)