]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.7-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Dec 2012 21:56:32 +0000 (13:56 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Dec 2012 21:56:32 +0000 (13:56 -0800)
added patches:
b43-fix-tx-path-skb-leaks.patch
b43legacy-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch
firmware-loader-fix-the-concurrent-request_firmware-race-for-kref_get-put.patch
firmware-loader-fix-the-race-fw_status_done-is-followed-by-class_timeout.patch
pnpacpi-fix-incorrect-test_alpha-test.patch

queue-3.7/b43-fix-tx-path-skb-leaks.patch [new file with mode: 0644]
queue-3.7/b43legacy-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch [new file with mode: 0644]
queue-3.7/firmware-loader-fix-the-concurrent-request_firmware-race-for-kref_get-put.patch [new file with mode: 0644]
queue-3.7/firmware-loader-fix-the-race-fw_status_done-is-followed-by-class_timeout.patch [new file with mode: 0644]
queue-3.7/pnpacpi-fix-incorrect-test_alpha-test.patch [new file with mode: 0644]
queue-3.7/series

diff --git a/queue-3.7/b43-fix-tx-path-skb-leaks.patch b/queue-3.7/b43-fix-tx-path-skb-leaks.patch
new file mode 100644 (file)
index 0000000..a5a2235
--- /dev/null
@@ -0,0 +1,100 @@
+From 78f18df4b323d2ac14d6c82e2fc3c8dc4556bccc Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Mon, 10 Dec 2012 17:40:21 +0100
+Subject: b43: fix tx path skb leaks
+
+From: Felix Fietkau <nbd@openwrt.org>
+
+commit 78f18df4b323d2ac14d6c82e2fc3c8dc4556bccc upstream.
+
+ieee80211_free_txskb() needs to be used instead of dev_kfree_skb_any for
+tx packets passed to the driver from mac80211
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/b43/dma.c  |    7 +++++--
+ drivers/net/wireless/b43/main.c |   12 ++++++++----
+ drivers/net/wireless/b43/pio.c  |    4 ++--
+ 3 files changed, 15 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/wireless/b43/dma.c
++++ b/drivers/net/wireless/b43/dma.c
+@@ -409,7 +409,10 @@ static inline
+                               struct b43_dmadesc_meta *meta)
+ {
+       if (meta->skb) {
+-              dev_kfree_skb_any(meta->skb);
++              if (ring->tx)
++                      ieee80211_free_txskb(ring->dev->wl->hw, meta->skb);
++              else
++                      dev_kfree_skb_any(meta->skb);
+               meta->skb = NULL;
+       }
+ }
+@@ -1454,7 +1457,7 @@ int b43_dma_tx(struct b43_wldev *dev, st
+       if (unlikely(err == -ENOKEY)) {
+               /* Drop this packet, as we don't have the encryption key
+                * anymore and must not transmit it unencrypted. */
+-              dev_kfree_skb_any(skb);
++              ieee80211_free_txskb(dev->wl->hw, skb);
+               err = 0;
+               goto out;
+       }
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -3397,7 +3397,7 @@ static void b43_tx_work(struct work_stru
+                               break;
+                       }
+                       if (unlikely(err))
+-                              dev_kfree_skb(skb); /* Drop it */
++                              ieee80211_free_txskb(wl->hw, skb);
+                       err = 0;
+               }
+@@ -3419,7 +3419,7 @@ static void b43_op_tx(struct ieee80211_h
+       if (unlikely(skb->len < 2 + 2 + 6)) {
+               /* Too short, this can't be a valid frame. */
+-              dev_kfree_skb_any(skb);
++              ieee80211_free_txskb(hw, skb);
+               return;
+       }
+       B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+@@ -4229,8 +4229,12 @@ redo:
+       /* Drain all TX queues. */
+       for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
+-              while (skb_queue_len(&wl->tx_queue[queue_num]))
+-                      dev_kfree_skb(skb_dequeue(&wl->tx_queue[queue_num]));
++              while (skb_queue_len(&wl->tx_queue[queue_num])) {
++                      struct sk_buff *skb;
++
++                      skb = skb_dequeue(&wl->tx_queue[queue_num]);
++                      ieee80211_free_txskb(wl->hw, skb);
++              }
+       }
+       b43_mac_suspend(dev);
+--- a/drivers/net/wireless/b43/pio.c
++++ b/drivers/net/wireless/b43/pio.c
+@@ -196,7 +196,7 @@ static void b43_pio_cancel_tx_packets(st
+       for (i = 0; i < ARRAY_SIZE(q->packets); i++) {
+               pack = &(q->packets[i]);
+               if (pack->skb) {
+-                      dev_kfree_skb_any(pack->skb);
++                      ieee80211_free_txskb(q->dev->wl->hw, pack->skb);
+                       pack->skb = NULL;
+               }
+       }
+@@ -552,7 +552,7 @@ int b43_pio_tx(struct b43_wldev *dev, st
+       if (unlikely(err == -ENOKEY)) {
+               /* Drop this packet, as we don't have the encryption key
+                * anymore and must not transmit it unencrypted. */
+-              dev_kfree_skb_any(skb);
++              ieee80211_free_txskb(dev->wl->hw, skb);
+               err = 0;
+               goto out;
+       }
diff --git a/queue-3.7/b43legacy-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch b/queue-3.7/b43legacy-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch
new file mode 100644 (file)
index 0000000..6337e92
--- /dev/null
@@ -0,0 +1,134 @@
+From 576d28a7c73013717311cfcb514dbcae27c82eeb Mon Sep 17 00:00:00 2001
+From: Larry Finger <Larry.Finger@lwfinger.net>
+Date: Thu, 6 Dec 2012 21:55:16 -0600
+Subject: b43legacy: Fix firmware loading when driver is built into the kernel
+
+From: Larry Finger <Larry.Finger@lwfinger.net>
+
+commit 576d28a7c73013717311cfcb514dbcae27c82eeb upstream.
+
+Recent versions of udev cause synchronous firmware loading from the
+probe routine to fail because the request to user space times out.
+The original fix for b43legacy (commit a3ea2c7) moved the firmware
+load from the probe routine to a work queue, but it still used synchronous
+firmware loading. This method is OK when b43legacy is built as a module;
+however, it fails when the driver is compiled into the kernel.
+
+This version changes the code to load the initial firmware file
+using request_firmware_nowait(). A completion event is used to
+hold the work queue until that file is available. The remaining
+firmware files are read synchronously.
+
+Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/b43legacy/b43legacy.h |    5 +++
+ drivers/net/wireless/b43legacy/main.c      |   37 ++++++++++++++++++++++++-----
+ 2 files changed, 36 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/wireless/b43legacy/b43legacy.h
++++ b/drivers/net/wireless/b43legacy/b43legacy.h
+@@ -13,6 +13,7 @@
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_driver_chipcommon.h>
++#include <linux/completion.h>
+ #include <net/mac80211.h>
+@@ -733,6 +734,10 @@ struct b43legacy_wldev {
+       /* Firmware data */
+       struct b43legacy_firmware fw;
++      const struct firmware *fwp;     /* needed to pass fw pointer */
++
++      /* completion struct for firmware loading */
++      struct completion fw_load_complete;
+       /* Devicelist in struct b43legacy_wl (all 802.11 cores) */
+       struct list_head list;
+--- a/drivers/net/wireless/b43legacy/main.c
++++ b/drivers/net/wireless/b43legacy/main.c
+@@ -1513,9 +1513,17 @@ static void b43legacy_print_fw_helptext(
+                    "and download the correct firmware (version 3).\n");
+ }
++static void b43legacy_fw_cb(const struct firmware *firmware, void *context)
++{
++      struct b43legacy_wldev *dev = context;
++
++      dev->fwp = firmware;
++      complete(&dev->fw_load_complete);
++}
++
+ static int do_request_fw(struct b43legacy_wldev *dev,
+                        const char *name,
+-                       const struct firmware **fw)
++                       const struct firmware **fw, bool async)
+ {
+       char path[sizeof(modparam_fwpostfix) + 32];
+       struct b43legacy_fw_header *hdr;
+@@ -1528,7 +1536,24 @@ static int do_request_fw(struct b43legac
+       snprintf(path, ARRAY_SIZE(path),
+                "b43legacy%s/%s.fw",
+                modparam_fwpostfix, name);
+-      err = request_firmware(fw, path, dev->dev->dev);
++      b43legacyinfo(dev->wl, "Loading firmware %s\n", path);
++      if (async) {
++              init_completion(&dev->fw_load_complete);
++              err = request_firmware_nowait(THIS_MODULE, 1, path,
++                                            dev->dev->dev, GFP_KERNEL,
++                                            dev, b43legacy_fw_cb);
++              if (err) {
++                      b43legacyerr(dev->wl, "Unable to load firmware\n");
++                      return err;
++              }
++              /* stall here until fw ready */
++              wait_for_completion(&dev->fw_load_complete);
++              if (!dev->fwp)
++                      err = -EINVAL;
++              *fw = dev->fwp;
++      } else {
++              err = request_firmware(fw, path, dev->dev->dev);
++      }
+       if (err) {
+               b43legacyerr(dev->wl, "Firmware file \"%s\" not found "
+                      "or load failed.\n", path);
+@@ -1580,7 +1605,7 @@ static void b43legacy_request_firmware(s
+                       filename = "ucode4";
+               else
+                       filename = "ucode5";
+-              err = do_request_fw(dev, filename, &fw->ucode);
++              err = do_request_fw(dev, filename, &fw->ucode, true);
+               if (err)
+                       goto err_load;
+       }
+@@ -1589,7 +1614,7 @@ static void b43legacy_request_firmware(s
+                       filename = "pcm4";
+               else
+                       filename = "pcm5";
+-              err = do_request_fw(dev, filename, &fw->pcm);
++              err = do_request_fw(dev, filename, &fw->pcm, false);
+               if (err)
+                       goto err_load;
+       }
+@@ -1607,7 +1632,7 @@ static void b43legacy_request_firmware(s
+               default:
+                       goto err_no_initvals;
+               }
+-              err = do_request_fw(dev, filename, &fw->initvals);
++              err = do_request_fw(dev, filename, &fw->initvals, false);
+               if (err)
+                       goto err_load;
+       }
+@@ -1627,7 +1652,7 @@ static void b43legacy_request_firmware(s
+               default:
+                       goto err_no_initvals;
+               }
+-              err = do_request_fw(dev, filename, &fw->initvals_band);
++              err = do_request_fw(dev, filename, &fw->initvals_band, false);
+               if (err)
+                       goto err_load;
+       }
diff --git a/queue-3.7/firmware-loader-fix-the-concurrent-request_firmware-race-for-kref_get-put.patch b/queue-3.7/firmware-loader-fix-the-concurrent-request_firmware-race-for-kref_get-put.patch
new file mode 100644 (file)
index 0000000..033a3b7
--- /dev/null
@@ -0,0 +1,69 @@
+From bd9eb7fbe69111ea0ff1f999ef4a5f26d223d1d5 Mon Sep 17 00:00:00 2001
+From: Chuansheng Liu <chuansheng.liu@intel.com>
+Date: Sat, 10 Nov 2012 01:27:22 +0800
+Subject: firmware loader: Fix the concurrent request_firmware() race for kref_get/put
+
+From: Chuansheng Liu <chuansheng.liu@intel.com>
+
+commit bd9eb7fbe69111ea0ff1f999ef4a5f26d223d1d5 upstream.
+
+There is one race that both request_firmware() with the same
+firmware name.
+
+The race scenerio is as below:
+CPU1                                                  CPU2
+request_firmware() -->
+_request_firmware_load() return err                   another request_firmware() is coming -->
+_request_firmware_cleanup is called -->               _request_firmware_prepare -->
+release_firmware --->                                 fw_lookup_and_allocate_buf -->
+                                                      spin_lock(&fwc->lock)
+...                                                   __fw_lookup_buf() return true
+fw_free_buf() will be called -->                      ...
+kref_put -->
+decrease the refcount to 0
+                                                      kref_get(&tmp->ref) ==> it will trigger warning
+                                                                              due to refcount == 0
+__fw_free_buf() -->
+...                                                   spin_unlock(&fwc->lock)
+spin_lock(&fwc->lock)
+list_del(&buf->list)
+spin_unlock(&fwc->lock)
+kfree(buf)
+                                                      After that, the freed buf will be used.
+
+The key race is decreasing refcount to 0 and list_del is not protected together by
+fwc->lock, and it is possible another thread try to get it between refcount==0
+and list_del.
+
+Fix it here to protect it together.
+
+Acked-by: Ming Lei <ming.lei@canonical.com>
+Signed-off-by: liu chuansheng <chuansheng.liu@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/base/firmware_class.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -246,7 +246,6 @@ static void __fw_free_buf(struct kref *r
+                __func__, buf->fw_id, buf, buf->data,
+                (unsigned int)buf->size);
+-      spin_lock(&fwc->lock);
+       list_del(&buf->list);
+       spin_unlock(&fwc->lock);
+@@ -263,7 +262,10 @@ static void __fw_free_buf(struct kref *r
+ static void fw_free_buf(struct firmware_buf *buf)
+ {
+-      kref_put(&buf->ref, __fw_free_buf);
++      struct firmware_cache *fwc = buf->fwc;
++      spin_lock(&fwc->lock);
++      if (!kref_put(&buf->ref, __fw_free_buf))
++              spin_unlock(&fwc->lock);
+ }
+ /* direct firmware loading support */
diff --git a/queue-3.7/firmware-loader-fix-the-race-fw_status_done-is-followed-by-class_timeout.patch b/queue-3.7/firmware-loader-fix-the-race-fw_status_done-is-followed-by-class_timeout.patch
new file mode 100644 (file)
index 0000000..d3f527c
--- /dev/null
@@ -0,0 +1,112 @@
+From ce2fcbd99cef580623116bb33531dbc3e6f690b0 Mon Sep 17 00:00:00 2001
+From: Chuansheng Liu <chuansheng.liu@intel.com>
+Date: Thu, 8 Nov 2012 19:14:40 +0800
+Subject: firmware loader: Fix the race FW_STATUS_DONE is followed by class_timeout
+
+From: Chuansheng Liu <chuansheng.liu@intel.com>
+
+commit ce2fcbd99cef580623116bb33531dbc3e6f690b0 upstream.
+
+There is a race as below when calling request_firmware():
+CPU1                                   CPU2
+write 0 > loading
+mutex_lock(&fw_lock)
+...
+set_bit FW_STATUS_DONE                 class_timeout is coming
+                                       set_bit FW_STATUS_ABORT
+complete_all &completion
+...
+mutex_unlock(&fw_lock)
+
+In this time, the bit FW_STATUS_DONE and FW_STATUS_ABORT are set,
+and request_firmware() will return failure due to condition in
+_request_firmware_load():
+       if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
+               retval = -ENOENT;
+
+But from the above scenerio, it should be a successful requesting.
+So we need judge if the bit FW_STATUS_DONE is already set before
+calling fw_load_abort() in timeout function.
+
+As Ming's proposal, we need change the timer into sched_work to
+benefit from using &fw_lock mutex also.
+
+Signed-off-by: liu chuansheng <chuansheng.liu@intel.com>
+Acked-by: Ming Lei <ming.lei@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/base/firmware_class.c |   24 ++++++++++++++++--------
+ 1 file changed, 16 insertions(+), 8 deletions(-)
+
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -143,7 +143,7 @@ struct fw_cache_entry {
+ };
+ struct firmware_priv {
+-      struct timer_list timeout;
++      struct delayed_work timeout_work;
+       bool nowait;
+       struct device dev;
+       struct firmware_buf *buf;
+@@ -667,11 +667,18 @@ static struct bin_attribute firmware_att
+       .write = firmware_data_write,
+ };
+-static void firmware_class_timeout(u_long data)
++static void firmware_class_timeout_work(struct work_struct *work)
+ {
+-      struct firmware_priv *fw_priv = (struct firmware_priv *) data;
++      struct firmware_priv *fw_priv = container_of(work,
++                      struct firmware_priv, timeout_work.work);
++      mutex_lock(&fw_lock);
++      if (test_bit(FW_STATUS_DONE, &(fw_priv->buf->status))) {
++              mutex_unlock(&fw_lock);
++              return;
++      }
+       fw_load_abort(fw_priv);
++      mutex_unlock(&fw_lock);
+ }
+ static struct firmware_priv *
+@@ -690,8 +697,8 @@ fw_create_instance(struct firmware *firm
+       fw_priv->nowait = nowait;
+       fw_priv->fw = firmware;
+-      setup_timer(&fw_priv->timeout,
+-                  firmware_class_timeout, (u_long) fw_priv);
++      INIT_DELAYED_WORK(&fw_priv->timeout_work,
++              firmware_class_timeout_work);
+       f_dev = &fw_priv->dev;
+@@ -858,7 +865,9 @@ static int _request_firmware_load(struct
+               dev_dbg(f_dev->parent, "firmware: direct-loading"
+                       " firmware %s\n", buf->fw_id);
++              mutex_lock(&fw_lock);
+               set_bit(FW_STATUS_DONE, &buf->status);
++              mutex_unlock(&fw_lock);
+               complete_all(&buf->completion);
+               direct_load = 1;
+               goto handle_fw;
+@@ -894,15 +903,14 @@ static int _request_firmware_load(struct
+               dev_set_uevent_suppress(f_dev, false);
+               dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
+               if (timeout != MAX_SCHEDULE_TIMEOUT)
+-                      mod_timer(&fw_priv->timeout,
+-                                round_jiffies_up(jiffies + timeout));
++                      schedule_delayed_work(&fw_priv->timeout_work, timeout);
+               kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+       }
+       wait_for_completion(&buf->completion);
+-      del_timer_sync(&fw_priv->timeout);
++      cancel_delayed_work_sync(&fw_priv->timeout_work);
+ handle_fw:
+       mutex_lock(&fw_lock);
diff --git a/queue-3.7/pnpacpi-fix-incorrect-test_alpha-test.patch b/queue-3.7/pnpacpi-fix-incorrect-test_alpha-test.patch
new file mode 100644 (file)
index 0000000..cd8c69a
--- /dev/null
@@ -0,0 +1,32 @@
+From cdc87c5a30f407ed1ce43d8a22261116873d5ef1 Mon Sep 17 00:00:00 2001
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Date: Fri, 7 Dec 2012 23:11:14 +0100
+Subject: pnpacpi: fix incorrect TEST_ALPHA() test
+
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+
+commit cdc87c5a30f407ed1ce43d8a22261116873d5ef1 upstream.
+
+TEST_ALPHA() is broken and always returns 0.
+
+[akpm@linux-foundation.org: return false for '@' as well, per Bjorn]
+Signed-off-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pnp/pnpacpi/core.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pnp/pnpacpi/core.c
++++ b/drivers/pnp/pnpacpi/core.c
+@@ -58,7 +58,7 @@ static inline int __init is_exclusive_de
+       if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
+               return 0
+ #define TEST_ALPHA(c) \
+-      if (!('@' <= (c) || (c) <= 'Z')) \
++      if (!('A' <= (c) && (c) <= 'Z')) \
+               return 0
+ static int __init ispnpidacpi(const char *id)
+ {
index f9f610dcbed27a16e734c7da39cb04b2cc604e84..c462511c920a2364fe5038069b926b1ca508afee 100644 (file)
@@ -1 +1,6 @@
 net-fix-a-race-in-gro_cell_poll.patch
+firmware-loader-fix-the-race-fw_status_done-is-followed-by-class_timeout.patch
+firmware-loader-fix-the-concurrent-request_firmware-race-for-kref_get-put.patch
+b43legacy-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch
+b43-fix-tx-path-skb-leaks.patch
+pnpacpi-fix-incorrect-test_alpha-test.patch