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

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

Advertisement

Kernel v2.6.25-rc7 /kernel/futex.c

Filename:/kernel/futex.c
Lines Added:74
Lines Deleted:20
Also changed in: (Previous) 2.6.25-rc6  2.6.25-rc5  2.6.25-rc4  2.6.25-rc3  2.6.25-rc2-git8  2.6.25-rc2 
(Following) 2.6.25-rc7-git3  2.6.25-rc7-git4  2.6.25-rc7-git5  2.6.25-rc7-git6  2.6.25-rc8  2.6.25-rc9 

Location
[  2.6.25-rc7
  [  kernel
     o  futex.c

Patch

diff --git a/kernel/futex.c b/kernel/futex.c
index db9824d..06968cd 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -60,6 +60,8 @@
 
 #include "rtmutex_common.h"
 
+int __read_mostly futex_cmpxchg_enabled;
+
 #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
 
 /*
@@ -109,6 +111,9 @@ struct futex_q {
    /* Optional priority inheritance state: */
    struct futex_pi_state *pi_state;
    struct task_struct *task;
+
+   /* Bitset for the optional bitmasked wakeup */
+   u32 bitset;
 };
 
 /*
@@ -466,6 +471,8 @@ void exit_pi_state_list(struct task_struct *curr)
    struct futex_hash_bucket *hb;
    union futex_key key;
 
+   if (!futex_cmpxchg_enabled)
+      return;
    /*
     * We are a ZOMBIE and nobody can enqueue itself on
     * pi_state_list anymore, but we have to be careful
@@ -722,7 +729,7 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
  * to this virtual address:
  */
 static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
-            int nr_wake)
+            int nr_wake, u32 bitset)
 {
    struct futex_hash_bucket *hb;
    struct futex_q *this, *next;
@@ -730,6 +737,9 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
    union futex_key key;
    int ret;
 
+   if (!bitset)
+      return -EINVAL;
+
    futex_lock_mm(fshared);
 
    ret = get_futex_key(uaddr, fshared, &key);
@@ -746,6 +756,11 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
             ret = -EINVAL;
             break;
          }
+
+         /* Check if one of the bits is set in both bitsets */
+         if (!(this->bitset & bitset))
+            continue;
+
          wake_futex(this);
          if (++ret >= nr_wake)
             break;
@@ -1156,7 +1171,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
 static long futex_wait_restart(struct restart_block *restart);
 
 static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
-            u32 val, ktime_t *abs_time)
+            u32 val, ktime_t *abs_time, u32 bitset)
 {
    struct task_struct *curr = current;
    DECLARE_WAITQUEUE(wait, curr);
@@ -1167,7 +1182,11 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
    struct hrtimer_sleeper t;
    int rem = 0;
 
+   if (!bitset)
+      return -EINVAL;
+
    q.pi_state = NULL;
+   q.bitset = bitset;
  retry:
    futex_lock_mm(fshared);
 
@@ -1252,6 +1271,8 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
          t.timer.expires = *abs_time;
 
          hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS);
+         if (!hrtimer_active(&t.timer))
+            t.task = NULL;
 
          /*
           * the timer could have already expired, in which
@@ -1293,6 +1314,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
       restart->futex.uaddr = (u32 *)uaddr;
       restart->futex.val = val;
       restart->futex.time = abs_time->tv64;
+      restart->futex.bitset = bitset;
       restart->futex.flags = 0;
 
       if (fshared)
@@ -1319,7 +1341,8 @@ static long futex_wait_restart(struct restart_block *restart)
    restart->fn = do_no_restart_syscall;
    if (restart->futex.flags & FLAGS_SHARED)
       fshared = ¤t->mm->mmap_sem;
-   return (long)futex_wait(uaddr, fshared, restart->futex.val, &t);
+   return (long)futex_wait(uaddr, fshared, restart->futex.val, &t,
+            restart->futex.bitset);
 }
 
 
@@ -1535,9 +1558,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
             owner = rt_mutex_owner(&q.pi_state->pi_mutex);
             res = fixup_pi_state_owner(uaddr, &q, owner);
 
-            WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) !=
-               owner);
-
             /* propagate -EFAULT, if the fixup failed */
             if (res)
                ret = res;
@@ -1854,6 +1874,8 @@ asmlinkage long
 sys_set_robust_list(struct robust_list_head __user *head,
           size_t len)
 {
+   if (!futex_cmpxchg_enabled)
+      return -ENOSYS;
    /*
     * The kernel knows only one size for now:
     */
@@ -1878,6 +1900,9 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr,
    struct robust_list_head __user *head;
    unsigned long ret;
 
+   if (!futex_cmpxchg_enabled)
+      return -ENOSYS;
+
    if (!pid)
       head = current->robust_list;
    else {
@@ -1943,7 +1968,8 @@ retry:
        * PI futexes happens in exit_pi_state():
        */
       if (!pi && (uval & FUTEX_WAITERS))
-            futex_wake(uaddr, &curr->mm->mmap_sem, 1);
+         futex_wake(uaddr, &curr->mm->mmap_sem, 1,
+               FUTEX_BITSET_MATCH_ANY);
    }
    return 0;
 }
@@ -1980,6 +2006,9 @@ void exit_robust_list(struct task_struct *curr)
    unsigned long futex_offset;
    int rc;
 
+   if (!futex_cmpxchg_enabled)
+      return;
+
    /*
     * Fetch the list head (which was registered earlier, via
     * sys_set_robust_list()):
@@ -2034,7 +2063,7 @@ void exit_robust_list(struct task_struct *curr)
 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
       u32 __user *uaddr2, u32 val2, u32 val3)
 {
-   int ret;
+   int ret = -ENOSYS;
    int cmd = op & FUTEX_CMD_MASK;
    struct rw_semaphore *fshared = NULL;
 
@@ -2043,10 +2072,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
 
    switch (cmd) {
    case FUTEX_WAIT:
-      ret = futex_wait(uaddr, fshared, val, timeout);
+      val3 = FUTEX_BITSET_MATCH_ANY;
+   case FUTEX_WAIT_BITSET:
+      ret = futex_wait(uaddr, fshared, val, timeout, val3);
       break;
    case FUTEX_WAKE:
-      ret = futex_wake(uaddr, fshared, val);
+      val3 = FUTEX_BITSET_MATCH_ANY;
+   case FUTEX_WAKE_BITSET:
+      ret = futex_wake(uaddr, fshared, val, val3);
       break;
    case FUTEX_FD:
       /* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
@@ -2062,13 +2095,16 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
       ret = futex_wake_op(uaddr, fshared, uaddr2, val, val2, val3);
       break;
    case FUTEX_LOCK_PI:
-      ret = futex_lock_pi(uaddr, fshared, val, timeout, 0);
+      if (futex_cmpxchg_enabled)
+         ret = futex_lock_pi(uaddr, fshared, val, timeout, 0);
       break;
    case FUTEX_UNLOCK_PI:
-      ret = futex_unlock_pi(uaddr, fshared);
+      if (futex_cmpxchg_enabled)
+         ret = futex_unlock_pi(uaddr, fshared);
       break;
    case FUTEX_TRYLOCK_PI:
-      ret = futex_lock_pi(uaddr, fshared, 0, timeout, 1);
+      if (futex_cmpxchg_enabled)
+         ret = futex_lock_pi(uaddr, fshared, 0, timeout, 1);
       break;
    default:
       ret = -ENOSYS;
@@ -2086,7 +2122,8 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
    u32 val2 = 0;
    int cmd = op & FUTEX_CMD_MASK;
 
-   if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
+   if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
+            cmd == FUTEX_WAIT_BITSET)) {
       if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
          return -EFAULT;
       if (!timespec_valid(&ts))
@@ -2094,7 +2131,7 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
 
       t = timespec_to_ktime(ts);
       if (cmd == FUTEX_WAIT)
-         t = ktime_add(ktime_get(), t);
+         t = ktime_add_safe(ktime_get(), t);
       tp = &t;
    }
    /*
@@ -2123,8 +2160,29 @@ static struct file_system_type futex_fs_type = {
 
 static int __init init(void)
 {
-   int i = register_filesystem(&futex_fs_type);
+   u32 curval;
+   int i;
+
+   /*
+    * This will fail and we want it. Some arch implementations do
+    * runtime detection of the futex_atomic_cmpxchg_inatomic()
+    * functionality. We want to know that before we call in any
+    * of the complex code paths. Also we want to prevent
+    * registration of robust lists in that case. NULL is
+    * guaranteed to fault and we get -EFAULT on functional
+    * implementation, the non functional ones will return
+    * -ENOSYS.
+    */
+   curval = cmpxchg_futex_value_locked(NULL, 0, 0);
+   if (curval == -EFAULT)
+      futex_cmpxchg_enabled = 1;
 
+   for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
+      plist_head_init(&futex_queues[i].chain, &futex_queues[i].lock);
+      spin_lock_init(&futex_queues[i].lock);
+   }
+
+   i = register_filesystem(&futex_fs_type);
    if (i)
       return i;
 
@@ -2134,10 +2192,6 @@ static int __init init(void)
       return PTR_ERR(futex_mnt);
    }
 
-   for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
-      plist_head_init(&futex_queues[i].chain, &futex_queues[i].lock);
-      spin_lock_init(&futex_queues[i].lock);
-   }
    return 0;
 }
 __initcall(init);


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