+++ /dev/null
-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
-@@ -518,6 +518,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)
- {
-@@ -530,6 +545,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;
-
---- a/fs/cifs/smb2ops.c
-+++ b/fs/cifs/smb2ops.c
-@@ -30,6 +30,7 @@
- #include "smb2glob.h"
- #include "cifs_ioctl.h"
-
-+/* Change credits for different ops and return the total number of credits */
- static int
- change_conf(struct TCP_Server_Info *server)
- {
-@@ -37,17 +38,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;
-@@ -60,14 +59,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);
- *val += add;
-@@ -91,8 +91,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