diff mbox series

[2/3] CIFS: Do not miss cancelled OPEN responses

Message ID 20210311181857.10268-3-tim.gardner@canonical.com
State New
Headers show
Series [1/3] CIFS: Close open handle after interrupted close | expand

Commit Message

Tim Gardner March 11, 2021, 6:18 p.m. UTC
From: Pavel Shilovsky <pshilov@microsoft.com>

BugLink: https://bugs.launchpad.net/bugs/1918714

When an OPEN command is cancelled we mark a mid as
cancelled and let the demultiplex thread process it
by closing an open handle. The problem is there is
a race between a system call thread and the demultiplex
thread and there may be a situation when the mid has
been already processed before it is set as cancelled.

Fix this by processing cancelled requests when mids
are being destroyed which means that there is only
one thread referencing a particular mid. Also set
mids as cancelled unconditionally on their state.

Cc: Stable <stable@vger.kernel.org>
Tested-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
(backported from commit 7b71843fa7028475b052107664cbe120156a2cfc)
[ fs/cifs/transport.c has changed significantly, I pieced in the
intended changes to the old function DeleteMidQEntry() ]
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
---
 fs/cifs/connect.c   | 7 -------
 fs/cifs/transport.c | 9 ++++++++-
 2 files changed, 8 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c96b9d60f625..7f8a65d325b8 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -996,13 +996,6 @@  cifs_demultiplex_thread(void *p)
 
 		server->lstrp = jiffies;
 		if (mid_entry != NULL) {
-			if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) &&
-			     mid_entry->mid_state == MID_RESPONSE_RECEIVED &&
-					server->ops->handle_cancelled_mid)
-				server->ops->handle_cancelled_mid(
-							mid_entry->resp_buf,
-							server);
-
 			if (!mid_entry->multiRsp || mid_entry->multiEnd)
 				mid_entry->callback(mid_entry);
 
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 22d421054303..143b2de71dec 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -100,6 +100,13 @@  DeleteMidQEntry(struct mid_q_entry *midEntry)
 	__le16 command = midEntry->server->vals->lock_cmd;
 	unsigned long now;
 #endif
+	struct TCP_Server_Info *server = midEntry->server;
+
+	if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
+	    midEntry->mid_state == MID_RESPONSE_RECEIVED &&
+	    server->ops->handle_cancelled_mid)
+		server->ops->handle_cancelled_mid(midEntry->resp_buf, server);
+
 	midEntry->mid_state = MID_FREE;
 	atomic_dec(&midCount);
 	if (midEntry->large_buf)
@@ -768,8 +775,8 @@  cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
 		cifs_dbg(FYI, "Cancelling wait for mid %llu\n",	midQ->mid);
 		send_cancel(ses->server, rqst, midQ);
 		spin_lock(&GlobalMid_Lock);
+        midQ->mid_flags |= MID_WAIT_CANCELLED;
 		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
-			midQ->mid_flags |= MID_WAIT_CANCELLED;
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
 			add_credits(ses->server, 1, optype);