diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/mutex-debug.c | 2 | ||||
| -rw-r--r-- | kernel/mutex-debug.h | 2 | ||||
| -rw-r--r-- | kernel/mutex.c | 2 | ||||
| -rw-r--r-- | kernel/mutex.h | 2 | ||||
| -rw-r--r-- | kernel/sched.c | 83 | 
5 files changed, 37 insertions, 54 deletions
diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c index ec815a960b5..73da83aff41 100644 --- a/kernel/mutex-debug.c +++ b/kernel/mutex-debug.c @@ -75,7 +75,7 @@ void debug_mutex_unlock(struct mutex *lock)  		return;  	DEBUG_LOCKS_WARN_ON(lock->magic != lock); -	DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info()); +	DEBUG_LOCKS_WARN_ON(lock->owner != current);  	DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next);  	mutex_clear_owner(lock);  } diff --git a/kernel/mutex-debug.h b/kernel/mutex-debug.h index 57d527a16f9..0799fd3e4cf 100644 --- a/kernel/mutex-debug.h +++ b/kernel/mutex-debug.h @@ -29,7 +29,7 @@ extern void debug_mutex_init(struct mutex *lock, const char *name,  static inline void mutex_set_owner(struct mutex *lock)  { -	lock->owner = current_thread_info(); +	lock->owner = current;  }  static inline void mutex_clear_owner(struct mutex *lock) diff --git a/kernel/mutex.c b/kernel/mutex.c index c4195fa9890..fe4706cb0c5 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -160,7 +160,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,  	 */  	for (;;) { -		struct thread_info *owner; +		struct task_struct *owner;  		/*  		 * If we own the BKL, then don't spin. The owner of diff --git a/kernel/mutex.h b/kernel/mutex.h index 67578ca48f9..4115fbf83b1 100644 --- a/kernel/mutex.h +++ b/kernel/mutex.h @@ -19,7 +19,7 @@  #ifdef CONFIG_SMP  static inline void mutex_set_owner(struct mutex *lock)  { -	lock->owner = current_thread_info(); +	lock->owner = current;  }  static inline void mutex_clear_owner(struct mutex *lock) diff --git a/kernel/sched.c b/kernel/sched.c index cd2593e1a3e..55cc50323ce 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4173,70 +4173,53 @@ need_resched:  EXPORT_SYMBOL(schedule);  #ifdef CONFIG_MUTEX_SPIN_ON_OWNER -/* - * Look out! "owner" is an entirely speculative pointer - * access and not reliable. - */ -int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner) -{ -	unsigned int cpu; -	struct rq *rq; -	if (!sched_feat(OWNER_SPIN)) -		return 0; +static inline bool owner_running(struct mutex *lock, struct task_struct *owner) +{ +	bool ret = false; -#ifdef CONFIG_DEBUG_PAGEALLOC -	/* -	 * Need to access the cpu field knowing that -	 * DEBUG_PAGEALLOC could have unmapped it if -	 * the mutex owner just released it and exited. -	 */ -	if (probe_kernel_address(&owner->cpu, cpu)) -		return 0; -#else -	cpu = owner->cpu; -#endif +	rcu_read_lock(); +	if (lock->owner != owner) +		goto fail;  	/* -	 * Even if the access succeeded (likely case), -	 * the cpu field may no longer be valid. +	 * Ensure we emit the owner->on_cpu, dereference _after_ checking +	 * lock->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.  	 */ -	if (cpu >= nr_cpumask_bits) -		return 0; +	barrier(); -	/* -	 * We need to validate that we can do a -	 * get_cpu() and that we have the percpu area. -	 */ -	if (!cpu_online(cpu)) -		return 0; +	ret = owner->on_cpu; +fail: +	rcu_read_unlock(); -	rq = cpu_rq(cpu); +	return ret; +} -	for (;;) { -		/* -		 * Owner changed, break to re-assess state. -		 */ -		if (lock->owner != owner) { -			/* -			 * If the lock has switched to a different owner, -			 * we likely have heavy contention. Return 0 to quit -			 * optimistic spinning and not contend further: -			 */ -			if (lock->owner) -				return 0; -			break; -		} +/* + * Look out! "owner" is an entirely speculative pointer + * access and not reliable. + */ +int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner) +{ +	if (!sched_feat(OWNER_SPIN)) +		return 0; -		/* -		 * Is that owner really running on that cpu? -		 */ -		if (task_thread_info(rq->curr) != owner || need_resched()) +	while (owner_running(lock, owner)) { +		if (need_resched())  			return 0;  		arch_mutex_cpu_relax();  	} +	/* +	 * If the owner changed to another task there is likely +	 * heavy contention, stop spinning. +	 */ +	if (lock->owner) +		return 0; +  	return 1;  }  #endif  |