The patch titled pi-futex: robust-futex exit has been removed from the -mm tree. Its filename is pi-futex-robust-futex-exit.patch This patch was dropped because it was merged into mainline or a subsystem tree ------------------------------------------------------ Subject: pi-futex: robust-futex exit From: Ingo Molnar <mingo@xxxxxxx> I found the bug that caused the robust-PI-futex crash by the x86-64 glibc tests Ulrich and Jakub were running. The essential fix boils down to an embarrasing oneliner thinko in futex.c: - list_del_init(&pi_state->owner->pi_state_list); + list_del_init(&pi_state->list); the patch below fixes the crash and a locking bug as well (we manipulated the pi-list without holding the right lock to it). I have also added a few more debugging checks for the list ops we do there. (since i spent a few hours on this i'll now spend a few hours on improving Linux's list.h debugging capabilities. It's bad that we dont detect such clearly incorrect list ops as buggy. I'll see how much we can do with the current list assumptions and APIs.) Fix pi_state->list handling bugs: list handling mishap, locking error. Plus add more debug checks and fix a few style issues i noticed while debugging this. (reported by Ulrich Drepper and Jakub Jelinek.) Signed-off-by: Ingo Molnar <mingo@xxxxxxx> Cc: Jakub Jelinek <jakub@xxxxxxxxxx> Acked-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Cc: Ulrich Drepper <drepper@xxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxx> --- kernel/futex.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff -puN kernel/futex.c~pi-futex-robust-futex-exit kernel/futex.c --- a/kernel/futex.c~pi-futex-robust-futex-exit +++ a/kernel/futex.c @@ -415,15 +415,15 @@ out_unlock: */ void exit_pi_state_list(struct task_struct *curr) { - struct futex_hash_bucket *hb; struct list_head *next, *head = &curr->pi_state_list; struct futex_pi_state *pi_state; + struct futex_hash_bucket *hb; union futex_key key; /* * We are a ZOMBIE and nobody can enqueue itself on * pi_state_list anymore, but we have to be careful - * versus waiters unqueueing themselfs + * versus waiters unqueueing themselves: */ spin_lock_irq(&curr->pi_lock); while (!list_empty(head)) { @@ -431,21 +431,24 @@ void exit_pi_state_list(struct task_stru next = head->next; pi_state = list_entry(next, struct futex_pi_state, list); key = pi_state->key; + hb = hash_futex(&key); spin_unlock_irq(&curr->pi_lock); - hb = hash_futex(&key); spin_lock(&hb->lock); spin_lock_irq(&curr->pi_lock); + /* + * We dropped the pi-lock, so re-check whether this + * task still owns the PI-state: + */ if (head->next != next) { spin_unlock(&hb->lock); continue; } - list_del_init(&pi_state->list); - WARN_ON(pi_state->owner != curr); - + WARN_ON(list_empty(&pi_state->list)); + list_del_init(&pi_state->list); pi_state->owner = NULL; spin_unlock_irq(&curr->pi_lock); @@ -470,7 +473,7 @@ lookup_pi_state(u32 uval, struct futex_h head = &hb->chain; list_for_each_entry_safe(this, next, head, list) { - if (match_futex (&this->key, &me->key)) { + if (match_futex(&this->key, &me->key)) { /* * Another waiter already exists - bump up * the refcount and return its pi_state: @@ -482,6 +485,8 @@ lookup_pi_state(u32 uval, struct futex_h if (unlikely(!pi_state)) return -EINVAL; + WARN_ON(!atomic_read(&pi_state->refcount)); + atomic_inc(&pi_state->refcount); me->pi_state = pi_state; @@ -510,6 +515,7 @@ lookup_pi_state(u32 uval, struct futex_h pi_state->key = me->key; spin_lock_irq(&p->pi_lock); + WARN_ON(!list_empty(&pi_state->list)); list_add(&pi_state->list, &p->pi_state_list); pi_state->owner = p; spin_unlock_irq(&p->pi_lock); @@ -584,9 +590,17 @@ static int wake_futex_pi(u32 __user *uad if (curval != uval) return -EINVAL; - list_del_init(&pi_state->owner->pi_state_list); + spin_lock_irq(&pi_state->owner->pi_lock); + WARN_ON(list_empty(&pi_state->list)); + list_del_init(&pi_state->list); + spin_unlock_irq(&pi_state->owner->pi_lock); + + spin_lock_irq(&new_owner->pi_lock); + WARN_ON(!list_empty(&pi_state->list)); list_add(&pi_state->list, &new_owner->pi_state_list); pi_state->owner = new_owner; + spin_unlock_irq(&new_owner->pi_lock); + rt_mutex_unlock(&pi_state->pi_mutex); return 0; @@ -1236,6 +1250,7 @@ static int do_futex_lock_pi(u32 __user * /* Owner died? */ if (q.pi_state->owner != NULL) { spin_lock_irq(&q.pi_state->owner->pi_lock); + WARN_ON(list_empty(&q.pi_state->list)); list_del_init(&q.pi_state->list); spin_unlock_irq(&q.pi_state->owner->pi_lock); } else @@ -1244,6 +1259,7 @@ static int do_futex_lock_pi(u32 __user * q.pi_state->owner = current; spin_lock_irq(¤t->pi_lock); + WARN_ON(!list_empty(&q.pi_state->list)); list_add(&q.pi_state->list, ¤t->pi_state_list); spin_unlock_irq(¤t->pi_lock); _ Patches currently in -mm which might be from mingo@xxxxxxx are origin.patch genirq-endisable_irq_wake-need-refcounting-too.patch disable-debugging-version-of-write_lock.patch git-netdev-all.patch lockdep-fix-sk_dst_check-deadlock.patch lockdep-split-the-skb_queue_head_init-lock-class.patch bootmem-use-max_dma_address-instead-of-low32limit.patch i386-early-fault-handler.patch make-touch_nmi_watchdog-imply-touch_softlockup_watchdog-on.patch make-touch_nmi_watchdog-imply-touch_softlockup_watchdog-on-fix.patch let-warn_on-warn_on_once-return-the-condition.patch let-warn_on-warn_on_once-return-the-condition-fix.patch let-warn_on-warn_on_once-return-the-condition-fix-2.patch fix-cond_resched-fix.patch spinlock_debug-dont-recompute-jiffies_per_loop.patch pi-futex-missing-pi_waiters-plist-initialization.patch inotify-fix-deadlock-found-by-lockdep.patch lockdep-dont-pull-in-includes-when-lockdep-disabled.patch reducing-local_bh_enable-disable-overhead-in-irqtrace.patch reference-rt-mutex-design-in-rtmutexc.patch ipc-msgc-clean-up-coding-style.patch sched-force-sbin-init-off-isolated-cpus.patch sched-add-above-background-load-function.patch mm-implement-swap-prefetching.patch sched-cleanup-remove-task_t-convert-to-struct-task_struct-prefetch.patch genirq-convert-the-x86_64-architecture-to-irq-chips.patch genirq-convert-the-i386-architecture-to-irq-chips.patch genirq-irq-convert-the-move_irq-flag-from-a-32bit-word-to-a-single-bit.patch genirq-irq-add-moved_masked_irq.patch genirq-x86_64-irq-reenable-migrating-irqs-to-other-cpus.patch genirq-msi-simplify-msi-enable-and-disable.patch genirq-msi-make-the-msi-boolean-tests-return-either-0-or-1.patch genirq-msi-implement-helper-functions-read_msi_msg-and-write_msi_msg.patch genirq-msi-refactor-the-msi_ops.patch genirq-msi-simplify-the-msi-irq-limit-policy.patch genirq-irq-add-a-dynamic-irq-creation-api.patch genirq-ia64-irq-dynamic-irq-support.patch genirq-i386-irq-dynamic-irq-support.patch genirq-x86_64-irq-dynamic-irq-support.patch genirq-msi-make-the-msi-code-irq-based-and-not-vector-based.patch genirq-x86_64-irq-move-msi-message-composition-into-io_apicc.patch genirq-i386-irq-move-msi-message-composition-into-io_apicc.patch genirq-msi-only-build-msi-apicc-on-ia64.patch genirq-x86_64-irq-remove-the-msi-assumption-that-irq-==-vector.patch genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector.patch genirq-irq-remove-msi-hacks.patch genirq-irq-generalize-the-check-for-hardirq_bits.patch genirq-x86_64-irq-make-the-external-irq-handlers-report-their-vector-not-the-irq-number.patch genirq-x86_64-irq-make-vector_irq-per-cpu.patch genirq-x86_64-irq-kill-gsi_irq_sharing.patch genirq-x86_64-irq-kill-irq-compression.patch detect-atomic-counter-underflows.patch debug-shared-irqs.patch make-frame_pointer-default=y.patch mutex-subsystem-synchro-test-module.patch vdso-print-fatal-signals.patch vdso-improve-print_fatal_signals-support-by-adding-memory-maps.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html