Commit 3fd8ec2f authored by Wang Zhaolong's avatar Wang Zhaolong Committed by Steve French
Browse files

smb: client: smb: client: eliminate mid_flags field



This is step 3/4 of a patch series to fix mid_q_entry memory leaks
caused by race conditions in callback execution.

Replace the mid_flags bitmask with dedicated boolean fields to
simplify locking logic and improve code readability:

- Replace MID_DELETED with bool deleted_from_q
- Replace MID_WAIT_CANCELLED with bool wait_cancelled
- Remove mid_flags field entirely

The new boolean fields have clearer semantics:
- deleted_from_q: whether mid has been removed from pending_mid_q
- wait_cancelled: whether request was cancelled during wait

This change reduces memory usage (from 4-byte bitmask to 2 boolean
flags) and eliminates confusion about which lock protects which
flag bits, preparing for per-mid locking in the next patch.

Signed-off-by: default avatarWang Zhaolong <wangzhaolong@huaweicloud.com>
Acked-by: default avatarEnzo Matsumiya <ematsumiya@suse.de>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 9bd42798
Loading
Loading
Loading
Loading
+3 −6
Original line number Diff line number Diff line
@@ -1730,9 +1730,10 @@ struct mid_q_entry {
	unsigned int resp_buf_size;
	int mid_state;	/* wish this were enum but can not pass to wait_event */
	int mid_rc;		/* rc for MID_RC */
	unsigned int mid_flags;
	__le16 command;		/* smb command code */
	unsigned int optype;	/* operation type */
	bool wait_cancelled:1;  /* Cancelled while waiting for response */
	bool deleted_from_q:1;  /* Whether Mid has been dequeued frem pending_mid_q */
	bool large_buf:1;	/* if valid response, is pointer to large buf */
	bool multiRsp:1;	/* multiple trans2 responses for one request  */
	bool multiEnd:1;	/* both received */
@@ -1894,10 +1895,6 @@ static inline bool is_replayable_error(int error)
#define   MID_RESPONSE_READY 0x40 /* ready for other process handle the rsp */
#define   MID_RC             0x80 /* mid_rc contains custom rc */

/* Flags */
#define   MID_WAIT_CANCELLED	 1 /* Cancelled while waiting for response */
#define   MID_DELETED            2 /* Mid has been dequeued/deleted */

/* Types of response buffer returned from SendReceive2 */
#define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
#define   CIFS_SMALL_BUFFER     1
@@ -2009,7 +2006,7 @@ require use of the stronger protocol */
 *				GlobalTotalActiveXid
 * TCP_Server_Info->srv_lock	(anything in struct not protected by another lock and can change)
 * TCP_Server_Info->mid_queue_lock	TCP_Server_Info->pending_mid_q	cifs_get_tcp_session
 *				(any changes in mid_q_entry fields)
 *				mid_q_entry->deleted_from_q
 * TCP_Server_Info->mid_counter_lock    TCP_Server_Info->current_mid    cifs_get_tcp_session
 * TCP_Server_Info->req_lock	TCP_Server_Info->in_flight	cifs_get_tcp_session
 *				->credits
+5 −5
Original line number Diff line number Diff line
@@ -327,7 +327,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
		if (mid->mid_state == MID_REQUEST_SUBMITTED)
			mid->mid_state = MID_RETRY_NEEDED;
		list_move(&mid->qhead, &retry_list);
		mid->mid_flags |= MID_DELETED;
		mid->deleted_from_q = true;
	}
	spin_unlock(&server->mid_queue_lock);
	cifs_server_unlock(server);
@@ -888,7 +888,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
			list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) {
				kref_get(&mid->refcount);
				list_move(&mid->qhead, &dispose_list);
				mid->mid_flags |= MID_DELETED;
				mid->deleted_from_q = true;
			}
			spin_unlock(&server->mid_queue_lock);

@@ -966,12 +966,12 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
	 * Trying to handle/dequeue a mid after the send_recv()
	 * function has finished processing it is a bug.
	 */
	if (mid->mid_flags & MID_DELETED) {
	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);
		mid->mid_flags |= MID_DELETED;
		mid->deleted_from_q = true;
		spin_unlock(&mid->server->mid_queue_lock);
	}
}
@@ -1108,7 +1108,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
			kref_get(&mid_entry->refcount);
			mid_entry->mid_state = MID_SHUTDOWN;
			list_move(&mid_entry->qhead, &dispose_list);
			mid_entry->mid_flags |= MID_DELETED;
			mid_entry->deleted_from_q = true;
		}
		spin_unlock(&server->mid_queue_lock);

+2 −2
Original line number Diff line number Diff line
@@ -409,7 +409,7 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
			kref_get(&mid->refcount);
			if (dequeue) {
				list_del_init(&mid->qhead);
				mid->mid_flags |= MID_DELETED;
				mid->deleted_from_q = true;
			}
			spin_unlock(&server->mid_queue_lock);
			return mid;
@@ -4817,7 +4817,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
			} else {
				spin_lock(&dw->server->mid_queue_lock);
				mid->mid_state = MID_REQUEST_SUBMITTED;
				mid->mid_flags &= ~(MID_DELETED);
				mid->deleted_from_q = false;
				list_add_tail(&mid->qhead,
					&dw->server->pending_mid_q);
				spin_unlock(&dw->server->mid_queue_lock);
+6 −6
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ void __release_mid(struct kref *refcount)
#endif
	struct TCP_Server_Info *server = midEntry->server;

	if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
	if (midEntry->resp_buf && (midEntry->wait_cancelled) &&
	    (midEntry->mid_state == MID_RESPONSE_RECEIVED ||
	     midEntry->mid_state == MID_RESPONSE_READY) &&
	    server->ops->handle_cancelled_mid)
@@ -161,9 +161,9 @@ void
delete_mid(struct mid_q_entry *mid)
{
	spin_lock(&mid->server->mid_queue_lock);
	if (!(mid->mid_flags & MID_DELETED)) {
	if (mid->deleted_from_q == false) {
		list_del_init(&mid->qhead);
		mid->mid_flags |= MID_DELETED;
		mid->deleted_from_q = true;
	}
	spin_unlock(&mid->server->mid_queue_lock);

@@ -898,9 +898,9 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
		rc = mid->mid_rc;
		break;
	default:
		if (!(mid->mid_flags & MID_DELETED)) {
		if (mid->deleted_from_q == false) {
			list_del_init(&mid->qhead);
			mid->mid_flags |= MID_DELETED;
			mid->deleted_from_q = true;
		}
		spin_unlock(&server->mid_queue_lock);
		cifs_server_dbg(VFS, "%s: invalid mid state mid=%llu state=%d\n",
@@ -1214,7 +1214,7 @@ 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(&server->mid_queue_lock);
			midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
			midQ[i]->wait_cancelled = true;
			if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED ||
			    midQ[i]->mid_state == MID_RESPONSE_RECEIVED) {
				midQ[i]->callback = cifs_cancelled_callback;