]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 1 May 2016 23:32:23 +0000 (16:32 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 1 May 2016 23:32:23 +0000 (16:32 -0700)
added patches:
asoc-rt5640-correct-the-digital-interface-data-select.patch
asoc-s3c24xx-use-const-snd_soc_component_driver-pointer.patch
efi-fix-out-of-bounds-read-in-variable_matches.patch
workqueue-fix-ghost-pending-flag-while-doing-mq-io.patch

queue-3.14/asoc-rt5640-correct-the-digital-interface-data-select.patch [new file with mode: 0644]
queue-3.14/asoc-s3c24xx-use-const-snd_soc_component_driver-pointer.patch [new file with mode: 0644]
queue-3.14/efi-fix-out-of-bounds-read-in-variable_matches.patch [new file with mode: 0644]
queue-3.14/series
queue-3.14/workqueue-fix-ghost-pending-flag-while-doing-mq-io.patch [new file with mode: 0644]

diff --git a/queue-3.14/asoc-rt5640-correct-the-digital-interface-data-select.patch b/queue-3.14/asoc-rt5640-correct-the-digital-interface-data-select.patch
new file mode 100644 (file)
index 0000000..93d24b1
--- /dev/null
@@ -0,0 +1,92 @@
+From 653aa4645244042826f105aab1be3d01b3d493ca Mon Sep 17 00:00:00 2001
+From: Sugar Zhang <sugar.zhang@rock-chips.com>
+Date: Fri, 18 Mar 2016 14:54:22 +0800
+Subject: ASoC: rt5640: Correct the digital interface data select
+
+From: Sugar Zhang <sugar.zhang@rock-chips.com>
+
+commit 653aa4645244042826f105aab1be3d01b3d493ca upstream.
+
+this patch corrects the interface adc/dac control register definition
+according to datasheet.
+
+Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/soc/codecs/rt5640.c |    2 +-
+ sound/soc/codecs/rt5640.h |   36 ++++++++++++++++++------------------
+ 2 files changed, 19 insertions(+), 19 deletions(-)
+
+--- a/sound/soc/codecs/rt5640.c
++++ b/sound/soc/codecs/rt5640.c
+@@ -359,7 +359,7 @@ static unsigned int bst_tlv[] = {
+ /* Interface data select */
+ static const char * const rt5640_data_select[] = {
+-      "Normal", "left copy to right", "right copy to left", "Swap"};
++      "Normal", "Swap", "left copy to right", "right copy to left"};
+ static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA,
+                               RT5640_IF1_DAC_SEL_SFT, rt5640_data_select);
+--- a/sound/soc/codecs/rt5640.h
++++ b/sound/soc/codecs/rt5640.h
+@@ -435,39 +435,39 @@
+ #define RT5640_IF1_DAC_SEL_MASK                       (0x3 << 14)
+ #define RT5640_IF1_DAC_SEL_SFT                        14
+ #define RT5640_IF1_DAC_SEL_NOR                        (0x0 << 14)
+-#define RT5640_IF1_DAC_SEL_L2R                        (0x1 << 14)
+-#define RT5640_IF1_DAC_SEL_R2L                        (0x2 << 14)
+-#define RT5640_IF1_DAC_SEL_SWAP                       (0x3 << 14)
++#define RT5640_IF1_DAC_SEL_SWAP                       (0x1 << 14)
++#define RT5640_IF1_DAC_SEL_L2R                        (0x2 << 14)
++#define RT5640_IF1_DAC_SEL_R2L                        (0x3 << 14)
+ #define RT5640_IF1_ADC_SEL_MASK                       (0x3 << 12)
+ #define RT5640_IF1_ADC_SEL_SFT                        12
+ #define RT5640_IF1_ADC_SEL_NOR                        (0x0 << 12)
+-#define RT5640_IF1_ADC_SEL_L2R                        (0x1 << 12)
+-#define RT5640_IF1_ADC_SEL_R2L                        (0x2 << 12)
+-#define RT5640_IF1_ADC_SEL_SWAP                       (0x3 << 12)
++#define RT5640_IF1_ADC_SEL_SWAP                       (0x1 << 12)
++#define RT5640_IF1_ADC_SEL_L2R                        (0x2 << 12)
++#define RT5640_IF1_ADC_SEL_R2L                        (0x3 << 12)
+ #define RT5640_IF2_DAC_SEL_MASK                       (0x3 << 10)
+ #define RT5640_IF2_DAC_SEL_SFT                        10
+ #define RT5640_IF2_DAC_SEL_NOR                        (0x0 << 10)
+-#define RT5640_IF2_DAC_SEL_L2R                        (0x1 << 10)
+-#define RT5640_IF2_DAC_SEL_R2L                        (0x2 << 10)
+-#define RT5640_IF2_DAC_SEL_SWAP                       (0x3 << 10)
++#define RT5640_IF2_DAC_SEL_SWAP                       (0x1 << 10)
++#define RT5640_IF2_DAC_SEL_L2R                        (0x2 << 10)
++#define RT5640_IF2_DAC_SEL_R2L                        (0x3 << 10)
+ #define RT5640_IF2_ADC_SEL_MASK                       (0x3 << 8)
+ #define RT5640_IF2_ADC_SEL_SFT                        8
+ #define RT5640_IF2_ADC_SEL_NOR                        (0x0 << 8)
+-#define RT5640_IF2_ADC_SEL_L2R                        (0x1 << 8)
+-#define RT5640_IF2_ADC_SEL_R2L                        (0x2 << 8)
+-#define RT5640_IF2_ADC_SEL_SWAP                       (0x3 << 8)
++#define RT5640_IF2_ADC_SEL_SWAP                       (0x1 << 8)
++#define RT5640_IF2_ADC_SEL_L2R                        (0x2 << 8)
++#define RT5640_IF2_ADC_SEL_R2L                        (0x3 << 8)
+ #define RT5640_IF3_DAC_SEL_MASK                       (0x3 << 6)
+ #define RT5640_IF3_DAC_SEL_SFT                        6
+ #define RT5640_IF3_DAC_SEL_NOR                        (0x0 << 6)
+-#define RT5640_IF3_DAC_SEL_L2R                        (0x1 << 6)
+-#define RT5640_IF3_DAC_SEL_R2L                        (0x2 << 6)
+-#define RT5640_IF3_DAC_SEL_SWAP                       (0x3 << 6)
++#define RT5640_IF3_DAC_SEL_SWAP                       (0x1 << 6)
++#define RT5640_IF3_DAC_SEL_L2R                        (0x2 << 6)
++#define RT5640_IF3_DAC_SEL_R2L                        (0x3 << 6)
+ #define RT5640_IF3_ADC_SEL_MASK                       (0x3 << 4)
+ #define RT5640_IF3_ADC_SEL_SFT                        4
+ #define RT5640_IF3_ADC_SEL_NOR                        (0x0 << 4)
+-#define RT5640_IF3_ADC_SEL_L2R                        (0x1 << 4)
+-#define RT5640_IF3_ADC_SEL_R2L                        (0x2 << 4)
+-#define RT5640_IF3_ADC_SEL_SWAP                       (0x3 << 4)
++#define RT5640_IF3_ADC_SEL_SWAP                       (0x1 << 4)
++#define RT5640_IF3_ADC_SEL_L2R                        (0x2 << 4)
++#define RT5640_IF3_ADC_SEL_R2L                        (0x3 << 4)
+ /* REC Left Mixer Control 1 (0x3b) */
+ #define RT5640_G_HP_L_RM_L_MASK                       (0x7 << 13)
diff --git a/queue-3.14/asoc-s3c24xx-use-const-snd_soc_component_driver-pointer.patch b/queue-3.14/asoc-s3c24xx-use-const-snd_soc_component_driver-pointer.patch
new file mode 100644 (file)
index 0000000..86f32f1
--- /dev/null
@@ -0,0 +1,53 @@
+From ba4bc32eaa39ba7687f0958ae90eec94da613b46 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Mon, 25 Jan 2016 18:07:33 +0100
+Subject: ASoC: s3c24xx: use const snd_soc_component_driver pointer
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+commit ba4bc32eaa39ba7687f0958ae90eec94da613b46 upstream.
+
+An older patch to convert the API in the s3c i2s driver
+ended up passing a const pointer into a function that takes
+a non-const pointer, so we now get a warning:
+
+sound/soc/samsung/s3c2412-i2s.c: In function 's3c2412_iis_dev_probe':
+sound/soc/samsung/s3c2412-i2s.c:172:9: error: passing argument 3 of 's3c_i2sv2_register_component' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers]
+
+However, the s3c_i2sv2_register_component() function again
+passes the pointer into another function taking a const, so
+we just need to change its prototype.
+
+Fixes: eca3b01d0885 ("ASoC: switch over to use snd_soc_register_component() on s3c i2s")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/soc/samsung/s3c-i2s-v2.c |    2 +-
+ sound/soc/samsung/s3c-i2s-v2.h |    2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/samsung/s3c-i2s-v2.c
++++ b/sound/soc/samsung/s3c-i2s-v2.c
+@@ -726,7 +726,7 @@ static int s3c2412_i2s_resume(struct snd
+ #endif
+ int s3c_i2sv2_register_component(struct device *dev, int id,
+-                         struct snd_soc_component_driver *cmp_drv,
++                         const struct snd_soc_component_driver *cmp_drv,
+                          struct snd_soc_dai_driver *dai_drv)
+ {
+       struct snd_soc_dai_ops *ops = dai_drv->ops;
+--- a/sound/soc/samsung/s3c-i2s-v2.h
++++ b/sound/soc/samsung/s3c-i2s-v2.h
+@@ -101,7 +101,7 @@ extern int s3c_i2sv2_probe(struct snd_so
+  * soc core.
+  */
+ extern int s3c_i2sv2_register_component(struct device *dev, int id,
+-                                      struct snd_soc_component_driver *cmp_drv,
++                                      const struct snd_soc_component_driver *cmp_drv,
+                                       struct snd_soc_dai_driver *dai_drv);
+ #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/queue-3.14/efi-fix-out-of-bounds-read-in-variable_matches.patch b/queue-3.14/efi-fix-out-of-bounds-read-in-variable_matches.patch
new file mode 100644 (file)
index 0000000..cc7e533
--- /dev/null
@@ -0,0 +1,93 @@
+From 630ba0cc7a6dbafbdee43795617c872b35cde1b4 Mon Sep 17 00:00:00 2001
+From: Laszlo Ersek <lersek@redhat.com>
+Date: Thu, 21 Apr 2016 18:21:11 +0200
+Subject: efi: Fix out-of-bounds read in variable_matches()
+
+From: Laszlo Ersek <lersek@redhat.com>
+
+commit 630ba0cc7a6dbafbdee43795617c872b35cde1b4 upstream.
+
+The variable_matches() function can currently read "var_name[len]", for
+example when:
+
+ - var_name[0] == 'a',
+ - len == 1
+ - match_name points to the NUL-terminated string "ab".
+
+This function is supposed to accept "var_name" inputs that are not
+NUL-terminated (hence the "len" parameter"). Document the function, and
+access "var_name[*match]" only if "*match" is smaller than "len".
+
+Reported-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Laszlo Ersek <lersek@redhat.com>
+Cc: Peter Jones <pjones@redhat.com>
+Cc: Matthew Garrett <mjg59@coreos.com>
+Cc: Jason Andryuk <jandryuk@gmail.com>
+Cc: Jani Nikula <jani.nikula@linux.intel.com>
+Link: http://thread.gmane.org/gmane.comp.freedesktop.xorg.drivers.intel/86906
+Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/firmware/efi/vars.c |   39 +++++++++++++++++++++++++++------------
+ 1 file changed, 27 insertions(+), 12 deletions(-)
+
+--- a/drivers/firmware/efi/vars.c
++++ b/drivers/firmware/efi/vars.c
+@@ -202,29 +202,44 @@ static const struct variable_validate va
+       { NULL_GUID, "", NULL },
+ };
++/*
++ * Check if @var_name matches the pattern given in @match_name.
++ *
++ * @var_name: an array of @len non-NUL characters.
++ * @match_name: a NUL-terminated pattern string, optionally ending in "*". A
++ *              final "*" character matches any trailing characters @var_name,
++ *              including the case when there are none left in @var_name.
++ * @match: on output, the number of non-wildcard characters in @match_name
++ *         that @var_name matches, regardless of the return value.
++ * @return: whether @var_name fully matches @match_name.
++ */
+ static bool
+ variable_matches(const char *var_name, size_t len, const char *match_name,
+                int *match)
+ {
+       for (*match = 0; ; (*match)++) {
+               char c = match_name[*match];
+-              char u = var_name[*match];
+-              /* Wildcard in the matching name means we've matched */
+-              if (c == '*')
++              switch (c) {
++              case '*':
++                      /* Wildcard in @match_name means we've matched. */
+                       return true;
+-              /* Case sensitive match */
+-              if (!c && *match == len)
+-                      return true;
+-
+-              if (c != u)
++              case '\0':
++                      /* @match_name has ended. Has @var_name too? */
++                      return (*match == len);
++
++              default:
++                      /*
++                       * We've reached a non-wildcard char in @match_name.
++                       * Continue only if there's an identical character in
++                       * @var_name.
++                       */
++                      if (*match < len && c == var_name[*match])
++                              continue;
+                       return false;
+-
+-              if (!c)
+-                      return true;
++              }
+       }
+-      return true;
+ }
+ bool
index dd6427d7f6b4b27925fdc8f83ba2bbe5f865f900..eb01ad371c3fb37b7d5e8be52d5a3347c0e973f2 100644 (file)
@@ -14,3 +14,7 @@ pinctrl-single-fix-pcs_parse_bits_in_pinctrl_entry-to-use-__ffs-than-ffs.patch
 i2c-cpm-fix-build-break-due-to-incompatible-pointer-types.patch
 i2c-exynos5-fix-possible-abba-deadlock-by-keeping-i2c-clock-prepared.patch
 edac-i7core-sb_edac-don-t-return-notify_bad-from-mce_decoder-callback.patch
+asoc-s3c24xx-use-const-snd_soc_component_driver-pointer.patch
+asoc-rt5640-correct-the-digital-interface-data-select.patch
+efi-fix-out-of-bounds-read-in-variable_matches.patch
+workqueue-fix-ghost-pending-flag-while-doing-mq-io.patch
diff --git a/queue-3.14/workqueue-fix-ghost-pending-flag-while-doing-mq-io.patch b/queue-3.14/workqueue-fix-ghost-pending-flag-while-doing-mq-io.patch
new file mode 100644 (file)
index 0000000..53c436b
--- /dev/null
@@ -0,0 +1,163 @@
+From 346c09f80459a3ad97df1816d6d606169a51001a Mon Sep 17 00:00:00 2001
+From: Roman Pen <roman.penyaev@profitbricks.com>
+Date: Tue, 26 Apr 2016 13:15:35 +0200
+Subject: workqueue: fix ghost PENDING flag while doing MQ IO
+
+From: Roman Pen <roman.penyaev@profitbricks.com>
+
+commit 346c09f80459a3ad97df1816d6d606169a51001a upstream.
+
+The bug in a workqueue leads to a stalled IO request in MQ ctx->rq_list
+with the following backtrace:
+
+[  601.347452] INFO: task kworker/u129:5:1636 blocked for more than 120 seconds.
+[  601.347574]       Tainted: G           O    4.4.5-1-storage+ #6
+[  601.347651] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+[  601.348142] kworker/u129:5  D ffff880803077988     0  1636      2 0x00000000
+[  601.348519] Workqueue: ibnbd_server_fileio_wq ibnbd_dev_file_submit_io_worker [ibnbd_server]
+[  601.348999]  ffff880803077988 ffff88080466b900 ffff8808033f9c80 ffff880803078000
+[  601.349662]  ffff880807c95000 7fffffffffffffff ffffffff815b0920 ffff880803077ad0
+[  601.350333]  ffff8808030779a0 ffffffff815b01d5 0000000000000000 ffff880803077a38
+[  601.350965] Call Trace:
+[  601.351203]  [<ffffffff815b0920>] ? bit_wait+0x60/0x60
+[  601.351444]  [<ffffffff815b01d5>] schedule+0x35/0x80
+[  601.351709]  [<ffffffff815b2dd2>] schedule_timeout+0x192/0x230
+[  601.351958]  [<ffffffff812d43f7>] ? blk_flush_plug_list+0xc7/0x220
+[  601.352208]  [<ffffffff810bd737>] ? ktime_get+0x37/0xa0
+[  601.352446]  [<ffffffff815b0920>] ? bit_wait+0x60/0x60
+[  601.352688]  [<ffffffff815af784>] io_schedule_timeout+0xa4/0x110
+[  601.352951]  [<ffffffff815b3a4e>] ? _raw_spin_unlock_irqrestore+0xe/0x10
+[  601.353196]  [<ffffffff815b093b>] bit_wait_io+0x1b/0x70
+[  601.353440]  [<ffffffff815b056d>] __wait_on_bit+0x5d/0x90
+[  601.353689]  [<ffffffff81127bd0>] wait_on_page_bit+0xc0/0xd0
+[  601.353958]  [<ffffffff81096db0>] ? autoremove_wake_function+0x40/0x40
+[  601.354200]  [<ffffffff81127cc4>] __filemap_fdatawait_range+0xe4/0x140
+[  601.354441]  [<ffffffff81127d34>] filemap_fdatawait_range+0x14/0x30
+[  601.354688]  [<ffffffff81129a9f>] filemap_write_and_wait_range+0x3f/0x70
+[  601.354932]  [<ffffffff811ced3b>] blkdev_fsync+0x1b/0x50
+[  601.355193]  [<ffffffff811c82d9>] vfs_fsync_range+0x49/0xa0
+[  601.355432]  [<ffffffff811cf45a>] blkdev_write_iter+0xca/0x100
+[  601.355679]  [<ffffffff81197b1a>] __vfs_write+0xaa/0xe0
+[  601.355925]  [<ffffffff81198379>] vfs_write+0xa9/0x1a0
+[  601.356164]  [<ffffffff811c59d8>] kernel_write+0x38/0x50
+
+The underlying device is a null_blk, with default parameters:
+
+  queue_mode    = MQ
+  submit_queues = 1
+
+Verification that nullb0 has something inflight:
+
+root@pserver8:~# cat /sys/block/nullb0/inflight
+       0        1
+root@pserver8:~# find /sys/block/nullb0/mq/0/cpu* -name rq_list -print -exec cat {} \;
+...
+/sys/block/nullb0/mq/0/cpu2/rq_list
+CTX pending:
+        ffff8838038e2400
+...
+
+During debug it became clear that stalled request is always inserted in
+the rq_list from the following path:
+
+   save_stack_trace_tsk + 34
+   blk_mq_insert_requests + 231
+   blk_mq_flush_plug_list + 281
+   blk_flush_plug_list + 199
+   wait_on_page_bit + 192
+   __filemap_fdatawait_range + 228
+   filemap_fdatawait_range + 20
+   filemap_write_and_wait_range + 63
+   blkdev_fsync + 27
+   vfs_fsync_range + 73
+   blkdev_write_iter + 202
+   __vfs_write + 170
+   vfs_write + 169
+   kernel_write + 56
+
+So blk_flush_plug_list() was called with from_schedule == true.
+
+If from_schedule is true, that means that finally blk_mq_insert_requests()
+offloads execution of __blk_mq_run_hw_queue() and uses kblockd workqueue,
+i.e. it calls kblockd_schedule_delayed_work_on().
+
+That means, that we race with another CPU, which is about to execute
+__blk_mq_run_hw_queue() work.
+
+Further debugging shows the following traces from different CPUs:
+
+  CPU#0                                  CPU#1
+  ----------------------------------     -------------------------------
+  reqeust A inserted
+  STORE hctx->ctx_map[0] bit marked
+  kblockd_schedule...() returns 1
+  <schedule to kblockd workqueue>
+                                         request B inserted
+                                         STORE hctx->ctx_map[1] bit marked
+                                         kblockd_schedule...() returns 0
+  *** WORK PENDING bit is cleared ***
+  flush_busy_ctxs() is executed, but
+  bit 1, set by CPU#1, is not observed
+
+As a result request B pended forever.
+
+This behaviour can be explained by speculative LOAD of hctx->ctx_map on
+CPU#0, which is reordered with clear of PENDING bit and executed _before_
+actual STORE of bit 1 on CPU#1.
+
+The proper fix is an explicit full barrier <mfence>, which guarantees
+that clear of PENDING bit is to be executed before all possible
+speculative LOADS or STORES inside actual work function.
+
+Signed-off-by: Roman Pen <roman.penyaev@profitbricks.com>
+Cc: Gioh Kim <gi-oh.kim@profitbricks.com>
+Cc: Michael Wang <yun.wang@profitbricks.com>
+Cc: Tejun Heo <tj@kernel.org>
+Cc: Jens Axboe <axboe@kernel.dk>
+Cc: linux-block@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/workqueue.c |   29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+--- a/kernel/workqueue.c
++++ b/kernel/workqueue.c
+@@ -629,6 +629,35 @@ static void set_work_pool_and_clear_pend
+        */
+       smp_wmb();
+       set_work_data(work, (unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT, 0);
++      /*
++       * The following mb guarantees that previous clear of a PENDING bit
++       * will not be reordered with any speculative LOADS or STORES from
++       * work->current_func, which is executed afterwards.  This possible
++       * reordering can lead to a missed execution on attempt to qeueue
++       * the same @work.  E.g. consider this case:
++       *
++       *   CPU#0                         CPU#1
++       *   ----------------------------  --------------------------------
++       *
++       * 1  STORE event_indicated
++       * 2  queue_work_on() {
++       * 3    test_and_set_bit(PENDING)
++       * 4 }                             set_..._and_clear_pending() {
++       * 5                                 set_work_data() # clear bit
++       * 6                                 smp_mb()
++       * 7                               work->current_func() {
++       * 8                                  LOAD event_indicated
++       *                                 }
++       *
++       * Without an explicit full barrier speculative LOAD on line 8 can
++       * be executed before CPU#0 does STORE on line 1.  If that happens,
++       * CPU#0 observes the PENDING bit is still set and new execution of
++       * a @work is not queued in a hope, that CPU#1 will eventually
++       * finish the queued @work.  Meanwhile CPU#1 does not see
++       * event_indicated is set, because speculative LOAD was executed
++       * before actual STORE.
++       */
++      smp_mb();
+ }
+ static void clear_work_data(struct work_struct *work)