From: Greg Kroah-Hartman Date: Mon, 28 Jan 2019 10:13:43 +0000 (+0100) Subject: 4.20-stable patches X-Git-Tag: v4.9.154~49 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2f706f180b68b9704eb79589b708b53e90bb325c;p=thirdparty%2Fkernel%2Fstable-queue.git 4.20-stable patches 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 --- 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 index 00000000000..3d5b21c7c14 --- /dev/null +++ b/queue-4.20/cifs-do-not-reconnect-tcp-session-in-add_credits.patch @@ -0,0 +1,145 @@ +From ef68e831840c40c7d01b328b3c0f5d8c4796c232 Mon Sep 17 00:00:00 2001 +From: Pavel Shilovsky +Date: Fri, 18 Jan 2019 17:25:36 -0800 +Subject: CIFS: Do not reconnect TCP session in add_credits() + +From: Pavel Shilovsky + +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: +Signed-off-by: Pavel Shilovsky +Reviewed-by: Ronnie Sahlberg +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..dcdc3f429ed --- /dev/null +++ b/queue-4.20/cifs-fix-credit-calculation-for-encrypted-reads-with-errors.patch @@ -0,0 +1,65 @@ +From ec678eae746dd25766a61c4095e2b649d3b20b09 Mon Sep 17 00:00:00 2001 +From: Pavel Shilovsky +Date: Fri, 18 Jan 2019 15:38:11 -0800 +Subject: CIFS: Fix credit calculation for encrypted reads with errors + +From: Pavel Shilovsky + +commit ec678eae746dd25766a61c4095e2b649d3b20b09 upstream. + +We do need to account for credits received in error responses +to read requests on encrypted sessions. + +Cc: +Signed-off-by: Pavel Shilovsky +Reviewed-by: Ronnie Sahlberg +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..26567effc6f --- /dev/null +++ b/queue-4.20/cifs-fix-credits-calculations-for-reads-with-errors.patch @@ -0,0 +1,96 @@ +From 8004c78c68e894e4fd5ac3c22cc22eb7dc24cabc Mon Sep 17 00:00:00 2001 +From: Pavel Shilovsky +Date: Thu, 17 Jan 2019 15:29:26 -0800 +Subject: CIFS: Fix credits calculations for reads with errors + +From: Pavel Shilovsky + +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: +Signed-off-by: Pavel Shilovsky +Reviewed-by: Ronnie Sahlberg +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..280b1e0c3cd --- /dev/null +++ b/queue-4.20/cifs-fix-possible-hang-during-async-mtu-reads-and-writes.patch @@ -0,0 +1,55 @@ +From acc58d0bab55a50e02c25f00bd6a210ee121595f Mon Sep 17 00:00:00 2001 +From: Pavel Shilovsky +Date: Thu, 17 Jan 2019 08:21:24 -0800 +Subject: CIFS: Fix possible hang during async MTU reads and writes + +From: Pavel Shilovsky + +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: +Signed-off-by: Pavel Shilovsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + diff --git a/queue-4.20/series b/queue-4.20/series index 8d532ef073c..db29ed94eb3 100644 --- a/queue-4.20/series +++ b/queue-4.20/series @@ -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 index 00000000000..4ee3b6cb84e --- /dev/null +++ b/queue-4.20/smb3-add-credits-we-receive-from-oplock-break-pdus.patch @@ -0,0 +1,38 @@ +From 2e5700bdde438ed708b36d8acd0398dc73cbf759 Mon Sep 17 00:00:00 2001 +From: Ronnie Sahlberg +Date: Wed, 23 Jan 2019 16:20:38 +1000 +Subject: smb3: add credits we receive from oplock/break PDUs + +From: Ronnie Sahlberg + +commit 2e5700bdde438ed708b36d8acd0398dc73cbf759 upstream. + +Otherwise we gradually leak credits leading to potential +hung session. + +Signed-off-by: Ronnie Sahlberg +CC: Stable +Reviewed-by: Pavel Shilovsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + 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)