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
This commit is contained in:
@@ -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,
|
|||||||
* 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)
|
|||||||
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,
|
|||||||
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 @@ retry_private:
|
|||||||
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 @@ retry_private:
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 @@
|
|||||||
#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)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user