lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250811140738.1141817-3-wangzhaolong@huaweicloud.com>
Date: Mon, 11 Aug 2025 22:07:38 +0800
From: Wang Zhaolong <wangzhaolong@...weicloud.com>
To: sfrench@...ba.org,
	pshilov@...rosoft.com
Cc: linux-cifs@...r.kernel.org,
	samba-technical@...ts.samba.org,
	linux-kernel@...r.kernel.org,
	chengzhihao1@...wei.com,
	yi.zhang@...wei.com,
	yangerkun@...wei.com
Subject: [PATCH V3 2/2] smb: client: Clean up mid_queue_lock usage and standardize mid_state access

This patch cleans up unnecessary mid_queue_lock usage in several places
where the lock is not actually needed. Many functions were holding
mid_queue_lock to protect mid state updates on mids that are no longer
in the queue, such as in smb2_decrypt_offload() and various callback
functions.

This patch also standardizes mid_state access using READ_ONCE/WRITE_ONCE
throughout the codebase to ensure consistent memory access patterns and
prevent compiler optimizations that could cause issues.

The core insight is that mid_state synchronization doesn't require the
same lock as queue structure protection. Separating these concerns makes
the locking model clearer and reduces unnecessary lock contention.

Signed-off-by: Wang Zhaolong <wangzhaolong@...weicloud.com>
---
 fs/smb/client/cifssmb.c       |  8 +++---
 fs/smb/client/cifstransport.c | 50 ++++++++++++++++++++++++++---------
 fs/smb/client/connect.c       | 17 ++++++------
 fs/smb/client/smb1ops.c       |  5 ++--
 fs/smb/client/smb2ops.c       | 22 +++++++--------
 fs/smb/client/smb2pdu.c       | 10 ++++---
 fs/smb/client/smb2transport.c |  2 +-
 fs/smb/client/transport.c     | 43 +++++++++++++++++-------------
 8 files changed, 95 insertions(+), 62 deletions(-)

diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index d20766f664c4..1da3436a52cb 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -1309,16 +1309,17 @@ cifs_readv_callback(struct mid_q_entry *mid)
 		.value = 1,
 		.instance = 0,
 		.rreq_debug_id = rdata->rreq->debug_id,
 		.rreq_debug_index = rdata->subreq.debug_index,
 	};
+	int mid_state = READ_ONCE(mid->mid_state);
 
 	cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n",
-		 __func__, mid->mid, mid->mid_state, rdata->result,
+		 __func__, mid->mid, mid_state, rdata->result,
 		 rdata->subreq.len);
 
-	switch (mid->mid_state) {
+	switch (mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		/* result already set, check signature */
 		if (server->sign) {
 			int rc = 0;
 
@@ -1694,12 +1695,13 @@ cifs_writev_callback(struct mid_q_entry *mid)
 		.rreq_debug_id = wdata->rreq->debug_id,
 		.rreq_debug_index = wdata->subreq.debug_index,
 	};
 	ssize_t result;
 	size_t written;
+	int mid_state = READ_ONCE(mid->mid_state);
 
-	switch (mid->mid_state) {
+	switch (mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		result = cifs_check_receive(mid, tcon->ses->server, 0);
 		if (result != 0)
 			break;
 
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index e98b95eff8c9..c69aff70c7a4 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -64,11 +64,11 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 	temp->creator = current;
 	temp->callback = cifs_wake_up_task;
 	temp->callback_data = current;
 
 	atomic_inc(&mid_count);
-	temp->mid_state = MID_REQUEST_ALLOCATED;
+	WRITE_ONCE(temp->mid_state, MID_REQUEST_ALLOCATED);
 	return temp;
 }
 
 int
 smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
@@ -328,11 +328,11 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	if (rc) {
 		cifs_server_unlock(server);
 		goto out;
 	}
 
-	midQ->mid_state = MID_REQUEST_SUBMITTED;
+	WRITE_ONCE(midQ->mid_state, MID_REQUEST_SUBMITTED);
 
 	rc = smb_send(server, in_buf, len);
 	cifs_save_when_sent(midQ);
 
 	if (rc < 0)
@@ -362,11 +362,11 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 		add_credits(server, &credits, 0);
 		return rc;
 	}
 
 	if (!midQ->resp_buf || !out_buf ||
-	    midQ->mid_state != MID_RESPONSE_READY) {
+	    READ_ONCE(midQ->mid_state) != MID_RESPONSE_READY) {
 		rc = -EIO;
 		cifs_server_dbg(VFS, "Bad MID state?\n");
 		goto out;
 	}
 
@@ -403,10 +403,40 @@ send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
 
 	return SendReceive(xid, ses, in_buf, out_buf,
 			&bytes_returned, 0);
 }
 
+static inline bool cifs_blocking_lock_should_exit(struct mid_q_entry *midQ,
+					struct TCP_Server_Info *server)
+{
+	int mid_state = READ_ONCE(midQ->mid_state);
+	int tcp_status = READ_ONCE(server->tcpStatus);
+
+	if (mid_state != MID_REQUEST_SUBMITTED &&
+		mid_state != MID_RESPONSE_RECEIVED)
+		return true;
+
+	if (tcp_status != CifsGood && tcp_status != CifsNew)
+		return true;
+
+	return false;
+}
+
+static inline bool cifs_blocking_lock_can_cancel(struct mid_q_entry *midQ,
+					struct TCP_Server_Info *server)
+{
+	int mid_state = READ_ONCE(midQ->mid_state);
+	int tcp_status = READ_ONCE(server->tcpStatus);
+	/* Can only cancel if still pending */
+	bool still_pending = (mid_state == MID_REQUEST_SUBMITTED ||
+			mid_state == MID_RESPONSE_RECEIVED);
+	/* Can only cancel if server connection is good */
+	bool server_good = (tcp_status == CifsGood || tcp_status == CifsNew);
+
+	return still_pending && server_good;
+}
+
 int
 SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
 	    int *pbytes_returned)
 {
@@ -470,11 +500,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 		delete_mid(midQ);
 		cifs_server_unlock(server);
 		return rc;
 	}
 
-	midQ->mid_state = MID_REQUEST_SUBMITTED;
+	WRITE_ONCE(midQ->mid_state, MID_REQUEST_SUBMITTED);
 	rc = smb_send(server, in_buf, len);
 	cifs_save_when_sent(midQ);
 
 	if (rc < 0)
 		server->sequence_number -= 2;
@@ -486,22 +516,16 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 		return rc;
 	}
 
 	/* Wait for a reply - allow signals to interrupt. */
 	rc = wait_event_interruptible(server->response_q,
-		(!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
-		   midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
-		((server->tcpStatus != CifsGood) &&
-		 (server->tcpStatus != CifsNew)));
+		cifs_blocking_lock_should_exit(midQ, server));
 
 	/* Were we interrupted by a signal ? */
 	spin_lock(&server->srv_lock);
 	if ((rc == -ERESTARTSYS) &&
-		(midQ->mid_state == MID_REQUEST_SUBMITTED ||
-		 midQ->mid_state == MID_RESPONSE_RECEIVED) &&
-		((server->tcpStatus == CifsGood) ||
-		 (server->tcpStatus == CifsNew))) {
+	     cifs_blocking_lock_can_cancel(midQ, server)) {
 		spin_unlock(&server->srv_lock);
 
 		if (in_buf->Command == SMB_COM_TRANSACTION2) {
 			/* POSIX lock. We send a NT_CANCEL SMB to cause the
 			   blocking lock to return. */
@@ -546,11 +570,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	rc = cifs_sync_mid_result(midQ, server);
 	if (rc != 0)
 		return rc;
 
 	/* rcvd frame is ok */
-	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
+	if (out_buf == NULL || READ_ONCE(midQ->mid_state) != MID_RESPONSE_READY) {
 		rc = -EIO;
 		cifs_tcon_dbg(VFS, "Bad MID state?\n");
 		goto out;
 	}
 
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 281ccbeea719..4cbaf8fe3ccf 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -322,12 +322,12 @@ cifs_abort_connection(struct TCP_Server_Info *server)
 	INIT_LIST_HEAD(&retry_list);
 	cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
 	spin_lock(&server->mid_queue_lock);
 	list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) {
 		kref_get(&mid->refcount);
-		if (mid->mid_state == MID_REQUEST_SUBMITTED)
-			mid->mid_state = MID_RETRY_NEEDED;
+		if (READ_ONCE(mid->mid_state) == MID_REQUEST_SUBMITTED)
+			WRITE_ONCE(mid->mid_state, MID_RETRY_NEEDED);
 		list_move(&mid->qhead, &retry_list);
 		mid->deleted_from_q = true;
 	}
 	spin_unlock(&server->mid_queue_lock);
 	cifs_server_unlock(server);
@@ -916,11 +916,11 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 			 * return code should be read from mid_rc member.
 			 */
 			list_for_each_entry_safe(mid, nmid, &dispose_list, qhead) {
 				list_del_init(&mid->qhead);
 				mid->mid_rc = mid_rc;
-				mid->mid_state = MID_RC;
+				WRITE_ONCE(mid->mid_state, MID_RC);
 				mid_execute_callback(mid);
 				release_mid(mid);
 			}
 
 			/*
@@ -955,19 +955,18 @@ void
 dequeue_mid(struct mid_q_entry *mid, bool malformed)
 {
 #ifdef CONFIG_CIFS_STATS2
 	mid->when_received = jiffies;
 #endif
-	spin_lock(&mid->server->mid_queue_lock);
-	if (!malformed)
-		mid->mid_state = MID_RESPONSE_RECEIVED;
-	else
-		mid->mid_state = MID_RESPONSE_MALFORMED;
+	WRITE_ONCE(mid->mid_state, malformed ? MID_RESPONSE_MALFORMED :
+		   MID_RESPONSE_RECEIVED);
 	/*
 	 * Trying to handle/dequeue a mid after the send_recv()
 	 * function has finished processing it is a bug.
 	 */
+
+	spin_lock(&mid->server->mid_queue_lock);
 	if (mid->deleted_from_q == true) {
 		spin_unlock(&mid->server->mid_queue_lock);
 		pr_warn_once("trying to dequeue a deleted mid\n");
 	} else {
 		list_del_init(&mid->qhead);
@@ -1104,11 +1103,11 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
 		spin_lock(&server->mid_queue_lock);
 		list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
 			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
 			cifs_dbg(FYI, "Clearing mid %llu\n", mid_entry->mid);
 			kref_get(&mid_entry->refcount);
-			mid_entry->mid_state = MID_SHUTDOWN;
+			WRITE_ONCE(mid_entry->mid_state, MID_SHUTDOWN);
 			list_move(&mid_entry->qhead, &dispose_list);
 			mid_entry->deleted_from_q = true;
 		}
 		spin_unlock(&server->mid_queue_lock);
 
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index 893a1ea8c000..5ef007a0bad0 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -96,11 +96,11 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
 	struct mid_q_entry *mid;
 
 	spin_lock(&server->mid_queue_lock);
 	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
 		if (compare_mid(mid->mid, buf) &&
-		    mid->mid_state == MID_REQUEST_SUBMITTED &&
+		    READ_ONCE(mid->mid_state) == MID_REQUEST_SUBMITTED &&
 		    le16_to_cpu(mid->command) == buf->Command) {
 			kref_get(&mid->refcount);
 			spin_unlock(&server->mid_queue_lock);
 			return mid;
 		}
@@ -199,11 +199,12 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
 		num_mids = 0;
 		spin_lock(&server->mid_queue_lock);
 		list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
 			++num_mids;
 			if (mid_entry->mid == cur_mid &&
-			    mid_entry->mid_state == MID_REQUEST_SUBMITTED) {
+			    READ_ONCE(mid_entry->mid_state) ==
+				      MID_REQUEST_SUBMITTED) {
 				/* This mid is in use, try a different one */
 				collision = true;
 				break;
 			}
 		}
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index f7a0f1c81b43..0938a33a7856 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -402,11 +402,11 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
 	}
 
 	spin_lock(&server->mid_queue_lock);
 	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
 		if ((mid->mid == wire_mid) &&
-		    (mid->mid_state == MID_REQUEST_SUBMITTED) &&
+		    (READ_ONCE(mid->mid_state) == MID_REQUEST_SUBMITTED) &&
 		    (mid->command == shdr->Command)) {
 			kref_get(&mid->refcount);
 			if (dequeue) {
 				list_del_init(&mid->qhead);
 				mid->deleted_from_q = true;
@@ -4661,11 +4661,11 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 	if (rdata->result != 0) {
 		cifs_dbg(FYI, "%s: server returned error %d\n",
 			 __func__, rdata->result);
 		/* normal error on read response */
 		if (is_offloaded)
-			mid->mid_state = MID_RESPONSE_RECEIVED;
+			WRITE_ONCE(mid->mid_state, MID_RESPONSE_RECEIVED);
 		else
 			dequeue_mid(mid, false);
 		return 0;
 	}
 
@@ -4688,11 +4688,11 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 		/* data_offset is beyond the end of smallbuf */
 		cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
 			 __func__, data_offset);
 		rdata->result = -EIO;
 		if (is_offloaded)
-			mid->mid_state = MID_RESPONSE_MALFORMED;
+			WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED);
 		else
 			dequeue_mid(mid, rdata->result);
 		return 0;
 	}
 
@@ -4707,32 +4707,32 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 			/* data offset is beyond the 1st page of response */
 			cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
 				 __func__, data_offset);
 			rdata->result = -EIO;
 			if (is_offloaded)
-				mid->mid_state = MID_RESPONSE_MALFORMED;
+				WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED);
 			else
 				dequeue_mid(mid, rdata->result);
 			return 0;
 		}
 
 		if (data_len > buffer_len - pad_len) {
 			/* data_len is corrupt -- discard frame */
 			rdata->result = -EIO;
 			if (is_offloaded)
-				mid->mid_state = MID_RESPONSE_MALFORMED;
+				WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED);
 			else
 				dequeue_mid(mid, rdata->result);
 			return 0;
 		}
 
 		/* Copy the data to the output I/O iterator. */
 		rdata->result = cifs_copy_folioq_to_iter(buffer, buffer_len,
 							 cur_off, &rdata->subreq.io_iter);
 		if (rdata->result != 0) {
 			if (is_offloaded)
-				mid->mid_state = MID_RESPONSE_MALFORMED;
+				WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED);
 			else
 				dequeue_mid(mid, rdata->result);
 			return 0;
 		}
 		rdata->got_bytes = buffer_len;
@@ -4747,18 +4747,18 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 	} else {
 		/* read response payload cannot be in both buf and pages */
 		WARN_ONCE(1, "buf can not contain only a part of read data");
 		rdata->result = -EIO;
 		if (is_offloaded)
-			mid->mid_state = MID_RESPONSE_MALFORMED;
+			WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED);
 		else
 			dequeue_mid(mid, rdata->result);
 		return 0;
 	}
 
 	if (is_offloaded)
-		mid->mid_state = MID_RESPONSE_RECEIVED;
+		WRITE_ONCE(mid->mid_state, MID_RESPONSE_RECEIVED);
 	else
 		dequeue_mid(mid, false);
 	return 0;
 }
 
@@ -4807,18 +4807,16 @@ static void smb2_decrypt_offload(struct work_struct *work)
 
 			mid_execute_callback(mid);
 		} else {
 			spin_lock(&dw->server->srv_lock);
 			if (dw->server->tcpStatus == CifsNeedReconnect) {
-				spin_lock(&dw->server->mid_queue_lock);
-				mid->mid_state = MID_RETRY_NEEDED;
-				spin_unlock(&dw->server->mid_queue_lock);
 				spin_unlock(&dw->server->srv_lock);
+				WRITE_ONCE(mid->mid_state, MID_RETRY_NEEDED);
 				mid_execute_callback(mid);
 			} else {
 				spin_lock(&dw->server->mid_queue_lock);
-				mid->mid_state = MID_REQUEST_SUBMITTED;
+				WRITE_ONCE(mid->mid_state, MID_REQUEST_SUBMITTED);
 				mid->deleted_from_q = false;
 				list_add_tail(&mid->qhead,
 					&dw->server->pending_mid_q);
 				spin_unlock(&dw->server->mid_queue_lock);
 				spin_unlock(&dw->server->srv_lock);
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 2df93a75e3b8..a9aab1207ee4 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -4092,13 +4092,14 @@ static void
 smb2_echo_callback(struct mid_q_entry *mid)
 {
 	struct TCP_Server_Info *server = mid->callback_data;
 	struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf;
 	struct cifs_credits credits = { .value = 0, .instance = 0 };
+	int mid_state = READ_ONCE(mid->mid_state);
 
-	if (mid->mid_state == MID_RESPONSE_RECEIVED
-	    || mid->mid_state == MID_RESPONSE_MALFORMED) {
+	if (mid_state == MID_RESPONSE_RECEIVED
+	    || mid_state == MID_RESPONSE_MALFORMED) {
 		credits.value = le16_to_cpu(rsp->hdr.CreditRequest);
 		credits.instance = server->reconnect_instance;
 	}
 
 	release_mid(mid);
@@ -4531,24 +4532,25 @@ smb2_readv_callback(struct mid_q_entry *mid)
 		.rreq_debug_index = rdata->subreq.debug_index,
 	};
 	struct smb_rqst rqst = { .rq_iov = &rdata->iov[1], .rq_nvec = 1 };
 	unsigned int rreq_debug_id = rdata->rreq->debug_id;
 	unsigned int subreq_debug_index = rdata->subreq.debug_index;
+	int mid_state = READ_ONCE(mid->mid_state);
 
 	if (rdata->got_bytes) {
 		rqst.rq_iter	  = rdata->subreq.io_iter;
 	}
 
 	WARN_ONCE(rdata->server != mid->server,
 		  "rdata server %p != mid server %p",
 		  rdata->server, mid->server);
 
 	cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu/%zu\n",
-		 __func__, mid->mid, mid->mid_state, rdata->result,
+		 __func__, mid->mid, mid_state, rdata->result,
 		 rdata->got_bytes, rdata->subreq.len - rdata->subreq.transferred);
 
-	switch (mid->mid_state) {
+	switch (mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		credits.value = le16_to_cpu(shdr->CreditRequest);
 		credits.instance = server->reconnect_instance;
 		/* result already set, check signature */
 		if (server->sign && !mid->decrypted) {
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index bc0e92eb2b64..7c4108f1a28b 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -787,11 +787,11 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr,
 	temp->creator = current;
 	temp->callback = cifs_wake_up_task;
 	temp->callback_data = current;
 
 	atomic_inc(&mid_count);
-	temp->mid_state = MID_REQUEST_ALLOCATED;
+	WRITE_ONCE(temp->mid_state, MID_REQUEST_ALLOCATED);
 	trace_smb3_cmd_enter(le32_to_cpu(shdr->Id.SyncId.TreeId),
 			     le64_to_cpu(shdr->SessionId),
 			     le16_to_cpu(shdr->Command), temp->mid);
 	return temp;
 }
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index a61ba7f3fb86..28b5b7011017 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -31,12 +31,12 @@
 #include "compress.h"
 
 void
 cifs_wake_up_task(struct mid_q_entry *mid)
 {
-	if (mid->mid_state == MID_RESPONSE_RECEIVED)
-		mid->mid_state = MID_RESPONSE_READY;
+	if (READ_ONCE(mid->mid_state) == MID_RESPONSE_RECEIVED)
+		WRITE_ONCE(mid->mid_state, MID_RESPONSE_READY);
 	wake_up_process(mid->callback_data);
 }
 
 void __release_mid(struct kref *refcount)
 {
@@ -47,18 +47,19 @@ void __release_mid(struct kref *refcount)
 	__u16 smb_cmd = le16_to_cpu(midEntry->command);
 	unsigned long now;
 	unsigned long roundtrip_time;
 #endif
 	struct TCP_Server_Info *server = midEntry->server;
+	int mid_state = READ_ONCE(midEntry->mid_state);
 
 	if (midEntry->resp_buf && (midEntry->wait_cancelled) &&
-	    (midEntry->mid_state == MID_RESPONSE_RECEIVED ||
-	     midEntry->mid_state == MID_RESPONSE_READY) &&
+	    (mid_state == MID_RESPONSE_RECEIVED ||
+	     mid_state == MID_RESPONSE_READY) &&
 	    server->ops->handle_cancelled_mid)
 		server->ops->handle_cancelled_mid(midEntry, server);
 
-	midEntry->mid_state = MID_FREE;
+	WRITE_ONCE(midEntry->mid_state, MID_FREE);
 	atomic_dec(&mid_count);
 	if (midEntry->large_buf)
 		cifs_buf_release(midEntry->resp_buf);
 	else
 		cifs_small_buf_release(midEntry->resp_buf);
@@ -631,17 +632,24 @@ cifs_wait_mtu_credits(struct TCP_Server_Info *server, size_t size,
 	credits->value = 0;
 	credits->instance = server->reconnect_instance;
 	return 0;
 }
 
+static inline bool cifs_mid_response_ready(struct mid_q_entry *mid)
+{
+	int mid_state = READ_ONCE(mid->mid_state);
+
+	return (mid_state != MID_REQUEST_SUBMITTED &&
+		mid_state != MID_RESPONSE_RECEIVED);
+}
+
 int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
 {
 	int error;
 
 	error = wait_event_state(server->response_q,
-				 midQ->mid_state != MID_REQUEST_SUBMITTED &&
-				 midQ->mid_state != MID_RESPONSE_RECEIVED,
+				 cifs_mid_response_ready(midQ),
 				 (TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
 	if (error < 0)
 		return -ERESTARTSYS;
 
 	return 0;
@@ -696,11 +704,11 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 
 	mid->receive = receive;
 	mid->callback = callback;
 	mid->callback_data = cbdata;
 	mid->handle = handle;
-	mid->mid_state = MID_REQUEST_SUBMITTED;
+	WRITE_ONCE(mid->mid_state, MID_REQUEST_SUBMITTED);
 
 	/* put it on the pending_mid_q */
 	spin_lock(&server->mid_queue_lock);
 	list_add_tail(&mid->qhead, &server->pending_mid_q);
 	spin_unlock(&server->mid_queue_lock);
@@ -728,18 +736,17 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 }
 
 int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 {
 	int rc = 0;
+	int state = READ_ONCE(mid->mid_state);
 
 	cifs_dbg(FYI, "%s: cmd=%d mid=%llu state=%d\n",
-		 __func__, le16_to_cpu(mid->command), mid->mid, mid->mid_state);
+		 __func__, le16_to_cpu(mid->command), mid->mid, state);
 
-	spin_lock(&server->mid_queue_lock);
-	switch (mid->mid_state) {
+	switch (state) {
 	case MID_RESPONSE_READY:
-		spin_unlock(&server->mid_queue_lock);
 		return rc;
 	case MID_RETRY_NEEDED:
 		rc = -EAGAIN;
 		break;
 	case MID_RESPONSE_MALFORMED:
@@ -750,21 +757,21 @@ int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server
 		break;
 	case MID_RC:
 		rc = mid->mid_rc;
 		break;
 	default:
+		spin_lock(&server->mid_queue_lock);
 		if (mid->deleted_from_q == false) {
 			list_del_init(&mid->qhead);
 			mid->deleted_from_q = true;
 		}
 		spin_unlock(&server->mid_queue_lock);
 		cifs_server_dbg(VFS, "%s: invalid mid state mid=%llu state=%d\n",
-			 __func__, mid->mid, mid->mid_state);
+			 __func__, mid->mid, state);
 		rc = -EIO;
 		goto sync_mid_done;
 	}
-	spin_unlock(&server->mid_queue_lock);
 
 sync_mid_done:
 	release_mid(mid);
 	return rc;
 }
@@ -778,12 +785,12 @@ cifs_compound_callback(struct mid_q_entry *mid)
 		.instance = server->reconnect_instance,
 	};
 
 	add_credits(server, &credits, mid->optype);
 
-	if (mid->mid_state == MID_RESPONSE_RECEIVED)
-		mid->mid_state = MID_RESPONSE_READY;
+	if (READ_ONCE(mid->mid_state) == MID_RESPONSE_RECEIVED)
+		WRITE_ONCE(mid->mid_state, MID_RESPONSE_READY);
 }
 
 static void
 cifs_compound_last_callback(struct mid_q_entry *mid)
 {
@@ -936,11 +943,11 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 			for (j = 0; j < num_rqst; j++)
 				add_credits(server, &credits[j], optype);
 			return PTR_ERR(midQ[i]);
 		}
 
-		midQ[i]->mid_state = MID_REQUEST_SUBMITTED;
+		WRITE_ONCE(midQ[i]->mid_state, MID_REQUEST_SUBMITTED);
 		midQ[i]->optype = optype;
 		/*
 		 * Invoke callback for every part of the compound chain
 		 * to calculate credits properly. Wake up this thread only when
 		 * the last element is received.
@@ -1026,11 +1033,11 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 			cancelled_mid[i] = true;
 			goto out;
 		}
 
 		if (!midQ[i]->resp_buf ||
-		    midQ[i]->mid_state != MID_RESPONSE_READY) {
+		    READ_ONCE(midQ[i]->mid_state) != MID_RESPONSE_READY) {
 			rc = -EIO;
 			cifs_dbg(FYI, "Bad MID state?\n");
 			goto out;
 		}
 
-- 
2.39.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ