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

smb: client: rename server mid_lock to mid_queue_lock



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

The current mid_lock name is somewhat ambiguous about what it protects.
To prepare for splitting this lock into separate, more granular locks,
this patch renames mid_lock to mid_queue_lock to clearly indicate its
specific responsibility for protecting the pending_mid_q list and
related queue operations.

No functional changes are made in this patch - it only prepares the
codebase for the lock splitting that follows.

- mid_queue_lock for queue operations
- mid_counter_lock for mid counter operations
- per-mid locks for individual mid state management

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 5b432ae5
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
		return;

	cifs_dbg(VFS, "Dump pending requests:\n");
	spin_lock(&server->mid_lock);
	spin_lock(&server->mid_queue_lock);
	list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
		cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n",
			 mid_entry->mid_state,
@@ -83,7 +83,7 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
				mid_entry->resp_buf, 62);
		}
	}
	spin_unlock(&server->mid_lock);
	spin_unlock(&server->mid_queue_lock);
#endif /* CONFIG_CIFS_DEBUG2 */
}

@@ -672,7 +672,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)

				seq_printf(m, "\n\tServer ConnectionId: 0x%llx",
					   chan_server->conn_id);
				spin_lock(&chan_server->mid_lock);
				spin_lock(&chan_server->mid_queue_lock);
				list_for_each_entry(mid_entry, &chan_server->pending_mid_q, qhead) {
					seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu",
						   mid_entry->mid_state,
@@ -681,7 +681,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
						   mid_entry->callback_data,
						   mid_entry->mid);
				}
				spin_unlock(&chan_server->mid_lock);
				spin_unlock(&chan_server->mid_queue_lock);
			}
			spin_unlock(&ses->chan_lock);
			seq_puts(m, "\n--\n");
+2 −2
Original line number Diff line number Diff line
@@ -732,7 +732,7 @@ struct TCP_Server_Info {
#endif
	wait_queue_head_t response_q;
	wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
	spinlock_t mid_lock;  /* protect mid queue and it's entries */
	spinlock_t mid_queue_lock;  /* protect mid queue */
	struct list_head pending_mid_q;
	bool noblocksnd;		/* use blocking sendmsg */
	bool noautotune;		/* do not autotune send buf sizes */
@@ -2007,7 +2007,7 @@ require use of the stronger protocol */
 *				GlobalCurrentXid
 *				GlobalTotalActiveXid
 * TCP_Server_Info->srv_lock	(anything in struct not protected by another lock and can change)
 * TCP_Server_Info->mid_lock	TCP_Server_Info->pending_mid_q	cifs_get_tcp_session
 * TCP_Server_Info->mid_queue_lock	TCP_Server_Info->pending_mid_q	cifs_get_tcp_session
 *				->CurrentMid
 *				(any changes in mid_q_entry fields)
 * TCP_Server_Info->req_lock	TCP_Server_Info->in_flight	cifs_get_tcp_session
+10 −10
Original line number Diff line number Diff line
@@ -321,7 +321,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
	/* mark submitted MIDs for retry and issue callback */
	INIT_LIST_HEAD(&retry_list);
	cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
	spin_lock(&server->mid_lock);
	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)
@@ -329,7 +329,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
		list_move(&mid->qhead, &retry_list);
		mid->mid_flags |= MID_DELETED;
	}
	spin_unlock(&server->mid_lock);
	spin_unlock(&server->mid_queue_lock);
	cifs_server_unlock(server);

	cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
@@ -884,13 +884,13 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
			 * server there should be exactly one pending mid
			 * corresponding to SMB1/SMB2 Negotiate packet.
			 */
			spin_lock(&server->mid_lock);
			spin_lock(&server->mid_queue_lock);
			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;
			}
			spin_unlock(&server->mid_lock);
			spin_unlock(&server->mid_queue_lock);

			/* Now try to reconnect once with NetBIOS session. */
			server->with_rfc1001 = true;
@@ -957,7 +957,7 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
#ifdef CONFIG_CIFS_STATS2
	mid->when_received = jiffies;
#endif
	spin_lock(&mid->server->mid_lock);
	spin_lock(&mid->server->mid_queue_lock);
	if (!malformed)
		mid->mid_state = MID_RESPONSE_RECEIVED;
	else
@@ -967,12 +967,12 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
	 * function has finished processing it is a bug.
	 */
	if (mid->mid_flags & MID_DELETED) {
		spin_unlock(&mid->server->mid_lock);
		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;
		spin_unlock(&mid->server->mid_lock);
		spin_unlock(&mid->server->mid_queue_lock);
	}
}

@@ -1101,7 +1101,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
		struct list_head *tmp, *tmp2;
		LIST_HEAD(dispose_list);

		spin_lock(&server->mid_lock);
		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);
@@ -1110,7 +1110,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
			list_move(&mid_entry->qhead, &dispose_list);
			mid_entry->mid_flags |= MID_DELETED;
		}
		spin_unlock(&server->mid_lock);
		spin_unlock(&server->mid_queue_lock);

		/* now walk dispose list and issue callbacks */
		list_for_each_safe(tmp, tmp2, &dispose_list) {
@@ -1822,7 +1822,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
	tcp_ses->compression.requested = ctx->compress;
	spin_lock_init(&tcp_ses->req_lock);
	spin_lock_init(&tcp_ses->srv_lock);
	spin_lock_init(&tcp_ses->mid_lock);
	spin_lock_init(&tcp_ses->mid_queue_lock);
	INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
	INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
	INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
+5 −5
Original line number Diff line number Diff line
@@ -95,17 +95,17 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
	struct smb_hdr *buf = (struct smb_hdr *)buffer;
	struct mid_q_entry *mid;

	spin_lock(&server->mid_lock);
	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 &&
		    le16_to_cpu(mid->command) == buf->Command) {
			kref_get(&mid->refcount);
			spin_unlock(&server->mid_lock);
			spin_unlock(&server->mid_queue_lock);
			return mid;
		}
	}
	spin_unlock(&server->mid_lock);
	spin_unlock(&server->mid_queue_lock);
	return NULL;
}

@@ -169,7 +169,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
	__u16 last_mid, cur_mid;
	bool collision, reconnect = false;

	spin_lock(&server->mid_lock);
	spin_lock(&server->mid_queue_lock);

	/* mid is 16 bit only for CIFS/SMB */
	cur_mid = (__u16)((server->CurrentMid) & 0xffff);
@@ -228,7 +228,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
		}
		cur_mid++;
	}
	spin_unlock(&server->mid_lock);
	spin_unlock(&server->mid_queue_lock);

	if (reconnect) {
		cifs_signal_cifsd_for_reconnect(server, false);
+13 −13
Original line number Diff line number Diff line
@@ -374,19 +374,19 @@ smb2_get_next_mid(struct TCP_Server_Info *server)
{
	__u64 mid;
	/* for SMB2 we need the current value */
	spin_lock(&server->mid_lock);
	spin_lock(&server->mid_queue_lock);
	mid = server->CurrentMid++;
	spin_unlock(&server->mid_lock);
	spin_unlock(&server->mid_queue_lock);
	return mid;
}

static void
smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
{
	spin_lock(&server->mid_lock);
	spin_lock(&server->mid_queue_lock);
	if (server->CurrentMid >= val)
		server->CurrentMid -= val;
	spin_unlock(&server->mid_lock);
	spin_unlock(&server->mid_queue_lock);
}

static struct mid_q_entry *
@@ -401,7 +401,7 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
		return NULL;
	}

	spin_lock(&server->mid_lock);
	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) &&
@@ -411,11 +411,11 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
				list_del_init(&mid->qhead);
				mid->mid_flags |= MID_DELETED;
			}
			spin_unlock(&server->mid_lock);
			spin_unlock(&server->mid_queue_lock);
			return mid;
		}
	}
	spin_unlock(&server->mid_lock);
	spin_unlock(&server->mid_queue_lock);
	return NULL;
}

@@ -460,9 +460,9 @@ smb2_negotiate(const unsigned int xid,
{
	int rc;

	spin_lock(&server->mid_lock);
	spin_lock(&server->mid_queue_lock);
	server->CurrentMid = 0;
	spin_unlock(&server->mid_lock);
	spin_unlock(&server->mid_queue_lock);
	rc = SMB2_negotiate(xid, ses, server);
	return rc;
}
@@ -4809,18 +4809,18 @@ static void smb2_decrypt_offload(struct work_struct *work)
		} else {
			spin_lock(&dw->server->srv_lock);
			if (dw->server->tcpStatus == CifsNeedReconnect) {
				spin_lock(&dw->server->mid_lock);
				spin_lock(&dw->server->mid_queue_lock);
				mid->mid_state = MID_RETRY_NEEDED;
				spin_unlock(&dw->server->mid_lock);
				spin_unlock(&dw->server->mid_queue_lock);
				spin_unlock(&dw->server->srv_lock);
				mid->callback(mid);
			} else {
				spin_lock(&dw->server->mid_lock);
				spin_lock(&dw->server->mid_queue_lock);
				mid->mid_state = MID_REQUEST_SUBMITTED;
				mid->mid_flags &= ~(MID_DELETED);
				list_add_tail(&mid->qhead,
					&dw->server->pending_mid_q);
				spin_unlock(&dw->server->mid_lock);
				spin_unlock(&dw->server->mid_queue_lock);
				spin_unlock(&dw->server->srv_lock);
			}
		}
Loading