diff options
Diffstat (limited to 'kernel/locking')
| -rw-r--r-- | kernel/locking/Makefile | 11 | ||||
| -rw-r--r-- | kernel/locking/mcs_spinlock.h | 16 | ||||
| -rw-r--r-- | kernel/locking/mutex.c | 62 | ||||
| -rw-r--r-- | kernel/locking/osq_lock.c (renamed from kernel/locking/mcs_spinlock.c) | 9 | ||||
| -rw-r--r-- | kernel/locking/rtmutex.c | 7 | ||||
| -rw-r--r-- | kernel/locking/rwsem-spinlock.c | 2 | ||||
| -rw-r--r-- | kernel/locking/rwsem-xadd.c | 3 | ||||
| -rw-r--r-- | kernel/locking/spinlock.c | 8 | 
8 files changed, 54 insertions, 64 deletions
| diff --git a/kernel/locking/Makefile b/kernel/locking/Makefile index 8541bfdfd232..de7a416cca2a 100644 --- a/kernel/locking/Makefile +++ b/kernel/locking/Makefile @@ -1,11 +1,11 @@ -obj-y += mutex.o semaphore.o rwsem.o mcs_spinlock.o +obj-y += mutex.o semaphore.o rwsem.o  ifdef CONFIG_FUNCTION_TRACER -CFLAGS_REMOVE_lockdep.o = -pg -CFLAGS_REMOVE_lockdep_proc.o = -pg -CFLAGS_REMOVE_mutex-debug.o = -pg -CFLAGS_REMOVE_rtmutex-debug.o = -pg +CFLAGS_REMOVE_lockdep.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_lockdep_proc.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_mutex-debug.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_rtmutex-debug.o = $(CC_FLAGS_FTRACE)  endif  obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o @@ -14,6 +14,7 @@ ifeq ($(CONFIG_PROC_FS),y)  obj-$(CONFIG_LOCKDEP) += lockdep_proc.o  endif  obj-$(CONFIG_SMP) += spinlock.o +obj-$(CONFIG_LOCK_SPIN_ON_OWNER) += osq_lock.o  obj-$(CONFIG_SMP) += lglock.o  obj-$(CONFIG_PROVE_LOCKING) += spinlock.o  obj-$(CONFIG_RT_MUTEXES) += rtmutex.o diff --git a/kernel/locking/mcs_spinlock.h b/kernel/locking/mcs_spinlock.h index 4d60986fcbee..d1fe2ba5bac9 100644 --- a/kernel/locking/mcs_spinlock.h +++ b/kernel/locking/mcs_spinlock.h @@ -108,20 +108,4 @@ void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *node)  	arch_mcs_spin_unlock_contended(&next->locked);  } -/* - * Cancellable version of the MCS lock above. - * - * Intended for adaptive spinning of sleeping locks: - * mutex_lock()/rwsem_down_{read,write}() etc. - */ - -struct optimistic_spin_node { -	struct optimistic_spin_node *next, *prev; -	int locked; /* 1 if lock acquired */ -	int cpu; /* encoded CPU # value */ -}; - -extern bool osq_lock(struct optimistic_spin_queue *lock); -extern void osq_unlock(struct optimistic_spin_queue *lock); -  #endif /* __LINUX_MCS_SPINLOCK_H */ diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 454195194d4a..94674e5919cb 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -81,7 +81,7 @@ __visible void __sched __mutex_lock_slowpath(atomic_t *lock_count);   * The mutex must later on be released by the same task that   * acquired it. Recursive locking is not allowed. The task   * may not exit without first unlocking the mutex. Also, kernel - * memory where the mutex resides mutex must not be freed with + * memory where the mutex resides must not be freed with   * the mutex still locked. The mutex must first be initialized   * (or statically defined) before it can be locked. memset()-ing   * the mutex to 0 is not allowed. @@ -147,7 +147,7 @@ static __always_inline void ww_mutex_lock_acquired(struct ww_mutex *ww,  }  /* - * after acquiring lock with fastpath or when we lost out in contested + * After acquiring lock with fastpath or when we lost out in contested   * slowpath, set ctx and wake up any waiters so they can recheck.   *   * This function is never called when CONFIG_DEBUG_LOCK_ALLOC is set, @@ -191,19 +191,32 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock,  	spin_unlock_mutex(&lock->base.wait_lock, flags);  } - -#ifdef CONFIG_MUTEX_SPIN_ON_OWNER  /* - * In order to avoid a stampede of mutex spinners from acquiring the mutex - * more or less simultaneously, the spinners need to acquire a MCS lock - * first before spinning on the owner field. + * After acquiring lock in the slowpath set ctx and wake up any + * waiters so they can recheck.   * + * Callers must hold the mutex wait_lock.   */ +static __always_inline void +ww_mutex_set_context_slowpath(struct ww_mutex *lock, +			      struct ww_acquire_ctx *ctx) +{ +	struct mutex_waiter *cur; -/* - * Mutex spinning code migrated from kernel/sched/core.c - */ +	ww_mutex_lock_acquired(lock, ctx); +	lock->ctx = ctx; + +	/* +	 * Give any possible sleeping processes the chance to wake up, +	 * so they can recheck if they have to back off. +	 */ +	list_for_each_entry(cur, &lock->base.wait_list, list) { +		debug_mutex_wake_waiter(&lock->base, cur); +		wake_up_process(cur->task); +	} +} +#ifdef CONFIG_MUTEX_SPIN_ON_OWNER  static inline bool owner_running(struct mutex *lock, struct task_struct *owner)  {  	if (lock->owner != owner) @@ -307,6 +320,11 @@ static bool mutex_optimistic_spin(struct mutex *lock,  	if (!mutex_can_spin_on_owner(lock))  		goto done; +	/* +	 * In order to avoid a stampede of mutex spinners trying to +	 * acquire the mutex all at once, the spinners need to take a +	 * MCS (queued) lock first before spinning on the owner field. +	 */  	if (!osq_lock(&lock->osq))  		goto done; @@ -469,7 +487,7 @@ void __sched ww_mutex_unlock(struct ww_mutex *lock)  EXPORT_SYMBOL(ww_mutex_unlock);  static inline int __sched -__mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx) +__ww_mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx)  {  	struct ww_mutex *ww = container_of(lock, struct ww_mutex, base);  	struct ww_acquire_ctx *hold_ctx = ACCESS_ONCE(ww->ctx); @@ -557,7 +575,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,  		}  		if (use_ww_ctx && ww_ctx->acquired > 0) { -			ret = __mutex_lock_check_stamp(lock, ww_ctx); +			ret = __ww_mutex_lock_check_stamp(lock, ww_ctx);  			if (ret)  				goto err;  		} @@ -569,6 +587,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,  		schedule_preempt_disabled();  		spin_lock_mutex(&lock->wait_lock, flags);  	} +	__set_task_state(task, TASK_RUNNING); +  	mutex_remove_waiter(lock, &waiter, current_thread_info());  	/* set it to 0 if there are no waiters left: */  	if (likely(list_empty(&lock->wait_list))) @@ -582,23 +602,7 @@ skip_wait:  	if (use_ww_ctx) {  		struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); -		struct mutex_waiter *cur; - -		/* -		 * This branch gets optimized out for the common case, -		 * and is only important for ww_mutex_lock. -		 */ -		ww_mutex_lock_acquired(ww, ww_ctx); -		ww->ctx = ww_ctx; - -		/* -		 * Give any possible sleeping processes the chance to wake up, -		 * so they can recheck if they have to back off. -		 */ -		list_for_each_entry(cur, &lock->wait_list, list) { -			debug_mutex_wake_waiter(lock, cur); -			wake_up_process(cur->task); -		} +		ww_mutex_set_context_slowpath(ww, ww_ctx);  	}  	spin_unlock_mutex(&lock->wait_lock, flags); diff --git a/kernel/locking/mcs_spinlock.c b/kernel/locking/osq_lock.c index 9887a905a762..c112d00341b0 100644 --- a/kernel/locking/mcs_spinlock.c +++ b/kernel/locking/osq_lock.c @@ -1,8 +1,6 @@  #include <linux/percpu.h>  #include <linux/sched.h> -#include "mcs_spinlock.h" - -#ifdef CONFIG_SMP +#include <linux/osq_lock.h>  /*   * An MCS like lock especially tailored for optimistic spinning for sleeping @@ -111,7 +109,7 @@ bool osq_lock(struct optimistic_spin_queue *lock)  	 * cmpxchg in an attempt to undo our queueing.  	 */ -	while (!smp_load_acquire(&node->locked)) { +	while (!ACCESS_ONCE(node->locked)) {  		/*  		 * If we need to reschedule bail... so we can block.  		 */ @@ -203,6 +201,3 @@ void osq_unlock(struct optimistic_spin_queue *lock)  	if (next)  		ACCESS_ONCE(next->locked) = 1;  } - -#endif - diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 7c98873a3077..3059bc2f022d 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -1130,6 +1130,7 @@ __rt_mutex_slowlock(struct rt_mutex *lock, int state,  		set_current_state(state);  	} +	__set_current_state(TASK_RUNNING);  	return ret;  } @@ -1188,10 +1189,9 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,  	ret = task_blocks_on_rt_mutex(lock, &waiter, current, chwalk);  	if (likely(!ret)) +		/* sleep on the mutex */  		ret = __rt_mutex_slowlock(lock, state, timeout, &waiter); -	set_current_state(TASK_RUNNING); -  	if (unlikely(ret)) {  		remove_waiter(lock, &waiter);  		rt_mutex_handle_deadlock(ret, chwalk, &waiter); @@ -1626,10 +1626,9 @@ int rt_mutex_finish_proxy_lock(struct rt_mutex *lock,  	set_current_state(TASK_INTERRUPTIBLE); +	/* sleep on the mutex */  	ret = __rt_mutex_slowlock(lock, TASK_INTERRUPTIBLE, to, waiter); -	set_current_state(TASK_RUNNING); -  	if (unlikely(ret))  		remove_waiter(lock, waiter); diff --git a/kernel/locking/rwsem-spinlock.c b/kernel/locking/rwsem-spinlock.c index 2c93571162cb..2555ae15ec14 100644 --- a/kernel/locking/rwsem-spinlock.c +++ b/kernel/locking/rwsem-spinlock.c @@ -154,7 +154,7 @@ void __sched __down_read(struct rw_semaphore *sem)  		set_task_state(tsk, TASK_UNINTERRUPTIBLE);  	} -	tsk->state = TASK_RUNNING; +	__set_task_state(tsk, TASK_RUNNING);   out:  	;  } diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 7628c3fc37ca..2f7cc4076f50 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -242,8 +242,7 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)  		schedule();  	} -	tsk->state = TASK_RUNNING; - +	__set_task_state(tsk, TASK_RUNNING);  	return sem;  }  EXPORT_SYMBOL(rwsem_down_read_failed); diff --git a/kernel/locking/spinlock.c b/kernel/locking/spinlock.c index 4b082b5cac9e..db3ccb1dd614 100644 --- a/kernel/locking/spinlock.c +++ b/kernel/locking/spinlock.c @@ -363,6 +363,14 @@ void __lockfunc _raw_spin_lock_nested(raw_spinlock_t *lock, int subclass)  }  EXPORT_SYMBOL(_raw_spin_lock_nested); +void __lockfunc _raw_spin_lock_bh_nested(raw_spinlock_t *lock, int subclass) +{ +	__local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); +	spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); +	LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); +} +EXPORT_SYMBOL(_raw_spin_lock_bh_nested); +  unsigned long __lockfunc _raw_spin_lock_irqsave_nested(raw_spinlock_t *lock,  						   int subclass)  { |