diff options
Diffstat (limited to 'kernel/futex.c')
| -rw-r--r-- | kernel/futex.c | 40 | 
1 files changed, 26 insertions, 14 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 11cbe052b2e..1614be20173 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -55,7 +55,7 @@  #include <linux/pagemap.h>  #include <linux/syscalls.h>  #include <linux/signal.h> -#include <linux/module.h> +#include <linux/export.h>  #include <linux/magic.h>  #include <linux/pid.h>  #include <linux/nsproxy.h> @@ -314,17 +314,29 @@ again:  #endif  	lock_page(page_head); + +	/* +	 * If page_head->mapping is NULL, then it cannot be a PageAnon +	 * page; but it might be the ZERO_PAGE or in the gate area or +	 * in a special mapping (all cases which we are happy to fail); +	 * or it may have been a good file page when get_user_pages_fast +	 * found it, but truncated or holepunched or subjected to +	 * invalidate_complete_page2 before we got the page lock (also +	 * cases which we are happy to fail).  And we hold a reference, +	 * so refcount care in invalidate_complete_page's remove_mapping +	 * prevents drop_caches from setting mapping to NULL beneath us. +	 * +	 * The case we do have to guard against is when memory pressure made +	 * shmem_writepage move it from filecache to swapcache beneath us: +	 * an unlikely race, but we do need to retry for page_head->mapping. +	 */  	if (!page_head->mapping) { +		int shmem_swizzled = PageSwapCache(page_head);  		unlock_page(page_head);  		put_page(page_head); -		/* -		* ZERO_PAGE pages don't have a mapping. Avoid a busy loop -		* trying to find one. RW mapping would have COW'd (and thus -		* have a mapping) so this page is RO and won't ever change. -		*/ -		if ((page_head == ZERO_PAGE(address))) -			return -EFAULT; -		goto again; +		if (shmem_swizzled) +			goto again; +		return -EFAULT;  	}  	/* @@ -854,7 +866,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)  {  	struct task_struct *new_owner;  	struct futex_pi_state *pi_state = this->pi_state; -	u32 curval, newval; +	u32 uninitialized_var(curval), newval;  	if (!pi_state)  		return -EINVAL; @@ -916,7 +928,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)  static int unlock_futex_pi(u32 __user *uaddr, u32 uval)  { -	u32 oldval; +	u32 uninitialized_var(oldval);  	/*  	 * There is no waiter, so we unlock the futex. The owner died @@ -1576,7 +1588,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,  	u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;  	struct futex_pi_state *pi_state = q->pi_state;  	struct task_struct *oldowner = pi_state->owner; -	u32 uval, curval, newval; +	u32 uval, uninitialized_var(curval), newval;  	int ret;  	/* Owner died? */ @@ -1793,7 +1805,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,   *   * Returns:   *  0 - uaddr contains val and hb has been locked - * <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlcoked + * <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlocked   */  static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,  			   struct futex_q *q, struct futex_hash_bucket **hb) @@ -2481,7 +2493,7 @@ err_unlock:   */  int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)  { -	u32 uval, nval, mval; +	u32 uval, uninitialized_var(nval), mval;  retry:  	if (get_user(uval, uaddr))  |