Merge branch 'locking/urgent' into locking/core, to pick up dependent commits
We are applying further, lower-prio fixes on top of two ww_mutex fixes in locking/urgent. Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -4321,8 +4321,6 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, struct btf *btf,
|
||||
* is not supported yet.
|
||||
* BPF_PROG_TYPE_RAW_TRACEPOINT is fine.
|
||||
*/
|
||||
if (log->level & BPF_LOG_LEVEL)
|
||||
bpf_log(log, "arg#%d type is not a struct\n", arg);
|
||||
return NULL;
|
||||
}
|
||||
tname = btf_name_by_offset(btf, t->name_off);
|
||||
|
||||
@@ -1118,6 +1118,8 @@ static void bpf_prog_clone_free(struct bpf_prog *fp)
|
||||
* clone is guaranteed to not be locked.
|
||||
*/
|
||||
fp->aux = NULL;
|
||||
fp->stats = NULL;
|
||||
fp->active = NULL;
|
||||
__bpf_prog_free(fp);
|
||||
}
|
||||
|
||||
@@ -2342,6 +2344,10 @@ bool __weak bpf_helper_changes_pkt_data(void *func)
|
||||
/* Return TRUE if the JIT backend wants verifier to enable sub-register usage
|
||||
* analysis code and wants explicit zero extension inserted by verifier.
|
||||
* Otherwise, return FALSE.
|
||||
*
|
||||
* The verifier inserts an explicit zero extension after BPF_CMPXCHGs even if
|
||||
* you don't override this. JITs that don't want these extra insns can detect
|
||||
* them using insn_is_zext.
|
||||
*/
|
||||
bool __weak bpf_jit_needs_zext(void)
|
||||
{
|
||||
|
||||
+58
-33
@@ -504,6 +504,13 @@ static bool is_ptr_cast_function(enum bpf_func_id func_id)
|
||||
func_id == BPF_FUNC_skc_to_tcp_request_sock;
|
||||
}
|
||||
|
||||
static bool is_cmpxchg_insn(const struct bpf_insn *insn)
|
||||
{
|
||||
return BPF_CLASS(insn->code) == BPF_STX &&
|
||||
BPF_MODE(insn->code) == BPF_ATOMIC &&
|
||||
insn->imm == BPF_CMPXCHG;
|
||||
}
|
||||
|
||||
/* string representation of 'enum bpf_reg_type' */
|
||||
static const char * const reg_type_str[] = {
|
||||
[NOT_INIT] = "?",
|
||||
@@ -1120,7 +1127,7 @@ static void mark_ptr_not_null_reg(struct bpf_reg_state *reg)
|
||||
reg->type = PTR_TO_RDWR_BUF;
|
||||
break;
|
||||
default:
|
||||
WARN_ON("unknown nullable register type");
|
||||
WARN_ONCE(1, "unknown nullable register type");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1703,7 +1710,11 @@ static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn,
|
||||
}
|
||||
|
||||
if (class == BPF_STX) {
|
||||
if (reg->type != SCALAR_VALUE)
|
||||
/* BPF_STX (including atomic variants) has multiple source
|
||||
* operands, one of which is a ptr. Check whether the caller is
|
||||
* asking about it.
|
||||
*/
|
||||
if (t == SRC_OP && reg->type != SCALAR_VALUE)
|
||||
return true;
|
||||
return BPF_SIZE(code) == BPF_DW;
|
||||
}
|
||||
@@ -1735,22 +1746,38 @@ static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn,
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return TRUE if INSN doesn't have explicit value define. */
|
||||
static bool insn_no_def(struct bpf_insn *insn)
|
||||
/* Return the regno defined by the insn, or -1. */
|
||||
static int insn_def_regno(const struct bpf_insn *insn)
|
||||
{
|
||||
u8 class = BPF_CLASS(insn->code);
|
||||
|
||||
return (class == BPF_JMP || class == BPF_JMP32 ||
|
||||
class == BPF_STX || class == BPF_ST);
|
||||
switch (BPF_CLASS(insn->code)) {
|
||||
case BPF_JMP:
|
||||
case BPF_JMP32:
|
||||
case BPF_ST:
|
||||
return -1;
|
||||
case BPF_STX:
|
||||
if (BPF_MODE(insn->code) == BPF_ATOMIC &&
|
||||
(insn->imm & BPF_FETCH)) {
|
||||
if (insn->imm == BPF_CMPXCHG)
|
||||
return BPF_REG_0;
|
||||
else
|
||||
return insn->src_reg;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
default:
|
||||
return insn->dst_reg;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return TRUE if INSN has defined any 32-bit value explicitly. */
|
||||
static bool insn_has_def32(struct bpf_verifier_env *env, struct bpf_insn *insn)
|
||||
{
|
||||
if (insn_no_def(insn))
|
||||
int dst_reg = insn_def_regno(insn);
|
||||
|
||||
if (dst_reg == -1)
|
||||
return false;
|
||||
|
||||
return !is_reg64(env, insn, insn->dst_reg, NULL, DST_OP);
|
||||
return !is_reg64(env, insn, dst_reg, NULL, DST_OP);
|
||||
}
|
||||
|
||||
static void mark_insn_zext(struct bpf_verifier_env *env,
|
||||
@@ -11006,9 +11033,10 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
|
||||
for (i = 0; i < len; i++) {
|
||||
int adj_idx = i + delta;
|
||||
struct bpf_insn insn;
|
||||
u8 load_reg;
|
||||
int load_reg;
|
||||
|
||||
insn = insns[adj_idx];
|
||||
load_reg = insn_def_regno(&insn);
|
||||
if (!aux[adj_idx].zext_dst) {
|
||||
u8 code, class;
|
||||
u32 imm_rnd;
|
||||
@@ -11018,14 +11046,14 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
|
||||
|
||||
code = insn.code;
|
||||
class = BPF_CLASS(code);
|
||||
if (insn_no_def(&insn))
|
||||
if (load_reg == -1)
|
||||
continue;
|
||||
|
||||
/* NOTE: arg "reg" (the fourth one) is only used for
|
||||
* BPF_STX which has been ruled out in above
|
||||
* check, it is safe to pass NULL here.
|
||||
* BPF_STX + SRC_OP, so it is safe to pass NULL
|
||||
* here.
|
||||
*/
|
||||
if (is_reg64(env, &insn, insn.dst_reg, NULL, DST_OP)) {
|
||||
if (is_reg64(env, &insn, load_reg, NULL, DST_OP)) {
|
||||
if (class == BPF_LD &&
|
||||
BPF_MODE(code) == BPF_IMM)
|
||||
i++;
|
||||
@@ -11040,31 +11068,28 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
|
||||
imm_rnd = get_random_int();
|
||||
rnd_hi32_patch[0] = insn;
|
||||
rnd_hi32_patch[1].imm = imm_rnd;
|
||||
rnd_hi32_patch[3].dst_reg = insn.dst_reg;
|
||||
rnd_hi32_patch[3].dst_reg = load_reg;
|
||||
patch = rnd_hi32_patch;
|
||||
patch_len = 4;
|
||||
goto apply_patch_buffer;
|
||||
}
|
||||
|
||||
if (!bpf_jit_needs_zext())
|
||||
/* Add in an zero-extend instruction if a) the JIT has requested
|
||||
* it or b) it's a CMPXCHG.
|
||||
*
|
||||
* The latter is because: BPF_CMPXCHG always loads a value into
|
||||
* R0, therefore always zero-extends. However some archs'
|
||||
* equivalent instruction only does this load when the
|
||||
* comparison is successful. This detail of CMPXCHG is
|
||||
* orthogonal to the general zero-extension behaviour of the
|
||||
* CPU, so it's treated independently of bpf_jit_needs_zext.
|
||||
*/
|
||||
if (!bpf_jit_needs_zext() && !is_cmpxchg_insn(&insn))
|
||||
continue;
|
||||
|
||||
/* zext_dst means that we want to zero-extend whatever register
|
||||
* the insn defines, which is dst_reg most of the time, with
|
||||
* the notable exception of BPF_STX + BPF_ATOMIC + BPF_FETCH.
|
||||
*/
|
||||
if (BPF_CLASS(insn.code) == BPF_STX &&
|
||||
BPF_MODE(insn.code) == BPF_ATOMIC) {
|
||||
/* BPF_STX + BPF_ATOMIC insns without BPF_FETCH do not
|
||||
* define any registers, therefore zext_dst cannot be
|
||||
* set.
|
||||
*/
|
||||
if (WARN_ON(!(insn.imm & BPF_FETCH)))
|
||||
return -EINVAL;
|
||||
load_reg = insn.imm == BPF_CMPXCHG ? BPF_REG_0
|
||||
: insn.src_reg;
|
||||
} else {
|
||||
load_reg = insn.dst_reg;
|
||||
if (WARN_ON(load_reg == -1)) {
|
||||
verbose(env, "verifier bug. zext_dst is set, but no reg is defined\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
zext_patch[0] = insn;
|
||||
|
||||
+38
-4
@@ -386,6 +386,7 @@ static DEFINE_MUTEX(perf_sched_mutex);
|
||||
static atomic_t perf_sched_count;
|
||||
|
||||
static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
|
||||
static DEFINE_PER_CPU(int, perf_sched_cb_usages);
|
||||
static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events);
|
||||
|
||||
static atomic_t nr_mmap_events __read_mostly;
|
||||
@@ -3461,11 +3462,16 @@ unlock:
|
||||
}
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct list_head, sched_cb_list);
|
||||
|
||||
void perf_sched_cb_dec(struct pmu *pmu)
|
||||
{
|
||||
struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
|
||||
|
||||
--cpuctx->sched_cb_usage;
|
||||
this_cpu_dec(perf_sched_cb_usages);
|
||||
|
||||
if (!--cpuctx->sched_cb_usage)
|
||||
list_del(&cpuctx->sched_cb_entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -3473,7 +3479,10 @@ void perf_sched_cb_inc(struct pmu *pmu)
|
||||
{
|
||||
struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
|
||||
|
||||
cpuctx->sched_cb_usage++;
|
||||
if (!cpuctx->sched_cb_usage++)
|
||||
list_add(&cpuctx->sched_cb_entry, this_cpu_ptr(&sched_cb_list));
|
||||
|
||||
this_cpu_inc(perf_sched_cb_usages);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3502,6 +3511,24 @@ static void __perf_pmu_sched_task(struct perf_cpu_context *cpuctx, bool sched_in
|
||||
perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
|
||||
}
|
||||
|
||||
static void perf_pmu_sched_task(struct task_struct *prev,
|
||||
struct task_struct *next,
|
||||
bool sched_in)
|
||||
{
|
||||
struct perf_cpu_context *cpuctx;
|
||||
|
||||
if (prev == next)
|
||||
return;
|
||||
|
||||
list_for_each_entry(cpuctx, this_cpu_ptr(&sched_cb_list), sched_cb_entry) {
|
||||
/* will be handled in perf_event_context_sched_in/out */
|
||||
if (cpuctx->task_ctx)
|
||||
continue;
|
||||
|
||||
__perf_pmu_sched_task(cpuctx, sched_in);
|
||||
}
|
||||
}
|
||||
|
||||
static void perf_event_switch(struct task_struct *task,
|
||||
struct task_struct *next_prev, bool sched_in);
|
||||
|
||||
@@ -3524,6 +3551,9 @@ void __perf_event_task_sched_out(struct task_struct *task,
|
||||
{
|
||||
int ctxn;
|
||||
|
||||
if (__this_cpu_read(perf_sched_cb_usages))
|
||||
perf_pmu_sched_task(task, next, false);
|
||||
|
||||
if (atomic_read(&nr_switch_events))
|
||||
perf_event_switch(task, next, false);
|
||||
|
||||
@@ -3832,6 +3862,9 @@ void __perf_event_task_sched_in(struct task_struct *prev,
|
||||
|
||||
if (atomic_read(&nr_switch_events))
|
||||
perf_event_switch(task, prev, true);
|
||||
|
||||
if (__this_cpu_read(perf_sched_cb_usages))
|
||||
perf_pmu_sched_task(prev, task, true);
|
||||
}
|
||||
|
||||
static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
|
||||
@@ -4656,7 +4689,7 @@ static void unaccount_event(struct perf_event *event)
|
||||
if (event->parent)
|
||||
return;
|
||||
|
||||
if (event->attach_state & PERF_ATTACH_TASK)
|
||||
if (event->attach_state & (PERF_ATTACH_TASK | PERF_ATTACH_SCHED_CB))
|
||||
dec = true;
|
||||
if (event->attr.mmap || event->attr.mmap_data)
|
||||
atomic_dec(&nr_mmap_events);
|
||||
@@ -11175,7 +11208,7 @@ static void account_event(struct perf_event *event)
|
||||
if (event->parent)
|
||||
return;
|
||||
|
||||
if (event->attach_state & PERF_ATTACH_TASK)
|
||||
if (event->attach_state & (PERF_ATTACH_TASK | PERF_ATTACH_SCHED_CB))
|
||||
inc = true;
|
||||
if (event->attr.mmap || event->attr.mmap_data)
|
||||
atomic_inc(&nr_mmap_events);
|
||||
@@ -12972,6 +13005,7 @@ static void __init perf_event_init_all_cpus(void)
|
||||
#ifdef CONFIG_CGROUP_PERF
|
||||
INIT_LIST_HEAD(&per_cpu(cgrp_cpuctx_list, cpu));
|
||||
#endif
|
||||
INIT_LIST_HEAD(&per_cpu(sched_cb_list, cpu));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -994,6 +994,13 @@ static void mm_init_owner(struct mm_struct *mm, struct task_struct *p)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mm_init_pasid(struct mm_struct *mm)
|
||||
{
|
||||
#ifdef CONFIG_IOMMU_SUPPORT
|
||||
mm->pasid = INIT_PASID;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mm_init_uprobes_state(struct mm_struct *mm)
|
||||
{
|
||||
#ifdef CONFIG_UPROBES
|
||||
@@ -1024,6 +1031,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
|
||||
mm_init_cpumask(mm);
|
||||
mm_init_aio(mm);
|
||||
mm_init_owner(mm, p);
|
||||
mm_init_pasid(mm);
|
||||
RCU_INIT_POINTER(mm->exe_file, NULL);
|
||||
mmu_notifier_subscriptions_init(mm);
|
||||
init_tlb_flush_pending(mm);
|
||||
@@ -2436,6 +2444,7 @@ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node)
|
||||
if (!IS_ERR(tsk)) {
|
||||
sigfillset(&tsk->blocked);
|
||||
sigdelsetmask(&tsk->blocked, sigmask(SIGKILL));
|
||||
tsk->flags |= PF_NOFREEZE;
|
||||
}
|
||||
return tsk;
|
||||
}
|
||||
|
||||
@@ -1898,16 +1898,15 @@ DEFINE_SHOW_ATTRIBUTE(irq_domain_debug);
|
||||
|
||||
static void debugfs_add_domain_dir(struct irq_domain *d)
|
||||
{
|
||||
if (!d->name || !domain_dir || d->debugfs_file)
|
||||
if (!d->name || !domain_dir)
|
||||
return;
|
||||
d->debugfs_file = debugfs_create_file(d->name, 0444, domain_dir, d,
|
||||
&irq_domain_debug_fops);
|
||||
debugfs_create_file(d->name, 0444, domain_dir, d,
|
||||
&irq_domain_debug_fops);
|
||||
}
|
||||
|
||||
static void debugfs_remove_domain_dir(struct irq_domain *d)
|
||||
{
|
||||
debugfs_remove(d->debugfs_file);
|
||||
d->debugfs_file = NULL;
|
||||
debugfs_remove(debugfs_lookup(d->name, domain_dir));
|
||||
}
|
||||
|
||||
void __init irq_domain_debugfs_init(struct dentry *root)
|
||||
|
||||
+14
-11
@@ -626,7 +626,7 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
|
||||
*/
|
||||
static __always_inline bool
|
||||
mutex_optimistic_spin(struct mutex *lock, struct ww_acquire_ctx *ww_ctx,
|
||||
const bool use_ww_ctx, struct mutex_waiter *waiter)
|
||||
struct mutex_waiter *waiter)
|
||||
{
|
||||
if (!waiter) {
|
||||
/*
|
||||
@@ -702,7 +702,7 @@ fail:
|
||||
#else
|
||||
static __always_inline bool
|
||||
mutex_optimistic_spin(struct mutex *lock, struct ww_acquire_ctx *ww_ctx,
|
||||
const bool use_ww_ctx, struct mutex_waiter *waiter)
|
||||
struct mutex_waiter *waiter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -922,6 +922,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
||||
struct ww_mutex *ww;
|
||||
int ret;
|
||||
|
||||
if (!use_ww_ctx)
|
||||
ww_ctx = NULL;
|
||||
|
||||
might_sleep();
|
||||
|
||||
#ifdef CONFIG_DEBUG_MUTEXES
|
||||
@@ -929,7 +932,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
||||
#endif
|
||||
|
||||
ww = container_of(lock, struct ww_mutex, base);
|
||||
if (use_ww_ctx && ww_ctx) {
|
||||
if (ww_ctx) {
|
||||
if (unlikely(ww_ctx == READ_ONCE(ww->ctx)))
|
||||
return -EALREADY;
|
||||
|
||||
@@ -946,10 +949,10 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
||||
mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
|
||||
|
||||
if (__mutex_trylock(lock) ||
|
||||
mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, NULL)) {
|
||||
mutex_optimistic_spin(lock, ww_ctx, NULL)) {
|
||||
/* got the lock, yay! */
|
||||
lock_acquired(&lock->dep_map, ip);
|
||||
if (use_ww_ctx && ww_ctx)
|
||||
if (ww_ctx)
|
||||
ww_mutex_set_context_fastpath(ww, ww_ctx);
|
||||
preempt_enable();
|
||||
return 0;
|
||||
@@ -960,7 +963,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
||||
* After waiting to acquire the wait_lock, try again.
|
||||
*/
|
||||
if (__mutex_trylock(lock)) {
|
||||
if (use_ww_ctx && ww_ctx)
|
||||
if (ww_ctx)
|
||||
__ww_mutex_check_waiters(lock, ww_ctx);
|
||||
|
||||
goto skip_wait;
|
||||
@@ -1013,7 +1016,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (use_ww_ctx && ww_ctx) {
|
||||
if (ww_ctx) {
|
||||
ret = __ww_mutex_check_kill(lock, &waiter, ww_ctx);
|
||||
if (ret)
|
||||
goto err;
|
||||
@@ -1026,7 +1029,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
||||
* ww_mutex needs to always recheck its position since its waiter
|
||||
* list is not FIFO ordered.
|
||||
*/
|
||||
if ((use_ww_ctx && ww_ctx) || !first) {
|
||||
if (ww_ctx || !first) {
|
||||
first = __mutex_waiter_is_first(lock, &waiter);
|
||||
if (first)
|
||||
__mutex_set_flag(lock, MUTEX_FLAG_HANDOFF);
|
||||
@@ -1039,7 +1042,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
||||
* or we must see its unlock and acquire.
|
||||
*/
|
||||
if (__mutex_trylock(lock) ||
|
||||
(first && mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, &waiter)))
|
||||
(first && mutex_optimistic_spin(lock, ww_ctx, &waiter)))
|
||||
break;
|
||||
|
||||
spin_lock(&lock->wait_lock);
|
||||
@@ -1048,7 +1051,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
||||
acquired:
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
||||
if (use_ww_ctx && ww_ctx) {
|
||||
if (ww_ctx) {
|
||||
/*
|
||||
* Wound-Wait; we stole the lock (!first_waiter), check the
|
||||
* waiters as anyone might want to wound us.
|
||||
@@ -1068,7 +1071,7 @@ skip_wait:
|
||||
/* got the lock - cleanup and rejoice! */
|
||||
lock_acquired(&lock->dep_map, ip);
|
||||
|
||||
if (use_ww_ctx && ww_ctx)
|
||||
if (ww_ctx)
|
||||
ww_mutex_lock_acquired(ww, ww_ctx);
|
||||
|
||||
spin_unlock(&lock->wait_lock);
|
||||
|
||||
+63
-65
@@ -1862,8 +1862,13 @@ struct migration_arg {
|
||||
struct set_affinity_pending *pending;
|
||||
};
|
||||
|
||||
/*
|
||||
* @refs: number of wait_for_completion()
|
||||
* @stop_pending: is @stop_work in use
|
||||
*/
|
||||
struct set_affinity_pending {
|
||||
refcount_t refs;
|
||||
unsigned int stop_pending;
|
||||
struct completion done;
|
||||
struct cpu_stop_work stop_work;
|
||||
struct migration_arg arg;
|
||||
@@ -1898,8 +1903,8 @@ static struct rq *__migrate_task(struct rq *rq, struct rq_flags *rf,
|
||||
*/
|
||||
static int migration_cpu_stop(void *data)
|
||||
{
|
||||
struct set_affinity_pending *pending;
|
||||
struct migration_arg *arg = data;
|
||||
struct set_affinity_pending *pending = arg->pending;
|
||||
struct task_struct *p = arg->task;
|
||||
int dest_cpu = arg->dest_cpu;
|
||||
struct rq *rq = this_rq();
|
||||
@@ -1921,7 +1926,6 @@ static int migration_cpu_stop(void *data)
|
||||
raw_spin_lock(&p->pi_lock);
|
||||
rq_lock(rq, &rf);
|
||||
|
||||
pending = p->migration_pending;
|
||||
/*
|
||||
* If task_rq(p) != rq, it cannot be migrated here, because we're
|
||||
* holding rq->lock, if p->on_rq == 0 it cannot get enqueued because
|
||||
@@ -1932,21 +1936,14 @@ static int migration_cpu_stop(void *data)
|
||||
goto out;
|
||||
|
||||
if (pending) {
|
||||
p->migration_pending = NULL;
|
||||
if (p->migration_pending == pending)
|
||||
p->migration_pending = NULL;
|
||||
complete = true;
|
||||
}
|
||||
|
||||
/* migrate_enable() -- we must not race against SCA */
|
||||
if (dest_cpu < 0) {
|
||||
/*
|
||||
* When this was migrate_enable() but we no longer
|
||||
* have a @pending, a concurrent SCA 'fixed' things
|
||||
* and we should be valid again. Nothing to do.
|
||||
*/
|
||||
if (!pending) {
|
||||
WARN_ON_ONCE(!cpumask_test_cpu(task_cpu(p), &p->cpus_mask));
|
||||
if (cpumask_test_cpu(task_cpu(p), &p->cpus_mask))
|
||||
goto out;
|
||||
}
|
||||
|
||||
dest_cpu = cpumask_any_distribute(&p->cpus_mask);
|
||||
}
|
||||
@@ -1956,7 +1953,14 @@ static int migration_cpu_stop(void *data)
|
||||
else
|
||||
p->wake_cpu = dest_cpu;
|
||||
|
||||
} else if (dest_cpu < 0 || pending) {
|
||||
/*
|
||||
* XXX __migrate_task() can fail, at which point we might end
|
||||
* up running on a dodgy CPU, AFAICT this can only happen
|
||||
* during CPU hotplug, at which point we'll get pushed out
|
||||
* anyway, so it's probably not a big deal.
|
||||
*/
|
||||
|
||||
} else if (pending) {
|
||||
/*
|
||||
* This happens when we get migrated between migrate_enable()'s
|
||||
* preempt_enable() and scheduling the stopper task. At that
|
||||
@@ -1971,43 +1975,32 @@ static int migration_cpu_stop(void *data)
|
||||
* ->pi_lock, so the allowed mask is stable - if it got
|
||||
* somewhere allowed, we're done.
|
||||
*/
|
||||
if (pending && cpumask_test_cpu(task_cpu(p), p->cpus_ptr)) {
|
||||
p->migration_pending = NULL;
|
||||
if (cpumask_test_cpu(task_cpu(p), p->cpus_ptr)) {
|
||||
if (p->migration_pending == pending)
|
||||
p->migration_pending = NULL;
|
||||
complete = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* When this was migrate_enable() but we no longer have an
|
||||
* @pending, a concurrent SCA 'fixed' things and we should be
|
||||
* valid again. Nothing to do.
|
||||
*/
|
||||
if (!pending) {
|
||||
WARN_ON_ONCE(!cpumask_test_cpu(task_cpu(p), &p->cpus_mask));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* When migrate_enable() hits a rq mis-match we can't reliably
|
||||
* determine is_migration_disabled() and so have to chase after
|
||||
* it.
|
||||
*/
|
||||
WARN_ON_ONCE(!pending->stop_pending);
|
||||
task_rq_unlock(rq, p, &rf);
|
||||
stop_one_cpu_nowait(task_cpu(p), migration_cpu_stop,
|
||||
&pending->arg, &pending->stop_work);
|
||||
return 0;
|
||||
}
|
||||
out:
|
||||
if (pending)
|
||||
pending->stop_pending = false;
|
||||
task_rq_unlock(rq, p, &rf);
|
||||
|
||||
if (complete)
|
||||
complete_all(&pending->done);
|
||||
|
||||
/* For pending->{arg,stop_work} */
|
||||
pending = arg->pending;
|
||||
if (pending && refcount_dec_and_test(&pending->refs))
|
||||
wake_up_var(&pending->refs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2194,11 +2187,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
|
||||
int dest_cpu, unsigned int flags)
|
||||
{
|
||||
struct set_affinity_pending my_pending = { }, *pending = NULL;
|
||||
struct migration_arg arg = {
|
||||
.task = p,
|
||||
.dest_cpu = dest_cpu,
|
||||
};
|
||||
bool complete = false;
|
||||
bool stop_pending, complete = false;
|
||||
|
||||
/* Can the task run on the task's current CPU? If so, we're done */
|
||||
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
|
||||
push_task = get_task_struct(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are pending waiters, but no pending stop_work,
|
||||
* then complete now.
|
||||
*/
|
||||
pending = p->migration_pending;
|
||||
if (pending) {
|
||||
refcount_inc(&pending->refs);
|
||||
if (pending && !pending->stop_pending) {
|
||||
p->migration_pending = NULL;
|
||||
complete = true;
|
||||
}
|
||||
|
||||
task_rq_unlock(rq, p, rf);
|
||||
|
||||
if (push_task) {
|
||||
@@ -2224,7 +2217,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
|
||||
}
|
||||
|
||||
if (complete)
|
||||
goto do_complete;
|
||||
complete_all(&pending->done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2235,6 +2228,12 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
|
||||
/* Install the request */
|
||||
refcount_set(&my_pending.refs, 1);
|
||||
init_completion(&my_pending.done);
|
||||
my_pending.arg = (struct migration_arg) {
|
||||
.task = p,
|
||||
.dest_cpu = -1, /* any */
|
||||
.pending = &my_pending,
|
||||
};
|
||||
|
||||
p->migration_pending = &my_pending;
|
||||
} else {
|
||||
pending = p->migration_pending;
|
||||
@@ -2259,45 +2258,41 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (flags & SCA_MIGRATE_ENABLE) {
|
||||
|
||||
refcount_inc(&pending->refs); /* pending->{arg,stop_work} */
|
||||
p->migration_flags &= ~MDF_PUSH;
|
||||
task_rq_unlock(rq, p, rf);
|
||||
|
||||
pending->arg = (struct migration_arg) {
|
||||
.task = p,
|
||||
.dest_cpu = -1,
|
||||
.pending = pending,
|
||||
};
|
||||
|
||||
stop_one_cpu_nowait(cpu_of(rq), migration_cpu_stop,
|
||||
&pending->arg, &pending->stop_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (task_running(rq, p) || p->state == TASK_WAKING) {
|
||||
/*
|
||||
* Lessen races (and headaches) by delegating
|
||||
* is_migration_disabled(p) checks to the stopper, which will
|
||||
* run on the same CPU as said p.
|
||||
* MIGRATE_ENABLE gets here because 'p == current', but for
|
||||
* anything else we cannot do is_migration_disabled(), punt
|
||||
* and have the stopper function handle it all race-free.
|
||||
*/
|
||||
task_rq_unlock(rq, p, rf);
|
||||
stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg);
|
||||
stop_pending = pending->stop_pending;
|
||||
if (!stop_pending)
|
||||
pending->stop_pending = true;
|
||||
|
||||
if (flags & SCA_MIGRATE_ENABLE)
|
||||
p->migration_flags &= ~MDF_PUSH;
|
||||
|
||||
task_rq_unlock(rq, p, rf);
|
||||
|
||||
if (!stop_pending) {
|
||||
stop_one_cpu_nowait(cpu_of(rq), migration_cpu_stop,
|
||||
&pending->arg, &pending->stop_work);
|
||||
}
|
||||
|
||||
if (flags & SCA_MIGRATE_ENABLE)
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
if (!is_migration_disabled(p)) {
|
||||
if (task_on_rq_queued(p))
|
||||
rq = move_queued_task(rq, rf, p, dest_cpu);
|
||||
|
||||
p->migration_pending = NULL;
|
||||
complete = true;
|
||||
if (!pending->stop_pending) {
|
||||
p->migration_pending = NULL;
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
task_rq_unlock(rq, p, rf);
|
||||
|
||||
do_complete:
|
||||
if (complete)
|
||||
complete_all(&pending->done);
|
||||
}
|
||||
@@ -2305,7 +2300,7 @@ do_complete:
|
||||
wait_for_completion(&pending->done);
|
||||
|
||||
if (refcount_dec_and_test(&pending->refs))
|
||||
wake_up_var(&pending->refs);
|
||||
wake_up_var(&pending->refs); /* No UaF, just an address */
|
||||
|
||||
/*
|
||||
* Block the original owner of &pending until all subsequent callers
|
||||
@@ -2313,6 +2308,9 @@ do_complete:
|
||||
*/
|
||||
wait_var_event(&my_pending.refs, !refcount_read(&my_pending.refs));
|
||||
|
||||
/* ARGH */
|
||||
WARN_ON_ONCE(my_pending.stop_pending);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -471,9 +471,7 @@ static int sync_runqueues_membarrier_state(struct mm_struct *mm)
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
preempt_disable();
|
||||
smp_call_function_many(tmpmask, ipi_sync_rq_state, mm, 1);
|
||||
preempt_enable();
|
||||
on_each_cpu_mask(tmpmask, ipi_sync_rq_state, mm, true);
|
||||
|
||||
free_cpumask_var(tmpmask);
|
||||
cpus_read_unlock();
|
||||
|
||||
+1
-1
@@ -2079,7 +2079,7 @@ static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr,
|
||||
* up to the caller to provide sane values here, otherwise userspace
|
||||
* tools which use this vector might be unhappy.
|
||||
*/
|
||||
unsigned long user_auxv[AT_VECTOR_SIZE];
|
||||
unsigned long user_auxv[AT_VECTOR_SIZE] = {};
|
||||
|
||||
if (len > sizeof(user_auxv))
|
||||
return -EINVAL;
|
||||
|
||||
+39
-21
@@ -546,8 +546,11 @@ static ktime_t __hrtimer_next_event_base(struct hrtimer_cpu_base *cpu_base,
|
||||
}
|
||||
|
||||
/*
|
||||
* Recomputes cpu_base::*next_timer and returns the earliest expires_next but
|
||||
* does not set cpu_base::*expires_next, that is done by hrtimer_reprogram.
|
||||
* Recomputes cpu_base::*next_timer and returns the earliest expires_next
|
||||
* but does not set cpu_base::*expires_next, that is done by
|
||||
* hrtimer[_force]_reprogram and hrtimer_interrupt only. When updating
|
||||
* cpu_base::*expires_next right away, reprogramming logic would no longer
|
||||
* work.
|
||||
*
|
||||
* When a softirq is pending, we can ignore the HRTIMER_ACTIVE_SOFT bases,
|
||||
* those timers will get run whenever the softirq gets handled, at the end of
|
||||
@@ -588,6 +591,37 @@ __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base, unsigned int active_
|
||||
return expires_next;
|
||||
}
|
||||
|
||||
static ktime_t hrtimer_update_next_event(struct hrtimer_cpu_base *cpu_base)
|
||||
{
|
||||
ktime_t expires_next, soft = KTIME_MAX;
|
||||
|
||||
/*
|
||||
* If the soft interrupt has already been activated, ignore the
|
||||
* soft bases. They will be handled in the already raised soft
|
||||
* interrupt.
|
||||
*/
|
||||
if (!cpu_base->softirq_activated) {
|
||||
soft = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_SOFT);
|
||||
/*
|
||||
* Update the soft expiry time. clock_settime() might have
|
||||
* affected it.
|
||||
*/
|
||||
cpu_base->softirq_expires_next = soft;
|
||||
}
|
||||
|
||||
expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_HARD);
|
||||
/*
|
||||
* If a softirq timer is expiring first, update cpu_base->next_timer
|
||||
* and program the hardware with the soft expiry time.
|
||||
*/
|
||||
if (expires_next > soft) {
|
||||
cpu_base->next_timer = cpu_base->softirq_next_timer;
|
||||
expires_next = soft;
|
||||
}
|
||||
|
||||
return expires_next;
|
||||
}
|
||||
|
||||
static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
|
||||
{
|
||||
ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
|
||||
@@ -628,23 +662,7 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
|
||||
{
|
||||
ktime_t expires_next;
|
||||
|
||||
/*
|
||||
* Find the current next expiration time.
|
||||
*/
|
||||
expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
|
||||
|
||||
if (cpu_base->next_timer && cpu_base->next_timer->is_soft) {
|
||||
/*
|
||||
* When the softirq is activated, hrtimer has to be
|
||||
* programmed with the first hard hrtimer because soft
|
||||
* timer interrupt could occur too late.
|
||||
*/
|
||||
if (cpu_base->softirq_activated)
|
||||
expires_next = __hrtimer_get_next_event(cpu_base,
|
||||
HRTIMER_ACTIVE_HARD);
|
||||
else
|
||||
cpu_base->softirq_expires_next = expires_next;
|
||||
}
|
||||
expires_next = hrtimer_update_next_event(cpu_base);
|
||||
|
||||
if (skip_equal && expires_next == cpu_base->expires_next)
|
||||
return;
|
||||
@@ -1644,8 +1662,8 @@ retry:
|
||||
|
||||
__hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD);
|
||||
|
||||
/* Reevaluate the clock bases for the next expiry */
|
||||
expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
|
||||
/* Reevaluate the clock bases for the [soft] next expiry */
|
||||
expires_next = hrtimer_update_next_event(cpu_base);
|
||||
/*
|
||||
* Store the new expiry value so the migration code can verify
|
||||
* against it.
|
||||
|
||||
Reference in New Issue
Block a user