]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 2 Jul 2014 23:18:49 +0000 (16:18 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 2 Jul 2014 23:18:49 +0000 (16:18 -0700)
added patches:
ubifs-fix-an-mmap-and-fsync-race-condition.patch
ubifs-remove-incorrect-assertion-in-shrink_tnc.patch
watchdog-ath79_wdt-avoid-spurious-restarts-on-ar934x.patch
watchdog-sp805-set-watchdog_device-timeout-from-set_timeout.patch

queue-3.10/series
queue-3.10/ubifs-fix-an-mmap-and-fsync-race-condition.patch [new file with mode: 0644]
queue-3.10/ubifs-remove-incorrect-assertion-in-shrink_tnc.patch [new file with mode: 0644]
queue-3.10/watchdog-ath79_wdt-avoid-spurious-restarts-on-ar934x.patch [new file with mode: 0644]
queue-3.10/watchdog-sp805-set-watchdog_device-timeout-from-set_timeout.patch [new file with mode: 0644]

index 64eb2ef0301716f51f750950938e111af5adb8d7..319bdbd92d98f1f1058d76383d21c9f16c097f41 100644 (file)
@@ -10,3 +10,7 @@ mtip32xx-increase-timeout-for-standby-immediate-command.patch
 mtip32xx-remove-dfs_parent-after-pci-unregister.patch
 recordmcount-mips-fix-possible-incorrect-mcount_loc-table-entries-in-modules.patch
 mips-msc-prevent-out-of-bounds-writes-to-mips-sc-ioremap-d-region.patch
+ubifs-fix-an-mmap-and-fsync-race-condition.patch
+ubifs-remove-incorrect-assertion-in-shrink_tnc.patch
+watchdog-sp805-set-watchdog_device-timeout-from-set_timeout.patch
+watchdog-ath79_wdt-avoid-spurious-restarts-on-ar934x.patch
diff --git a/queue-3.10/ubifs-fix-an-mmap-and-fsync-race-condition.patch b/queue-3.10/ubifs-fix-an-mmap-and-fsync-race-condition.patch
new file mode 100644 (file)
index 0000000..ce60ef7
--- /dev/null
@@ -0,0 +1,63 @@
+From 691a7c6f28ac90cccd0dbcf81348ea90b211bdd0 Mon Sep 17 00:00:00 2001
+From: hujianyang <hujianyang@huawei.com>
+Date: Wed, 30 Apr 2014 14:06:06 +0800
+Subject: UBIFS: fix an mmap and fsync race condition
+
+From: hujianyang <hujianyang@huawei.com>
+
+commit 691a7c6f28ac90cccd0dbcf81348ea90b211bdd0 upstream.
+
+There is a race condition in UBIFS:
+
+Thread A (mmap)                        Thread B (fsync)
+
+->__do_fault                           ->write_cache_pages
+   -> ubifs_vm_page_mkwrite
+       -> budget_space
+       -> lock_page
+       -> release/convert_page_budget
+       -> SetPagePrivate
+       -> TestSetPageDirty
+       -> unlock_page
+                                       -> lock_page
+                                           -> TestClearPageDirty
+                                           -> ubifs_writepage
+                                               -> do_writepage
+                                                   -> release_budget
+                                                   -> ClearPagePrivate
+                                                   -> unlock_page
+   -> !(ret & VM_FAULT_LOCKED)
+   -> lock_page
+   -> set_page_dirty
+       -> ubifs_set_page_dirty
+           -> TestSetPageDirty (set page dirty without budgeting)
+   -> unlock_page
+
+This leads to situation where we have a diry page but no budget allocated for
+this page, so further write-back may fail with -ENOSPC.
+
+In this fix we return from page_mkwrite without performing unlock_page. We
+return VM_FAULT_LOCKED instead. After doing this, the race above will not
+happen.
+
+Signed-off-by: hujianyang <hujianyang@huawei.com>
+Tested-by: Laurence Withers <lwithers@guralp.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ubifs/file.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/fs/ubifs/file.c
++++ b/fs/ubifs/file.c
+@@ -1524,8 +1524,7 @@ static int ubifs_vm_page_mkwrite(struct
+       }
+       wait_for_stable_page(page);
+-      unlock_page(page);
+-      return 0;
++      return VM_FAULT_LOCKED;
+ out_unlock:
+       unlock_page(page);
diff --git a/queue-3.10/ubifs-remove-incorrect-assertion-in-shrink_tnc.patch b/queue-3.10/ubifs-remove-incorrect-assertion-in-shrink_tnc.patch
new file mode 100644 (file)
index 0000000..a87039b
--- /dev/null
@@ -0,0 +1,104 @@
+From 72abc8f4b4e8574318189886de627a2bfe6cd0da Mon Sep 17 00:00:00 2001
+From: hujianyang <hujianyang@huawei.com>
+Date: Sat, 31 May 2014 11:39:32 +0800
+Subject: UBIFS: Remove incorrect assertion in shrink_tnc()
+
+From: hujianyang <hujianyang@huawei.com>
+
+commit 72abc8f4b4e8574318189886de627a2bfe6cd0da upstream.
+
+I hit the same assert failed as Dolev Raviv reported in Kernel v3.10
+shows like this:
+
+[ 9641.164028] UBIFS assert failed in shrink_tnc at 131 (pid 13297)
+[ 9641.234078] CPU: 1 PID: 13297 Comm: mmap.test Tainted: G           O 3.10.40 #1
+[ 9641.234116] [<c0011a6c>] (unwind_backtrace+0x0/0x12c) from [<c000d0b0>] (show_stack+0x20/0x24)
+[ 9641.234137] [<c000d0b0>] (show_stack+0x20/0x24) from [<c0311134>] (dump_stack+0x20/0x28)
+[ 9641.234188] [<c0311134>] (dump_stack+0x20/0x28) from [<bf22425c>] (shrink_tnc_trees+0x25c/0x350 [ubifs])
+[ 9641.234265] [<bf22425c>] (shrink_tnc_trees+0x25c/0x350 [ubifs]) from [<bf2245ac>] (ubifs_shrinker+0x25c/0x310 [ubifs])
+[ 9641.234307] [<bf2245ac>] (ubifs_shrinker+0x25c/0x310 [ubifs]) from [<c00cdad8>] (shrink_slab+0x1d4/0x2f8)
+[ 9641.234327] [<c00cdad8>] (shrink_slab+0x1d4/0x2f8) from [<c00d03d0>] (do_try_to_free_pages+0x300/0x544)
+[ 9641.234344] [<c00d03d0>] (do_try_to_free_pages+0x300/0x544) from [<c00d0a44>] (try_to_free_pages+0x2d0/0x398)
+[ 9641.234363] [<c00d0a44>] (try_to_free_pages+0x2d0/0x398) from [<c00c6a60>] (__alloc_pages_nodemask+0x494/0x7e8)
+[ 9641.234382] [<c00c6a60>] (__alloc_pages_nodemask+0x494/0x7e8) from [<c00f62d8>] (new_slab+0x78/0x238)
+[ 9641.234400] [<c00f62d8>] (new_slab+0x78/0x238) from [<c031081c>] (__slab_alloc.constprop.42+0x1a4/0x50c)
+[ 9641.234419] [<c031081c>] (__slab_alloc.constprop.42+0x1a4/0x50c) from [<c00f80e8>] (kmem_cache_alloc_trace+0x54/0x188)
+[ 9641.234459] [<c00f80e8>] (kmem_cache_alloc_trace+0x54/0x188) from [<bf227908>] (do_readpage+0x168/0x468 [ubifs])
+[ 9641.234553] [<bf227908>] (do_readpage+0x168/0x468 [ubifs]) from [<bf2296a0>] (ubifs_readpage+0x424/0x464 [ubifs])
+[ 9641.234606] [<bf2296a0>] (ubifs_readpage+0x424/0x464 [ubifs]) from [<c00c17c0>] (filemap_fault+0x304/0x418)
+[ 9641.234638] [<c00c17c0>] (filemap_fault+0x304/0x418) from [<c00de694>] (__do_fault+0xd4/0x530)
+[ 9641.234665] [<c00de694>] (__do_fault+0xd4/0x530) from [<c00e10c0>] (handle_pte_fault+0x480/0xf54)
+[ 9641.234690] [<c00e10c0>] (handle_pte_fault+0x480/0xf54) from [<c00e2bf8>] (handle_mm_fault+0x140/0x184)
+[ 9641.234716] [<c00e2bf8>] (handle_mm_fault+0x140/0x184) from [<c0316688>] (do_page_fault+0x150/0x3ac)
+[ 9641.234737] [<c0316688>] (do_page_fault+0x150/0x3ac) from [<c000842c>] (do_DataAbort+0x3c/0xa0)
+[ 9641.234759] [<c000842c>] (do_DataAbort+0x3c/0xa0) from [<c0314e38>] (__dabt_usr+0x38/0x40)
+
+After analyzing the code, I found a condition that may cause this failed
+in correct operations. Thus, I think this assertion is wrong and should be
+removed.
+
+Suppose there are two clean znodes and one dirty znode in TNC. So the
+per-filesystem atomic_t @clean_zn_cnt is (2). If commit start, dirty_znode
+is set to COW_ZNODE in get_znodes_to_commit() in case of potentially ops
+on this znode. We clear COW bit and DIRTY bit in write_index() without
+@tnc_mutex locked. We don't increase @clean_zn_cnt in this place. As the
+comments in write_index() shows, if another process hold @tnc_mutex and
+dirty this znode after we clean it, @clean_zn_cnt would be decreased to (1).
+We will increase @clean_zn_cnt to (2) with @tnc_mutex locked in
+free_obsolete_znodes() to keep it right.
+
+If shrink_tnc() performs between decrease and increase, it will release
+other 2 clean znodes it holds and found @clean_zn_cnt is less than zero
+(1 - 2 = -1), then hit the assertion. Because free_obsolete_znodes() will
+soon correct @clean_zn_cnt and no harm to fs in this case, I think this
+assertion could be removed.
+
+2 clean zondes and 1 dirty znode, @clean_zn_cnt == 2
+
+Thread A (commit)         Thread B (write or others)       Thread C (shrinker)
+->write_index
+   ->clear_bit(DIRTY_NODE)
+   ->clear_bit(COW_ZNODE)
+
+            @clean_zn_cnt == 2
+                          ->mutex_locked(&tnc_mutex)
+                          ->dirty_cow_znode
+                              ->!ubifs_zn_cow(znode)
+                              ->!test_and_set_bit(DIRTY_NODE)
+                              ->atomic_dec(&clean_zn_cnt)
+                          ->mutex_unlocked(&tnc_mutex)
+
+            @clean_zn_cnt == 1
+                                                           ->mutex_locked(&tnc_mutex)
+                                                           ->shrink_tnc
+                                                             ->destroy_tnc_subtree
+                                                             ->atomic_sub(&clean_zn_cnt, 2)
+                                                             ->ubifs_assert  <- hit
+                                                           ->mutex_unlocked(&tnc_mutex)
+
+            @clean_zn_cnt == -1
+->mutex_lock(&tnc_mutex)
+->free_obsolete_znodes
+   ->atomic_inc(&clean_zn_cnt)
+->mutux_unlock(&tnc_mutex)
+
+            @clean_zn_cnt == 0 (correct after shrink)
+
+Signed-off-by: hujianyang <hujianyang@huawei.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ubifs/shrinker.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/fs/ubifs/shrinker.c
++++ b/fs/ubifs/shrinker.c
+@@ -128,7 +128,6 @@ static int shrink_tnc(struct ubifs_info
+                       freed = ubifs_destroy_tnc_subtree(znode);
+                       atomic_long_sub(freed, &ubifs_clean_zn_cnt);
+                       atomic_long_sub(freed, &c->clean_zn_cnt);
+-                      ubifs_assert(atomic_long_read(&c->clean_zn_cnt) >= 0);
+                       total_freed += freed;
+                       znode = zprev;
+               }
diff --git a/queue-3.10/watchdog-ath79_wdt-avoid-spurious-restarts-on-ar934x.patch b/queue-3.10/watchdog-ath79_wdt-avoid-spurious-restarts-on-ar934x.patch
new file mode 100644 (file)
index 0000000..8467505
--- /dev/null
@@ -0,0 +1,55 @@
+From 23afeb613ec0e10aecfae7838a14d485db62ac52 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Wed, 16 Apr 2014 11:34:41 +0200
+Subject: watchdog: ath79_wdt: avoid spurious restarts on AR934x
+
+From: Gabor Juhos <juhosg@openwrt.org>
+
+commit 23afeb613ec0e10aecfae7838a14d485db62ac52 upstream.
+
+On some AR934x based systems, where the frequency of
+the AHB bus is relatively high, the built-in watchdog
+causes a spurious restart when it gets enabled.
+
+The possible cause of these restarts is that the timeout
+value written into the TIMER register does not reaches
+the hardware in time.
+
+Add an explicit delay into the ath79_wdt_enable function
+to avoid the spurious restarts.
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/watchdog/ath79_wdt.c |   10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/watchdog/ath79_wdt.c
++++ b/drivers/watchdog/ath79_wdt.c
+@@ -20,6 +20,7 @@
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ #include <linux/bitops.h>
++#include <linux/delay.h>
+ #include <linux/errno.h>
+ #include <linux/fs.h>
+ #include <linux/init.h>
+@@ -91,6 +92,15 @@ static inline void ath79_wdt_keepalive(v
+ static inline void ath79_wdt_enable(void)
+ {
+       ath79_wdt_keepalive();
++
++      /*
++       * Updating the TIMER register requires a few microseconds
++       * on the AR934x SoCs at least. Use a small delay to ensure
++       * that the TIMER register is updated within the hardware
++       * before enabling the watchdog.
++       */
++      udelay(2);
++
+       ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR);
+       /* flush write */
+       ath79_wdt_rr(WDOG_REG_CTRL);
diff --git a/queue-3.10/watchdog-sp805-set-watchdog_device-timeout-from-set_timeout.patch b/queue-3.10/watchdog-sp805-set-watchdog_device-timeout-from-set_timeout.patch
new file mode 100644 (file)
index 0000000..d44414f
--- /dev/null
@@ -0,0 +1,50 @@
+From 938626d96a3ffb9eb54552bb0d3a4f2b30ffdeb0 Mon Sep 17 00:00:00 2001
+From: Viresh Kumar <viresh.kumar@linaro.org>
+Date: Thu, 15 May 2014 10:01:59 +0530
+Subject: watchdog: sp805: Set watchdog_device->timeout from ->set_timeout()
+
+From: Viresh Kumar <viresh.kumar@linaro.org>
+
+commit 938626d96a3ffb9eb54552bb0d3a4f2b30ffdeb0 upstream.
+
+Implementation of ->set_timeout() is supposed to set 'timeout' field of 'struct
+watchdog_device' passed to it. sp805 was rather setting this in a local
+variable. Fix it.
+
+Reported-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
+Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/watchdog/sp805_wdt.c |    4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/watchdog/sp805_wdt.c
++++ b/drivers/watchdog/sp805_wdt.c
+@@ -60,7 +60,6 @@
+  * @adev: amba device structure of wdt
+  * @status: current status of wdt
+  * @load_val: load value to be set for current timeout
+- * @timeout: current programmed timeout
+  */
+ struct sp805_wdt {
+       struct watchdog_device          wdd;
+@@ -69,7 +68,6 @@ struct sp805_wdt {
+       struct clk                      *clk;
+       struct amba_device              *adev;
+       unsigned int                    load_val;
+-      unsigned int                    timeout;
+ };
+ static bool nowayout = WATCHDOG_NOWAYOUT;
+@@ -99,7 +97,7 @@ static int wdt_setload(struct watchdog_d
+       spin_lock(&wdt->lock);
+       wdt->load_val = load;
+       /* roundup timeout to closest positive integer value */
+-      wdt->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
++      wdd->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
+       spin_unlock(&wdt->lock);
+       return 0;