Merge branch 'WIP.locking/seqlocks' into locking/urgent
Pick up the full seqlock series PeterZ is working on. Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
+2
-4
@@ -1954,8 +1954,8 @@ static __latent_entropy struct task_struct *copy_process(
|
||||
|
||||
rt_mutex_init_task(p);
|
||||
|
||||
lockdep_assert_irqs_enabled();
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
|
||||
DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
|
||||
#endif
|
||||
retval = -EAGAIN;
|
||||
@@ -2032,11 +2032,10 @@ static __latent_entropy struct task_struct *copy_process(
|
||||
#ifdef CONFIG_CPUSETS
|
||||
p->cpuset_mem_spread_rotor = NUMA_NO_NODE;
|
||||
p->cpuset_slab_spread_rotor = NUMA_NO_NODE;
|
||||
seqcount_init(&p->mems_allowed_seq);
|
||||
seqcount_spinlock_init(&p->mems_allowed_seq, &p->alloc_lock);
|
||||
#endif
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
p->irq_events = 0;
|
||||
p->hardirqs_enabled = 0;
|
||||
p->hardirq_enable_ip = 0;
|
||||
p->hardirq_enable_event = 0;
|
||||
p->hardirq_disable_ip = _THIS_IP_;
|
||||
@@ -2046,7 +2045,6 @@ static __latent_entropy struct task_struct *copy_process(
|
||||
p->softirq_enable_event = 0;
|
||||
p->softirq_disable_ip = 0;
|
||||
p->softirq_disable_event = 0;
|
||||
p->hardirq_context = 0;
|
||||
p->softirq_context = 0;
|
||||
#endif
|
||||
|
||||
|
||||
+26
-88
@@ -32,30 +32,13 @@
|
||||
* "But they come in a choice of three flavours!"
|
||||
*/
|
||||
#include <linux/compat.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/futex.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/pid.h>
|
||||
#include <linux/nsproxy.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/sched/rt.h>
|
||||
#include <linux/sched/wake_q.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/fault-inject.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
#include <asm/futex.h>
|
||||
|
||||
@@ -476,7 +459,7 @@ static u64 get_inode_sequence_number(struct inode *inode)
|
||||
/**
|
||||
* get_futex_key() - Get parameters which are the keys for a futex
|
||||
* @uaddr: virtual address of the futex
|
||||
* @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
|
||||
* @fshared: false for a PROCESS_PRIVATE futex, true for PROCESS_SHARED
|
||||
* @key: address where result is stored.
|
||||
* @rw: mapping needs to be read/write (values: FUTEX_READ,
|
||||
* FUTEX_WRITE)
|
||||
@@ -500,8 +483,8 @@ static u64 get_inode_sequence_number(struct inode *inode)
|
||||
*
|
||||
* lock_page() might sleep, the caller should not hold a spinlock.
|
||||
*/
|
||||
static int
|
||||
get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, enum futex_access rw)
|
||||
static int get_futex_key(u32 __user *uaddr, bool fshared, union futex_key *key,
|
||||
enum futex_access rw)
|
||||
{
|
||||
unsigned long address = (unsigned long)uaddr;
|
||||
struct mm_struct *mm = current->mm;
|
||||
@@ -538,7 +521,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, enum futex_a
|
||||
|
||||
again:
|
||||
/* Ignore any VERIFY_READ mapping (futex common case) */
|
||||
if (unlikely(should_fail_futex(fshared)))
|
||||
if (unlikely(should_fail_futex(true)))
|
||||
return -EFAULT;
|
||||
|
||||
err = get_user_pages_fast(address, 1, FOLL_WRITE, &page);
|
||||
@@ -626,7 +609,7 @@ again:
|
||||
* A RO anonymous page will never change and thus doesn't make
|
||||
* sense for futex operations.
|
||||
*/
|
||||
if (unlikely(should_fail_futex(fshared)) || ro) {
|
||||
if (unlikely(should_fail_futex(true)) || ro) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
@@ -677,10 +660,6 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void put_futex_key(union futex_key *key)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* fault_in_user_writeable() - Fault in user address and verify RW access
|
||||
* @uaddr: pointer to faulting user space address
|
||||
@@ -1611,13 +1590,13 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
|
||||
|
||||
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_READ);
|
||||
if (unlikely(ret != 0))
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
hb = hash_futex(&key);
|
||||
|
||||
/* Make sure we really have tasks to wakeup */
|
||||
if (!hb_waiters_pending(hb))
|
||||
goto out_put_key;
|
||||
return ret;
|
||||
|
||||
spin_lock(&hb->lock);
|
||||
|
||||
@@ -1640,9 +1619,6 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
|
||||
|
||||
spin_unlock(&hb->lock);
|
||||
wake_up_q(&wake_q);
|
||||
out_put_key:
|
||||
put_futex_key(&key);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1709,10 +1685,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
|
||||
retry:
|
||||
ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
|
||||
if (unlikely(ret != 0))
|
||||
goto out;
|
||||
return ret;
|
||||
ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, FUTEX_WRITE);
|
||||
if (unlikely(ret != 0))
|
||||
goto out_put_key1;
|
||||
return ret;
|
||||
|
||||
hb1 = hash_futex(&key1);
|
||||
hb2 = hash_futex(&key2);
|
||||
@@ -1730,13 +1706,13 @@ retry_private:
|
||||
* an MMU, but we might get them from range checking
|
||||
*/
|
||||
ret = op_ret;
|
||||
goto out_put_keys;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (op_ret == -EFAULT) {
|
||||
ret = fault_in_user_writeable(uaddr2);
|
||||
if (ret)
|
||||
goto out_put_keys;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_SHARED)) {
|
||||
@@ -1744,8 +1720,6 @@ retry_private:
|
||||
goto retry_private;
|
||||
}
|
||||
|
||||
put_futex_key(&key2);
|
||||
put_futex_key(&key1);
|
||||
cond_resched();
|
||||
goto retry;
|
||||
}
|
||||
@@ -1781,11 +1755,6 @@ retry_private:
|
||||
out_unlock:
|
||||
double_unlock_hb(hb1, hb2);
|
||||
wake_up_q(&wake_q);
|
||||
out_put_keys:
|
||||
put_futex_key(&key2);
|
||||
out_put_key1:
|
||||
put_futex_key(&key1);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1992,20 +1961,18 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
|
||||
retry:
|
||||
ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
|
||||
if (unlikely(ret != 0))
|
||||
goto out;
|
||||
return ret;
|
||||
ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
|
||||
requeue_pi ? FUTEX_WRITE : FUTEX_READ);
|
||||
if (unlikely(ret != 0))
|
||||
goto out_put_key1;
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The check above which compares uaddrs is not sufficient for
|
||||
* shared futexes. We need to compare the keys:
|
||||
*/
|
||||
if (requeue_pi && match_futex(&key1, &key2)) {
|
||||
ret = -EINVAL;
|
||||
goto out_put_keys;
|
||||
}
|
||||
if (requeue_pi && match_futex(&key1, &key2))
|
||||
return -EINVAL;
|
||||
|
||||
hb1 = hash_futex(&key1);
|
||||
hb2 = hash_futex(&key2);
|
||||
@@ -2025,13 +1992,11 @@ retry_private:
|
||||
|
||||
ret = get_user(curval, uaddr1);
|
||||
if (ret)
|
||||
goto out_put_keys;
|
||||
return ret;
|
||||
|
||||
if (!(flags & FLAGS_SHARED))
|
||||
goto retry_private;
|
||||
|
||||
put_futex_key(&key2);
|
||||
put_futex_key(&key1);
|
||||
goto retry;
|
||||
}
|
||||
if (curval != *cmpval) {
|
||||
@@ -2090,12 +2055,10 @@ retry_private:
|
||||
case -EFAULT:
|
||||
double_unlock_hb(hb1, hb2);
|
||||
hb_waiters_dec(hb2);
|
||||
put_futex_key(&key2);
|
||||
put_futex_key(&key1);
|
||||
ret = fault_in_user_writeable(uaddr2);
|
||||
if (!ret)
|
||||
goto retry;
|
||||
goto out;
|
||||
return ret;
|
||||
case -EBUSY:
|
||||
case -EAGAIN:
|
||||
/*
|
||||
@@ -2106,8 +2069,6 @@ retry_private:
|
||||
*/
|
||||
double_unlock_hb(hb1, hb2);
|
||||
hb_waiters_dec(hb2);
|
||||
put_futex_key(&key2);
|
||||
put_futex_key(&key1);
|
||||
/*
|
||||
* Handle the case where the owner is in the middle of
|
||||
* exiting. Wait for the exit to complete otherwise
|
||||
@@ -2216,12 +2177,6 @@ out_unlock:
|
||||
double_unlock_hb(hb1, hb2);
|
||||
wake_up_q(&wake_q);
|
||||
hb_waiters_dec(hb2);
|
||||
|
||||
out_put_keys:
|
||||
put_futex_key(&key2);
|
||||
out_put_key1:
|
||||
put_futex_key(&key1);
|
||||
out:
|
||||
return ret ? ret : task_count;
|
||||
}
|
||||
|
||||
@@ -2567,7 +2522,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
|
||||
*/
|
||||
if (q->pi_state->owner != current)
|
||||
ret = fixup_pi_state_owner(uaddr, q, current);
|
||||
goto out;
|
||||
return ret ? ret : locked;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2580,7 +2535,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
|
||||
*/
|
||||
if (q->pi_state->owner == current) {
|
||||
ret = fixup_pi_state_owner(uaddr, q, NULL);
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2594,8 +2549,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
|
||||
q->pi_state->owner);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret ? ret : locked;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2692,12 +2646,11 @@ retry_private:
|
||||
|
||||
ret = get_user(uval, uaddr);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
if (!(flags & FLAGS_SHARED))
|
||||
goto retry_private;
|
||||
|
||||
put_futex_key(&q->key);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -2706,9 +2659,6 @@ retry_private:
|
||||
ret = -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
put_futex_key(&q->key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2853,7 +2803,6 @@ retry_private:
|
||||
* - EAGAIN: The user space value changed.
|
||||
*/
|
||||
queue_unlock(hb);
|
||||
put_futex_key(&q.key);
|
||||
/*
|
||||
* Handle the case where the owner is in the middle of
|
||||
* exiting. Wait for the exit to complete otherwise
|
||||
@@ -2961,13 +2910,11 @@ no_block:
|
||||
put_pi_state(pi_state);
|
||||
}
|
||||
|
||||
goto out_put_key;
|
||||
goto out;
|
||||
|
||||
out_unlock_put_key:
|
||||
queue_unlock(hb);
|
||||
|
||||
out_put_key:
|
||||
put_futex_key(&q.key);
|
||||
out:
|
||||
if (to) {
|
||||
hrtimer_cancel(&to->timer);
|
||||
@@ -2980,12 +2927,11 @@ uaddr_faulted:
|
||||
|
||||
ret = fault_in_user_writeable(uaddr);
|
||||
if (ret)
|
||||
goto out_put_key;
|
||||
goto out;
|
||||
|
||||
if (!(flags & FLAGS_SHARED))
|
||||
goto retry_private;
|
||||
|
||||
put_futex_key(&q.key);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -3114,16 +3060,13 @@ retry:
|
||||
out_unlock:
|
||||
spin_unlock(&hb->lock);
|
||||
out_putkey:
|
||||
put_futex_key(&key);
|
||||
return ret;
|
||||
|
||||
pi_retry:
|
||||
put_futex_key(&key);
|
||||
cond_resched();
|
||||
goto retry;
|
||||
|
||||
pi_faulted:
|
||||
put_futex_key(&key);
|
||||
|
||||
ret = fault_in_user_writeable(uaddr);
|
||||
if (!ret)
|
||||
@@ -3265,7 +3208,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||||
*/
|
||||
ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
|
||||
if (ret)
|
||||
goto out_key2;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* The check above which compares uaddrs is not sufficient for
|
||||
@@ -3274,7 +3217,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||||
if (match_futex(&q.key, &key2)) {
|
||||
queue_unlock(hb);
|
||||
ret = -EINVAL;
|
||||
goto out_put_keys;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Queue the futex_q, drop the hb lock, wait for wakeup. */
|
||||
@@ -3284,7 +3227,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||||
ret = handle_early_requeue_pi_wakeup(hb, &q, &key2, to);
|
||||
spin_unlock(&hb->lock);
|
||||
if (ret)
|
||||
goto out_put_keys;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* In order for us to be here, we know our q.key == key2, and since
|
||||
@@ -3374,11 +3317,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||||
ret = -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
out_put_keys:
|
||||
put_futex_key(&q.key);
|
||||
out_key2:
|
||||
put_futex_key(&key2);
|
||||
|
||||
out:
|
||||
if (to) {
|
||||
hrtimer_cancel(&to->timer);
|
||||
|
||||
+2
-3
@@ -397,8 +397,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
|
||||
}
|
||||
|
||||
if (!kcsan_interrupt_watcher)
|
||||
/* Use raw to avoid lockdep recursion via IRQ flags tracing. */
|
||||
raw_local_irq_save(irq_flags);
|
||||
local_irq_save(irq_flags);
|
||||
|
||||
watchpoint = insert_watchpoint((unsigned long)ptr, size, is_write);
|
||||
if (watchpoint == NULL) {
|
||||
@@ -539,7 +538,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
|
||||
kcsan_counter_dec(KCSAN_COUNTER_USED_WATCHPOINTS);
|
||||
out_unlock:
|
||||
if (!kcsan_interrupt_watcher)
|
||||
raw_local_irq_restore(irq_flags);
|
||||
local_irq_restore(irq_flags);
|
||||
out:
|
||||
user_access_restore(ua_flags);
|
||||
}
|
||||
|
||||
@@ -606,10 +606,11 @@ void kcsan_report(const volatile void *ptr, size_t size, int access_type,
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* With TRACE_IRQFLAGS, lockdep's IRQ trace state becomes corrupted if
|
||||
* we do not turn off lockdep here; this could happen due to recursion
|
||||
* into lockdep via KCSAN if we detect a race in utilities used by
|
||||
* lockdep.
|
||||
* Because we may generate reports when we're in scheduler code, the use
|
||||
* of printk() could deadlock. Until such time that all printing code
|
||||
* called in print_report() is scheduler-safe, accept the risk, and just
|
||||
* get our message out. As such, also disable lockdep to hide the
|
||||
* warning, and avoid disabling lockdep for the rest of the kernel.
|
||||
*/
|
||||
lockdep_off();
|
||||
|
||||
|
||||
+59
-21
@@ -395,7 +395,7 @@ void lockdep_init_task(struct task_struct *task)
|
||||
|
||||
static __always_inline void lockdep_recursion_finish(void)
|
||||
{
|
||||
if (WARN_ON_ONCE(--current->lockdep_recursion))
|
||||
if (WARN_ON_ONCE((--current->lockdep_recursion) & LOCKDEP_RECURSION_MASK))
|
||||
current->lockdep_recursion = 0;
|
||||
}
|
||||
|
||||
@@ -2062,9 +2062,9 @@ print_bad_irq_dependency(struct task_struct *curr,
|
||||
pr_warn("-----------------------------------------------------\n");
|
||||
pr_warn("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] is trying to acquire:\n",
|
||||
curr->comm, task_pid_nr(curr),
|
||||
curr->hardirq_context, hardirq_count() >> HARDIRQ_SHIFT,
|
||||
lockdep_hardirq_context(), hardirq_count() >> HARDIRQ_SHIFT,
|
||||
curr->softirq_context, softirq_count() >> SOFTIRQ_SHIFT,
|
||||
curr->hardirqs_enabled,
|
||||
lockdep_hardirqs_enabled(),
|
||||
curr->softirqs_enabled);
|
||||
print_lock(next);
|
||||
|
||||
@@ -3331,9 +3331,9 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
|
||||
|
||||
pr_warn("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] takes:\n",
|
||||
curr->comm, task_pid_nr(curr),
|
||||
lockdep_hardirq_context(curr), hardirq_count() >> HARDIRQ_SHIFT,
|
||||
lockdep_hardirq_context(), hardirq_count() >> HARDIRQ_SHIFT,
|
||||
lockdep_softirq_context(curr), softirq_count() >> SOFTIRQ_SHIFT,
|
||||
lockdep_hardirqs_enabled(curr),
|
||||
lockdep_hardirqs_enabled(),
|
||||
lockdep_softirqs_enabled(curr));
|
||||
print_lock(this);
|
||||
|
||||
@@ -3646,10 +3646,19 @@ static void __trace_hardirqs_on_caller(void)
|
||||
*/
|
||||
void lockdep_hardirqs_on_prepare(unsigned long ip)
|
||||
{
|
||||
if (unlikely(!debug_locks || current->lockdep_recursion))
|
||||
if (unlikely(!debug_locks))
|
||||
return;
|
||||
|
||||
if (unlikely(current->hardirqs_enabled)) {
|
||||
/*
|
||||
* NMIs do not (and cannot) track lock dependencies, nothing to do.
|
||||
*/
|
||||
if (unlikely(in_nmi()))
|
||||
return;
|
||||
|
||||
if (unlikely(current->lockdep_recursion & LOCKDEP_RECURSION_MASK))
|
||||
return;
|
||||
|
||||
if (unlikely(lockdep_hardirqs_enabled())) {
|
||||
/*
|
||||
* Neither irq nor preemption are disabled here
|
||||
* so this is racy by nature but losing one hit
|
||||
@@ -3677,7 +3686,7 @@ void lockdep_hardirqs_on_prepare(unsigned long ip)
|
||||
* Can't allow enabling interrupts while in an interrupt handler,
|
||||
* that's general bad form and such. Recursion, limited stack etc..
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(current->hardirq_context))
|
||||
if (DEBUG_LOCKS_WARN_ON(lockdep_hardirq_context()))
|
||||
return;
|
||||
|
||||
current->hardirq_chain_key = current->curr_chain_key;
|
||||
@@ -3692,10 +3701,30 @@ void noinstr lockdep_hardirqs_on(unsigned long ip)
|
||||
{
|
||||
struct task_struct *curr = current;
|
||||
|
||||
if (unlikely(!debug_locks || curr->lockdep_recursion))
|
||||
if (unlikely(!debug_locks))
|
||||
return;
|
||||
|
||||
if (curr->hardirqs_enabled) {
|
||||
/*
|
||||
* NMIs can happen in the middle of local_irq_{en,dis}able() where the
|
||||
* tracking state and hardware state are out of sync.
|
||||
*
|
||||
* NMIs must save lockdep_hardirqs_enabled() to restore IRQ state from,
|
||||
* and not rely on hardware state like normal interrupts.
|
||||
*/
|
||||
if (unlikely(in_nmi())) {
|
||||
/*
|
||||
* Skip:
|
||||
* - recursion check, because NMI can hit lockdep;
|
||||
* - hardware state check, because above;
|
||||
* - chain_key check, see lockdep_hardirqs_on_prepare().
|
||||
*/
|
||||
goto skip_checks;
|
||||
}
|
||||
|
||||
if (unlikely(current->lockdep_recursion & LOCKDEP_RECURSION_MASK))
|
||||
return;
|
||||
|
||||
if (lockdep_hardirqs_enabled()) {
|
||||
/*
|
||||
* Neither irq nor preemption are disabled here
|
||||
* so this is racy by nature but losing one hit
|
||||
@@ -3720,8 +3749,9 @@ void noinstr lockdep_hardirqs_on(unsigned long ip)
|
||||
DEBUG_LOCKS_WARN_ON(current->hardirq_chain_key !=
|
||||
current->curr_chain_key);
|
||||
|
||||
skip_checks:
|
||||
/* we'll do an OFF -> ON transition: */
|
||||
curr->hardirqs_enabled = 1;
|
||||
this_cpu_write(hardirqs_enabled, 1);
|
||||
curr->hardirq_enable_ip = ip;
|
||||
curr->hardirq_enable_event = ++curr->irq_events;
|
||||
debug_atomic_inc(hardirqs_on_events);
|
||||
@@ -3735,7 +3765,15 @@ void noinstr lockdep_hardirqs_off(unsigned long ip)
|
||||
{
|
||||
struct task_struct *curr = current;
|
||||
|
||||
if (unlikely(!debug_locks || curr->lockdep_recursion))
|
||||
if (unlikely(!debug_locks))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Matching lockdep_hardirqs_on(), allow NMIs in the middle of lockdep;
|
||||
* they will restore the software state. This ensures the software
|
||||
* state is consistent inside NMIs as well.
|
||||
*/
|
||||
if (unlikely(!in_nmi() && (current->lockdep_recursion & LOCKDEP_RECURSION_MASK)))
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -3745,11 +3783,11 @@ void noinstr lockdep_hardirqs_off(unsigned long ip)
|
||||
if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
|
||||
return;
|
||||
|
||||
if (curr->hardirqs_enabled) {
|
||||
if (lockdep_hardirqs_enabled()) {
|
||||
/*
|
||||
* We have done an ON -> OFF transition:
|
||||
*/
|
||||
curr->hardirqs_enabled = 0;
|
||||
this_cpu_write(hardirqs_enabled, 0);
|
||||
curr->hardirq_disable_ip = ip;
|
||||
curr->hardirq_disable_event = ++curr->irq_events;
|
||||
debug_atomic_inc(hardirqs_off_events);
|
||||
@@ -3794,7 +3832,7 @@ void lockdep_softirqs_on(unsigned long ip)
|
||||
* usage bit for all held locks, if hardirqs are
|
||||
* enabled too:
|
||||
*/
|
||||
if (curr->hardirqs_enabled)
|
||||
if (lockdep_hardirqs_enabled())
|
||||
mark_held_locks(curr, LOCK_ENABLED_SOFTIRQ);
|
||||
lockdep_recursion_finish();
|
||||
}
|
||||
@@ -3843,7 +3881,7 @@ mark_usage(struct task_struct *curr, struct held_lock *hlock, int check)
|
||||
*/
|
||||
if (!hlock->trylock) {
|
||||
if (hlock->read) {
|
||||
if (curr->hardirq_context)
|
||||
if (lockdep_hardirq_context())
|
||||
if (!mark_lock(curr, hlock,
|
||||
LOCK_USED_IN_HARDIRQ_READ))
|
||||
return 0;
|
||||
@@ -3852,7 +3890,7 @@ mark_usage(struct task_struct *curr, struct held_lock *hlock, int check)
|
||||
LOCK_USED_IN_SOFTIRQ_READ))
|
||||
return 0;
|
||||
} else {
|
||||
if (curr->hardirq_context)
|
||||
if (lockdep_hardirq_context())
|
||||
if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ))
|
||||
return 0;
|
||||
if (curr->softirq_context)
|
||||
@@ -3890,7 +3928,7 @@ lock_used:
|
||||
|
||||
static inline unsigned int task_irq_context(struct task_struct *task)
|
||||
{
|
||||
return LOCK_CHAIN_HARDIRQ_CONTEXT * !!task->hardirq_context +
|
||||
return LOCK_CHAIN_HARDIRQ_CONTEXT * !!lockdep_hardirq_context() +
|
||||
LOCK_CHAIN_SOFTIRQ_CONTEXT * !!task->softirq_context;
|
||||
}
|
||||
|
||||
@@ -3983,7 +4021,7 @@ static inline short task_wait_context(struct task_struct *curr)
|
||||
* Set appropriate wait type for the context; for IRQs we have to take
|
||||
* into account force_irqthread as that is implied by PREEMPT_RT.
|
||||
*/
|
||||
if (curr->hardirq_context) {
|
||||
if (lockdep_hardirq_context()) {
|
||||
/*
|
||||
* Check if force_irqthreads will run us threaded.
|
||||
*/
|
||||
@@ -4826,11 +4864,11 @@ static void check_flags(unsigned long flags)
|
||||
return;
|
||||
|
||||
if (irqs_disabled_flags(flags)) {
|
||||
if (DEBUG_LOCKS_WARN_ON(current->hardirqs_enabled)) {
|
||||
if (DEBUG_LOCKS_WARN_ON(lockdep_hardirqs_enabled())) {
|
||||
printk("possible reason: unannotated irqs-off.\n");
|
||||
}
|
||||
} else {
|
||||
if (DEBUG_LOCKS_WARN_ON(!current->hardirqs_enabled)) {
|
||||
if (DEBUG_LOCKS_WARN_ON(!lockdep_hardirqs_enabled())) {
|
||||
printk("possible reason: unannotated irqs-on.\n");
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -107,6 +107,12 @@ static bool ksoftirqd_running(unsigned long pending)
|
||||
* where hardirqs are disabled legitimately:
|
||||
*/
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
|
||||
DEFINE_PER_CPU(int, hardirqs_enabled);
|
||||
DEFINE_PER_CPU(int, hardirq_context);
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled);
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context);
|
||||
|
||||
void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
|
||||
{
|
||||
unsigned long flags;
|
||||
@@ -224,7 +230,7 @@ static inline bool lockdep_softirq_start(void)
|
||||
{
|
||||
bool in_hardirq = false;
|
||||
|
||||
if (lockdep_hardirq_context(current)) {
|
||||
if (lockdep_hardirq_context()) {
|
||||
in_hardirq = true;
|
||||
lockdep_hardirq_exit();
|
||||
}
|
||||
|
||||
+10
-3
@@ -135,7 +135,11 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
|
||||
* timer->base->cpu_base
|
||||
*/
|
||||
static struct hrtimer_cpu_base migration_cpu_base = {
|
||||
.clock_base = { { .cpu_base = &migration_cpu_base, }, },
|
||||
.clock_base = { {
|
||||
.cpu_base = &migration_cpu_base,
|
||||
.seq = SEQCNT_RAW_SPINLOCK_ZERO(migration_cpu_base.seq,
|
||||
&migration_cpu_base.lock),
|
||||
}, },
|
||||
};
|
||||
|
||||
#define migration_base migration_cpu_base.clock_base[0]
|
||||
@@ -1998,8 +2002,11 @@ int hrtimers_prepare_cpu(unsigned int cpu)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
|
||||
cpu_base->clock_base[i].cpu_base = cpu_base;
|
||||
timerqueue_init_head(&cpu_base->clock_base[i].active);
|
||||
struct hrtimer_clock_base *clock_b = &cpu_base->clock_base[i];
|
||||
|
||||
clock_b->cpu_base = cpu_base;
|
||||
seqcount_raw_spinlock_init(&clock_b->seq, &cpu_base->lock);
|
||||
timerqueue_init_head(&clock_b->active);
|
||||
}
|
||||
|
||||
cpu_base->cpu = cpu;
|
||||
|
||||
@@ -39,18 +39,19 @@ enum timekeeping_adv_mode {
|
||||
TK_ADV_FREQ
|
||||
};
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(timekeeper_lock);
|
||||
|
||||
/*
|
||||
* The most important data for readout fits into a single 64 byte
|
||||
* cache line.
|
||||
*/
|
||||
static struct {
|
||||
seqcount_t seq;
|
||||
seqcount_raw_spinlock_t seq;
|
||||
struct timekeeper timekeeper;
|
||||
} tk_core ____cacheline_aligned = {
|
||||
.seq = SEQCNT_ZERO(tk_core.seq),
|
||||
.seq = SEQCNT_RAW_SPINLOCK_ZERO(tk_core.seq, &timekeeper_lock),
|
||||
};
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(timekeeper_lock);
|
||||
static struct timekeeper shadow_timekeeper;
|
||||
|
||||
/**
|
||||
@@ -63,7 +64,7 @@ static struct timekeeper shadow_timekeeper;
|
||||
* See @update_fast_timekeeper() below.
|
||||
*/
|
||||
struct tk_fast {
|
||||
seqcount_t seq;
|
||||
seqcount_raw_spinlock_t seq;
|
||||
struct tk_read_base base[2];
|
||||
};
|
||||
|
||||
@@ -80,11 +81,13 @@ static struct clocksource dummy_clock = {
|
||||
};
|
||||
|
||||
static struct tk_fast tk_fast_mono ____cacheline_aligned = {
|
||||
.seq = SEQCNT_RAW_SPINLOCK_ZERO(tk_fast_mono.seq, &timekeeper_lock),
|
||||
.base[0] = { .clock = &dummy_clock, },
|
||||
.base[1] = { .clock = &dummy_clock, },
|
||||
};
|
||||
|
||||
static struct tk_fast tk_fast_raw ____cacheline_aligned = {
|
||||
.seq = SEQCNT_RAW_SPINLOCK_ZERO(tk_fast_raw.seq, &timekeeper_lock),
|
||||
.base[0] = { .clock = &dummy_clock, },
|
||||
.base[1] = { .clock = &dummy_clock, },
|
||||
};
|
||||
@@ -157,7 +160,7 @@ static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
|
||||
* tk_clock_read - atomic clocksource read() helper
|
||||
*
|
||||
* This helper is necessary to use in the read paths because, while the
|
||||
* seqlock ensures we don't return a bad value while structures are updated,
|
||||
* seqcount ensures we don't return a bad value while structures are updated,
|
||||
* it doesn't protect from potential crashes. There is the possibility that
|
||||
* the tkr's clocksource may change between the read reference, and the
|
||||
* clock reference passed to the read function. This can cause crashes if
|
||||
@@ -222,10 +225,10 @@ static inline u64 timekeeping_get_delta(const struct tk_read_base *tkr)
|
||||
unsigned int seq;
|
||||
|
||||
/*
|
||||
* Since we're called holding a seqlock, the data may shift
|
||||
* Since we're called holding a seqcount, the data may shift
|
||||
* under us while we're doing the calculation. This can cause
|
||||
* false positives, since we'd note a problem but throw the
|
||||
* results away. So nest another seqlock here to atomically
|
||||
* results away. So nest another seqcount here to atomically
|
||||
* grab the points we are checking with.
|
||||
*/
|
||||
do {
|
||||
@@ -486,7 +489,7 @@ EXPORT_SYMBOL_GPL(ktime_get_raw_fast_ns);
|
||||
*
|
||||
* To keep it NMI safe since we're accessing from tracing, we're not using a
|
||||
* separate timekeeper with updates to monotonic clock and boot offset
|
||||
* protected with seqlocks. This has the following minor side effects:
|
||||
* protected with seqcounts. This has the following minor side effects:
|
||||
*
|
||||
* (1) Its possible that a timestamp be taken after the boot offset is updated
|
||||
* but before the timekeeper is updated. If this happens, the new boot offset
|
||||
|
||||
Reference in New Issue
Block a user