]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Oct 2014 09:05:10 +0000 (17:05 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Oct 2014 09:05:10 +0000 (17:05 +0800)
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

queue-3.10/documentation-lzo-document-part-of-the-encoding.patch [new file with mode: 0644]
queue-3.10/lzo-check-for-length-overrun-in-variable-length-encoding.patch [new file with mode: 0644]
queue-3.10/m68k-disable-restore-interrupts-in-hwreg_present-hwreg_write.patch [new file with mode: 0644]
queue-3.10/nfsv4-fix-lock-recovery-when-create_session-setclientid_confirm-fails.patch [new file with mode: 0644]
queue-3.10/nfsv4-fix-open-lock-state-recovery-error-handling.patch [new file with mode: 0644]
queue-3.10/nfsv4.1-fix-an-nfsv4.1-state-renewal-regression.patch [new file with mode: 0644]
queue-3.10/revert-lzo-properly-check-for-overruns.patch [new file with mode: 0644]
queue-3.10/series

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 (file)
index 0000000..8e8866f
--- /dev/null
@@ -0,0 +1,189 @@
+From d98a0526434d27e261f622cf9d2e0028b5ff1a00 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sat, 27 Sep 2014 12:31:35 +0200
+Subject: Documentation: lzo: document part of the encoding
+
+From: Willy Tarreau <w@1wt.eu>
+
+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 <willem@lekkertech.net>
+Cc: "Don A. Bailey" <donb@securitymouse.com>
+Signed-off-by: Willy Tarreau <w@1wt.eu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <state> 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 <state> 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 <w@1wt.eu> 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 (file)
index 0000000..75b91e7
--- /dev/null
@@ -0,0 +1,124 @@
+From 72cf90124e87d975d0b2114d930808c58b4c05e4 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sat, 27 Sep 2014 12:31:37 +0200
+Subject: lzo: check for length overrun in variable length encoding.
+
+From: Willy Tarreau <w@1wt.eu>
+
+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 <willem@lekkertech.net>
+Cc: "Don A. Bailey" <donb@securitymouse.com>
+Signed-off-by: Willy Tarreau <w@1wt.eu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..cfe1a15
--- /dev/null
@@ -0,0 +1,77 @@
+From e4dc601bf99ccd1c95b7e6eef1d3cf3c4b0d4961 Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert@linux-m68k.org>
+Date: Sun, 28 Sep 2014 10:50:06 +0200
+Subject: m68k: Disable/restore interrupts in hwreg_present()/hwreg_write()
+
+From: Geert Uytterhoeven <geert@linux-m68k.org>
+
+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 <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..b756efb
--- /dev/null
@@ -0,0 +1,35 @@
+From a4339b7b686b4acc8b6de2b07d7bacbe3ae44b83 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+Date: Sat, 27 Sep 2014 17:02:26 -0400
+Subject: NFSv4: Fix lock recovery when CREATE_SESSION/SETCLIENTID_CONFIRM fails
+
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+
+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 <trond.myklebust@primarydata.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..6d1b4de
--- /dev/null
@@ -0,0 +1,71 @@
+From df817ba35736db2d62b07de6f050a4db53492ad8 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+Date: Sat, 27 Sep 2014 17:41:51 -0400
+Subject: NFSv4: fix open/lock state recovery error handling
+
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+
+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 <trond.myklebust@primarydata.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..9e58cc3
--- /dev/null
@@ -0,0 +1,91 @@
+From d1f456b0b9545f1606a54cd17c20775f159bd2ce Mon Sep 17 00:00:00 2001
+From: Andy Adamson <andros@netapp.com>
+Date: Mon, 29 Sep 2014 12:31:57 -0400
+Subject: NFSv4.1: Fix an NFSv4.1 state renewal regression
+
+From: Andy Adamson <andros@netapp.com>
+
+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 <andros@netapp.com>
+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 <trond.myklebust@primarydata.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..00937da
--- /dev/null
@@ -0,0 +1,181 @@
+From af958a38a60c7ca3d8a39c918c1baa2ff7b6b233 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sat, 27 Sep 2014 12:31:36 +0200
+Subject: Revert "lzo: properly check for overruns"
+
+From: Willy Tarreau <w@1wt.eu>
+
+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 <willem@lekkertech.net>
+Cc: "Don A. Bailey" <donb@securitymouse.com>
+Signed-off-by: Willy Tarreau <w@1wt.eu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/lzo.h>
+ #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--;
index 68d7a9169fde393e411e4d30794a079abf5d568a..f7f6d36f6adf2948456d5253955d0460fae17029 100644 (file)
@@ -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