Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.30.10 /kernel/futex.c

Filename:/kernel/futex.c
Lines Added:24
Lines Deleted:19
Also changed in: (Previous) 2.6.30.9  2.6.30.8  2.6.30.7  2.6.30-git7  2.6.30-git6  2.6.30-git5 
(Following) 2.6.31.8  2.6.31.9-rc1  2.6.31.9  2.6.31.10  2.6.31.11  2.6.31.12 

Location
[  2.6.30.10
  [  kernel
     o  futex.c

Patch

diff --git a/kernel/futex.c b/kernel/futex.c
index d546b2d..4d973bd 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -241,6 +241,7 @@ again:
    if (err < 0)
       return err;
 
+   page = compound_head(page);
    lock_page(page);
    if (!page->mapping) {
       unlock_page(page);
@@ -278,6 +279,25 @@ void put_futex_key(int fshared, union futex_key *key)
    drop_futex_key_refs(key);
 }
 
+/*
+ * fault_in_user_writeable - fault in user address and verify RW access
+ * @uaddr:   pointer to faulting user space address
+ *
+ * Slow path to fixup the fault we just took in the atomic write
+ * access to @uaddr.
+ *
+ * We have no generic implementation of a non destructive write to the
+ * user address. We know that we faulted in the atomic pagefault
+ * disabled section so we can as well avoid the #PF overhead by
+ * calling get_user_pages() right away.
+ */
+static int fault_in_user_writeable(u32 __user *uaddr)
+{
+   int ret = get_user_pages(current, current->mm, (unsigned long)uaddr,
+             1, 1, 0, NULL, NULL);
+   return ret < 0 ? ret : 0;
+}
+
 static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
 {
    u32 curval;
@@ -739,7 +759,6 @@ retry:
 retry_private:
    op_ret = futex_atomic_op_inuser(op, uaddr2);
    if (unlikely(op_ret < 0)) {
-      u32 dummy;
 
       double_unlock_hb(hb1, hb2);
 
@@ -757,7 +776,7 @@ retry_private:
          goto out_put_keys;
       }
 
-      ret = get_user(dummy, uaddr2);
+      ret = fault_in_user_writeable(uaddr2);
       if (ret)
          goto out_put_keys;
 
@@ -1097,7 +1116,7 @@ retry:
 handle_fault:
    spin_unlock(q->lock_ptr);
 
-   ret = get_user(uval, uaddr);
+   ret = fault_in_user_writeable(uaddr);
 
    spin_lock(q->lock_ptr);
 
@@ -1552,16 +1571,9 @@ out:
    return ret;
 
 uaddr_faulted:
-   /*
-    * We have to r/w  *(int __user *)uaddr, and we have to modify it
-    * atomically.  Therefore, if we continue to fault after get_user()
-    * below, we need to handle the fault ourselves, while still holding
-    * the mmap_sem.  This can occur if the uaddr is under contention as
-    * we have to drop the mmap_sem in order to call get_user().
-    */
    queue_unlock(&q, hb);
 
-   ret = get_user(uval, uaddr);
+   ret = fault_in_user_writeable(uaddr);
    if (ret)
       goto out_put_key;
 
@@ -1657,17 +1669,10 @@ out:
    return ret;
 
 pi_faulted:
-   /*
-    * We have to r/w  *(int __user *)uaddr, and we have to modify it
-    * atomically.  Therefore, if we continue to fault after get_user()
-    * below, we need to handle the fault ourselves, while still holding
-    * the mmap_sem.  This can occur if the uaddr is under contention as
-    * we have to drop the mmap_sem in order to call get_user().
-    */
    spin_unlock(&hb->lock);
    put_futex_key(fshared, &key);
 
-   ret = get_user(uval, uaddr);
+   ret = fault_in_user_writeable(uaddr);
    if (!ret)
       goto retry;
 


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.