git.openpandora.org
/
pandora-kernel.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git]
/
kernel
/
futex.c
diff --git
a/kernel/futex.c
b/kernel/futex.c
index
0a30897
..
11cbe05
100644
(file)
--- a/
kernel/futex.c
+++ b/
kernel/futex.c
@@
-218,6
+218,8
@@
static void drop_futex_key_refs(union futex_key *key)
* @uaddr: virtual address of the futex
* @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
* @key: address where result is stored.
* @uaddr: virtual address of the futex
* @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
* @key: address where result is stored.
+ * @rw: mapping needs to be read/write (values: VERIFY_READ,
+ * VERIFY_WRITE)
*
* Returns a negative error code or 0
* The key words are stored in *key on success.
*
* Returns a negative error code or 0
* The key words are stored in *key on success.
@@
-229,12
+231,12
@@
static void drop_futex_key_refs(union futex_key *key)
* lock_page() might sleep, the caller should not hold a spinlock.
*/
static int
* lock_page() might sleep, the caller should not hold a spinlock.
*/
static int
-get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
+get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key
, int rw
)
{
unsigned long address = (unsigned long)uaddr;
struct mm_struct *mm = current->mm;
struct page *page, *page_head;
{
unsigned long address = (unsigned long)uaddr;
struct mm_struct *mm = current->mm;
struct page *page, *page_head;
- int err;
+ int err
, ro = 0
;
/*
* The futex address must be "naturally" aligned.
/*
* The futex address must be "naturally" aligned.
@@
-262,8
+264,18
@@
get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
again:
err = get_user_pages_fast(address, 1, 1, &page);
again:
err = get_user_pages_fast(address, 1, 1, &page);
+ /*
+ * If write access is not required (eg. FUTEX_WAIT), try
+ * and get read-only access.
+ */
+ if (err == -EFAULT && rw == VERIFY_READ) {
+ err = get_user_pages_fast(address, 1, 0, &page);
+ ro = 1;
+ }
if (err < 0)
return err;
if (err < 0)
return err;
+ else
+ err = 0;
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
page_head = page;
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
page_head = page;
@@
-305,6
+317,13
@@
again:
if (!page_head->mapping) {
unlock_page(page_head);
put_page(page_head);
if (!page_head->mapping) {
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;
}
goto again;
}
@@
-316,6
+335,15
@@
again:
* the object not the particular process.
*/
if (PageAnon(page_head)) {
* the object not the particular process.
*/
if (PageAnon(page_head)) {
+ /*
+ * A RO anonymous page will never change and thus doesn't make
+ * sense for futex operations.
+ */
+ if (ro) {
+ err = -EFAULT;
+ goto out;
+ }
+
key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
key->private.mm = mm;
key->private.address = address;
key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
key->private.mm = mm;
key->private.address = address;
@@
-327,9
+355,10
@@
again:
get_futex_key_refs(key);
get_futex_key_refs(key);
+out:
unlock_page(page_head);
put_page(page_head);
unlock_page(page_head);
put_page(page_head);
- return
0
;
+ return
err
;
}
static inline void put_futex_key(union futex_key *key)
}
static inline void put_futex_key(union futex_key *key)
@@
-940,7
+969,7
@@
futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
if (!bitset)
return -EINVAL;
if (!bitset)
return -EINVAL;
- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key);
+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key
, VERIFY_READ
);
if (unlikely(ret != 0))
goto out;
if (unlikely(ret != 0))
goto out;
@@
-986,10
+1015,10
@@
futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
int ret, op_ret;
retry:
int ret, op_ret;
retry:
- ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1);
+ ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1
, VERIFY_READ
);
if (unlikely(ret != 0))
goto out;
if (unlikely(ret != 0))
goto out;
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
+ ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2
, VERIFY_WRITE
);
if (unlikely(ret != 0))
goto out_put_key1;
if (unlikely(ret != 0))
goto out_put_key1;
@@
-1243,10
+1272,11
@@
retry:
pi_state = NULL;
}
pi_state = NULL;
}
- ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1);
+ ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1
, VERIFY_READ
);
if (unlikely(ret != 0))
goto out;
if (unlikely(ret != 0))
goto out;
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
+ ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
+ requeue_pi ? VERIFY_WRITE : VERIFY_READ);
if (unlikely(ret != 0))
goto out_put_key1;
if (unlikely(ret != 0))
goto out_put_key1;
@@
-1790,7
+1820,7
@@
static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
* while the syscall executes.
*/
retry:
* while the syscall executes.
*/
retry:
- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key);
+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key
, VERIFY_READ
);
if (unlikely(ret != 0))
return ret;
if (unlikely(ret != 0))
return ret;
@@
-1941,7
+1971,7
@@
static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, int detect,
}
retry:
}
retry:
- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key);
+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key
, VERIFY_WRITE
);
if (unlikely(ret != 0))
goto out;
if (unlikely(ret != 0))
goto out;
@@
-2060,7
+2090,7
@@
retry:
if ((uval & FUTEX_TID_MASK) != vpid)
return -EPERM;
if ((uval & FUTEX_TID_MASK) != vpid)
return -EPERM;
- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key);
+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key
, VERIFY_WRITE
);
if (unlikely(ret != 0))
goto out;
if (unlikely(ret != 0))
goto out;
@@
-2249,7
+2279,7
@@
static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
debug_rt_mutex_init_waiter(&rt_waiter);
rt_waiter.task = NULL;
debug_rt_mutex_init_waiter(&rt_waiter);
rt_waiter.task = NULL;
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
+ ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2
, VERIFY_WRITE
);
if (unlikely(ret != 0))
goto out;
if (unlikely(ret != 0))
goto out;