]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.20-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 28 Jan 2019 10:13:43 +0000 (11:13 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 28 Jan 2019 10:13:43 +0000 (11:13 +0100)
added patches:
cifs-do-not-reconnect-tcp-session-in-add_credits.patch
cifs-fix-credit-calculation-for-encrypted-reads-with-errors.patch
cifs-fix-credits-calculations-for-reads-with-errors.patch
cifs-fix-possible-hang-during-async-mtu-reads-and-writes.patch
smb3-add-credits-we-receive-from-oplock-break-pdus.patch

queue-4.20/cifs-do-not-reconnect-tcp-session-in-add_credits.patch [new file with mode: 0644]
queue-4.20/cifs-fix-credit-calculation-for-encrypted-reads-with-errors.patch [new file with mode: 0644]
queue-4.20/cifs-fix-credits-calculations-for-reads-with-errors.patch [new file with mode: 0644]
queue-4.20/cifs-fix-possible-hang-during-async-mtu-reads-and-writes.patch [new file with mode: 0644]
queue-4.20/series
queue-4.20/smb3-add-credits-we-receive-from-oplock-break-pdus.patch [new file with mode: 0644]

diff --git a/queue-4.20/cifs-do-not-reconnect-tcp-session-in-add_credits.patch b/queue-4.20/cifs-do-not-reconnect-tcp-session-in-add_credits.patch
new file mode 100644 (file)
index 0000000..3d5b21c
--- /dev/null
@@ -0,0 +1,145 @@
+From ef68e831840c40c7d01b328b3c0f5d8c4796c232 Mon Sep 17 00:00:00 2001
+From: Pavel Shilovsky <pshilov@microsoft.com>
+Date: Fri, 18 Jan 2019 17:25:36 -0800
+Subject: CIFS: Do not reconnect TCP session in add_credits()
+
+From: Pavel Shilovsky <pshilov@microsoft.com>
+
+commit ef68e831840c40c7d01b328b3c0f5d8c4796c232 upstream.
+
+When executing add_credits() we currently call cifs_reconnect()
+if the number of credits is zero and there are no requests in
+flight. In this case we may call cifs_reconnect() recursively
+twice and cause memory corruption given the following sequence
+of functions:
+
+mid1.callback() -> add_credits() -> cifs_reconnect() ->
+-> mid2.callback() -> add_credits() -> cifs_reconnect().
+
+Fix this by avoiding to call cifs_reconnect() in add_credits()
+and checking for zero credits in the demultiplex thread.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
+Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/cifs/connect.c |   21 +++++++++++++++++++++
+ fs/cifs/smb2ops.c |   32 +++++++++++++++++++++++++-------
+ 2 files changed, 46 insertions(+), 7 deletions(-)
+
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -534,6 +534,21 @@ server_unresponsive(struct TCP_Server_In
+       return false;
+ }
++static inline bool
++zero_credits(struct TCP_Server_Info *server)
++{
++      int val;
++
++      spin_lock(&server->req_lock);
++      val = server->credits + server->echo_credits + server->oplock_credits;
++      if (server->in_flight == 0 && val == 0) {
++              spin_unlock(&server->req_lock);
++              return true;
++      }
++      spin_unlock(&server->req_lock);
++      return false;
++}
++
+ static int
+ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
+ {
+@@ -546,6 +561,12 @@ cifs_readv_from_socket(struct TCP_Server
+       for (total_read = 0; msg_data_left(smb_msg); total_read += length) {
+               try_to_freeze();
++              /* reconnect if no credits and no requests in flight */
++              if (zero_credits(server)) {
++                      cifs_reconnect(server);
++                      return -ECONNABORTED;
++              }
++
+               if (server_unresponsive(server))
+                       return -ECONNABORTED;
+               if (cifs_rdma_enabled(server) && server->smbd_conn)
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -34,6 +34,7 @@
+ #include "cifs_ioctl.h"
+ #include "smbdirect.h"
++/* Change credits for different ops and return the total number of credits */
+ static int
+ change_conf(struct TCP_Server_Info *server)
+ {
+@@ -41,17 +42,15 @@ change_conf(struct TCP_Server_Info *serv
+       server->oplock_credits = server->echo_credits = 0;
+       switch (server->credits) {
+       case 0:
+-              return -1;
++              return 0;
+       case 1:
+               server->echoes = false;
+               server->oplocks = false;
+-              cifs_dbg(VFS, "disabling echoes and oplocks\n");
+               break;
+       case 2:
+               server->echoes = true;
+               server->oplocks = false;
+               server->echo_credits = 1;
+-              cifs_dbg(FYI, "disabling oplocks\n");
+               break;
+       default:
+               server->echoes = true;
+@@ -64,14 +63,15 @@ change_conf(struct TCP_Server_Info *serv
+               server->echo_credits = 1;
+       }
+       server->credits -= server->echo_credits + server->oplock_credits;
+-      return 0;
++      return server->credits + server->echo_credits + server->oplock_credits;
+ }
+ static void
+ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
+                const int optype)
+ {
+-      int *val, rc = 0;
++      int *val, rc = -1;
++
+       spin_lock(&server->req_lock);
+       val = server->ops->get_credits_field(server, optype);
+@@ -101,8 +101,26 @@ smb2_add_credits(struct TCP_Server_Info
+       }
+       spin_unlock(&server->req_lock);
+       wake_up(&server->request_q);
+-      if (rc)
+-              cifs_reconnect(server);
++
++      if (server->tcpStatus == CifsNeedReconnect)
++              return;
++
++      switch (rc) {
++      case -1:
++              /* change_conf hasn't been executed */
++              break;
++      case 0:
++              cifs_dbg(VFS, "Possible client or server bug - zero credits\n");
++              break;
++      case 1:
++              cifs_dbg(VFS, "disabling echoes and oplocks\n");
++              break;
++      case 2:
++              cifs_dbg(FYI, "disabling oplocks\n");
++              break;
++      default:
++              cifs_dbg(FYI, "add %u credits total=%d\n", add, rc);
++      }
+ }
+ static void
diff --git a/queue-4.20/cifs-fix-credit-calculation-for-encrypted-reads-with-errors.patch b/queue-4.20/cifs-fix-credit-calculation-for-encrypted-reads-with-errors.patch
new file mode 100644 (file)
index 0000000..dcdc3f4
--- /dev/null
@@ -0,0 +1,65 @@
+From ec678eae746dd25766a61c4095e2b649d3b20b09 Mon Sep 17 00:00:00 2001
+From: Pavel Shilovsky <pshilov@microsoft.com>
+Date: Fri, 18 Jan 2019 15:38:11 -0800
+Subject: CIFS: Fix credit calculation for encrypted reads with errors
+
+From: Pavel Shilovsky <pshilov@microsoft.com>
+
+commit ec678eae746dd25766a61c4095e2b649d3b20b09 upstream.
+
+We do need to account for credits received in error responses
+to read requests on encrypted sessions.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
+Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/cifs/smb2ops.c |   24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -3101,11 +3101,23 @@ handle_read_data(struct TCP_Server_Info
+                       server->ops->is_status_pending(buf, server, 0))
+               return -1;
+-      rdata->result = server->ops->map_error(buf, false);
++      /* set up first two iov to get credits */
++      rdata->iov[0].iov_base = buf;
++      rdata->iov[0].iov_len = 4;
++      rdata->iov[1].iov_base = buf + 4;
++      rdata->iov[1].iov_len =
++              min_t(unsigned int, buf_len, server->vals->read_rsp_size) - 4;
++      cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
++               rdata->iov[0].iov_base, rdata->iov[0].iov_len);
++      cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
++               rdata->iov[1].iov_base, rdata->iov[1].iov_len);
++
++      rdata->result = server->ops->map_error(buf, true);
+       if (rdata->result != 0) {
+               cifs_dbg(FYI, "%s: server returned error %d\n",
+                        __func__, rdata->result);
+-              dequeue_mid(mid, rdata->result);
++              /* normal error on read response */
++              dequeue_mid(mid, false);
+               return 0;
+       }
+@@ -3178,14 +3190,6 @@ handle_read_data(struct TCP_Server_Info
+               return 0;
+       }
+-      /* set up first iov for signature check */
+-      rdata->iov[0].iov_base = buf;
+-      rdata->iov[0].iov_len = 4;
+-      rdata->iov[1].iov_base = buf + 4;
+-      rdata->iov[1].iov_len = server->vals->read_rsp_size - 4;
+-      cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
+-               rdata->iov[0].iov_base, server->vals->read_rsp_size);
+-
+       length = rdata->copy_into_pages(server, rdata, &iter);
+       kfree(bvec);
diff --git a/queue-4.20/cifs-fix-credits-calculations-for-reads-with-errors.patch b/queue-4.20/cifs-fix-credits-calculations-for-reads-with-errors.patch
new file mode 100644 (file)
index 0000000..26567ef
--- /dev/null
@@ -0,0 +1,96 @@
+From 8004c78c68e894e4fd5ac3c22cc22eb7dc24cabc Mon Sep 17 00:00:00 2001
+From: Pavel Shilovsky <pshilov@microsoft.com>
+Date: Thu, 17 Jan 2019 15:29:26 -0800
+Subject: CIFS: Fix credits calculations for reads with errors
+
+From: Pavel Shilovsky <pshilov@microsoft.com>
+
+commit 8004c78c68e894e4fd5ac3c22cc22eb7dc24cabc upstream.
+
+Currently we mark MID as malformed if we get an error from server
+in a read response. This leads to not properly processing credits
+in the readv callback. Fix this by marking such a response as
+normal received response and process it appropriately.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
+Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/cifs/cifssmb.c |   35 +++++++++++++++++++++++------------
+ 1 file changed, 23 insertions(+), 12 deletions(-)
+
+--- a/fs/cifs/cifssmb.c
++++ b/fs/cifs/cifssmb.c
+@@ -1458,18 +1458,26 @@ cifs_discard_remaining_data(struct TCP_S
+ }
+ static int
+-cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
++__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
++                   bool malformed)
+ {
+       int length;
+-      struct cifs_readdata *rdata = mid->callback_data;
+       length = cifs_discard_remaining_data(server);
+-      dequeue_mid(mid, rdata->result);
++      dequeue_mid(mid, malformed);
+       mid->resp_buf = server->smallbuf;
+       server->smallbuf = NULL;
+       return length;
+ }
++static int
++cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
++{
++      struct cifs_readdata *rdata = mid->callback_data;
++
++      return  __cifs_readv_discard(server, mid, rdata->result);
++}
++
+ int
+ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+ {
+@@ -1511,12 +1519,23 @@ cifs_readv_receive(struct TCP_Server_Inf
+               return -1;
+       }
++      /* set up first two iov for signature check and to get credits */
++      rdata->iov[0].iov_base = buf;
++      rdata->iov[0].iov_len = 4;
++      rdata->iov[1].iov_base = buf + 4;
++      rdata->iov[1].iov_len = server->total_read - 4;
++      cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
++               rdata->iov[0].iov_base, rdata->iov[0].iov_len);
++      cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
++               rdata->iov[1].iov_base, rdata->iov[1].iov_len);
++
+       /* Was the SMB read successful? */
+       rdata->result = server->ops->map_error(buf, false);
+       if (rdata->result != 0) {
+               cifs_dbg(FYI, "%s: server returned error %d\n",
+                        __func__, rdata->result);
+-              return cifs_readv_discard(server, mid);
++              /* normal error on read response */
++              return __cifs_readv_discard(server, mid, false);
+       }
+       /* Is there enough to get to the rest of the READ_RSP header? */
+@@ -1560,14 +1579,6 @@ cifs_readv_receive(struct TCP_Server_Inf
+               server->total_read += length;
+       }
+-      /* set up first iov for signature check */
+-      rdata->iov[0].iov_base = buf;
+-      rdata->iov[0].iov_len = 4;
+-      rdata->iov[1].iov_base = buf + 4;
+-      rdata->iov[1].iov_len = server->total_read - 4;
+-      cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
+-               rdata->iov[0].iov_base, server->total_read);
+-
+       /* how much data is in the response? */
+ #ifdef CONFIG_CIFS_SMB_DIRECT
+       use_rdma_mr = rdata->mr;
diff --git a/queue-4.20/cifs-fix-possible-hang-during-async-mtu-reads-and-writes.patch b/queue-4.20/cifs-fix-possible-hang-during-async-mtu-reads-and-writes.patch
new file mode 100644 (file)
index 0000000..280b1e0
--- /dev/null
@@ -0,0 +1,55 @@
+From acc58d0bab55a50e02c25f00bd6a210ee121595f Mon Sep 17 00:00:00 2001
+From: Pavel Shilovsky <pshilov@microsoft.com>
+Date: Thu, 17 Jan 2019 08:21:24 -0800
+Subject: CIFS: Fix possible hang during async MTU reads and writes
+
+From: Pavel Shilovsky <pshilov@microsoft.com>
+
+commit acc58d0bab55a50e02c25f00bd6a210ee121595f upstream.
+
+When doing MTU i/o we need to leave some credits for
+possible reopen requests and other operations happening
+in parallel. Currently we leave 1 credit which is not
+enough even for reopen only: we need at least 2 credits
+if durable handle reconnect fails. Also there may be
+other operations at the same time including compounding
+ones which require 3 credits at a time each. Fix this
+by leaving 8 credits which is big enough to cover most
+scenarios.
+
+Was able to reproduce this when server was configured
+to give out fewer credits than usual.
+
+The proper fix would be to reconnect a file handle first
+and then obtain credits for an MTU request but this leads
+to bigger code changes and should happen in other patches.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/cifs/smb2ops.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -165,14 +165,14 @@ smb2_wait_mtu_credits(struct TCP_Server_
+                       scredits = server->credits;
+                       /* can deadlock with reopen */
+-                      if (scredits == 1) {
++                      if (scredits <= 8) {
+                               *num = SMB2_MAX_BUFFER_SIZE;
+                               *credits = 0;
+                               break;
+                       }
+-                      /* leave one credit for a possible reopen */
+-                      scredits--;
++                      /* leave some credits for reopen and other ops */
++                      scredits -= 8;
+                       *num = min_t(unsigned int, size,
+                                    scredits * SMB2_MAX_BUFFER_SIZE);
index 8d532ef073cc7ee20791b181608b5107c6e73761..db29ed94eb357df53aab1ab37310b4eca64ee66e 100644 (file)
@@ -58,3 +58,8 @@ tty-n_hdlc-fix-__might_sleep-warning.patch
 hv_balloon-avoid-touching-uninitialized-struct-page-during-tail-onlining.patch
 drivers-hv-vmbus-check-for-ring-when-getting-debug-info.patch
 vgacon-unconfuse-vc_origin-when-using-soft-scrollback.patch
+cifs-fix-possible-hang-during-async-mtu-reads-and-writes.patch
+cifs-fix-credits-calculations-for-reads-with-errors.patch
+cifs-fix-credit-calculation-for-encrypted-reads-with-errors.patch
+cifs-do-not-reconnect-tcp-session-in-add_credits.patch
+smb3-add-credits-we-receive-from-oplock-break-pdus.patch
diff --git a/queue-4.20/smb3-add-credits-we-receive-from-oplock-break-pdus.patch b/queue-4.20/smb3-add-credits-we-receive-from-oplock-break-pdus.patch
new file mode 100644 (file)
index 0000000..4ee3b6c
--- /dev/null
@@ -0,0 +1,38 @@
+From 2e5700bdde438ed708b36d8acd0398dc73cbf759 Mon Sep 17 00:00:00 2001
+From: Ronnie Sahlberg <lsahlber@redhat.com>
+Date: Wed, 23 Jan 2019 16:20:38 +1000
+Subject: smb3: add credits we receive from oplock/break PDUs
+
+From: Ronnie Sahlberg <lsahlber@redhat.com>
+
+commit 2e5700bdde438ed708b36d8acd0398dc73cbf759 upstream.
+
+Otherwise we gradually leak credits leading to potential
+hung session.
+
+Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
+CC: Stable <stable@vger.kernel.org>
+Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/cifs/smb2misc.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/fs/cifs/smb2misc.c
++++ b/fs/cifs/smb2misc.c
+@@ -648,6 +648,13 @@ smb2_is_valid_oplock_break(char *buffer,
+       if (rsp->sync_hdr.Command != SMB2_OPLOCK_BREAK)
+               return false;
++      if (rsp->sync_hdr.CreditRequest) {
++              spin_lock(&server->req_lock);
++              server->credits += le16_to_cpu(rsp->sync_hdr.CreditRequest);
++              spin_unlock(&server->req_lock);
++              wake_up(&server->request_q);
++      }
++
+       if (rsp->StructureSize !=
+                               smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
+               if (le16_to_cpu(rsp->StructureSize) == 44)