From: Chris Wright Date: Mon, 11 Jun 2007 23:50:31 +0000 (-0700) Subject: restart the 2.6.21 queue X-Git-Tag: v2.6.22.1~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=51b97645ac6058ceaf37b51db705207984e2a4af;p=thirdparty%2Fkernel%2Fstable-queue.git restart the 2.6.21 queue --- diff --git a/queue-2.6.21/bnx2-fix-netdev-watchdog-on-5708.patch b/queue-2.6.21/bnx2-fix-netdev-watchdog-on-5708.patch new file mode 100644 index 00000000000..792c1c08dea --- /dev/null +++ b/queue-2.6.21/bnx2-fix-netdev-watchdog-on-5708.patch @@ -0,0 +1,73 @@ +From stable-bounces@linux.kernel.org Tue Jun 5 10:44:15 2007 +From: "Michael Chan" +To: stable@kernel.org +Date: Tue, 05 Jun 2007 11:33:20 -0700 +Message-ID: <1181068400.4832.3.camel@dell> +Subject: BNX2: Fix netdev watchdog on 5708. + +There's a bug in the driver that only initializes half of the context +memory on the 5708. Surprisingly, this works most of the time except +for some occasional netdev watchdogs when sending a lot of 64-byte +packets. This fix is to add the missing code to initialize the 2nd +half of the context memory. + +Update version to 1.5.8.2. + +Signed-off-by: Michael Chan +Signed-off-by: David S. Miller +Signed-off-by: Chris Wright + +--- + drivers/net/bnx2.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +--- linux-2.6.21.5.orig/drivers/net/bnx2.c ++++ linux-2.6.21.5/drivers/net/bnx2.c +@@ -54,8 +54,8 @@ + + #define DRV_MODULE_NAME "bnx2" + #define PFX DRV_MODULE_NAME ": " +-#define DRV_MODULE_VERSION "1.5.8.1" +-#define DRV_MODULE_RELDATE "May 7, 2007" ++#define DRV_MODULE_VERSION "1.5.8.2" ++#define DRV_MODULE_RELDATE "June 5, 2007" + + #define RUN_AT(x) (jiffies + (x)) + +@@ -1550,6 +1550,7 @@ bnx2_init_context(struct bnx2 *bp) + vcid = 96; + while (vcid) { + u32 vcid_addr, pcid_addr, offset; ++ int i; + + vcid--; + +@@ -1570,16 +1571,20 @@ bnx2_init_context(struct bnx2 *bp) + pcid_addr = vcid_addr; + } + +- REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00); +- REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr); ++ for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) { ++ vcid_addr += (i << PHY_CTX_SHIFT); ++ pcid_addr += (i << PHY_CTX_SHIFT); ++ ++ REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00); ++ REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr); ++ ++ /* Zero out the context. */ ++ for (offset = 0; offset < PHY_CTX_SIZE; offset += 4) ++ CTX_WR(bp, 0x00, offset, 0); + +- /* Zero out the context. */ +- for (offset = 0; offset < PHY_CTX_SIZE; offset += 4) { +- CTX_WR(bp, 0x00, offset, 0); ++ REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr); ++ REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr); + } +- +- REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr); +- REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr); + } + } + diff --git a/queue-2.6.21/fix-show_mem-x86_64-sparsemem.patch b/queue-2.6.21/fix-show_mem-x86_64-sparsemem.patch new file mode 100644 index 00000000000..801e0d39d9e --- /dev/null +++ b/queue-2.6.21/fix-show_mem-x86_64-sparsemem.patch @@ -0,0 +1,39 @@ +From stable-bounces@linux.kernel.org Thu Jun 7 18:02:08 2007 +From: "Bob Picco" +Date: Thu, 7 Jun 2007 21:01:35 -0400 +To: stable@kernel.org +Message-ID: <20070608010135.GG11999@localhost> +Cc: andi@firstfloor.org, johnstul@us.ibm.com, Bernhard Walle , Bob Picco , acme@redhat.com, Sripathi Kodi , Chuck Ebbert , tglx@linutronix.de +Subject: sparsemem: fix oops in x86_64 show_mem + +We aren't sampling for holes in memory. Thus we encounter a section hole with +empty section map pointer for SPARSEMEM and OOPs for show_mem. This issue +has been seen in 2.6.21, current git and current mm. This patch is for +2.6.21 stable. It was tested against sparsemem. + +Previous to commit f0a5a58aa812b31fd9f197c4ba48245942364eae memory_present +was called for node_start_pfn to node_end_pfn. This would cover the hole(s) +with reserved pages and valid sections. Most SPARSEMEM supported arches +do a pfn_valid check in show_mem before computing the page structure address. + +This issue was brought to my attention on IRC by Arnaldo Carvalho de Melo at +acme@redhat.com. Thanks to Arnaldo for testing. + +Signed-off-by: Bob Picco +Signed-off-by: Chris Wright +--- + + arch/x86_64/mm/init.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- linux-2.6.21.5.orig/arch/x86_64/mm/init.c ++++ linux-2.6.21.5/arch/x86_64/mm/init.c +@@ -72,6 +72,8 @@ void show_mem(void) + + for_each_online_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; ++i) { ++ if (!pfn_valid(pgdat->node_start_pfn + i)) ++ continue; + page = pfn_to_page(pgdat->node_start_pfn + i); + total++; + if (PageReserved(page)) diff --git a/queue-2.6.21/pi-futex-fix-exit-races-and-locking-problems.patch b/queue-2.6.21/pi-futex-fix-exit-races-and-locking-problems.patch new file mode 100644 index 00000000000..1fe614b17a0 --- /dev/null +++ b/queue-2.6.21/pi-futex-fix-exit-races-and-locking-problems.patch @@ -0,0 +1,445 @@ +From stable-bounces@linux.kernel.org Fri Jun 8 03:16:17 2007 +Message-Id: <20070608101735.114323310@inhelltoy.tec.linutronix.de> +Date: Fri, 08 Jun 2007 10:29:30 -0000 +From: Thomas Gleixner +To: stable@kernel.org +Cc: kuznet@ms2.inr.ac.ru, mingo@elte.hu, linux-kernel@vger.kernel.org +Subject: pi-futex: Fix exit races and locking problems + + +From: Alexey Kuznetsov +1. New entries can be added to tsk->pi_state_list after task completed + exit_pi_state_list(). The result is memory leakage and deadlocks. + +2. handle_mm_fault() is called under spinlock. The result is obvious. + +3. results in self-inflicted deadlock inside glibc. + Sometimes futex_lock_pi returns -ESRCH, when it is not expected + and glibc enters to for(;;) sleep() to simulate deadlock. This problem + is quite obvious and I think the patch is right. Though it looks like + each "if" in futex_lock_pi() got some stupid special case "else if". :-) + +4. sometimes futex_lock_pi() returns -EDEADLK, + when nobody has the lock. The reason is also obvious (see comment + in the patch), but correct fix is far beyond my comprehension. + I guess someone already saw this, the chunk: + + if (rt_mutex_trylock(&q.pi_state->pi_mutex)) + ret = 0; + + is obviously from the same opera. But it does not work, because the + rtmutex is really taken at this point: wake_futex_pi() of previous + owner reassigned it to us. My fix works. But it looks very stupid. + I would think about removal of shift of ownership in wake_futex_pi() + and making all the work in context of process taking lock. + +From: Thomas Gleixner + +Fix 1) Avoid the tasklist lock variant of the exit race fix by adding + an additional state transition to the exit code. + + This fixes also the issue, when a task with recursive segfaults + is not able to release the futexes. + +Fix 2) Cleanup the lookup_pi_state() failure path and solve the -ESRCH + problem finally. + +Fix 3) Solve the fixup_pi_state_owner() problem which needs to do the fixup + in the lock protected section by using the in_atomic userspace access + functions. + + This removes also the ugly lock drop / unqueue inside of fixup_pi_state() + +Fix 4) Fix a stale lock in the error path of futex_wake_pi() + +Added some error checks for verification. + +The -EDEADLK problem is solved by the rtmutex fixups. + +Cc: Alexey Kuznetsov +Signed-off-by: Thomas Gleixner +Acked-by: Ingo Molnar +Signed-off-by: Chris Wright + +--- + include/linux/sched.h | 1 + kernel/exit.c | 22 +++++ + kernel/futex.c | 191 +++++++++++++++++++++++++++++++++----------------- + 3 files changed, 150 insertions(+), 64 deletions(-) + +--- linux-2.6.21.5.orig/kernel/futex.c ++++ linux-2.6.21.5/kernel/futex.c +@@ -396,10 +396,6 @@ static struct task_struct * futex_find_g + p = NULL; + goto out_unlock; + } +- if (p->exit_state != 0) { +- p = NULL; +- goto out_unlock; +- } + get_task_struct(p); + out_unlock: + rcu_read_unlock(); +@@ -467,7 +463,7 @@ lookup_pi_state(u32 uval, struct futex_h + struct futex_q *this, *next; + struct list_head *head; + struct task_struct *p; +- pid_t pid; ++ pid_t pid = uval & FUTEX_TID_MASK; + + head = &hb->chain; + +@@ -485,6 +481,8 @@ lookup_pi_state(u32 uval, struct futex_h + return -EINVAL; + + WARN_ON(!atomic_read(&pi_state->refcount)); ++ WARN_ON(pid && pi_state->owner && ++ pi_state->owner->pid != pid); + + atomic_inc(&pi_state->refcount); + me->pi_state = pi_state; +@@ -495,15 +493,33 @@ lookup_pi_state(u32 uval, struct futex_h + + /* + * We are the first waiter - try to look up the real owner and attach +- * the new pi_state to it, but bail out when the owner died bit is set +- * and TID = 0: ++ * the new pi_state to it, but bail out when TID = 0 + */ +- pid = uval & FUTEX_TID_MASK; +- if (!pid && (uval & FUTEX_OWNER_DIED)) ++ if (!pid) + return -ESRCH; + p = futex_find_get_task(pid); +- if (!p) +- return -ESRCH; ++ if (IS_ERR(p)) ++ return PTR_ERR(p); ++ ++ /* ++ * We need to look at the task state flags to figure out, ++ * whether the task is exiting. To protect against the do_exit ++ * change of the task flags, we do this protected by ++ * p->pi_lock: ++ */ ++ spin_lock_irq(&p->pi_lock); ++ if (unlikely(p->flags & PF_EXITING)) { ++ /* ++ * The task is on the way out. When PF_EXITPIDONE is ++ * set, we know that the task has finished the ++ * cleanup: ++ */ ++ int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN; ++ ++ spin_unlock_irq(&p->pi_lock); ++ put_task_struct(p); ++ return ret; ++ } + + pi_state = alloc_pi_state(); + +@@ -516,7 +532,6 @@ lookup_pi_state(u32 uval, struct futex_h + /* Store the key for possible exit cleanups: */ + 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; +@@ -583,15 +598,22 @@ static int wake_futex_pi(u32 __user *uad + * preserve the owner died bit.) + */ + if (!(uval & FUTEX_OWNER_DIED)) { ++ int ret = 0; ++ + newval = FUTEX_WAITERS | new_owner->pid; + + pagefault_disable(); + curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval); + pagefault_enable(); ++ + if (curval == -EFAULT) +- return -EFAULT; ++ ret = -EFAULT; + if (curval != uval) +- return -EINVAL; ++ ret = -EINVAL; ++ if (ret) { ++ spin_unlock(&pi_state->pi_mutex.wait_lock); ++ return ret; ++ } + } + + spin_lock_irq(&pi_state->owner->pi_lock); +@@ -1149,6 +1171,7 @@ static int futex_lock_pi(u32 __user *uad + if (unlikely(ret != 0)) + goto out_release_sem; + ++ retry_unlocked: + hb = queue_lock(&q, -1, NULL); + + retry_locked: +@@ -1200,34 +1223,58 @@ static int futex_lock_pi(u32 __user *uad + ret = lookup_pi_state(uval, hb, &q); + + if (unlikely(ret)) { +- /* +- * There were no waiters and the owner task lookup +- * failed. When the OWNER_DIED bit is set, then we +- * know that this is a robust futex and we actually +- * take the lock. This is safe as we are protected by +- * the hash bucket lock. We also set the waiters bit +- * unconditionally here, to simplify glibc handling of +- * multiple tasks racing to acquire the lock and +- * cleanup the problems which were left by the dead +- * owner. +- */ +- if (curval & FUTEX_OWNER_DIED) { +- uval = newval; +- newval = current->pid | +- FUTEX_OWNER_DIED | FUTEX_WAITERS; ++ switch (ret) { + +- pagefault_disable(); +- curval = futex_atomic_cmpxchg_inatomic(uaddr, +- uval, newval); +- pagefault_enable(); ++ case -EAGAIN: ++ /* ++ * Task is exiting and we just wait for the ++ * exit to complete. ++ */ ++ queue_unlock(&q, hb); ++ up_read(&curr->mm->mmap_sem); ++ cond_resched(); ++ goto retry; + +- if (unlikely(curval == -EFAULT)) ++ case -ESRCH: ++ /* ++ * No owner found for this futex. Check if the ++ * OWNER_DIED bit is set to figure out whether ++ * this is a robust futex or not. ++ */ ++ if (get_futex_value_locked(&curval, uaddr)) + goto uaddr_faulted; +- if (unlikely(curval != uval)) +- goto retry_locked; +- ret = 0; ++ ++ /* ++ * There were no waiters and the owner task lookup ++ * failed. When the OWNER_DIED bit is set, then we ++ * know that this is a robust futex and we actually ++ * take the lock. This is safe as we are protected by ++ * the hash bucket lock. We also set the waiters bit ++ * unconditionally here, to simplify glibc handling of ++ * multiple tasks racing to acquire the lock and ++ * cleanup the problems which were left by the dead ++ * owner. ++ */ ++ if (curval & FUTEX_OWNER_DIED) { ++ uval = newval; ++ newval = current->pid | ++ FUTEX_OWNER_DIED | FUTEX_WAITERS; ++ ++ pagefault_disable(); ++ curval = futex_atomic_cmpxchg_inatomic(uaddr, ++ uval, ++ newval); ++ pagefault_enable(); ++ ++ if (unlikely(curval == -EFAULT)) ++ goto uaddr_faulted; ++ if (unlikely(curval != uval)) ++ goto retry_locked; ++ ret = 0; ++ } ++ default: ++ goto out_unlock_release_sem; + } +- goto out_unlock_release_sem; + } + + /* +@@ -1279,39 +1326,52 @@ static int futex_lock_pi(u32 __user *uad + list_add(&q.pi_state->list, ¤t->pi_state_list); + spin_unlock_irq(¤t->pi_lock); + +- /* Unqueue and drop the lock */ +- unqueue_me_pi(&q, hb); +- up_read(&curr->mm->mmap_sem); + /* + * We own it, so we have to replace the pending owner +- * TID. This must be atomic as we have preserve the ++ * TID. This must be atomic as we have to preserve the + * owner died bit here. + */ +- ret = get_user(uval, uaddr); ++ ret = get_futex_value_locked(&uval, uaddr); + while (!ret) { + newval = (uval & FUTEX_OWNER_DIED) | newtid; ++ ++ pagefault_disable(); + curval = futex_atomic_cmpxchg_inatomic(uaddr, + uval, newval); ++ pagefault_enable(); ++ + if (curval == -EFAULT) + ret = -EFAULT; + if (curval == uval) + break; + uval = curval; + } +- } else { ++ } else if (ret) { + /* + * Catch the rare case, where the lock was released + * when we were on the way back before we locked + * the hash bucket. + */ +- if (ret && q.pi_state->owner == curr) { +- if (rt_mutex_trylock(&q.pi_state->pi_mutex)) +- ret = 0; ++ if (q.pi_state->owner == curr && ++ rt_mutex_trylock(&q.pi_state->pi_mutex)) { ++ ret = 0; ++ } else { ++ /* ++ * Paranoia check. If we did not take the lock ++ * in the trylock above, then we should not be ++ * the owner of the rtmutex, neither the real ++ * nor the pending one: ++ */ ++ if (rt_mutex_owner(&q.pi_state->pi_mutex) == curr) ++ printk(KERN_ERR "futex_lock_pi: ret = %d " ++ "pi-mutex: %p pi-state %p\n", ret, ++ q.pi_state->pi_mutex.owner, ++ q.pi_state->owner); + } +- /* Unqueue and drop the lock */ +- unqueue_me_pi(&q, hb); +- up_read(&curr->mm->mmap_sem); + } ++ /* Unqueue and drop the lock */ ++ unqueue_me_pi(&q, hb); ++ up_read(&curr->mm->mmap_sem); + + if (!detect && ret == -EDEADLK && 0) + force_sig(SIGKILL, current); +@@ -1331,16 +1391,18 @@ static int futex_lock_pi(u32 __user *uad + * non-atomically. Therefore, if get_user below is not + * enough, we need to handle the fault ourselves, while + * still holding the mmap_sem. ++ * ++ * ... and hb->lock. :-) --ANK + */ ++ queue_unlock(&q, hb); ++ + if (attempt++) { +- if (futex_handle_fault((unsigned long)uaddr, attempt)) { +- ret = -EFAULT; +- goto out_unlock_release_sem; +- } +- goto retry_locked; ++ ret = futex_handle_fault((unsigned long)uaddr, attempt); ++ if (ret) ++ goto out_release_sem; ++ goto retry_unlocked; + } + +- queue_unlock(&q, hb); + up_read(&curr->mm->mmap_sem); + + ret = get_user(uval, uaddr); +@@ -1382,9 +1444,9 @@ retry: + goto out; + + hb = hash_futex(&key); ++retry_unlocked: + spin_lock(&hb->lock); + +-retry_locked: + /* + * To avoid races, try to do the TID -> 0 atomic transition + * again. If it succeeds then we can return without waking +@@ -1446,16 +1508,17 @@ pi_faulted: + * non-atomically. Therefore, if get_user below is not + * enough, we need to handle the fault ourselves, while + * still holding the mmap_sem. ++ * ++ * ... and hb->lock. :-) --ANK + */ ++ spin_unlock(&hb->lock); ++ + if (attempt++) { +- if (futex_handle_fault((unsigned long)uaddr, attempt)) { +- ret = -EFAULT; +- goto out_unlock; +- } +- goto retry_locked; ++ ret = futex_handle_fault((unsigned long)uaddr, attempt); ++ if (ret) ++ goto out; ++ goto retry_unlocked; + } +- +- spin_unlock(&hb->lock); + up_read(¤t->mm->mmap_sem); + + ret = get_user(uval, uaddr); +--- linux-2.6.21.5.orig/include/linux/sched.h ++++ linux-2.6.21.5/include/linux/sched.h +@@ -1138,6 +1138,7 @@ static inline void put_task_struct(struc + /* Not implemented yet, only for 486*/ + #define PF_STARTING 0x00000002 /* being created */ + #define PF_EXITING 0x00000004 /* getting shut down */ ++#define PF_EXITPIDONE 0x00000008 /* pi exit done on shut down */ + #define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ + #define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ + #define PF_DUMPCORE 0x00000200 /* dumped core */ +--- linux-2.6.21.5.orig/kernel/exit.c ++++ linux-2.6.21.5/kernel/exit.c +@@ -884,13 +884,29 @@ fastcall NORET_TYPE void do_exit(long co + if (unlikely(tsk->flags & PF_EXITING)) { + printk(KERN_ALERT + "Fixing recursive fault but reboot is needed!\n"); ++ /* ++ * We can do this unlocked here. The futex code uses ++ * this flag just to verify whether the pi state ++ * cleanup has been done or not. In the worst case it ++ * loops once more. We pretend that the cleanup was ++ * done as there is no way to return. Either the ++ * OWNER_DIED bit is set by now or we push the blocked ++ * task into the wait for ever nirwana as well. ++ */ ++ tsk->flags |= PF_EXITPIDONE; + if (tsk->io_context) + exit_io_context(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + ++ /* ++ * tsk->flags are checked in the futex code to protect against ++ * an exiting task cleaning up the robust pi futexes. ++ */ ++ spin_lock_irq(&tsk->pi_lock); + tsk->flags |= PF_EXITING; ++ spin_unlock_irq(&tsk->pi_lock); + + if (unlikely(in_atomic())) + printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", +@@ -957,6 +973,12 @@ fastcall NORET_TYPE void do_exit(long co + * Make sure we are holding no locks: + */ + debug_check_no_locks_held(tsk); ++ /* ++ * We can do this unlocked here. The futex code uses this flag ++ * just to verify whether the pi state cleanup has been done ++ * or not. In the worst case it loops once more. ++ */ ++ tsk->flags |= PF_EXITPIDONE; + + if (tsk->io_context) + exit_io_context(); diff --git a/queue-2.6.21/rt-mutex-fix-chain-walk-early-wakeup-bug.patch b/queue-2.6.21/rt-mutex-fix-chain-walk-early-wakeup-bug.patch new file mode 100644 index 00000000000..5be8c6493cb --- /dev/null +++ b/queue-2.6.21/rt-mutex-fix-chain-walk-early-wakeup-bug.patch @@ -0,0 +1,48 @@ +From stable-bounces@linux.kernel.org Fri Jun 8 03:16:14 2007 +Message-Id: <20070608101735.088903362@inhelltoy.tec.linutronix.de> +Date: Fri, 08 Jun 2007 10:29:29 -0000 +From: Thomas Gleixner +To: stable@kernel.org +Cc: kuznet@ms2.inr.ac.ru, mingo@elte.hu, linux-kernel@vger.kernel.org +Subject: rt-mutex: Fix chain walk early wakeup bug + +Alexey Kuznetsov found some problems in the pi-futex code. + +One of the root causes is: + +When a wakeup happens, we do not to stop the chain walk so we +we follow a non existing locking chain. + +Drop out when this happens. + +Cc: Alexey Kuznetsov +Signed-off-by: Thomas Gleixner +Acked-by: Ingo Molnar +Signed-off-by: Chris Wright + +--- + kernel/rtmutex.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- linux-2.6.21.5.orig/kernel/rtmutex.c ++++ linux-2.6.21.5/kernel/rtmutex.c +@@ -212,6 +212,19 @@ static int rt_mutex_adjust_prio_chain(st + if (!waiter || !waiter->task) + goto out_unlock_pi; + ++ /* ++ * Check the orig_waiter state. After we dropped the locks, ++ * the previous owner of the lock might have released the lock ++ * and made us the pending owner: ++ */ ++ if (orig_waiter && !orig_waiter->task) ++ goto out_unlock_pi; ++ ++ /* ++ * Drop out, when the task has no waiters. Note, ++ * top_waiter can be NULL, when we are in the deboosting ++ * mode! ++ */ + if (top_waiter && (!task_has_pi_waiters(task) || + top_waiter != task_top_pi_waiter(task))) + goto out_unlock_pi; diff --git a/queue-2.6.21/rt-mutex-fix-stale-return-value.patch b/queue-2.6.21/rt-mutex-fix-stale-return-value.patch new file mode 100644 index 00000000000..771cb0e5956 --- /dev/null +++ b/queue-2.6.21/rt-mutex-fix-stale-return-value.patch @@ -0,0 +1,49 @@ +From stable-bounces@linux.kernel.org Fri Jun 8 03:16:12 2007 +Message-Id: <20070608101735.036883282@inhelltoy.tec.linutronix.de> +Date: Fri, 08 Jun 2007 10:29:28 -0000 +From: Thomas Gleixner +To: stable@kernel.org +Cc: kuznet@ms2.inr.ac.ru, mingo@elte.hu +Subject: rt-mutex: Fix stale return value + +Alexey Kuznetsov found some problems in the pi-futex code. + +The major problem is a stale return value in rt_mutex_slowlock(): + +When the pi chain walk returns -EDEADLK, but the waiter was woken up +during the phases where the locks were dropped, the rtmutex could be +acquired, but due to the stale return value -EDEADLK returned to the +caller. + +Reset the return value in the woken up path. + +Cc: Alexey Kuznetsov +Signed-off-by: Thomas Gleixner +Acked-by: Ingo Molnar +Signed-off-by: Chris Wright + +--- + kernel/rtmutex.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- linux-2.6.21.5.orig/kernel/rtmutex.c ++++ linux-2.6.21.5/kernel/rtmutex.c +@@ -659,9 +659,16 @@ rt_mutex_slowlock(struct rt_mutex *lock, + * all over without going into schedule to try + * to get the lock now: + */ +- if (unlikely(!waiter.task)) ++ if (unlikely(!waiter.task)) { ++ /* ++ * Reset the return value. We might ++ * have returned with -EDEADLK and the ++ * owner released the lock while we ++ * were walking the pi chain. ++ */ ++ ret = 0; + continue; +- ++ } + if (unlikely(ret)) + break; + } diff --git a/queue-2.6.21/series b/queue-2.6.21/series new file mode 100644 index 00000000000..04a0a24d571 --- /dev/null +++ b/queue-2.6.21/series @@ -0,0 +1,5 @@ +bnx2-fix-netdev-watchdog-on-5708.patch +fix-show_mem-x86_64-sparsemem.patch +rt-mutex-fix-stale-return-value.patch +rt-mutex-fix-chain-walk-early-wakeup-bug.patch +pi-futex-fix-exit-races-and-locking-problems.patch