Commit 919aa96a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-fixes-for-linus' of...

Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  futex: Fix handling of bad requeue syscall pairing
  futex: Fix compat_futex to be same as futex for REQUEUE_PI
  locking, sched: Give waitqueue spinlocks their own lockdep classes
  futex: Update futex_q lock_ptr on requeue proxy lock
parents 1c2ffff4 392741e0
...@@ -77,7 +77,14 @@ struct task_struct; ...@@ -77,7 +77,14 @@ struct task_struct;
#define __WAIT_BIT_KEY_INITIALIZER(word, bit) \ #define __WAIT_BIT_KEY_INITIALIZER(word, bit) \
{ .flags = word, .bit_nr = bit, } { .flags = word, .bit_nr = bit, }
extern void init_waitqueue_head(wait_queue_head_t *q); extern void __init_waitqueue_head(wait_queue_head_t *q, struct lock_class_key *);
#define init_waitqueue_head(q) \
do { \
static struct lock_class_key __key; \
\
__init_waitqueue_head((q), &__key); \
} while (0)
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
# define __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) \ # define __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) \
......
...@@ -1010,15 +1010,19 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1, ...@@ -1010,15 +1010,19 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
* requeue_pi_wake_futex() - Wake a task that acquired the lock during requeue * requeue_pi_wake_futex() - Wake a task that acquired the lock during requeue
* q: the futex_q * q: the futex_q
* key: the key of the requeue target futex * key: the key of the requeue target futex
* hb: the hash_bucket of the requeue target futex
* *
* During futex_requeue, with requeue_pi=1, it is possible to acquire the * During futex_requeue, with requeue_pi=1, it is possible to acquire the
* target futex if it is uncontended or via a lock steal. Set the futex_q key * target futex if it is uncontended or via a lock steal. Set the futex_q key
* to the requeue target futex so the waiter can detect the wakeup on the right * to the requeue target futex so the waiter can detect the wakeup on the right
* futex, but remove it from the hb and NULL the rt_waiter so it can detect * futex, but remove it from the hb and NULL the rt_waiter so it can detect
* atomic lock acquisition. Must be called with the q->lock_ptr held. * atomic lock acquisition. Set the q->lock_ptr to the requeue target hb->lock
* to protect access to the pi_state to fixup the owner later. Must be called
* with both q->lock_ptr and hb->lock held.
*/ */
static inline static inline
void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key) void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
struct futex_hash_bucket *hb)
{ {
drop_futex_key_refs(&q->key); drop_futex_key_refs(&q->key);
get_futex_key_refs(key); get_futex_key_refs(key);
...@@ -1030,6 +1034,11 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key) ...@@ -1030,6 +1034,11 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key)
WARN_ON(!q->rt_waiter); WARN_ON(!q->rt_waiter);
q->rt_waiter = NULL; q->rt_waiter = NULL;
q->lock_ptr = &hb->lock;
#ifdef CONFIG_DEBUG_PI_LIST
q->list.plist.lock = &hb->lock;
#endif
wake_up_state(q->task, TASK_NORMAL); wake_up_state(q->task, TASK_NORMAL);
} }
...@@ -1088,7 +1097,7 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex, ...@@ -1088,7 +1097,7 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task, ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task,
set_waiters); set_waiters);
if (ret == 1) if (ret == 1)
requeue_pi_wake_futex(top_waiter, key2); requeue_pi_wake_futex(top_waiter, key2, hb2);
return ret; return ret;
} }
...@@ -1247,8 +1256,15 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -1247,8 +1256,15 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
if (!match_futex(&this->key, &key1)) if (!match_futex(&this->key, &key1))
continue; continue;
WARN_ON(!requeue_pi && this->rt_waiter); /*
WARN_ON(requeue_pi && !this->rt_waiter); * FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always
* be paired with each other and no other futex ops.
*/
if ((requeue_pi && !this->rt_waiter) ||
(!requeue_pi && this->rt_waiter)) {
ret = -EINVAL;
break;
}
/* /*
* Wake nr_wake waiters. For requeue_pi, if we acquired the * Wake nr_wake waiters. For requeue_pi, if we acquired the
...@@ -1273,7 +1289,7 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -1273,7 +1289,7 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
this->task, 1); this->task, 1);
if (ret == 1) { if (ret == 1) {
/* We got the lock. */ /* We got the lock. */
requeue_pi_wake_futex(this, &key2); requeue_pi_wake_futex(this, &key2, hb2);
continue; continue;
} else if (ret) { } else if (ret) {
/* -EDEADLK */ /* -EDEADLK */
......
...@@ -180,7 +180,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, ...@@ -180,7 +180,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
int cmd = op & FUTEX_CMD_MASK; 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)) { cmd == FUTEX_WAIT_BITSET ||
cmd == FUTEX_WAIT_REQUEUE_PI)) {
if (get_compat_timespec(&ts, utime)) if (get_compat_timespec(&ts, utime))
return -EFAULT; return -EFAULT;
if (!timespec_valid(&ts)) if (!timespec_valid(&ts))
...@@ -191,7 +192,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, ...@@ -191,7 +192,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
t = ktime_add_safe(ktime_get(), t); t = ktime_add_safe(ktime_get(), t);
tp = &t; tp = &t;
} }
if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE) if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
val2 = (int) (unsigned long) utime; val2 = (int) (unsigned long) utime;
return do_futex(uaddr, op, val, tp, uaddr2, val2, val3); return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
......
...@@ -10,13 +10,14 @@ ...@@ -10,13 +10,14 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/hash.h> #include <linux/hash.h>
void init_waitqueue_head(wait_queue_head_t *q) void __init_waitqueue_head(wait_queue_head_t *q, struct lock_class_key *key)
{ {
spin_lock_init(&q->lock); spin_lock_init(&q->lock);
lockdep_set_class(&q->lock, key);
INIT_LIST_HEAD(&q->task_list); INIT_LIST_HEAD(&q->task_list);
} }
EXPORT_SYMBOL(init_waitqueue_head); EXPORT_SYMBOL(__init_waitqueue_head);
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment