From: Greg Kroah-Hartman Date: Wed, 14 Mar 2012 18:42:29 +0000 (-0700) Subject: 3.0-stable patches X-Git-Tag: v3.0.25~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ed72b5d58d0a18d81da36a5c2985c3eb85937e50;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches added patches: rt2x00-fix-random-stalls.patch vfs-fix-double-put-after-complete_walk.patch vfs-fix-return-value-from-do_last.patch --- diff --git a/queue-3.0/rt2x00-fix-random-stalls.patch b/queue-3.0/rt2x00-fix-random-stalls.patch new file mode 100644 index 00000000000..8118606ba97 --- /dev/null +++ b/queue-3.0/rt2x00-fix-random-stalls.patch @@ -0,0 +1,93 @@ +From 3780d038fdf4b5ef26ead10b0604ab1f46dd9510 Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Fri, 9 Mar 2012 12:39:54 +0100 +Subject: rt2x00: fix random stalls + +From: Stanislaw Gruszka + +commit 3780d038fdf4b5ef26ead10b0604ab1f46dd9510 upstream. + +Is possible that we stop queue and then do not wake up it again, +especially when packets are transmitted fast. That can be easily +reproduced with modified tx queue entry_num to some small value e.g. 16. + +If mac80211 already hold local->queue_stop_reason_lock, then we can wait +on that lock in both rt2x00queue_pause_queue() and +rt2x00queue_unpause_queue(). After drooping ->queue_stop_reason_lock +is possible that __ieee80211_wake_queue() will be performed before +__ieee80211_stop_queue(), hence we stop queue and newer wake up it +again. + +Another race condition is possible when between rt2x00queue_threshold() +check and rt2x00queue_pause_queue() we will process all pending tx +buffers on different cpu. This might happen if for example interrupt +will be triggered on cpu performing rt2x00mac_tx(). + +To prevent race conditions serialize pause/unpause by queue->tx_lock. + +Signed-off-by: Stanislaw Gruszka +Acked-by: Gertjan van Wingerde +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/rt2x00/rt2x00dev.c | 6 +++++- + drivers/net/wireless/rt2x00/rt2x00mac.c | 9 +++++++++ + drivers/net/wireless/rt2x00/rt2x00queue.c | 3 +++ + 3 files changed, 17 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c +@@ -410,10 +410,14 @@ void rt2x00lib_txdone(struct queue_entry + /* + * If the data queue was below the threshold before the txdone + * handler we must make sure the packet queue in the mac80211 stack +- * is reenabled when the txdone handler has finished. ++ * is reenabled when the txdone handler has finished. This has to be ++ * serialized with rt2x00mac_tx(), otherwise we can wake up queue ++ * before it was stopped. + */ ++ spin_lock_bh(&entry->queue->tx_lock); + if (!rt2x00queue_threshold(entry->queue)) + rt2x00queue_unpause_queue(entry->queue); ++ spin_unlock_bh(&entry->queue->tx_lock); + } + EXPORT_SYMBOL_GPL(rt2x00lib_txdone); + +--- a/drivers/net/wireless/rt2x00/rt2x00mac.c ++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c +@@ -152,13 +152,22 @@ void rt2x00mac_tx(struct ieee80211_hw *h + if (unlikely(rt2x00queue_write_tx_frame(queue, skb, false))) + goto exit_fail; + ++ /* ++ * Pausing queue has to be serialized with rt2x00lib_txdone(). Note ++ * we should not use spin_lock_bh variant as bottom halve was already ++ * disabled before ieee80211_xmit() call. ++ */ ++ spin_lock(&queue->tx_lock); + if (rt2x00queue_threshold(queue)) + rt2x00queue_pause_queue(queue); ++ spin_unlock(&queue->tx_lock); + + return; + + exit_fail: ++ spin_lock(&queue->tx_lock); + rt2x00queue_pause_queue(queue); ++ spin_unlock(&queue->tx_lock); + exit_free_skb: + dev_kfree_skb_any(skb); + } +--- a/drivers/net/wireless/rt2x00/rt2x00queue.c ++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c +@@ -562,6 +562,9 @@ int rt2x00queue_write_tx_frame(struct da + u8 rate_idx, rate_flags; + int ret = 0; + ++ /* ++ * That function must be called with bh disabled. ++ */ + spin_lock(&queue->tx_lock); + + entry = rt2x00queue_get_entry(queue, Q_INDEX); diff --git a/queue-3.0/series b/queue-3.0/series index ee0353f1046..50ebcf1ace6 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -6,3 +6,6 @@ pci-ignore-pre-1.1-aspm-quirking-when-aspm-is-disabled.patch firewire-cdev-fix-32-bit-userland-on-64-bit-kernel-compat-corner-cases.patch firewire-core-handle-ack_busy-when-fetching-the-config-rom.patch pm-driver-core-leave-runtime-pm-enabled-during-system-shutdown.patch +rt2x00-fix-random-stalls.patch +vfs-fix-return-value-from-do_last.patch +vfs-fix-double-put-after-complete_walk.patch diff --git a/queue-3.0/vfs-fix-double-put-after-complete_walk.patch b/queue-3.0/vfs-fix-double-put-after-complete_walk.patch new file mode 100644 index 00000000000..3d89bcce7c7 --- /dev/null +++ b/queue-3.0/vfs-fix-double-put-after-complete_walk.patch @@ -0,0 +1,33 @@ +From 097b180ca09b581ef0dc24fbcfc1b227de3875df Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 6 Mar 2012 13:56:33 +0100 +Subject: vfs: fix double put after complete_walk() + +From: Miklos Szeredi + +commit 097b180ca09b581ef0dc24fbcfc1b227de3875df upstream. + +complete_walk() already puts nd->path, no need to do it again at cleanup time. + +This would result in Oopses if triggered, apparently the codepath is not too +well exercised. + +Signed-off-by: Miklos Szeredi +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/namei.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -2208,7 +2208,7 @@ static struct file *do_last(struct namei + /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ + error = complete_walk(nd); + if (error) +- goto exit; ++ return ERR_PTR(error); + error = -EISDIR; + if (S_ISDIR(nd->inode->i_mode)) + goto exit; diff --git a/queue-3.0/vfs-fix-return-value-from-do_last.patch b/queue-3.0/vfs-fix-return-value-from-do_last.patch new file mode 100644 index 00000000000..69ba0973afd --- /dev/null +++ b/queue-3.0/vfs-fix-return-value-from-do_last.patch @@ -0,0 +1,32 @@ +From 7f6c7e62fcc123e6bd9206da99a2163fe3facc31 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 6 Mar 2012 13:56:34 +0100 +Subject: vfs: fix return value from do_last() + +From: Miklos Szeredi + +commit 7f6c7e62fcc123e6bd9206da99a2163fe3facc31 upstream. + +complete_walk() returns either ECHILD or ESTALE. do_last() turns this into +ECHILD unconditionally. If not in RCU mode, this error will reach userspace +which is complete nonsense. + +Signed-off-by: Miklos Szeredi +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/namei.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -2109,7 +2109,7 @@ static struct file *do_last(struct namei + /* sayonara */ + error = complete_walk(nd); + if (error) +- return ERR_PTR(-ECHILD); ++ return ERR_PTR(error); + + error = -ENOTDIR; + if (nd->flags & LOOKUP_DIRECTORY) {