Commit 7b71843f authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Steve French
Browse files

CIFS: Do not miss cancelled OPEN responses



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: default avatarFrank Sorenson <sorenson@redhat.com>
Reviewed-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 86a7964b
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -1237,12 +1237,6 @@ next_pdu:
		for (i = 0; i < num_mids; i++) {
			if (mids[i] != NULL) {
				mids[i]->resp_buf_size = server->pdu_size;
				if ((mids[i]->mid_flags & MID_WAIT_CANCELLED) &&
				    mids[i]->mid_state == MID_RESPONSE_RECEIVED &&
				    server->ops->handle_cancelled_mid)
					server->ops->handle_cancelled_mid(
							mids[i]->resp_buf,
							server);

				if (!mids[i]->multiRsp || mids[i]->multiEnd)
					mids[i]->callback(mids[i]);
+8 −2
Original line number Diff line number Diff line
@@ -93,8 +93,14 @@ static void _cifs_mid_q_entry_release(struct kref *refcount)
	__u16 smb_cmd = le16_to_cpu(midEntry->command);
	unsigned long now;
	unsigned long roundtrip_time;
	struct TCP_Server_Info *server = midEntry->server;
#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)
@@ -1119,8 +1125,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
				 midQ[i]->mid, le16_to_cpu(midQ[i]->command));
			send_cancel(server, &rqst[i], midQ[i]);
			spin_lock(&GlobalMid_Lock);
			if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
			midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
			if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
				midQ[i]->callback = cifs_cancelled_callback;
				cancelled_mid[i] = true;
				credits[i].value = 0;