From: Greg Kroah-Hartman Date: Wed, 3 Apr 2019 14:10:58 +0000 (+0200) Subject: 4.14-stable patches X-Git-Tag: v4.9.168~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1fd55d4764de3bf58f80cbe20dee80774281c91a;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch lib-int_sqrt-optimize-initial-value-compute.patch mm-mempolicy-make-mbind-return-eio-when-mpol_mf_strict-is-specified.patch tty-serial-atmel-add-is_half_duplex-helper.patch tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch --- diff --git a/queue-4.14/ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch b/queue-4.14/ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch new file mode 100644 index 00000000000..47ca58708df --- /dev/null +++ b/queue-4.14/ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch @@ -0,0 +1,163 @@ +From 5e86bdda41534e17621d5a071b294943cae4376e Mon Sep 17 00:00:00 2001 +From: "zhangyi (F)" +Date: Sat, 23 Mar 2019 11:56:01 -0400 +Subject: ext4: cleanup bh release code in ext4_ind_remove_space() + +From: zhangyi (F) + +commit 5e86bdda41534e17621d5a071b294943cae4376e upstream. + +Currently, we are releasing the indirect buffer where we are done with +it in ext4_ind_remove_space(), so we can see the brelse() and +BUFFER_TRACE() everywhere. It seems fragile and hard to read, and we +may probably forget to release the buffer some day. This patch cleans +up the code by putting of the code which releases the buffers to the +end of the function. + +Signed-off-by: zhangyi (F) +Signed-off-by: Theodore Ts'o +Reviewed-by: Jan Kara +Cc: Jari Ruusu +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/indirect.c | 47 ++++++++++++++++++++++------------------------- + 1 file changed, 22 insertions(+), 25 deletions(-) + +--- a/fs/ext4/indirect.c ++++ b/fs/ext4/indirect.c +@@ -1219,6 +1219,7 @@ int ext4_ind_remove_space(handle_t *hand + ext4_lblk_t offsets[4], offsets2[4]; + Indirect chain[4], chain2[4]; + Indirect *partial, *partial2; ++ Indirect *p = NULL, *p2 = NULL; + ext4_lblk_t max_block; + __le32 nr = 0, nr2 = 0; + int n = 0, n2 = 0; +@@ -1260,7 +1261,7 @@ int ext4_ind_remove_space(handle_t *hand + } + + +- partial = ext4_find_shared(inode, n, offsets, chain, &nr); ++ partial = p = ext4_find_shared(inode, n, offsets, chain, &nr); + if (nr) { + if (partial == chain) { + /* Shared branch grows from the inode */ +@@ -1285,13 +1286,11 @@ int ext4_ind_remove_space(handle_t *hand + partial->p + 1, + (__le32 *)partial->bh->b_data+addr_per_block, + (chain+n-1) - partial); +- BUFFER_TRACE(partial->bh, "call brelse"); +- brelse(partial->bh); + partial--; + } + + end_range: +- partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); ++ partial2 = p2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); + if (nr2) { + if (partial2 == chain2) { + /* +@@ -1321,16 +1320,14 @@ end_range: + (__le32 *)partial2->bh->b_data, + partial2->p, + (chain2+n2-1) - partial2); +- BUFFER_TRACE(partial2->bh, "call brelse"); +- brelse(partial2->bh); + partial2--; + } + goto do_indirects; + } + + /* Punch happened within the same level (n == n2) */ +- partial = ext4_find_shared(inode, n, offsets, chain, &nr); +- partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); ++ partial = p = ext4_find_shared(inode, n, offsets, chain, &nr); ++ partial2 = p2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); + + /* Free top, but only if partial2 isn't its subtree. */ + if (nr) { +@@ -1387,15 +1384,7 @@ end_range: + partial->p + 1, + partial2->p, + (chain+n-1) - partial); +- while (partial > chain) { +- BUFFER_TRACE(partial->bh, "call brelse"); +- brelse(partial->bh); +- } +- while (partial2 > chain2) { +- BUFFER_TRACE(partial2->bh, "call brelse"); +- brelse(partial2->bh); +- } +- return 0; ++ goto cleanup; + } + + /* +@@ -1410,8 +1399,6 @@ end_range: + partial->p + 1, + (__le32 *)partial->bh->b_data+addr_per_block, + (chain+n-1) - partial); +- BUFFER_TRACE(partial->bh, "call brelse"); +- brelse(partial->bh); + partial--; + } + if (partial2 > chain2 && depth2 <= depth) { +@@ -1419,11 +1406,21 @@ end_range: + (__le32 *)partial2->bh->b_data, + partial2->p, + (chain2+n2-1) - partial2); +- BUFFER_TRACE(partial2->bh, "call brelse"); +- brelse(partial2->bh); + partial2--; + } + } ++ ++cleanup: ++ while (p && p > chain) { ++ BUFFER_TRACE(p->bh, "call brelse"); ++ brelse(p->bh); ++ p--; ++ } ++ while (p2 && p2 > chain2) { ++ BUFFER_TRACE(p2->bh, "call brelse"); ++ brelse(p2->bh); ++ p2--; ++ } + return 0; + + do_indirects: +@@ -1431,7 +1428,7 @@ do_indirects: + switch (offsets[0]) { + default: + if (++n >= n2) +- return 0; ++ break; + nr = i_data[EXT4_IND_BLOCK]; + if (nr) { + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); +@@ -1439,7 +1436,7 @@ do_indirects: + } + case EXT4_IND_BLOCK: + if (++n >= n2) +- return 0; ++ break; + nr = i_data[EXT4_DIND_BLOCK]; + if (nr) { + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); +@@ -1447,7 +1444,7 @@ do_indirects: + } + case EXT4_DIND_BLOCK: + if (++n >= n2) +- return 0; ++ break; + nr = i_data[EXT4_TIND_BLOCK]; + if (nr) { + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); +@@ -1456,5 +1453,5 @@ do_indirects: + case EXT4_TIND_BLOCK: + ; + } +- return 0; ++ goto cleanup; + } diff --git a/queue-4.14/lib-int_sqrt-optimize-initial-value-compute.patch b/queue-4.14/lib-int_sqrt-optimize-initial-value-compute.patch new file mode 100644 index 00000000000..82b6c2a313e --- /dev/null +++ b/queue-4.14/lib-int_sqrt-optimize-initial-value-compute.patch @@ -0,0 +1,91 @@ +From f8ae107eef209bff29a5816bc1aad40d5cd69a80 Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra +Date: Fri, 17 Nov 2017 15:28:08 -0800 +Subject: lib/int_sqrt: optimize initial value compute + +From: Peter Zijlstra + +commit f8ae107eef209bff29a5816bc1aad40d5cd69a80 upstream. + +The initial value (@m) compute is: + + m = 1UL << (BITS_PER_LONG - 2); + while (m > x) + m >>= 2; + +Which is a linear search for the highest even bit smaller or equal to @x +We can implement this using a binary search using __fls() (or better when +its hardware implemented). + + m = 1UL << (__fls(x) & ~1UL); + +Especially for small values of @x; which are the more common arguments +when doing a CDF on idle times; the linear search is near to worst case, +while the binary search of __fls() is a constant 6 (or 5 on 32bit) +branches. + + cycles: branches: branch-misses: + +PRE: + +hot: 43.633557 +- 0.034373 45.333132 +- 0.002277 0.023529 +- 0.000681 +cold: 207.438411 +- 0.125840 45.333132 +- 0.002277 6.976486 +- 0.004219 + +SOFTWARE FLS: + +hot: 29.576176 +- 0.028850 26.666730 +- 0.004511 0.019463 +- 0.000663 +cold: 165.947136 +- 0.188406 26.666746 +- 0.004511 6.133897 +- 0.004386 + +HARDWARE FLS: + +hot: 24.720922 +- 0.025161 20.666784 +- 0.004509 0.020836 +- 0.000677 +cold: 132.777197 +- 0.127471 20.666776 +- 0.004509 5.080285 +- 0.003874 + +Averages computed over all values <128k using a LFSR to generate order. +Cold numbers have a LFSR based branch trace buffer 'confuser' ran between +each int_sqrt() invocation. + +Link: http://lkml.kernel.org/r/20171020164644.936577234@infradead.org +Signed-off-by: Peter Zijlstra (Intel) +Suggested-by: Joe Perches +Acked-by: Will Deacon +Acked-by: Linus Torvalds +Cc: Anshul Garg +Cc: Davidlohr Bueso +Cc: David Miller +Cc: Ingo Molnar +Cc: Kees Cook +Cc: Matthew Wilcox +Cc: Michael Davidson +Cc: Thomas Gleixner +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Joe Perches +Signed-off-by: Greg Kroah-Hartman + +--- + lib/int_sqrt.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/lib/int_sqrt.c ++++ b/lib/int_sqrt.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + + /** + * int_sqrt - rough approximation to sqrt +@@ -22,10 +23,7 @@ unsigned long int_sqrt(unsigned long x) + if (x <= 1) + return x; + +- m = 1UL << (BITS_PER_LONG - 2); +- while (m > x) +- m >>= 2; +- ++ m = 1UL << (__fls(x) & ~1UL); + while (m != 0) { + b = y + m; + y >>= 1; diff --git a/queue-4.14/mm-mempolicy-make-mbind-return-eio-when-mpol_mf_strict-is-specified.patch b/queue-4.14/mm-mempolicy-make-mbind-return-eio-when-mpol_mf_strict-is-specified.patch new file mode 100644 index 00000000000..a39c136438d --- /dev/null +++ b/queue-4.14/mm-mempolicy-make-mbind-return-eio-when-mpol_mf_strict-is-specified.patch @@ -0,0 +1,142 @@ +From a7f40cfe3b7ada57af9b62fd28430eeb4a7cfcb7 Mon Sep 17 00:00:00 2001 +From: Yang Shi +Date: Thu, 28 Mar 2019 20:43:55 -0700 +Subject: mm: mempolicy: make mbind() return -EIO when MPOL_MF_STRICT is specified + +From: Yang Shi + +commit a7f40cfe3b7ada57af9b62fd28430eeb4a7cfcb7 upstream. + +When MPOL_MF_STRICT was specified and an existing page was already on a +node that does not follow the policy, mbind() should return -EIO. But +commit 6f4576e3687b ("mempolicy: apply page table walker on +queue_pages_range()") broke the rule. + +And commit c8633798497c ("mm: mempolicy: mbind and migrate_pages support +thp migration") didn't return the correct value for THP mbind() too. + +If MPOL_MF_STRICT is set, ignore vma_migratable() to make sure it +reaches queue_pages_to_pte_range() or queue_pages_pmd() to check if an +existing page was already on a node that does not follow the policy. +And, non-migratable vma may be used, return -EIO too if MPOL_MF_MOVE or +MPOL_MF_MOVE_ALL was specified. + +Tested with https://github.com/metan-ucw/ltp/blob/master/testcases/kernel/syscalls/mbind/mbind02.c + +[akpm@linux-foundation.org: tweak code comment] +Link: http://lkml.kernel.org/r/1553020556-38583-1-git-send-email-yang.shi@linux.alibaba.com +Fixes: 6f4576e3687b ("mempolicy: apply page table walker on queue_pages_range()") +Signed-off-by: Yang Shi +Signed-off-by: Oscar Salvador +Reported-by: Cyril Hrubis +Suggested-by: Kirill A. Shutemov +Acked-by: Rafael Aquini +Reviewed-by: Oscar Salvador +Acked-by: David Rientjes +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + + +--- + mm/mempolicy.c | 40 +++++++++++++++++++++++++++++++++------- + 1 file changed, 33 insertions(+), 7 deletions(-) + +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -427,6 +427,13 @@ static inline bool queue_pages_required( + return node_isset(nid, *qp->nmask) == !(flags & MPOL_MF_INVERT); + } + ++/* ++ * queue_pages_pmd() has three possible return values: ++ * 1 - pages are placed on the right node or queued successfully. ++ * 0 - THP was split. ++ * -EIO - is migration entry or MPOL_MF_STRICT was specified and an existing ++ * page was already on a node that does not follow the policy. ++ */ + static int queue_pages_pmd(pmd_t *pmd, spinlock_t *ptl, unsigned long addr, + unsigned long end, struct mm_walk *walk) + { +@@ -436,7 +443,7 @@ static int queue_pages_pmd(pmd_t *pmd, s + unsigned long flags; + + if (unlikely(is_pmd_migration_entry(*pmd))) { +- ret = 1; ++ ret = -EIO; + goto unlock; + } + page = pmd_page(*pmd); +@@ -462,8 +469,15 @@ static int queue_pages_pmd(pmd_t *pmd, s + ret = 1; + flags = qp->flags; + /* go to thp migration */ +- if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) ++ if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) { ++ if (!vma_migratable(walk->vma)) { ++ ret = -EIO; ++ goto unlock; ++ } ++ + migrate_page_add(page, qp->pagelist, flags); ++ } else ++ ret = -EIO; + unlock: + spin_unlock(ptl); + out: +@@ -488,8 +502,10 @@ static int queue_pages_pte_range(pmd_t * + ptl = pmd_trans_huge_lock(pmd, vma); + if (ptl) { + ret = queue_pages_pmd(pmd, ptl, addr, end, walk); +- if (ret) ++ if (ret > 0) + return 0; ++ else if (ret < 0) ++ return ret; + } + + if (pmd_trans_unstable(pmd)) +@@ -526,11 +542,16 @@ retry: + goto retry; + } + +- migrate_page_add(page, qp->pagelist, flags); ++ if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) { ++ if (!vma_migratable(vma)) ++ break; ++ migrate_page_add(page, qp->pagelist, flags); ++ } else ++ break; + } + pte_unmap_unlock(pte - 1, ptl); + cond_resched(); +- return 0; ++ return addr != end ? -EIO : 0; + } + + static int queue_pages_hugetlb(pte_t *pte, unsigned long hmask, +@@ -600,7 +621,12 @@ static int queue_pages_test_walk(unsigne + unsigned long endvma = vma->vm_end; + unsigned long flags = qp->flags; + +- if (!vma_migratable(vma)) ++ /* ++ * Need check MPOL_MF_STRICT to return -EIO if possible ++ * regardless of vma_migratable ++ */ ++ if (!vma_migratable(vma) && ++ !(flags & MPOL_MF_STRICT)) + return 1; + + if (endvma > end) +@@ -627,7 +653,7 @@ static int queue_pages_test_walk(unsigne + } + + /* queue pages from current vma */ +- if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) ++ if (flags & MPOL_MF_VALID) + return 0; + return 1; + } diff --git a/queue-4.14/series b/queue-4.14/series index e7069e23242..9f24c2567c6 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -1 +1,6 @@ arm64-debug-don-t-propagate-unknown-far-into-si_code-for-debug-signals.patch +ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch +lib-int_sqrt-optimize-initial-value-compute.patch +tty-serial-atmel-add-is_half_duplex-helper.patch +tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch +mm-mempolicy-make-mbind-return-eio-when-mpol_mf_strict-is-specified.patch diff --git a/queue-4.14/tty-serial-atmel-add-is_half_duplex-helper.patch b/queue-4.14/tty-serial-atmel-add-is_half_duplex-helper.patch new file mode 100644 index 00000000000..1da0f2c8a1a --- /dev/null +++ b/queue-4.14/tty-serial-atmel-add-is_half_duplex-helper.patch @@ -0,0 +1,80 @@ +From f3040983132bf3477acd45d2452a906e67c2fec9 Mon Sep 17 00:00:00 2001 +From: Razvan Stefanescu +Date: Tue, 19 Mar 2019 15:20:34 +0200 +Subject: tty/serial: atmel: Add is_half_duplex helper + +From: Razvan Stefanescu + +commit f3040983132bf3477acd45d2452a906e67c2fec9 upstream. + +Use a helper function to check that a port needs to use half duplex +communication, replacing several occurrences of multi-line bit checking. + +Fixes: b389f173aaa1 ("tty/serial: atmel: RS485 half duplex w/DMA: enable RX after TX is done") +Cc: stable +Signed-off-by: Razvan Stefanescu +Acked-by: Richard Genoud +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/tty/serial/atmel_serial.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -238,6 +238,12 @@ static inline void atmel_uart_write_char + __raw_writeb(value, port->membase + ATMEL_US_THR); + } + ++static inline int atmel_uart_is_half_duplex(struct uart_port *port) ++{ ++ return (port->rs485.flags & SER_RS485_ENABLED) && ++ !(port->rs485.flags & SER_RS485_RX_DURING_TX); ++} ++ + #ifdef CONFIG_SERIAL_ATMEL_PDC + static bool atmel_use_pdc_rx(struct uart_port *port) + { +@@ -489,9 +495,9 @@ static void atmel_stop_tx(struct uart_po + /* Disable interrupts */ + atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); + +- if ((port->rs485.flags & SER_RS485_ENABLED) && +- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ++ if (atmel_uart_is_half_duplex(port)) + atmel_start_rx(port); ++ + } + + /* +@@ -508,8 +514,7 @@ static void atmel_start_tx(struct uart_p + return; + + if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port)) +- if ((port->rs485.flags & SER_RS485_ENABLED) && +- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ++ if (atmel_uart_is_half_duplex(port)) + atmel_stop_rx(port); + + if (atmel_use_pdc_tx(port)) +@@ -806,8 +811,7 @@ static void atmel_complete_tx_dma(void * + */ + if (!uart_circ_empty(xmit)) + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); +- else if ((port->rs485.flags & SER_RS485_ENABLED) && +- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { ++ else if (atmel_uart_is_half_duplex(port)) { + /* DMA done, stop TX, start RX for RS485 */ + atmel_start_rx(port); + } +@@ -1383,8 +1387,7 @@ static void atmel_tx_pdc(struct uart_por + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); + } else { +- if ((port->rs485.flags & SER_RS485_ENABLED) && +- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { ++ if (atmel_uart_is_half_duplex(port)) { + /* DMA done, stop TX, start RX for RS485 */ + atmel_start_rx(port); + } diff --git a/queue-4.14/tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch b/queue-4.14/tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch new file mode 100644 index 00000000000..4345260238c --- /dev/null +++ b/queue-4.14/tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch @@ -0,0 +1,79 @@ +From 69646d7a3689fbe1a65ae90397d22ac3f1b8d40f Mon Sep 17 00:00:00 2001 +From: Razvan Stefanescu +Date: Tue, 19 Mar 2019 15:20:35 +0200 +Subject: tty/serial: atmel: RS485 HD w/DMA: enable RX after TX is stopped + +From: Razvan Stefanescu + +commit 69646d7a3689fbe1a65ae90397d22ac3f1b8d40f upstream. + +In half-duplex operation, RX should be started after TX completes. + +If DMA is used, there is a case when the DMA transfer completes but the +TX FIFO is not emptied, so the RX cannot be restarted just yet. + +Use a boolean variable to store this state and rearm TX interrupt mask +to be signaled again that the transfer finished. In interrupt transmit +handler this variable is used to start RX. A warning message is generated +if RX is activated before TX fifo is cleared. + +Fixes: b389f173aaa1 ("tty/serial: atmel: RS485 half duplex w/DMA: enable +RX after TX is done") +Signed-off-by: Razvan Stefanescu +Acked-by: Richard Genoud +Cc: stable +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/serial/atmel_serial.c | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -176,6 +176,8 @@ struct atmel_uart_port { + unsigned int pending_status; + spinlock_t lock_suspended; + ++ bool hd_start_rx; /* can start RX during half-duplex operation */ ++ + #ifdef CONFIG_PM + struct { + u32 cr; +@@ -812,8 +814,13 @@ static void atmel_complete_tx_dma(void * + if (!uart_circ_empty(xmit)) + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); + else if (atmel_uart_is_half_duplex(port)) { +- /* DMA done, stop TX, start RX for RS485 */ +- atmel_start_rx(port); ++ /* ++ * DMA done, re-enable TXEMPTY and signal that we can stop ++ * TX and start RX for RS485 ++ */ ++ atmel_port->hd_start_rx = true; ++ atmel_uart_writel(port, ATMEL_US_IER, ++ atmel_port->tx_done_mask); + } + + spin_unlock_irqrestore(&port->lock, flags); +@@ -1258,9 +1265,20 @@ atmel_handle_transmit(struct uart_port * + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (pending & atmel_port->tx_done_mask) { +- /* Either PDC or interrupt transmission */ + atmel_uart_writel(port, ATMEL_US_IDR, + atmel_port->tx_done_mask); ++ ++ /* Start RX if flag was set and FIFO is empty */ ++ if (atmel_port->hd_start_rx) { ++ if (!(atmel_uart_readl(port, ATMEL_US_CSR) ++ & ATMEL_US_TXEMPTY)) ++ dev_warn(port->dev, "Should start RX, but TX fifo is not empty\n"); ++ ++ atmel_port->hd_start_rx = false; ++ atmel_start_rx(port); ++ return; ++ } ++ + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); + } + }