From: Greg Kroah-Hartman Date: Thu, 23 Oct 2014 09:05:10 +0000 (+0800) Subject: 3.10-stable patches X-Git-Tag: v3.10.59~23 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8ff8bacdfbf73b82de5c18446e6828406551f853;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: documentation-lzo-document-part-of-the-encoding.patch lzo-check-for-length-overrun-in-variable-length-encoding.patch m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.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 --- diff --git a/queue-3.10/documentation-lzo-document-part-of-the-encoding.patch b/queue-3.10/documentation-lzo-document-part-of-the-encoding.patch new file mode 100644 index 00000000000..8e8866f1afa --- /dev/null +++ b/queue-3.10/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.10/lzo-check-for-length-overrun-in-variable-length-encoding.patch b/queue-3.10/lzo-check-for-length-overrun-in-variable-length-encoding.patch new file mode 100644 index 00000000000..75b91e7e92e --- /dev/null +++ b/queue-3.10/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.10/m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.patch b/queue-3.10/m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.patch new file mode 100644 index 00000000000..cfe1a15b9ef --- /dev/null +++ b/queue-3.10/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.10/nfsv4-fix-lock-recovery-when-create_session-setclientid_confirm-fails.patch b/queue-3.10/nfsv4-fix-lock-recovery-when-create_session-setclientid_confirm-fails.patch new file mode 100644 index 00000000000..b756efbc56e --- /dev/null +++ b/queue-3.10/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 +@@ -1755,7 +1755,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.10/nfsv4-fix-open-lock-state-recovery-error-handling.patch b/queue-3.10/nfsv4-fix-open-lock-state-recovery-error-handling.patch new file mode 100644 index 00000000000..6d1b4de7bec --- /dev/null +++ b/queue-3.10/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 +@@ -1699,7 +1699,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); +@@ -1708,7 +1709,7 @@ restart: + spin_unlock(&clp->cl_lock); + } + rcu_read_unlock(); +- return status; ++ return 0; + } + + static int nfs4_check_lease(struct nfs_client *clp) +@@ -2173,14 +2174,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... */ +@@ -2188,9 +2186,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.10/nfsv4.1-fix-an-nfsv4.1-state-renewal-regression.patch b/queue-3.10/nfsv4.1-fix-an-nfsv4.1-state-renewal-regression.patch new file mode 100644 index 00000000000..9e58cc35531 --- /dev/null +++ b/queue-3.10/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 +@@ -6067,7 +6067,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.10/revert-lzo-properly-check-for-overruns.patch b/queue-3.10/revert-lzo-properly-check-for-overruns.patch new file mode 100644 index 00000000000..00937da9f30 --- /dev/null +++ b/queue-3.10/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.10/series b/queue-3.10/series index 68d7a9169fd..f7f6d36f6ad 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -20,3 +20,10 @@ drivers-hv-vmbus-cleanup-vmbus_post_msg.patch drivers-hv-vmbus-cleanup-vmbus_teardown_gpadl.patch drivers-hv-vmbus-cleanup-vmbus_establish_gpadl.patch drivers-hv-vmbus-fix-a-bug-in-vmbus_open.patch +m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.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 +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