diff options
Diffstat (limited to 'kernel/locking')
| -rw-r--r-- | kernel/locking/lockdep.c | 21 | ||||
| -rw-r--r-- | kernel/locking/locktorture.c | 14 | ||||
| -rw-r--r-- | kernel/locking/mutex.c | 63 | ||||
| -rw-r--r-- | kernel/locking/rtmutex.c | 19 | ||||
| -rw-r--r-- | kernel/locking/rwbase_rt.c | 11 | ||||
| -rw-r--r-- | kernel/locking/rwsem.c | 70 | ||||
| -rw-r--r-- | kernel/locking/spinlock.c | 3 | ||||
| -rw-r--r-- | kernel/locking/spinlock_rt.c | 17 | ||||
| -rw-r--r-- | kernel/locking/test-ww_mutex.c | 87 | ||||
| -rw-r--r-- | kernel/locking/ww_rt_mutex.c | 25 | 
10 files changed, 247 insertions, 83 deletions
| diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index bf1c00c881e4..74d371665747 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -788,6 +788,21 @@ static int very_verbose(struct lock_class *class)   * Is this the address of a static object:   */  #ifdef __KERNEL__ +/* + * Check if an address is part of freed initmem. After initmem is freed, + * memory can be allocated from it, and such allocations would then have + * addresses within the range [_stext, _end]. + */ +#ifndef arch_is_kernel_initmem_freed +static int arch_is_kernel_initmem_freed(unsigned long addr) +{ +	if (system_state < SYSTEM_FREEING_INITMEM) +		return 0; + +	return init_section_contains((void *)addr, 1); +} +#endif +  static int static_obj(const void *obj)  {  	unsigned long start = (unsigned long) &_stext, @@ -888,7 +903,7 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)  	if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))  		return NULL; -	hlist_for_each_entry_rcu(class, hash_head, hash_entry) { +	hlist_for_each_entry_rcu_notrace(class, hash_head, hash_entry) {  		if (class->key == key) {  			/*  			 * Huh! same key, different name? Did someone trample @@ -4671,7 +4686,7 @@ print_lock_invalid_wait_context(struct task_struct *curr,  /*   * Verify the wait_type context.   * - * This check validates we takes locks in the right wait-type order; that is it + * This check validates we take locks in the right wait-type order; that is it   * ensures that we do not take mutexes inside spinlocks and do not attempt to   * acquire spinlocks inside raw_spinlocks and the sort.   * @@ -5366,7 +5381,7 @@ int __lock_is_held(const struct lockdep_map *lock, int read)  		struct held_lock *hlock = curr->held_locks + i;  		if (match_held_lock(hlock, lock)) { -			if (read == -1 || hlock->read == read) +			if (read == -1 || !!hlock->read == read)  				return LOCK_STATE_HELD;  			return LOCK_STATE_NOT_HELD; diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c index 7c5a4a087cc7..397ac13d2ef7 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c @@ -1022,23 +1022,23 @@ static int __init lock_torture_init(void)  	if (onoff_interval > 0) {  		firsterr = torture_onoff_init(onoff_holdoff * HZ,  					      onoff_interval * HZ, NULL); -		if (firsterr) +		if (torture_init_error(firsterr))  			goto unwind;  	}  	if (shuffle_interval > 0) {  		firsterr = torture_shuffle_init(shuffle_interval); -		if (firsterr) +		if (torture_init_error(firsterr))  			goto unwind;  	}  	if (shutdown_secs > 0) {  		firsterr = torture_shutdown_init(shutdown_secs,  						 lock_torture_cleanup); -		if (firsterr) +		if (torture_init_error(firsterr))  			goto unwind;  	}  	if (stutter > 0) {  		firsterr = torture_stutter_init(stutter, stutter); -		if (firsterr) +		if (torture_init_error(firsterr))  			goto unwind;  	} @@ -1082,7 +1082,7 @@ static int __init lock_torture_init(void)  		/* Create writer. */  		firsterr = torture_create_kthread(lock_torture_writer, &cxt.lwsa[i],  						  writer_tasks[i]); -		if (firsterr) +		if (torture_init_error(firsterr))  			goto unwind;  	create_reader: @@ -1091,13 +1091,13 @@ static int __init lock_torture_init(void)  		/* Create reader. */  		firsterr = torture_create_kthread(lock_torture_reader, &cxt.lrsa[j],  						  reader_tasks[j]); -		if (firsterr) +		if (torture_init_error(firsterr))  			goto unwind;  	}  	if (stat_interval > 0) {  		firsterr = torture_create_kthread(lock_torture_stats, NULL,  						  stats_task); -		if (firsterr) +		if (torture_init_error(firsterr))  			goto unwind;  	}  	torture_init_end(); diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index d456579d0952..db1913611192 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -94,6 +94,9 @@ static inline unsigned long __owner_flags(unsigned long owner)  	return owner & MUTEX_FLAGS;  } +/* + * Returns: __mutex_owner(lock) on failure or NULL on success. + */  static inline struct task_struct *__mutex_trylock_common(struct mutex *lock, bool handoff)  {  	unsigned long owner, curr = (unsigned long)current; @@ -348,13 +351,16 @@ bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner,  {  	bool ret = true; -	rcu_read_lock(); +	lockdep_assert_preemption_disabled(); +  	while (__mutex_owner(lock) == owner) {  		/*  		 * Ensure we emit the owner->on_cpu, dereference _after_ -		 * checking lock->owner still matches owner. If that fails, -		 * owner might point to freed memory. If it still matches, -		 * the rcu_read_lock() ensures the memory stays valid. +		 * checking lock->owner still matches owner. And we already +		 * disabled preemption which is equal to the RCU read-side +		 * crital section in optimistic spinning code. Thus the +		 * task_strcut structure won't go away during the spinning +		 * period  		 */  		barrier(); @@ -374,7 +380,6 @@ bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner,  		cpu_relax();  	} -	rcu_read_unlock();  	return ret;  } @@ -387,19 +392,25 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)  	struct task_struct *owner;  	int retval = 1; +	lockdep_assert_preemption_disabled(); +  	if (need_resched())  		return 0; -	rcu_read_lock(); +	/* +	 * We already disabled preemption which is equal to the RCU read-side +	 * crital section in optimistic spinning code. Thus the task_strcut +	 * 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)); -	rcu_read_unlock();  	/*  	 * If lock->owner is not set, the mutex has been released. Return true @@ -736,6 +747,44 @@ __ww_mutex_lock(struct mutex *lock, unsigned int state, unsigned int subclass,  	return __mutex_lock_common(lock, state, subclass, NULL, ip, ww_ctx, true);  } +/** + * ww_mutex_trylock - tries to acquire the w/w mutex with optional acquire context + * @ww: mutex to lock + * @ww_ctx: optional w/w acquire context + * + * Trylocks a mutex with the optional acquire context; no deadlock detection is + * possible. Returns 1 if the mutex has been acquired successfully, 0 otherwise. + * + * Unlike ww_mutex_lock, no deadlock handling is performed. However, if a @ctx is + * specified, -EALREADY handling may happen in calls to ww_mutex_trylock. + * + * A mutex acquired with this function must be released with ww_mutex_unlock. + */ +int ww_mutex_trylock(struct ww_mutex *ww, struct ww_acquire_ctx *ww_ctx) +{ +	if (!ww_ctx) +		return mutex_trylock(&ww->base); + +	MUTEX_WARN_ON(ww->base.magic != &ww->base); + +	/* +	 * Reset the wounded flag after a kill. No other process can +	 * race and wound us here, since they can't have a valid owner +	 * pointer if we don't have any locks held. +	 */ +	if (ww_ctx->acquired == 0) +		ww_ctx->wounded = 0; + +	if (__mutex_trylock(&ww->base)) { +		ww_mutex_set_context_fastpath(ww, ww_ctx); +		mutex_acquire_nest(&ww->base.dep_map, 0, 1, &ww_ctx->dep_map, _RET_IP_); +		return 1; +	} + +	return 0; +} +EXPORT_SYMBOL(ww_mutex_trylock); +  #ifdef CONFIG_DEBUG_LOCK_ALLOC  void __sched  mutex_lock_nested(struct mutex *lock, unsigned int subclass) diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 6bb116c559b4..0c6a48dfcecb 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -446,19 +446,26 @@ static __always_inline void rt_mutex_adjust_prio(struct task_struct *p)  }  /* RT mutex specific wake_q wrappers */ -static __always_inline void rt_mutex_wake_q_add(struct rt_wake_q_head *wqh, -						struct rt_mutex_waiter *w) +static __always_inline void rt_mutex_wake_q_add_task(struct rt_wake_q_head *wqh, +						     struct task_struct *task, +						     unsigned int wake_state)  { -	if (IS_ENABLED(CONFIG_PREEMPT_RT) && w->wake_state != TASK_NORMAL) { +	if (IS_ENABLED(CONFIG_PREEMPT_RT) && wake_state == TASK_RTLOCK_WAIT) {  		if (IS_ENABLED(CONFIG_PROVE_LOCKING))  			WARN_ON_ONCE(wqh->rtlock_task); -		get_task_struct(w->task); -		wqh->rtlock_task = w->task; +		get_task_struct(task); +		wqh->rtlock_task = task;  	} else { -		wake_q_add(&wqh->head, w->task); +		wake_q_add(&wqh->head, task);  	}  } +static __always_inline void rt_mutex_wake_q_add(struct rt_wake_q_head *wqh, +						struct rt_mutex_waiter *w) +{ +	rt_mutex_wake_q_add_task(wqh, w->task, w->wake_state); +} +  static __always_inline void rt_mutex_wake_up_q(struct rt_wake_q_head *wqh)  {  	if (IS_ENABLED(CONFIG_PREEMPT_RT) && wqh->rtlock_task) { diff --git a/kernel/locking/rwbase_rt.c b/kernel/locking/rwbase_rt.c index 88191f6e252c..6fd3162e4098 100644 --- a/kernel/locking/rwbase_rt.c +++ b/kernel/locking/rwbase_rt.c @@ -59,8 +59,7 @@ static __always_inline int rwbase_read_trylock(struct rwbase_rt *rwb)  	 * set.  	 */  	for (r = atomic_read(&rwb->readers); r < 0;) { -		/* Fully-ordered if cmpxchg() succeeds, provides ACQUIRE */ -		if (likely(atomic_try_cmpxchg(&rwb->readers, &r, r + 1))) +		if (likely(atomic_try_cmpxchg_acquire(&rwb->readers, &r, r + 1)))  			return 1;  	}  	return 0; @@ -148,6 +147,7 @@ static void __sched __rwbase_read_unlock(struct rwbase_rt *rwb,  {  	struct rt_mutex_base *rtm = &rwb->rtmutex;  	struct task_struct *owner; +	DEFINE_RT_WAKE_Q(wqh);  	raw_spin_lock_irq(&rtm->wait_lock);  	/* @@ -158,9 +158,12 @@ static void __sched __rwbase_read_unlock(struct rwbase_rt *rwb,  	 */  	owner = rt_mutex_owner(rtm);  	if (owner) -		wake_up_state(owner, state); +		rt_mutex_wake_q_add_task(&wqh, owner, state); +	/* Pairs with the preempt_enable in rt_mutex_wake_up_q() */ +	preempt_disable();  	raw_spin_unlock_irq(&rtm->wait_lock); +	rt_mutex_wake_up_q(&wqh);  }  static __always_inline void rwbase_read_unlock(struct rwbase_rt *rwb, @@ -183,7 +186,7 @@ static inline void __rwbase_write_unlock(struct rwbase_rt *rwb, int bias,  	/*  	 * _release() is needed in case that reader is in fast path, pairing -	 * with atomic_try_cmpxchg() in rwbase_read_trylock(), provides RELEASE +	 * with atomic_try_cmpxchg_acquire() in rwbase_read_trylock().  	 */  	(void)atomic_add_return_release(READER_BIAS - bias, &rwb->readers);  	raw_spin_unlock_irqrestore(&rtm->wait_lock, flags); diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c index 000e8d5a2884..c51387a43265 100644 --- a/kernel/locking/rwsem.c +++ b/kernel/locking/rwsem.c @@ -56,7 +56,6 @@   *   * A fast path reader optimistic lock stealing is supported when the rwsem   * is previously owned by a writer and the following conditions are met: - *  - OSQ is empty   *  - rwsem is not currently writer owned   *  - the handoff isn't set.   */ @@ -485,7 +484,7 @@ static void rwsem_mark_wake(struct rw_semaphore *sem,  		/*  		 * Limit # of readers that can be woken up per wakeup call.  		 */ -		if (woken >= MAX_READERS_WAKEUP) +		if (unlikely(woken >= MAX_READERS_WAKEUP))  			break;  	} @@ -577,6 +576,24 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,  	return true;  } +/* + * The rwsem_spin_on_owner() function returns the following 4 values + * depending on the lock owner state. + *   OWNER_NULL  : owner is currently NULL + *   OWNER_WRITER: when owner changes and is a writer + *   OWNER_READER: when owner changes and the new owner may be a reader. + *   OWNER_NONSPINNABLE: + *		   when optimistic spinning has to stop because either the + *		   owner stops running, is unknown, or its timeslice has + *		   been used up. + */ +enum owner_state { +	OWNER_NULL		= 1 << 0, +	OWNER_WRITER		= 1 << 1, +	OWNER_READER		= 1 << 2, +	OWNER_NONSPINNABLE	= 1 << 3, +}; +  #ifdef CONFIG_RWSEM_SPIN_ON_OWNER  /*   * Try to acquire write lock before the writer has been put on wait queue. @@ -617,7 +634,10 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)  	}  	preempt_disable(); -	rcu_read_lock(); +	/* +	 * Disable preemption is equal to the RCU read-side crital section, +	 * thus the task_strcut structure won't go away. +	 */  	owner = rwsem_owner_flags(sem, &flags);  	/*  	 * Don't check the read-owner as the entry may be stale. @@ -625,30 +645,12 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)  	if ((flags & RWSEM_NONSPINNABLE) ||  	    (owner && !(flags & RWSEM_READER_OWNED) && !owner_on_cpu(owner)))  		ret = false; -	rcu_read_unlock();  	preempt_enable();  	lockevent_cond_inc(rwsem_opt_fail, !ret);  	return ret;  } -/* - * The rwsem_spin_on_owner() function returns the following 4 values - * depending on the lock owner state. - *   OWNER_NULL  : owner is currently NULL - *   OWNER_WRITER: when owner changes and is a writer - *   OWNER_READER: when owner changes and the new owner may be a reader. - *   OWNER_NONSPINNABLE: - *		   when optimistic spinning has to stop because either the - *		   owner stops running, is unknown, or its timeslice has - *		   been used up. - */ -enum owner_state { -	OWNER_NULL		= 1 << 0, -	OWNER_WRITER		= 1 << 1, -	OWNER_READER		= 1 << 2, -	OWNER_NONSPINNABLE	= 1 << 3, -};  #define OWNER_SPINNABLE		(OWNER_NULL | OWNER_WRITER | OWNER_READER)  static inline enum owner_state @@ -670,12 +672,13 @@ rwsem_spin_on_owner(struct rw_semaphore *sem)  	unsigned long flags, new_flags;  	enum owner_state state; +	lockdep_assert_preemption_disabled(); +  	owner = rwsem_owner_flags(sem, &flags);  	state = rwsem_owner_state(owner, flags);  	if (state != OWNER_WRITER)  		return state; -	rcu_read_lock();  	for (;;) {  		/*  		 * When a waiting writer set the handoff flag, it may spin @@ -693,7 +696,9 @@ rwsem_spin_on_owner(struct rw_semaphore *sem)  		 * Ensure we emit the owner->on_cpu, dereference _after_  		 * checking sem->owner still matches owner, if that fails,  		 * owner might point to free()d memory, if it still matches, -		 * the rcu_read_lock() ensures the memory stays valid. +		 * our spinning context already disabled preemption which is +		 * equal to RCU read-side crital section ensures the memory +		 * stays valid.  		 */  		barrier(); @@ -704,7 +709,6 @@ rwsem_spin_on_owner(struct rw_semaphore *sem)  		cpu_relax();  	} -	rcu_read_unlock();  	return state;  } @@ -878,12 +882,11 @@ static inline bool rwsem_optimistic_spin(struct rw_semaphore *sem)  static inline void clear_nonspinnable(struct rw_semaphore *sem) { } -static inline int +static inline enum owner_state  rwsem_spin_on_owner(struct rw_semaphore *sem)  { -	return 0; +	return OWNER_NONSPINNABLE;  } -#define OWNER_NULL	1  #endif  /* @@ -1095,9 +1098,16 @@ wait:  		 * In this case, we attempt to acquire the lock again  		 * without sleeping.  		 */ -		if (wstate == WRITER_HANDOFF && -		    rwsem_spin_on_owner(sem) == OWNER_NULL) -			goto trylock_again; +		if (wstate == WRITER_HANDOFF) { +			enum owner_state owner_state; + +			preempt_disable(); +			owner_state = rwsem_spin_on_owner(sem); +			preempt_enable(); + +			if (owner_state == OWNER_NULL) +				goto trylock_again; +		}  		/* Block until there are no active lockers. */  		for (;;) { diff --git a/kernel/locking/spinlock.c b/kernel/locking/spinlock.c index c5830cfa379a..b562f9289372 100644 --- a/kernel/locking/spinlock.c +++ b/kernel/locking/spinlock.c @@ -378,8 +378,7 @@ unsigned long __lockfunc _raw_spin_lock_irqsave_nested(raw_spinlock_t *lock,  	local_irq_save(flags);  	preempt_disable();  	spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); -	LOCK_CONTENDED_FLAGS(lock, do_raw_spin_trylock, do_raw_spin_lock, -				do_raw_spin_lock_flags, &flags); +	LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);  	return flags;  }  EXPORT_SYMBOL(_raw_spin_lock_irqsave_nested); diff --git a/kernel/locking/spinlock_rt.c b/kernel/locking/spinlock_rt.c index d2912e44d61f..b2e553f9255b 100644 --- a/kernel/locking/spinlock_rt.c +++ b/kernel/locking/spinlock_rt.c @@ -24,6 +24,17 @@  #define RT_MUTEX_BUILD_SPINLOCKS  #include "rtmutex.c" +/* + * __might_resched() skips the state check as rtlocks are state + * preserving. Take RCU nesting into account as spin/read/write_lock() can + * legitimately nest into an RCU read side critical section. + */ +#define RTLOCK_RESCHED_OFFSETS						\ +	(rcu_preempt_depth() << MIGHT_RESCHED_RCU_SHIFT) + +#define rtlock_might_resched()						\ +	__might_resched(__FILE__, __LINE__, RTLOCK_RESCHED_OFFSETS) +  static __always_inline void rtlock_lock(struct rt_mutex_base *rtm)  {  	if (unlikely(!rt_mutex_cmpxchg_acquire(rtm, NULL, current))) @@ -32,7 +43,7 @@ static __always_inline void rtlock_lock(struct rt_mutex_base *rtm)  static __always_inline void __rt_spin_lock(spinlock_t *lock)  { -	___might_sleep(__FILE__, __LINE__, 0); +	rtlock_might_resched();  	rtlock_lock(&lock->lock);  	rcu_read_lock();  	migrate_disable(); @@ -210,7 +221,7 @@ EXPORT_SYMBOL(rt_write_trylock);  void __sched rt_read_lock(rwlock_t *rwlock)  { -	___might_sleep(__FILE__, __LINE__, 0); +	rtlock_might_resched();  	rwlock_acquire_read(&rwlock->dep_map, 0, 0, _RET_IP_);  	rwbase_read_lock(&rwlock->rwbase, TASK_RTLOCK_WAIT);  	rcu_read_lock(); @@ -220,7 +231,7 @@ EXPORT_SYMBOL(rt_read_lock);  void __sched rt_write_lock(rwlock_t *rwlock)  { -	___might_sleep(__FILE__, __LINE__, 0); +	rtlock_might_resched();  	rwlock_acquire(&rwlock->dep_map, 0, 0, _RET_IP_);  	rwbase_write_lock(&rwlock->rwbase, TASK_RTLOCK_WAIT);  	rcu_read_lock(); diff --git a/kernel/locking/test-ww_mutex.c b/kernel/locking/test-ww_mutex.c index 3e82f449b4ff..353004155d65 100644 --- a/kernel/locking/test-ww_mutex.c +++ b/kernel/locking/test-ww_mutex.c @@ -16,6 +16,15 @@  static DEFINE_WD_CLASS(ww_class);  struct workqueue_struct *wq; +#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH +#define ww_acquire_init_noinject(a, b) do { \ +		ww_acquire_init((a), (b)); \ +		(a)->deadlock_inject_countdown = ~0U; \ +	} while (0) +#else +#define ww_acquire_init_noinject(a, b) ww_acquire_init((a), (b)) +#endif +  struct test_mutex {  	struct work_struct work;  	struct ww_mutex mutex; @@ -36,7 +45,7 @@ static void test_mutex_work(struct work_struct *work)  	wait_for_completion(&mtx->go);  	if (mtx->flags & TEST_MTX_TRY) { -		while (!ww_mutex_trylock(&mtx->mutex)) +		while (!ww_mutex_trylock(&mtx->mutex, NULL))  			cond_resched();  	} else {  		ww_mutex_lock(&mtx->mutex, NULL); @@ -109,19 +118,39 @@ static int test_mutex(void)  	return 0;  } -static int test_aa(void) +static int test_aa(bool trylock)  {  	struct ww_mutex mutex;  	struct ww_acquire_ctx ctx;  	int ret; +	const char *from = trylock ? "trylock" : "lock";  	ww_mutex_init(&mutex, &ww_class);  	ww_acquire_init(&ctx, &ww_class); -	ww_mutex_lock(&mutex, &ctx); +	if (!trylock) { +		ret = ww_mutex_lock(&mutex, &ctx); +		if (ret) { +			pr_err("%s: initial lock failed!\n", __func__); +			goto out; +		} +	} else { +		ret = !ww_mutex_trylock(&mutex, &ctx); +		if (ret) { +			pr_err("%s: initial trylock failed!\n", __func__); +			goto out; +		} +	} -	if (ww_mutex_trylock(&mutex))  { -		pr_err("%s: trylocked itself!\n", __func__); +	if (ww_mutex_trylock(&mutex, NULL))  { +		pr_err("%s: trylocked itself without context from %s!\n", __func__, from); +		ww_mutex_unlock(&mutex); +		ret = -EINVAL; +		goto out; +	} + +	if (ww_mutex_trylock(&mutex, &ctx))  { +		pr_err("%s: trylocked itself with context from %s!\n", __func__, from);  		ww_mutex_unlock(&mutex);  		ret = -EINVAL;  		goto out; @@ -129,17 +158,17 @@ static int test_aa(void)  	ret = ww_mutex_lock(&mutex, &ctx);  	if (ret != -EALREADY) { -		pr_err("%s: missed deadlock for recursing, ret=%d\n", -		       __func__, ret); +		pr_err("%s: missed deadlock for recursing, ret=%d from %s\n", +		       __func__, ret, from);  		if (!ret)  			ww_mutex_unlock(&mutex);  		ret = -EINVAL;  		goto out;  	} +	ww_mutex_unlock(&mutex);  	ret = 0;  out: -	ww_mutex_unlock(&mutex);  	ww_acquire_fini(&ctx);  	return ret;  } @@ -150,7 +179,7 @@ struct test_abba {  	struct ww_mutex b_mutex;  	struct completion a_ready;  	struct completion b_ready; -	bool resolve; +	bool resolve, trylock;  	int result;  }; @@ -160,8 +189,13 @@ static void test_abba_work(struct work_struct *work)  	struct ww_acquire_ctx ctx;  	int err; -	ww_acquire_init(&ctx, &ww_class); -	ww_mutex_lock(&abba->b_mutex, &ctx); +	ww_acquire_init_noinject(&ctx, &ww_class); +	if (!abba->trylock) +		ww_mutex_lock(&abba->b_mutex, &ctx); +	else +		WARN_ON(!ww_mutex_trylock(&abba->b_mutex, &ctx)); + +	WARN_ON(READ_ONCE(abba->b_mutex.ctx) != &ctx);  	complete(&abba->b_ready);  	wait_for_completion(&abba->a_ready); @@ -181,7 +215,7 @@ static void test_abba_work(struct work_struct *work)  	abba->result = err;  } -static int test_abba(bool resolve) +static int test_abba(bool trylock, bool resolve)  {  	struct test_abba abba;  	struct ww_acquire_ctx ctx; @@ -192,12 +226,18 @@ static int test_abba(bool resolve)  	INIT_WORK_ONSTACK(&abba.work, test_abba_work);  	init_completion(&abba.a_ready);  	init_completion(&abba.b_ready); +	abba.trylock = trylock;  	abba.resolve = resolve;  	schedule_work(&abba.work); -	ww_acquire_init(&ctx, &ww_class); -	ww_mutex_lock(&abba.a_mutex, &ctx); +	ww_acquire_init_noinject(&ctx, &ww_class); +	if (!trylock) +		ww_mutex_lock(&abba.a_mutex, &ctx); +	else +		WARN_ON(!ww_mutex_trylock(&abba.a_mutex, &ctx)); + +	WARN_ON(READ_ONCE(abba.a_mutex.ctx) != &ctx);  	complete(&abba.a_ready);  	wait_for_completion(&abba.b_ready); @@ -249,7 +289,7 @@ static void test_cycle_work(struct work_struct *work)  	struct ww_acquire_ctx ctx;  	int err, erra = 0; -	ww_acquire_init(&ctx, &ww_class); +	ww_acquire_init_noinject(&ctx, &ww_class);  	ww_mutex_lock(&cycle->a_mutex, &ctx);  	complete(cycle->a_signal); @@ -581,7 +621,9 @@ static int stress(int nlocks, int nthreads, unsigned int flags)  static int __init test_ww_mutex_init(void)  {  	int ncpus = num_online_cpus(); -	int ret; +	int ret, i; + +	printk(KERN_INFO "Beginning ww mutex selftests\n");  	wq = alloc_workqueue("test-ww_mutex", WQ_UNBOUND, 0);  	if (!wq) @@ -591,17 +633,19 @@ static int __init test_ww_mutex_init(void)  	if (ret)  		return ret; -	ret = test_aa(); +	ret = test_aa(false);  	if (ret)  		return ret; -	ret = test_abba(false); +	ret = test_aa(true);  	if (ret)  		return ret; -	ret = test_abba(true); -	if (ret) -		return ret; +	for (i = 0; i < 4; i++) { +		ret = test_abba(i & 1, i & 2); +		if (ret) +			return ret; +	}  	ret = test_cycle(ncpus);  	if (ret) @@ -619,6 +663,7 @@ static int __init test_ww_mutex_init(void)  	if (ret)  		return ret; +	printk(KERN_INFO "All ww mutex selftests passed\n");  	return 0;  } diff --git a/kernel/locking/ww_rt_mutex.c b/kernel/locking/ww_rt_mutex.c index 3f1fff7d2780..0e00205cf467 100644 --- a/kernel/locking/ww_rt_mutex.c +++ b/kernel/locking/ww_rt_mutex.c @@ -9,6 +9,31 @@  #define WW_RT  #include "rtmutex.c" +int ww_mutex_trylock(struct ww_mutex *lock, struct ww_acquire_ctx *ww_ctx) +{ +	struct rt_mutex *rtm = &lock->base; + +	if (!ww_ctx) +		return rt_mutex_trylock(rtm); + +	/* +	 * Reset the wounded flag after a kill. No other process can +	 * race and wound us here, since they can't have a valid owner +	 * pointer if we don't have any locks held. +	 */ +	if (ww_ctx->acquired == 0) +		ww_ctx->wounded = 0; + +	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_); +		return 1; +	} + +	return 0; +} +EXPORT_SYMBOL(ww_mutex_trylock); +  static int __sched  __ww_rt_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ww_ctx,  		   unsigned int state, unsigned long ip) |