From a72a3eef22262663b69473b7325d69aff406b093 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 23 Oct 2014 17:05:36 +0800 Subject: [PATCH] 3.16-stable patches added patches: documentation-lzo-document-part-of-the-encoding.patch fixing-lease-renewal.patch lzo-check-for-length-overrun-in-variable-length-encoding.patch m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.patch mei-bus-fix-possible-boundaries-violation.patch nfs-fix-a-bogus-warning-in-nfs_generic_pgio.patch nfs-fix-an-uninitialised-pointer-oops-in-the-writeback-error-path.patch nfsd4-reserve-adequate-space-for-lock-op.patch nfsv4-fix-lock-recovery-when-create_session-setclientid_confirm-fails.patch nfsv4-fix-open-lock-state-recovery-error-handling.patch nfsv4.1-fix-an-nfsv4.1-state-renewal-regression.patch revert-lzo-properly-check-for-overruns.patch tty-omap-serial-fix-division-by-zero.patch --- ...on-lzo-document-part-of-the-encoding.patch | 189 ++++++++++++++++++ queue-3.16/fixing-lease-renewal.patch | 34 ++++ ...-overrun-in-variable-length-encoding.patch | 124 ++++++++++++ ...errupts-in-hwreg_present-hwreg_write.patch | 77 +++++++ ...us-fix-possible-boundaries-violation.patch | 33 +++ ...-a-bogus-warning-in-nfs_generic_pgio.patch | 41 ++++ ...ter-oops-in-the-writeback-error-path.patch | 67 +++++++ ...4-reserve-adequate-space-for-lock-op.patch | 46 +++++ ...te_session-setclientid_confirm-fails.patch | 35 ++++ ...n-lock-state-recovery-error-handling.patch | 71 +++++++ ...-an-nfsv4.1-state-renewal-regression.patch | 91 +++++++++ ...vert-lzo-properly-check-for-overruns.patch | 181 +++++++++++++++++ queue-3.16/series | 13 ++ ...tty-omap-serial-fix-division-by-zero.patch | 58 ++++++ 14 files changed, 1060 insertions(+) create mode 100644 queue-3.16/documentation-lzo-document-part-of-the-encoding.patch create mode 100644 queue-3.16/fixing-lease-renewal.patch create mode 100644 queue-3.16/lzo-check-for-length-overrun-in-variable-length-encoding.patch create mode 100644 queue-3.16/m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.patch create mode 100644 queue-3.16/mei-bus-fix-possible-boundaries-violation.patch create mode 100644 queue-3.16/nfs-fix-a-bogus-warning-in-nfs_generic_pgio.patch create mode 100644 queue-3.16/nfs-fix-an-uninitialised-pointer-oops-in-the-writeback-error-path.patch create mode 100644 queue-3.16/nfsd4-reserve-adequate-space-for-lock-op.patch create mode 100644 queue-3.16/nfsv4-fix-lock-recovery-when-create_session-setclientid_confirm-fails.patch create mode 100644 queue-3.16/nfsv4-fix-open-lock-state-recovery-error-handling.patch create mode 100644 queue-3.16/nfsv4.1-fix-an-nfsv4.1-state-renewal-regression.patch create mode 100644 queue-3.16/revert-lzo-properly-check-for-overruns.patch create mode 100644 queue-3.16/tty-omap-serial-fix-division-by-zero.patch diff --git a/queue-3.16/documentation-lzo-document-part-of-the-encoding.patch b/queue-3.16/documentation-lzo-document-part-of-the-encoding.patch new file mode 100644 index 00000000000..8e8866f1afa --- /dev/null +++ b/queue-3.16/documentation-lzo-document-part-of-the-encoding.patch @@ -0,0 +1,189 @@ +From d98a0526434d27e261f622cf9d2e0028b5ff1a00 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sat, 27 Sep 2014 12:31:35 +0200 +Subject: Documentation: lzo: document part of the encoding + +From: Willy Tarreau + +commit d98a0526434d27e261f622cf9d2e0028b5ff1a00 upstream. + +Add a complete description of the LZO format as processed by the +decompressor. I have not found a public specification of this format +hence this analysis, which will be used to better understand the code. + +Cc: Willem Pinckaers +Cc: "Don A. Bailey" +Signed-off-by: Willy Tarreau +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/lzo.txt | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 164 insertions(+) + +--- /dev/null ++++ b/Documentation/lzo.txt +@@ -0,0 +1,164 @@ ++ ++LZO stream format as understood by Linux's LZO decompressor ++=========================================================== ++ ++Introduction ++ ++ This is not a specification. No specification seems to be publicly available ++ for the LZO stream format. This document describes what input format the LZO ++ decompressor as implemented in the Linux kernel understands. The file subject ++ of this analysis is lib/lzo/lzo1x_decompress_safe.c. No analysis was made on ++ the compressor nor on any other implementations though it seems likely that ++ the format matches the standard one. The purpose of this document is to ++ better understand what the code does in order to propose more efficient fixes ++ for future bug reports. ++ ++Description ++ ++ The stream is composed of a series of instructions, operands, and data. The ++ instructions consist in a few bits representing an opcode, and bits forming ++ the operands for the instruction, whose size and position depend on the ++ opcode and on the number of literals copied by previous instruction. The ++ operands are used to indicate : ++ ++ - a distance when copying data from the dictionary (past output buffer) ++ - a length (number of bytes to copy from dictionary) ++ - the number of literals to copy, which is retained in variable "state" ++ as a piece of information for next instructions. ++ ++ Optionally depending on the opcode and operands, extra data may follow. These ++ extra data can be a complement for the operand (eg: a length or a distance ++ encoded on larger values), or a literal to be copied to the output buffer. ++ ++ The first byte of the block follows a different encoding from other bytes, it ++ seems to be optimized for literal use only, since there is no dictionary yet ++ prior to that byte. ++ ++ Lengths are always encoded on a variable size starting with a small number ++ of bits in the operand. If the number of bits isn't enough to represent the ++ length, up to 255 may be added in increments by consuming more bytes with a ++ rate of at most 255 per extra byte (thus the compression ratio cannot exceed ++ around 255:1). The variable length encoding using #bits is always the same : ++ ++ length = byte & ((1 << #bits) - 1) ++ if (!length) { ++ length = ((1 << #bits) - 1) ++ length += 255*(number of zero bytes) ++ length += first-non-zero-byte ++ } ++ length += constant (generally 2 or 3) ++ ++ For references to the dictionary, distances are relative to the output ++ pointer. Distances are encoded using very few bits belonging to certain ++ ranges, resulting in multiple copy instructions using different encodings. ++ Certain encodings involve one extra byte, others involve two extra bytes ++ forming a little-endian 16-bit quantity (marked LE16 below). ++ ++ After any instruction except the large literal copy, 0, 1, 2 or 3 literals ++ are copied before starting the next instruction. The number of literals that ++ were copied may change the meaning and behaviour of the next instruction. In ++ practice, only one instruction needs to know whether 0, less than 4, or more ++ literals were copied. This is the information stored in the variable ++ in this implementation. This number of immediate literals to be copied is ++ generally encoded in the last two bits of the instruction but may also be ++ taken from the last two bits of an extra operand (eg: distance). ++ ++ End of stream is declared when a block copy of distance 0 is seen. Only one ++ instruction may encode this distance (0001HLLL), it takes one LE16 operand ++ for the distance, thus requiring 3 bytes. ++ ++ IMPORTANT NOTE : in the code some length checks are missing because certain ++ instructions are called under the assumption that a certain number of bytes ++ follow because it has already been garanteed before parsing the instructions. ++ They just have to "refill" this credit if they consume extra bytes. This is ++ an implementation design choice independant on the algorithm or encoding. ++ ++Byte sequences ++ ++ First byte encoding : ++ ++ 0..17 : follow regular instruction encoding, see below. It is worth ++ noting that codes 16 and 17 will represent a block copy from ++ the dictionary which is empty, and that they will always be ++ invalid at this place. ++ ++ 18..21 : copy 0..3 literals ++ state = (byte - 17) = 0..3 [ copy literals ] ++ skip byte ++ ++ 22..255 : copy literal string ++ length = (byte - 17) = 4..238 ++ state = 4 [ don't copy extra literals ] ++ skip byte ++ ++ Instruction encoding : ++ ++ 0 0 0 0 X X X X (0..15) ++ Depends on the number of literals copied by the last instruction. ++ If last instruction did not copy any literal (state == 0), this ++ encoding will be a copy of 4 or more literal, and must be interpreted ++ like this : ++ ++ 0 0 0 0 L L L L (0..15) : copy long literal string ++ length = 3 + (L ?: 15 + (zero_bytes * 255) + non_zero_byte) ++ state = 4 (no extra literals are copied) ++ ++ If last instruction used to copy between 1 to 3 literals (encoded in ++ the instruction's opcode or distance), the instruction is a copy of a ++ 2-byte block from the dictionary within a 1kB distance. It is worth ++ noting that this instruction provides little savings since it uses 2 ++ bytes to encode a copy of 2 other bytes but it encodes the number of ++ following literals for free. It must be interpreted like this : ++ ++ 0 0 0 0 D D S S (0..15) : copy 2 bytes from <= 1kB distance ++ length = 2 ++ state = S (copy S literals after this block) ++ Always followed by exactly one byte : H H H H H H H H ++ distance = (H << 2) + D + 1 ++ ++ If last instruction used to copy 4 or more literals (as detected by ++ state == 4), the instruction becomes a copy of a 3-byte block from the ++ dictionary from a 2..3kB distance, and must be interpreted like this : ++ ++ 0 0 0 0 D D S S (0..15) : copy 3 bytes from 2..3 kB distance ++ length = 3 ++ state = S (copy S literals after this block) ++ Always followed by exactly one byte : H H H H H H H H ++ distance = (H << 2) + D + 2049 ++ ++ 0 0 0 1 H L L L (16..31) ++ Copy of a block within 16..48kB distance (preferably less than 10B) ++ length = 2 + (L ?: 7 + (zero_bytes * 255) + non_zero_byte) ++ Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S ++ distance = 16384 + (H << 14) + D ++ state = S (copy S literals after this block) ++ End of stream is reached if distance == 16384 ++ ++ 0 0 1 L L L L L (32..63) ++ Copy of small block within 16kB distance (preferably less than 34B) ++ length = 2 + (L ?: 31 + (zero_bytes * 255) + non_zero_byte) ++ Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S ++ distance = D + 1 ++ state = S (copy S literals after this block) ++ ++ 0 1 L D D D S S (64..127) ++ Copy 3-4 bytes from block within 2kB distance ++ state = S (copy S literals after this block) ++ length = 3 + L ++ Always followed by exactly one byte : H H H H H H H H ++ distance = (H << 3) + D + 1 ++ ++ 1 L L D D D S S (128..255) ++ Copy 5-8 bytes from block within 2kB distance ++ state = S (copy S literals after this block) ++ length = 5 + L ++ Always followed by exactly one byte : H H H H H H H H ++ distance = (H << 3) + D + 1 ++ ++Authors ++ ++ This document was written by Willy Tarreau on 2014/07/19 during an ++ analysis of the decompression code available in Linux 3.16-rc5. The code is ++ tricky, it is possible that this document contains mistakes or that a few ++ corner cases were overlooked. In any case, please report any doubt, fix, or ++ proposed updates to the author(s) so that the document can be updated. diff --git a/queue-3.16/fixing-lease-renewal.patch b/queue-3.16/fixing-lease-renewal.patch new file mode 100644 index 00000000000..cf9e885decf --- /dev/null +++ b/queue-3.16/fixing-lease-renewal.patch @@ -0,0 +1,34 @@ +From 8faaa6d5d48b201527e0451296d9e71d23afb362 Mon Sep 17 00:00:00 2001 +From: Olga Kornievskaia +Date: Wed, 24 Sep 2014 18:11:28 -0400 +Subject: Fixing lease renewal + +From: Olga Kornievskaia + +commit 8faaa6d5d48b201527e0451296d9e71d23afb362 upstream. + +Commit c9fdeb28 removed a 'continue' after checking if the lease needs +to be renewed. However, if client hasn't moved, the code falls down to +starting reboot recovery erroneously (ie., sends open reclaim and gets +back stale_clientid error) before recovering from getting stale_clientid +on the renew operation. + +Signed-off-by: Olga Kornievskaia +Fixes: c9fdeb280b8c (NFS: Add basic migration support to state manager thread) +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4state.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -2372,6 +2372,7 @@ static void nfs4_state_manager(struct nf + status = nfs4_check_lease(clp); + if (status < 0) + goto out_error; ++ continue; + } + + if (test_and_clear_bit(NFS4CLNT_MOVED, &clp->cl_state)) { diff --git a/queue-3.16/lzo-check-for-length-overrun-in-variable-length-encoding.patch b/queue-3.16/lzo-check-for-length-overrun-in-variable-length-encoding.patch new file mode 100644 index 00000000000..75b91e7e92e --- /dev/null +++ b/queue-3.16/lzo-check-for-length-overrun-in-variable-length-encoding.patch @@ -0,0 +1,124 @@ +From 72cf90124e87d975d0b2114d930808c58b4c05e4 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sat, 27 Sep 2014 12:31:37 +0200 +Subject: lzo: check for length overrun in variable length encoding. + +From: Willy Tarreau + +commit 72cf90124e87d975d0b2114d930808c58b4c05e4 upstream. + +This fix ensures that we never meet an integer overflow while adding +255 while parsing a variable length encoding. It works differently from +commit 206a81c ("lzo: properly check for overruns") because instead of +ensuring that we don't overrun the input, which is tricky to guarantee +due to many assumptions in the code, it simply checks that the cumulated +number of 255 read cannot overflow by bounding this number. + +The MAX_255_COUNT is the maximum number of times we can add 255 to a base +count without overflowing an integer. The multiply will overflow when +multiplying 255 by more than MAXINT/255. The sum will overflow earlier +depending on the base count. Since the base count is taken from a u8 +and a few bits, it is safe to assume that it will always be lower than +or equal to 2*255, thus we can always prevent any overflow by accepting +two less 255 steps. + +This patch also reduces the CPU overhead and actually increases performance +by 1.1% compared to the initial code, while the previous fix costs 3.1% +(measured on x86_64). + +The fix needs to be backported to all currently supported stable kernels. + +Reported-by: Willem Pinckaers +Cc: "Don A. Bailey" +Signed-off-by: Willy Tarreau +Signed-off-by: Greg Kroah-Hartman + +--- + lib/lzo/lzo1x_decompress_safe.c | 43 ++++++++++++++++++++++++++++++++++------ + 1 file changed, 37 insertions(+), 6 deletions(-) + +--- a/lib/lzo/lzo1x_decompress_safe.c ++++ b/lib/lzo/lzo1x_decompress_safe.c +@@ -25,6 +25,16 @@ + #define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun + #define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun + ++/* This MAX_255_COUNT is the maximum number of times we can add 255 to a base ++ * count without overflowing an integer. The multiply will overflow when ++ * multiplying 255 by more than MAXINT/255. The sum will overflow earlier ++ * depending on the base count. Since the base count is taken from a u8 ++ * and a few bits, it is safe to assume that it will always be lower than ++ * or equal to 2*255, thus we can always prevent any overflow by accepting ++ * two less 255 steps. See Documentation/lzo.txt for more information. ++ */ ++#define MAX_255_COUNT ((((size_t)~0) / 255) - 2) ++ + int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, + unsigned char *out, size_t *out_len) + { +@@ -55,12 +65,19 @@ int lzo1x_decompress_safe(const unsigned + if (t < 16) { + if (likely(state == 0)) { + if (unlikely(t == 0)) { ++ size_t offset; ++ const unsigned char *ip_last = ip; ++ + while (unlikely(*ip == 0)) { +- t += 255; + ip++; + NEED_IP(1); + } +- t += 15 + *ip++; ++ offset = ip - ip_last; ++ if (unlikely(offset > MAX_255_COUNT)) ++ return LZO_E_ERROR; ++ ++ offset = (offset << 8) - offset; ++ t += offset + 15 + *ip++; + } + t += 3; + copy_literal_run: +@@ -116,12 +133,19 @@ copy_literal_run: + } else if (t >= 32) { + t = (t & 31) + (3 - 1); + if (unlikely(t == 2)) { ++ size_t offset; ++ const unsigned char *ip_last = ip; ++ + while (unlikely(*ip == 0)) { +- t += 255; + ip++; + NEED_IP(1); + } +- t += 31 + *ip++; ++ offset = ip - ip_last; ++ if (unlikely(offset > MAX_255_COUNT)) ++ return LZO_E_ERROR; ++ ++ offset = (offset << 8) - offset; ++ t += offset + 31 + *ip++; + NEED_IP(2); + } + m_pos = op - 1; +@@ -134,12 +158,19 @@ copy_literal_run: + m_pos -= (t & 8) << 11; + t = (t & 7) + (3 - 1); + if (unlikely(t == 2)) { ++ size_t offset; ++ const unsigned char *ip_last = ip; ++ + while (unlikely(*ip == 0)) { +- t += 255; + ip++; + NEED_IP(1); + } +- t += 7 + *ip++; ++ offset = ip - ip_last; ++ if (unlikely(offset > MAX_255_COUNT)) ++ return LZO_E_ERROR; ++ ++ offset = (offset << 8) - offset; ++ t += offset + 7 + *ip++; + NEED_IP(2); + } + next = get_unaligned_le16(ip); diff --git a/queue-3.16/m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.patch b/queue-3.16/m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.patch new file mode 100644 index 00000000000..cfe1a15b9ef --- /dev/null +++ b/queue-3.16/m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.patch @@ -0,0 +1,77 @@ +From e4dc601bf99ccd1c95b7e6eef1d3cf3c4b0d4961 Mon Sep 17 00:00:00 2001 +From: Geert Uytterhoeven +Date: Sun, 28 Sep 2014 10:50:06 +0200 +Subject: m68k: Disable/restore interrupts in hwreg_present()/hwreg_write() + +From: Geert Uytterhoeven + +commit e4dc601bf99ccd1c95b7e6eef1d3cf3c4b0d4961 upstream. + +hwreg_present() and hwreg_write() temporarily change the VBR register to +another vector table. This table contains a valid bus error handler +only, all other entries point to arbitrary addresses. + +If an interrupt comes in while the temporary table is active, the +processor will start executing at such an arbitrary address, and the +kernel will crash. + +While most callers run early, before interrupts are enabled, or +explicitly disable interrupts, Finn Thain pointed out that macsonic has +one callsite that doesn't, causing intermittent boot crashes. +There's another unsafe callsite in hilkbd. + +Fix this for good by disabling and restoring interrupts inside +hwreg_present() and hwreg_write(). + +Explicitly disabling interrupts can be removed from the callsites later. + +Reported-by: Finn Thain +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Greg Kroah-Hartman + +--- + arch/m68k/mm/hwtest.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/arch/m68k/mm/hwtest.c ++++ b/arch/m68k/mm/hwtest.c +@@ -28,9 +28,11 @@ + int hwreg_present( volatile void *regp ) + { + int ret = 0; ++ unsigned long flags; + long save_sp, save_vbr; + long tmp_vectors[3]; + ++ local_irq_save(flags); + __asm__ __volatile__ + ( "movec %/vbr,%2\n\t" + "movel #Lberr1,%4@(8)\n\t" +@@ -46,6 +48,7 @@ int hwreg_present( volatile void *regp ) + : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) + : "a" (regp), "a" (tmp_vectors) + ); ++ local_irq_restore(flags); + + return( ret ); + } +@@ -58,9 +61,11 @@ EXPORT_SYMBOL(hwreg_present); + int hwreg_write( volatile void *regp, unsigned short val ) + { + int ret; ++ unsigned long flags; + long save_sp, save_vbr; + long tmp_vectors[3]; + ++ local_irq_save(flags); + __asm__ __volatile__ + ( "movec %/vbr,%2\n\t" + "movel #Lberr2,%4@(8)\n\t" +@@ -78,6 +83,7 @@ int hwreg_write( volatile void *regp, un + : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) + : "a" (regp), "a" (tmp_vectors), "g" (val) + ); ++ local_irq_restore(flags); + + return( ret ); + } diff --git a/queue-3.16/mei-bus-fix-possible-boundaries-violation.patch b/queue-3.16/mei-bus-fix-possible-boundaries-violation.patch new file mode 100644 index 00000000000..5bb5a7411c3 --- /dev/null +++ b/queue-3.16/mei-bus-fix-possible-boundaries-violation.patch @@ -0,0 +1,33 @@ +From cfda2794b5afe7ce64ee9605c64bef0e56a48125 Mon Sep 17 00:00:00 2001 +From: Alexander Usyskin +Date: Mon, 25 Aug 2014 16:46:53 +0300 +Subject: mei: bus: fix possible boundaries violation + +From: Alexander Usyskin + +commit cfda2794b5afe7ce64ee9605c64bef0e56a48125 upstream. + +function 'strncpy' will fill whole buffer 'id.name' of fixed size (32) +with string value and will not leave place for NULL-terminator. +Possible buffer boundaries violation in following string operations. +Replace strncpy with strlcpy. + +Signed-off-by: Alexander Usyskin +Signed-off-by: Tomas Winkler +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/misc/mei/bus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/misc/mei/bus.c ++++ b/drivers/misc/mei/bus.c +@@ -70,7 +70,7 @@ static int mei_cl_device_probe(struct de + + dev_dbg(dev, "Device probe\n"); + +- strncpy(id.name, dev_name(dev), sizeof(id.name)); ++ strlcpy(id.name, dev_name(dev), sizeof(id.name)); + + return driver->probe(device, &id); + } diff --git a/queue-3.16/nfs-fix-a-bogus-warning-in-nfs_generic_pgio.patch b/queue-3.16/nfs-fix-a-bogus-warning-in-nfs_generic_pgio.patch new file mode 100644 index 00000000000..f7d9b9e5e37 --- /dev/null +++ b/queue-3.16/nfs-fix-a-bogus-warning-in-nfs_generic_pgio.patch @@ -0,0 +1,41 @@ +From b8fb9c30f25e45dab5d2cd310ab6913b6861d00f Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 13 Oct 2014 10:56:12 -0400 +Subject: NFS: Fix a bogus warning in nfs_generic_pgio + +From: Trond Myklebust + +commit b8fb9c30f25e45dab5d2cd310ab6913b6861d00f upstream. + +It is OK for pageused == pagecount in the loop, as long as we don't add +another entry to the *pages array. Move the test so that it only triggers +in that case. + +Reported-by: Steve Dickson +Fixes: bba5c1887a92 (nfs: disallow duplicate pages in pgio page vectors) +Cc: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/pagelist.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -754,12 +754,11 @@ int nfs_generic_pgio(struct nfs_pageio_d + nfs_list_remove_request(req); + nfs_list_add_request(req, &hdr->pages); + +- if (WARN_ON_ONCE(pageused >= pagecount)) +- return nfs_pgio_error(desc, hdr); +- + if (!last_page || last_page != req->wb_page) { +- *pages++ = last_page = req->wb_page; + pageused++; ++ if (pageused > pagecount) ++ break; ++ *pages++ = last_page = req->wb_page; + } + } + if (WARN_ON_ONCE(pageused != pagecount)) diff --git a/queue-3.16/nfs-fix-an-uninitialised-pointer-oops-in-the-writeback-error-path.patch b/queue-3.16/nfs-fix-an-uninitialised-pointer-oops-in-the-writeback-error-path.patch new file mode 100644 index 00000000000..d5cf1605e9b --- /dev/null +++ b/queue-3.16/nfs-fix-an-uninitialised-pointer-oops-in-the-writeback-error-path.patch @@ -0,0 +1,67 @@ +From 3caa0c6ed754d91b15266abf222498edbef982bd Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 13 Oct 2014 10:26:43 -0400 +Subject: NFS: Fix an uninitialised pointer Oops in the writeback error path + +From: Trond Myklebust + +commit 3caa0c6ed754d91b15266abf222498edbef982bd upstream. + +SteveD reports the following Oops: + RIP: 0010:[] [] __put_nfs_open_context+0x1d/0x100 [nfs] + RSP: 0018:ffff880fed687b90 EFLAGS: 00010286 + RAX: 0000000000000024 RBX: 0000000000000000 RCX: 0000000000000006 + RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 + RBP: ffff880fed687bc0 R08: 0000000000000092 R09: 000000000000047a + R10: 0000000000000000 R11: ffff880fed6878d6 R12: ffff880fed687d20 + R13: ffff880fed687d20 R14: 0000000000000070 R15: ffffea000aa33ec0 + FS: 00007fce290f0740(0000) GS:ffff8807ffc60000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 0000000000000070 CR3: 00000007f2e79000 CR4: 00000000000007e0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 + Stack: + 0000000000000000 ffff880036c5e510 ffff880fed687d20 ffff880fed687d20 + ffff880036c5e200 ffffea000aa33ec0 ffff880fed687bd0 ffffffffa0534710 + ffff880fed687be8 ffffffffa053d5f0 ffff880036c5e200 ffff880fed687c08 + Call Trace: + [] put_nfs_open_context+0x10/0x20 [nfs] + [] nfs_pgio_data_destroy+0x20/0x40 [nfs] + [] nfs_pgio_error+0x22/0x40 [nfs] + [] nfs_generic_pgio+0x74/0x2e0 [nfs] + [] pnfs_generic_pg_writepages+0x63/0x210 [nfsv4] + [] nfs_pageio_doio+0x19/0x50 [nfs] + [] nfs_pageio_complete+0x24/0x30 [nfs] + [] nfs_direct_write_schedule_iovec+0x115/0x1f0 [nfs] + [] ? nfs_get_lock_context+0x4f/0x120 [nfs] + [] nfs_file_direct_write+0x262/0x420 [nfs] + [] nfs_file_write+0x131/0x1d0 [nfs] + [] ? nfs_need_sync_write.isra.17+0x40/0x40 [nfs] + [] do_io_submit+0x3b8/0x840 + [] SyS_io_submit+0x10/0x20 + [] system_call_fastpath+0x16/0x1b + +This is due to the calls to nfs_pgio_error() in nfs_generic_pgio(), which +happen before the nfs_pgio_header's open context is referenced in +nfs_pgio_rpcsetup(). + +Reported-by: Steve Dickson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/pagelist.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -527,7 +527,8 @@ EXPORT_SYMBOL_GPL(nfs_pgio_header_free); + */ + void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr) + { +- put_nfs_open_context(hdr->args.context); ++ if (hdr->args.context) ++ put_nfs_open_context(hdr->args.context); + if (hdr->page_array.pagevec != hdr->page_array.page_array) + kfree(hdr->page_array.pagevec); + } diff --git a/queue-3.16/nfsd4-reserve-adequate-space-for-lock-op.patch b/queue-3.16/nfsd4-reserve-adequate-space-for-lock-op.patch new file mode 100644 index 00000000000..77f5f14ad69 --- /dev/null +++ b/queue-3.16/nfsd4-reserve-adequate-space-for-lock-op.patch @@ -0,0 +1,46 @@ +From f7b43d0c992c3ec3e8d9285c3fb5e1e0eb0d031a Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +Date: Tue, 12 Aug 2014 11:41:40 -0400 +Subject: nfsd4: reserve adequate space for LOCK op + +From: "J. Bruce Fields" + +commit f7b43d0c992c3ec3e8d9285c3fb5e1e0eb0d031a upstream. + +As of 8c7424cff6 "nfsd4: don't try to encode conflicting owner if low +on space", we permit the server to process a LOCK operation even if +there might not be space to return the conflicting lockowner, because +we've made returning the conflicting lockowner optional. + +However, the rpc server still wants to know the most we might possibly +return, so we need to take into account the possible conflicting +lockowner in the svc_reserve_space() call here. + +Symptoms were log messages like "RPC request reserved 88 but used 108". + +Fixes: 8c7424cff6 "nfsd4: don't try to encode conflicting owner if low on space" +Reported-by: Kinglong Mee +Signed-off-by: J. Bruce Fields +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfsd/nfs4xdr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1675,6 +1675,14 @@ nfsd4_decode_compound(struct nfsd4_compo + readbytes += nfsd4_max_reply(argp->rqstp, op); + } else + max_reply += nfsd4_max_reply(argp->rqstp, op); ++ /* ++ * OP_LOCK may return a conflicting lock. (Special case ++ * because it will just skip encoding this if it runs ++ * out of xdr buffer space, and it is the only operation ++ * that behaves this way.) ++ */ ++ if (op->opnum == OP_LOCK) ++ max_reply += NFS4_OPAQUE_LIMIT; + + if (op->status) { + argp->opcnt = i+1; diff --git a/queue-3.16/nfsv4-fix-lock-recovery-when-create_session-setclientid_confirm-fails.patch b/queue-3.16/nfsv4-fix-lock-recovery-when-create_session-setclientid_confirm-fails.patch new file mode 100644 index 00000000000..1629f9d7d72 --- /dev/null +++ b/queue-3.16/nfsv4-fix-lock-recovery-when-create_session-setclientid_confirm-fails.patch @@ -0,0 +1,35 @@ +From a4339b7b686b4acc8b6de2b07d7bacbe3ae44b83 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Sat, 27 Sep 2014 17:02:26 -0400 +Subject: NFSv4: Fix lock recovery when CREATE_SESSION/SETCLIENTID_CONFIRM fails + +From: Trond Myklebust + +commit a4339b7b686b4acc8b6de2b07d7bacbe3ae44b83 upstream. + +If a NFSv4.x server returns NFS4ERR_STALE_CLIENTID in response to a +CREATE_SESSION or SETCLIENTID_CONFIRM in order to tell us that it rebooted +a second time, then the client will currently take this to mean that it must +declare all locks to be stale, and hence ineligible for reboot recovery. + +RFC3530 and RFC5661 both suggest that the client should instead rely on the +server to respond to inelegible open share, lock and delegation reclaim +requests with NFS4ERR_NO_GRACE in this situation. + +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4state.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -1788,7 +1788,6 @@ static int nfs4_handle_reclaim_lease_err + break; + case -NFS4ERR_STALE_CLIENTID: + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); +- nfs4_state_clear_reclaim_reboot(clp); + nfs4_state_start_reclaim_reboot(clp); + break; + case -NFS4ERR_CLID_INUSE: diff --git a/queue-3.16/nfsv4-fix-open-lock-state-recovery-error-handling.patch b/queue-3.16/nfsv4-fix-open-lock-state-recovery-error-handling.patch new file mode 100644 index 00000000000..d621e21d332 --- /dev/null +++ b/queue-3.16/nfsv4-fix-open-lock-state-recovery-error-handling.patch @@ -0,0 +1,71 @@ +From df817ba35736db2d62b07de6f050a4db53492ad8 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Sat, 27 Sep 2014 17:41:51 -0400 +Subject: NFSv4: fix open/lock state recovery error handling + +From: Trond Myklebust + +commit df817ba35736db2d62b07de6f050a4db53492ad8 upstream. + +The current open/lock state recovery unfortunately does not handle errors +such as NFS4ERR_CONN_NOT_BOUND_TO_SESSION correctly. Instead of looping, +just proceeds as if the state manager is finished recovering. +This patch ensures that we loop back, handle higher priority errors +and complete the open/lock state recovery. + +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4state.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -1732,7 +1732,8 @@ restart: + if (status < 0) { + set_bit(ops->owner_flag_bit, &sp->so_flags); + nfs4_put_state_owner(sp); +- return nfs4_recovery_handle_error(clp, status); ++ status = nfs4_recovery_handle_error(clp, status); ++ return (status != 0) ? status : -EAGAIN; + } + + nfs4_put_state_owner(sp); +@@ -1741,7 +1742,7 @@ restart: + spin_unlock(&clp->cl_lock); + } + rcu_read_unlock(); +- return status; ++ return 0; + } + + static int nfs4_check_lease(struct nfs_client *clp) +@@ -2393,14 +2394,11 @@ static void nfs4_state_manager(struct nf + section = "reclaim reboot"; + status = nfs4_do_reclaim(clp, + clp->cl_mvops->reboot_recovery_ops); +- if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || +- test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) +- continue; +- nfs4_state_end_reclaim_reboot(clp); +- if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) ++ if (status == -EAGAIN) + continue; + if (status < 0) + goto out_error; ++ nfs4_state_end_reclaim_reboot(clp); + } + + /* Now recover expired state... */ +@@ -2408,9 +2406,7 @@ static void nfs4_state_manager(struct nf + section = "reclaim nograce"; + status = nfs4_do_reclaim(clp, + clp->cl_mvops->nograce_recovery_ops); +- if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || +- test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) || +- test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) ++ if (status == -EAGAIN) + continue; + if (status < 0) + goto out_error; diff --git a/queue-3.16/nfsv4.1-fix-an-nfsv4.1-state-renewal-regression.patch b/queue-3.16/nfsv4.1-fix-an-nfsv4.1-state-renewal-regression.patch new file mode 100644 index 00000000000..ad13ed9f16d --- /dev/null +++ b/queue-3.16/nfsv4.1-fix-an-nfsv4.1-state-renewal-regression.patch @@ -0,0 +1,91 @@ +From d1f456b0b9545f1606a54cd17c20775f159bd2ce Mon Sep 17 00:00:00 2001 +From: Andy Adamson +Date: Mon, 29 Sep 2014 12:31:57 -0400 +Subject: NFSv4.1: Fix an NFSv4.1 state renewal regression + +From: Andy Adamson + +commit d1f456b0b9545f1606a54cd17c20775f159bd2ce upstream. + +Commit 2f60ea6b8ced ("NFSv4: The NFSv4.0 client must send RENEW calls if it holds a delegation") set the NFS4_RENEW_TIMEOUT flag in nfs4_renew_state, and does +not put an nfs41_proc_async_sequence call, the NFSv4.1 lease renewal heartbeat +call, on the wire to renew the NFSv4.1 state if the flag was not set. + +The NFS4_RENEW_TIMEOUT flag is set when "now" is after the last renewal +(cl_last_renewal) plus the lease time divided by 3. This is arbitrary and +sometimes does the following: + +In normal operation, the only way a future state renewal call is put on the +wire is via a call to nfs4_schedule_state_renewal, which schedules a +nfs4_renew_state workqueue task. nfs4_renew_state determines if the +NFS4_RENEW_TIMEOUT should be set, and the calls nfs41_proc_async_sequence, +which only gets sent if the NFS4_RENEW_TIMEOUT flag is set. +Then the nfs41_proc_async_sequence rpc_release function schedules +another state remewal via nfs4_schedule_state_renewal. + +Without this change we can get into a state where an application stops +accessing the NFSv4.1 share, state renewal calls stop due to the +NFS4_RENEW_TIMEOUT flag _not_ being set. The only way to recover +from this situation is with a clientid re-establishment, once the application +resumes and the server has timed out the lease and so returns +NFS4ERR_BAD_SESSION on the subsequent SEQUENCE operation. + +An example application: +open, lock, write a file. + +sleep for 6 * lease (could be less) + +ulock, close. + +In the above example with NFSv4.1 delegations enabled, without this change, +there are no OP_SEQUENCE state renewal calls during the sleep, and the +clientid is recovered due to lease expiration on the close. + +This issue does not occur with NFSv4.1 delegations disabled, nor with +NFSv4.0, with or without delegations enabled. + +Signed-off-by: Andy Adamson +Link: http://lkml.kernel.org/r/1411486536-23401-1-git-send-email-andros@netapp.com +Fixes: 2f60ea6b8ced (NFSv4: The NFSv4.0 client must send RENEW calls...) +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 2 +- + fs/nfs/nfs4renewd.c | 12 ++++++++++-- + 2 files changed, 11 insertions(+), 3 deletions(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -7242,7 +7242,7 @@ static int nfs41_proc_async_sequence(str + int ret = 0; + + if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) +- return 0; ++ return -EAGAIN; + task = _nfs41_proc_sequence(clp, cred, false); + if (IS_ERR(task)) + ret = PTR_ERR(task); +--- a/fs/nfs/nfs4renewd.c ++++ b/fs/nfs/nfs4renewd.c +@@ -88,10 +88,18 @@ nfs4_renew_state(struct work_struct *wor + } + nfs_expire_all_delegations(clp); + } else { ++ int ret; ++ + /* Queue an asynchronous RENEW. */ +- ops->sched_state_renewal(clp, cred, renew_flags); ++ ret = ops->sched_state_renewal(clp, cred, renew_flags); + put_rpccred(cred); +- goto out_exp; ++ switch (ret) { ++ default: ++ goto out_exp; ++ case -EAGAIN: ++ case -ENOMEM: ++ break; ++ } + } + } else { + dprintk("%s: failed to call renewd. Reason: lease not expired \n", diff --git a/queue-3.16/revert-lzo-properly-check-for-overruns.patch b/queue-3.16/revert-lzo-properly-check-for-overruns.patch new file mode 100644 index 00000000000..00937da9f30 --- /dev/null +++ b/queue-3.16/revert-lzo-properly-check-for-overruns.patch @@ -0,0 +1,181 @@ +From af958a38a60c7ca3d8a39c918c1baa2ff7b6b233 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sat, 27 Sep 2014 12:31:36 +0200 +Subject: Revert "lzo: properly check for overruns" + +From: Willy Tarreau + +commit af958a38a60c7ca3d8a39c918c1baa2ff7b6b233 upstream. + +This reverts commit 206a81c ("lzo: properly check for overruns"). + +As analysed by Willem Pinckaers, this fix is still incomplete on +certain rare corner cases, and it is easier to restart from the +original code. + +Reported-by: Willem Pinckaers +Cc: "Don A. Bailey" +Signed-off-by: Willy Tarreau +Signed-off-by: Greg Kroah-Hartman + +--- + lib/lzo/lzo1x_decompress_safe.c | 62 +++++++++++++--------------------------- + 1 file changed, 21 insertions(+), 41 deletions(-) + +--- a/lib/lzo/lzo1x_decompress_safe.c ++++ b/lib/lzo/lzo1x_decompress_safe.c +@@ -19,31 +19,11 @@ + #include + #include "lzodefs.h" + +-#define HAVE_IP(t, x) \ +- (((size_t)(ip_end - ip) >= (size_t)(t + x)) && \ +- (((t + x) >= t) && ((t + x) >= x))) +- +-#define HAVE_OP(t, x) \ +- (((size_t)(op_end - op) >= (size_t)(t + x)) && \ +- (((t + x) >= t) && ((t + x) >= x))) +- +-#define NEED_IP(t, x) \ +- do { \ +- if (!HAVE_IP(t, x)) \ +- goto input_overrun; \ +- } while (0) +- +-#define NEED_OP(t, x) \ +- do { \ +- if (!HAVE_OP(t, x)) \ +- goto output_overrun; \ +- } while (0) +- +-#define TEST_LB(m_pos) \ +- do { \ +- if ((m_pos) < out) \ +- goto lookbehind_overrun; \ +- } while (0) ++#define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) ++#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) ++#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun ++#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun ++#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun + + int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, + unsigned char *out, size_t *out_len) +@@ -78,14 +58,14 @@ int lzo1x_decompress_safe(const unsigned + while (unlikely(*ip == 0)) { + t += 255; + ip++; +- NEED_IP(1, 0); ++ NEED_IP(1); + } + t += 15 + *ip++; + } + t += 3; + copy_literal_run: + #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) +- if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) { ++ if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { + const unsigned char *ie = ip + t; + unsigned char *oe = op + t; + do { +@@ -101,8 +81,8 @@ copy_literal_run: + } else + #endif + { +- NEED_OP(t, 0); +- NEED_IP(t, 3); ++ NEED_OP(t); ++ NEED_IP(t + 3); + do { + *op++ = *ip++; + } while (--t > 0); +@@ -115,7 +95,7 @@ copy_literal_run: + m_pos -= t >> 2; + m_pos -= *ip++ << 2; + TEST_LB(m_pos); +- NEED_OP(2, 0); ++ NEED_OP(2); + op[0] = m_pos[0]; + op[1] = m_pos[1]; + op += 2; +@@ -139,10 +119,10 @@ copy_literal_run: + while (unlikely(*ip == 0)) { + t += 255; + ip++; +- NEED_IP(1, 0); ++ NEED_IP(1); + } + t += 31 + *ip++; +- NEED_IP(2, 0); ++ NEED_IP(2); + } + m_pos = op - 1; + next = get_unaligned_le16(ip); +@@ -157,10 +137,10 @@ copy_literal_run: + while (unlikely(*ip == 0)) { + t += 255; + ip++; +- NEED_IP(1, 0); ++ NEED_IP(1); + } + t += 7 + *ip++; +- NEED_IP(2, 0); ++ NEED_IP(2); + } + next = get_unaligned_le16(ip); + ip += 2; +@@ -174,7 +154,7 @@ copy_literal_run: + #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + if (op - m_pos >= 8) { + unsigned char *oe = op + t; +- if (likely(HAVE_OP(t, 15))) { ++ if (likely(HAVE_OP(t + 15))) { + do { + COPY8(op, m_pos); + op += 8; +@@ -184,7 +164,7 @@ copy_literal_run: + m_pos += 8; + } while (op < oe); + op = oe; +- if (HAVE_IP(6, 0)) { ++ if (HAVE_IP(6)) { + state = next; + COPY4(op, ip); + op += next; +@@ -192,7 +172,7 @@ copy_literal_run: + continue; + } + } else { +- NEED_OP(t, 0); ++ NEED_OP(t); + do { + *op++ = *m_pos++; + } while (op < oe); +@@ -201,7 +181,7 @@ copy_literal_run: + #endif + { + unsigned char *oe = op + t; +- NEED_OP(t, 0); ++ NEED_OP(t); + op[0] = m_pos[0]; + op[1] = m_pos[1]; + op += 2; +@@ -214,15 +194,15 @@ match_next: + state = next; + t = next; + #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) +- if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) { ++ if (likely(HAVE_IP(6) && HAVE_OP(4))) { + COPY4(op, ip); + op += t; + ip += t; + } else + #endif + { +- NEED_IP(t, 3); +- NEED_OP(t, 0); ++ NEED_IP(t + 3); ++ NEED_OP(t); + while (t > 0) { + *op++ = *ip++; + t--; diff --git a/queue-3.16/series b/queue-3.16/series index 093294ad961..e2f220fb833 100644 --- a/queue-3.16/series +++ b/queue-3.16/series @@ -42,3 +42,16 @@ drivers-hv-vmbus-cleanup-vmbus_close_internal.patch drivers-hv-vmbus-cleanup-vmbus_establish_gpadl.patch drivers-hv-vmbus-fix-a-bug-in-vmbus_open.patch drivers-hv-vmbus-cleanup-hv_post_message.patch +mei-bus-fix-possible-boundaries-violation.patch +m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.patch +fixing-lease-renewal.patch +documentation-lzo-document-part-of-the-encoding.patch +revert-lzo-properly-check-for-overruns.patch +lzo-check-for-length-overrun-in-variable-length-encoding.patch +tty-omap-serial-fix-division-by-zero.patch +nfsv4-fix-lock-recovery-when-create_session-setclientid_confirm-fails.patch +nfsv4-fix-open-lock-state-recovery-error-handling.patch +nfsv4.1-fix-an-nfsv4.1-state-renewal-regression.patch +nfsd4-reserve-adequate-space-for-lock-op.patch +nfs-fix-an-uninitialised-pointer-oops-in-the-writeback-error-path.patch +nfs-fix-a-bogus-warning-in-nfs_generic_pgio.patch diff --git a/queue-3.16/tty-omap-serial-fix-division-by-zero.patch b/queue-3.16/tty-omap-serial-fix-division-by-zero.patch new file mode 100644 index 00000000000..d7dbd9bbe05 --- /dev/null +++ b/queue-3.16/tty-omap-serial-fix-division-by-zero.patch @@ -0,0 +1,58 @@ +From dc3187564e61260f49eceb21a4e7eb5e4428e90a Mon Sep 17 00:00:00 2001 +From: Frans Klaver +Date: Thu, 25 Sep 2014 11:19:51 +0200 +Subject: tty: omap-serial: fix division by zero + +From: Frans Klaver + +commit dc3187564e61260f49eceb21a4e7eb5e4428e90a upstream. + +If the chosen baud rate is large enough (e.g. 3.5 megabaud), the +calculated n values in serial_omap_is_baud_mode16() may become 0. This +causes a division by zero when calculating the difference between +calculated and desired baud rates. To prevent this, cap the n13 and n16 +values on 1. + +Division by zero in kernel. +[] (unwind_backtrace) from [] (show_stack+0x10/0x14) +[] (show_stack) from [] (Ldiv0+0x8/0x10) +[] (Ldiv0) from [] (serial_omap_baud_is_mode16+0x4c/0x68) +[] (serial_omap_baud_is_mode16) from [] (serial_omap_set_termios+0x90/0x8d8) +[] (serial_omap_set_termios) from [] (uart_change_speed+0xa4/0xa8) +[] (uart_change_speed) from [] (uart_set_termios+0xa0/0x1fc) +[] (uart_set_termios) from [] (tty_set_termios+0x248/0x2c0) +[] (tty_set_termios) from [] (set_termios+0x248/0x29c) +[] (set_termios) from [] (tty_mode_ioctl+0x1c8/0x4e8) +[] (tty_mode_ioctl) from [] (tty_ioctl+0xa94/0xb18) +[] (tty_ioctl) from [] (do_vfs_ioctl+0x4a0/0x560) +[] (do_vfs_ioctl) from [] (SyS_ioctl+0x4c/0x74) +[] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x30) + +Signed-off-by: Frans Klaver +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/serial/omap-serial.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/tty/serial/omap-serial.c ++++ b/drivers/tty/serial/omap-serial.c +@@ -254,8 +254,16 @@ serial_omap_baud_is_mode16(struct uart_p + { + unsigned int n13 = port->uartclk / (13 * baud); + unsigned int n16 = port->uartclk / (16 * baud); +- int baudAbsDiff13 = baud - (port->uartclk / (13 * n13)); +- int baudAbsDiff16 = baud - (port->uartclk / (16 * n16)); ++ int baudAbsDiff13; ++ int baudAbsDiff16; ++ ++ if (n13 == 0) ++ n13 = 1; ++ if (n16 == 0) ++ n16 = 1; ++ ++ baudAbsDiff13 = baud - (port->uartclk / (13 * n13)); ++ baudAbsDiff16 = baud - (port->uartclk / (16 * n16)); + if (baudAbsDiff13 < 0) + baudAbsDiff13 = -baudAbsDiff13; + if (baudAbsDiff16 < 0) -- 2.47.3