mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-11 13:27:06 +09:00
Merge tag 'locking_core_for_v5.17_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull locking updates from Borislav Petkov:
"Lots of cleanups and preparation. Highlights:
- futex: Cleanup and remove runtime futex_cmpxchg detection
- rtmutex: Some fixes for the PREEMPT_RT locking infrastructure
- kcsan: Share owner_on_cpu() between mutex,rtmutex and rwsem and
annotate the racy owner->on_cpu access *once*.
- atomic64: Dead-Code-Elemination"
[ Description above by Peter Zijlstra ]
* tag 'locking_core_for_v5.17_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
locking/atomic: atomic64: Remove unusable atomic ops
futex: Fix additional regressions
locking: Allow to include asm/spinlock_types.h from linux/spinlock_types_raw.h
x86/mm: Include spinlock_t definition in pgtable.
locking: Mark racy reads of owner->on_cpu
locking: Make owner_on_cpu() into <linux/sched.h>
lockdep/selftests: Adapt ww-tests for PREEMPT_RT
lockdep/selftests: Skip the softirq related tests on PREEMPT_RT
lockdep/selftests: Unbalanced migrate_disable() & rcu_read_lock().
lockdep/selftests: Avoid using local_lock_{acquire|release}().
lockdep: Remove softirq accounting on PREEMPT_RT.
locking/rtmutex: Add rt_mutex_lock_nest_lock() and rt_mutex_lock_killable().
locking/rtmutex: Squash self-deadlock check for ww_rt_mutex.
locking: Remove rt_rwlock_is_contended().
sched: Trigger warning if ->migration_disabled counter underflows.
futex: Fix sparc32/m68k/nds32 build regression
futex: Remove futex_cmpxchg detection
futex: Ensure futex_atomic_cmpxchg_inatomic() is present
kernel/locking: Use a pointer in ww_mutex_trylock().
This commit is contained in:
@@ -5485,6 +5485,7 @@ static noinstr void check_flags(unsigned long flags)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_PREEMPT_RT
|
||||
/*
|
||||
* We dont accurately track softirq state in e.g.
|
||||
* hardirq contexts (such as on 4KSTACKS), so only
|
||||
@@ -5499,6 +5500,7 @@ static noinstr void check_flags(unsigned long flags)
|
||||
DEBUG_LOCKS_WARN_ON(!current->softirqs_enabled);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!debug_locks)
|
||||
print_irqtrace_events(current);
|
||||
|
||||
@@ -367,8 +367,7 @@ bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner,
|
||||
/*
|
||||
* Use vcpu_is_preempted to detect lock holder preemption issue.
|
||||
*/
|
||||
if (!owner->on_cpu || need_resched() ||
|
||||
vcpu_is_preempted(task_cpu(owner))) {
|
||||
if (!owner_on_cpu(owner) || need_resched()) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
@@ -403,14 +402,8 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
|
||||
* structure won't go away during the spinning period.
|
||||
*/
|
||||
owner = __mutex_owner(lock);
|
||||
|
||||
/*
|
||||
* As lock holder preemption issue, we both skip spinning if task is not
|
||||
* on cpu or its cpu is preempted
|
||||
*/
|
||||
|
||||
if (owner)
|
||||
retval = owner->on_cpu && !vcpu_is_preempted(task_cpu(owner));
|
||||
retval = owner_on_cpu(owner);
|
||||
|
||||
/*
|
||||
* If lock->owner is not set, the mutex has been released. Return true
|
||||
|
||||
@@ -1103,8 +1103,11 @@ static int __sched task_blocks_on_rt_mutex(struct rt_mutex_base *lock,
|
||||
* the other will detect the deadlock and return -EDEADLOCK,
|
||||
* which is wrong, as the other waiter is not in a deadlock
|
||||
* situation.
|
||||
*
|
||||
* Except for ww_mutex, in that case the chain walk must already deal
|
||||
* with spurious cycles, see the comments at [3] and [6].
|
||||
*/
|
||||
if (owner == task)
|
||||
if (owner == task && !(build_ww_mutex() && ww_ctx))
|
||||
return -EDEADLK;
|
||||
|
||||
raw_spin_lock(&task->pi_lock);
|
||||
@@ -1379,9 +1382,8 @@ static bool rtmutex_spin_on_owner(struct rt_mutex_base *lock,
|
||||
* for CONFIG_PREEMPT_RCU=y)
|
||||
* - the VCPU on which owner runs is preempted
|
||||
*/
|
||||
if (!owner->on_cpu || need_resched() ||
|
||||
!rt_mutex_waiter_is_top_waiter(lock, waiter) ||
|
||||
vcpu_is_preempted(task_cpu(owner))) {
|
||||
if (!owner_on_cpu(owner) || need_resched() ||
|
||||
!rt_mutex_waiter_is_top_waiter(lock, waiter)) {
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -21,12 +21,13 @@ int max_lock_depth = 1024;
|
||||
*/
|
||||
static __always_inline int __rt_mutex_lock_common(struct rt_mutex *lock,
|
||||
unsigned int state,
|
||||
struct lockdep_map *nest_lock,
|
||||
unsigned int subclass)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
|
||||
mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, _RET_IP_);
|
||||
ret = __rt_mutex_lock(&lock->rtmutex, state);
|
||||
if (ret)
|
||||
mutex_release(&lock->dep_map, _RET_IP_);
|
||||
@@ -48,10 +49,16 @@ EXPORT_SYMBOL(rt_mutex_base_init);
|
||||
*/
|
||||
void __sched rt_mutex_lock_nested(struct rt_mutex *lock, unsigned int subclass)
|
||||
{
|
||||
__rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass);
|
||||
__rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, NULL, subclass);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt_mutex_lock_nested);
|
||||
|
||||
void __sched _rt_mutex_lock_nest_lock(struct rt_mutex *lock, struct lockdep_map *nest_lock)
|
||||
{
|
||||
__rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, nest_lock, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(_rt_mutex_lock_nest_lock);
|
||||
|
||||
#else /* !CONFIG_DEBUG_LOCK_ALLOC */
|
||||
|
||||
/**
|
||||
@@ -61,7 +68,7 @@ EXPORT_SYMBOL_GPL(rt_mutex_lock_nested);
|
||||
*/
|
||||
void __sched rt_mutex_lock(struct rt_mutex *lock)
|
||||
{
|
||||
__rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0);
|
||||
__rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt_mutex_lock);
|
||||
#endif
|
||||
@@ -77,10 +84,25 @@ EXPORT_SYMBOL_GPL(rt_mutex_lock);
|
||||
*/
|
||||
int __sched rt_mutex_lock_interruptible(struct rt_mutex *lock)
|
||||
{
|
||||
return __rt_mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0);
|
||||
return __rt_mutex_lock_common(lock, TASK_INTERRUPTIBLE, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt_mutex_lock_interruptible);
|
||||
|
||||
/**
|
||||
* rt_mutex_lock_killable - lock a rt_mutex killable
|
||||
*
|
||||
* @lock: the rt_mutex to be locked
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
* -EINTR when interrupted by a signal
|
||||
*/
|
||||
int __sched rt_mutex_lock_killable(struct rt_mutex *lock)
|
||||
{
|
||||
return __rt_mutex_lock_common(lock, TASK_KILLABLE, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt_mutex_lock_killable);
|
||||
|
||||
/**
|
||||
* rt_mutex_trylock - try to lock a rt_mutex
|
||||
*
|
||||
|
||||
@@ -658,15 +658,6 @@ static inline bool rwsem_try_write_lock_unqueued(struct rw_semaphore *sem)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool owner_on_cpu(struct task_struct *owner)
|
||||
{
|
||||
/*
|
||||
* As lock holder preemption issue, we both skip spinning if
|
||||
* task is not on cpu or its cpu is preempted
|
||||
*/
|
||||
return owner->on_cpu && !vcpu_is_preempted(task_cpu(owner));
|
||||
}
|
||||
|
||||
static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
|
||||
{
|
||||
struct task_struct *owner;
|
||||
|
||||
@@ -257,12 +257,6 @@ void __sched rt_write_unlock(rwlock_t *rwlock)
|
||||
}
|
||||
EXPORT_SYMBOL(rt_write_unlock);
|
||||
|
||||
int __sched rt_rwlock_is_contended(rwlock_t *rwlock)
|
||||
{
|
||||
return rw_base_is_contended(&rwlock->rwbase);
|
||||
}
|
||||
EXPORT_SYMBOL(rt_rwlock_is_contended);
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
void __rt_rwlock_init(rwlock_t *rwlock, const char *name,
|
||||
struct lock_class_key *key)
|
||||
|
||||
@@ -26,7 +26,7 @@ int ww_mutex_trylock(struct ww_mutex *lock, struct ww_acquire_ctx *ww_ctx)
|
||||
|
||||
if (__rt_mutex_trylock(&rtm->rtmutex)) {
|
||||
ww_mutex_set_context_fastpath(lock, ww_ctx);
|
||||
mutex_acquire_nest(&rtm->dep_map, 0, 1, ww_ctx->dep_map, _RET_IP_);
|
||||
mutex_acquire_nest(&rtm->dep_map, 0, 1, &ww_ctx->dep_map, _RET_IP_);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user