From nobody Sun Oct 5 00:10:01 2025 Received: from dggsgout11.his.huawei.com (dggsgout11.his.huawei.com [45.249.212.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF8221FE461; Mon, 11 Aug 2025 14:15:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754921723; cv=none; b=Z2L2URM+XxY5b1EbOhrUN3d9+WU1H4BnRlSwNr7AIky6S0qMJBbe8l5RNp4ZsSC7zAvylHGMak4gUAtTTJWovS06JKGi5itCxX4Q7aD5yIDsRzFKhWgI2PkLAaZMY4wHXTavGm+s4xFNgUhm2RZJ9eO/rrxOmStHiEWtRvpMO9Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754921723; c=relaxed/simple; bh=AlkAyxu1JrupushGlvmKYTy08dYbf7Sm/lANXNsdYiY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=b4sKrlPiuPjclwDTJ3t6wvabq6KIhsKaytLPuKW2Vqdugd5LX9jLYK7IIZ8M8DBH1QMjQIes1iY9f4g7u943yNzeHupCYo4mGias5yffUBm2Q+CPYTUmg1A0U2n0kCLf0/RdN22htUBcHU7HpdMFGi/+anALOSzt1DE5QiKEEe4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=45.249.212.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.19.163.216]) by dggsgout11.his.huawei.com (SkyGuard) with ESMTPS id 4c0xVZ2rMwzYQvBs; Mon, 11 Aug 2025 22:15:18 +0800 (CST) Received: from mail02.huawei.com (unknown [10.116.40.128]) by mail.maildlp.com (Postfix) with ESMTP id 09B1A1A14F2; Mon, 11 Aug 2025 22:15:17 +0800 (CST) Received: from huaweicloud.com (unknown [10.175.104.67]) by APP4 (Coremail) with SMTP id gCh0CgBXIBHw+plocdNUDQ--.57266S5; Mon, 11 Aug 2025 22:15:14 +0800 (CST) From: Wang Zhaolong To: sfrench@samba.org, pshilov@microsoft.com Cc: linux-cifs@vger.kernel.org, samba-technical@lists.samba.org, linux-kernel@vger.kernel.org, chengzhihao1@huawei.com, yi.zhang@huawei.com, yangerkun@huawei.com Subject: [PATCH V3 1/2] smb: client: fix mid_q_entry memleak leak with per-mid locking Date: Mon, 11 Aug 2025 22:07:37 +0800 Message-Id: <20250811140738.1141817-2-wangzhaolong@huaweicloud.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20250811140738.1141817-1-wangzhaolong@huaweicloud.com> References: <20250811140738.1141817-1-wangzhaolong@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: gCh0CgBXIBHw+plocdNUDQ--.57266S5 X-Coremail-Antispam: 1UD129KBjvJXoW3uw4DZrWxKw13KFWkJr4rGrg_yoWkZr1kpa n0q343Gr1rXFn7ZwnrJ3WDu3WrArs5u3W3G3yxGr1ayFZrurn8WryDKryq9FW3Crs0g3sI 9w4jywsIv3WDX3DanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUU9Kb4IE77IF4wAFF20E14v26ryj6rWUM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUGw A2048vs2IY020Ec7CjxVAFwI0_JFI_Gr1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW7JVWDJwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6rxl6s0DM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMc Ij6xIIjxv20xvE14v26r1j6r18McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_ Jr0_Gr1lF7xvr2IYc2Ij64vIr41lc7CjxVAaw2AFwI0_JF0_Jw1l42xK82IYc2Ij64vIr4 1l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK 67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI 8IcVAFwI0_Jr0_JF4lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE42xK8VAv wI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E87Iv6xkF7I0E14 v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjxU7qjgUUUUU X-CM-SenderInfo: pzdqw6xkdrz0tqj6x35dzhxuhorxvhhfrp/ Content-Type: text/plain; charset="utf-8" This is step 4/4 of a patch series to fix mid_q_entry memory leaks caused by race conditions in callback execution. In compound_send_recv(), when wait_for_response() is interrupted by signals, the code attempts to cancel pending requests by changing their callbacks to cifs_cancelled_callback. However, there's a race condition between signal interruption and network response processing that causes both mid_q_entry and server buffer leaks: ``` User foreground process cifsd cifs_readdir open_cached_dir cifs_send_recv compound_send_recv smb2_setup_request smb2_mid_entry_alloc smb2_get_mid_entry smb2_mid_entry_alloc mempool_alloc // alloc mid kref_init(&temp->refcount); // refcount =3D 1 mid[0]->callback =3D cifs_compound_callback; mid[1]->callback =3D cifs_compound_last_callback; smb_send_rqst rc =3D wait_for_response wait_event_state TASK_KILLABLE cifs_demultiplex_thread allocate_buffers server->bigbuf =3D cifs_buf_get() standard_receive3 ->find_mid() smb2_find_mid __smb2_find_mid kref_get(&mid->refcount) // +1 cifs_handle_standard handle_mid /* bigbuf will also leak */ mid->resp_buf =3D server->bigbuf server->bigbuf =3D NULL; dequeue_mid /* in for loop */ mids[0]->callback cifs_compound_callback /* Signal interrupts wait: rc =3D -ERESTARTSYS */ /* if (... || midQ[i]->mid_state =3D=3D MID_RESPONSE_RECEIVED) *? midQ[0]->callback =3D cifs_cancelled_callback; cancelled_mid[i] =3D true; /* The change comes too late */ mid->mid_state =3D MID_RESPONSE_READY release_mid // -1 /* cancelled_mid[i] =3D=3D true causes mid won't be released in compound_send_recv cleanup */ /* cifs_cancelled_callback won't executed to release mid */ ``` The root cause is that there's a race between callback assignment and execution. Fix this by introducing per-mid locking: - Add spinlock_t mid_lock to struct mid_q_entry - Add mid_execute_callback() for atomic callback execution - Use mid_lock in cancellation paths to ensure atomicity This ensures that either the original callback or the cancellation callback executes atomically, preventing reference count leaks when requests are interrupted by signals. Link: https://bugzilla.kernel.org/show_bug.cgi?id=3D220404 Fixes: ee258d79159a ("CIFS: Move credit processing to mid callbacks for SMB= 3") Signed-off-by: Wang Zhaolong Signed-off-by: Wang Zhaolong --- fs/smb/client/cifsglob.h | 21 +++++++++++++++++++++ fs/smb/client/cifstransport.c | 19 +++++++++---------- fs/smb/client/connect.c | 8 ++++---- fs/smb/client/smb2ops.c | 4 ++-- fs/smb/client/smb2transport.c | 1 + fs/smb/client/transport.c | 7 +++---- 6 files changed, 40 insertions(+), 20 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index e6830ab3a546..1e64a4fb6af0 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1730,10 +1730,11 @@ 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 */ __le16 command; /* smb command code */ unsigned int optype; /* operation type */ + spinlock_t mid_lock; 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 */ @@ -2034,10 +2035,13 @@ require use of the stronger protocol */ * init_cached_dir * cifsFileInfo->fh_mutex cifsFileInfo cifs_new_fileinfo * cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo * ->invalidHandle initiate_cifs_search * ->oplock_break_cancelled + * mid_q_entry->mid_lock mid_q_entry->callback alloc_mid + * smb2_mid_entry_alloc + * (Any fields of mid_q_entry that will need protection) *************************************************************************= ***/ =20 #ifdef DECLARE_GLOBALS_HERE #define GLOBAL_EXTERN #else @@ -2373,10 +2377,27 @@ static inline bool cifs_netbios_name(const char *na= me, size_t namelen) } } return ret; } =20 +/* + * Execute mid callback atomically - ensures callback runs exactly once + * and prevents sleeping in atomic context. + */ +static inline void mid_execute_callback(struct mid_q_entry *mid) +{ + void (*callback)(struct mid_q_entry *mid); + + spin_lock(&mid->mid_lock); + callback =3D mid->callback; + mid->callback =3D NULL; /* Mark as executed, */ + spin_unlock(&mid->mid_lock); + + if (callback) + callback(mid); +} + #define CIFS_REPARSE_SUPPORT(tcon) \ ((tcon)->posix_extensions || \ (le32_to_cpu((tcon)->fsAttrInfo.Attributes) & \ FILE_SUPPORTS_REPARSE_POINTS)) =20 diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c index 352dafb888dd..e98b95eff8c9 100644 --- a/fs/smb/client/cifstransport.c +++ b/fs/smb/client/cifstransport.c @@ -44,10 +44,11 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_= Server_Info *server) } =20 temp =3D mempool_alloc(cifs_mid_poolp, GFP_NOFS); memset(temp, 0, sizeof(struct mid_q_entry)); kref_init(&temp->refcount); + spin_lock_init(&temp->mid_lock); temp->mid =3D get_mid(smb_buffer); temp->pid =3D current->pid; temp->command =3D cpu_to_le16(smb_buffer->Command); cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command); /* easier to use jiffies */ @@ -343,20 +344,19 @@ SendReceive(const unsigned int xid, struct cifs_ses *= ses, goto out; =20 rc =3D wait_for_response(server, midQ); if (rc !=3D 0) { send_cancel(server, &rqst, midQ); - spin_lock(&server->mid_queue_lock); - if (midQ->mid_state =3D=3D MID_REQUEST_SUBMITTED || - midQ->mid_state =3D=3D MID_RESPONSE_RECEIVED) { + spin_lock(&midQ->mid_lock); + if (midQ->callback) { /* no longer considered to be "in-flight" */ midQ->callback =3D release_mid; - spin_unlock(&server->mid_queue_lock); + spin_unlock(&midQ->mid_lock); add_credits(server, &credits, 0); return rc; } - spin_unlock(&server->mid_queue_lock); + spin_unlock(&midQ->mid_lock); } =20 rc =3D cifs_sync_mid_result(midQ, server); if (rc !=3D 0) { add_credits(server, &credits, 0); @@ -525,19 +525,18 @@ SendReceiveBlockingLock(const unsigned int xid, struc= t cifs_tcon *tcon, } =20 rc =3D wait_for_response(server, midQ); if (rc) { send_cancel(server, &rqst, midQ); - spin_lock(&server->mid_queue_lock); - if (midQ->mid_state =3D=3D MID_REQUEST_SUBMITTED || - midQ->mid_state =3D=3D MID_RESPONSE_RECEIVED) { + spin_lock(&midQ->mid_lock); + if (midQ->callback) { /* no longer considered to be "in-flight" */ midQ->callback =3D release_mid; - spin_unlock(&server->mid_queue_lock); + spin_unlock(&midQ->mid_lock); return rc; } - spin_unlock(&server->mid_queue_lock); + spin_unlock(&midQ->mid_lock); } =20 /* We got the response - restart system call. */ rstart =3D 1; spin_lock(&server->srv_lock); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 587845a2452d..281ccbeea719 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -333,11 +333,11 @@ cifs_abort_connection(struct TCP_Server_Info *server) cifs_server_unlock(server); =20 cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__); list_for_each_entry_safe(mid, nmid, &retry_list, qhead) { list_del_init(&mid->qhead); - mid->callback(mid); + mid_execute_callback(mid); release_mid(mid); } =20 if (cifs_rdma_enabled(server)) { cifs_server_lock(server); @@ -917,11 +917,11 @@ is_smb_response(struct TCP_Server_Info *server, unsig= ned char type) */ list_for_each_entry_safe(mid, nmid, &dispose_list, qhead) { list_del_init(&mid->qhead); mid->mid_rc =3D mid_rc; mid->mid_state =3D MID_RC; - mid->callback(mid); + mid_execute_callback(mid); release_mid(mid); } =20 /* * If reconnect failed then wait two seconds. In most @@ -1115,11 +1115,11 @@ clean_demultiplex_info(struct TCP_Server_Info *serv= er) /* now walk dispose list and issue callbacks */ list_for_each_safe(tmp, tmp2, &dispose_list) { mid_entry =3D list_entry(tmp, struct mid_q_entry, qhead); cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid); list_del_init(&mid_entry->qhead); - mid_entry->callback(mid_entry); + mid_execute_callback(mid_entry); release_mid(mid_entry); } /* 1/8th of sec is more than enough time for them to exit */ msleep(125); } @@ -1392,11 +1392,11 @@ cifs_demultiplex_thread(void *p) "Share deleted. Reconnect needed"); } } =20 if (!mids[i]->multiRsp || mids[i]->multiEnd) - mids[i]->callback(mids[i]); + mid_execute_callback(mids[i]); =20 release_mid(mids[i]); } else if (server->ops->is_oplock_break && server->ops->is_oplock_break(bufs[i], server)) { diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index ad8947434b71..f7a0f1c81b43 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4803,19 +4803,19 @@ static void smb2_decrypt_offload(struct work_struct= *work) #endif if (dw->server->ops->is_network_name_deleted) dw->server->ops->is_network_name_deleted(dw->buf, dw->server); =20 - mid->callback(mid); + mid_execute_callback(mid); } else { spin_lock(&dw->server->srv_lock); if (dw->server->tcpStatus =3D=3D CifsNeedReconnect) { spin_lock(&dw->server->mid_queue_lock); mid->mid_state =3D MID_RETRY_NEEDED; spin_unlock(&dw->server->mid_queue_lock); spin_unlock(&dw->server->srv_lock); - mid->callback(mid); + mid_execute_callback(mid); } else { spin_lock(&dw->server->mid_queue_lock); mid->mid_state =3D MID_REQUEST_SUBMITTED; mid->deleted_from_q =3D false; list_add_tail(&mid->qhead, diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index ff9ef7fcd010..bc0e92eb2b64 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -769,10 +769,11 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr, } =20 temp =3D mempool_alloc(cifs_mid_poolp, GFP_NOFS); memset(temp, 0, sizeof(struct mid_q_entry)); kref_init(&temp->refcount); + spin_lock_init(&temp->mid_lock); temp->mid =3D le64_to_cpu(shdr->MessageId); temp->credits =3D credits > 0 ? credits : 1; temp->pid =3D current->pid; temp->command =3D shdr->Command; /* Always LE */ temp->when_alloc =3D jiffies; diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 32d528b4dd83..a61ba7f3fb86 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -1003,19 +1003,18 @@ compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, if (rc !=3D 0) { for (; i < num_rqst; i++) { cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n", midQ[i]->mid, le16_to_cpu(midQ[i]->command)); send_cancel(server, &rqst[i], midQ[i]); - spin_lock(&server->mid_queue_lock); + spin_lock(&midQ[i]->mid_lock); midQ[i]->wait_cancelled =3D true; - if (midQ[i]->mid_state =3D=3D MID_REQUEST_SUBMITTED || - midQ[i]->mid_state =3D=3D MID_RESPONSE_RECEIVED) { + if (midQ[i]->callback) { midQ[i]->callback =3D cifs_cancelled_callback; cancelled_mid[i] =3D true; credits[i].value =3D 0; } - spin_unlock(&server->mid_queue_lock); + spin_unlock(&midQ[i]->mid_lock); } } =20 for (i =3D 0; i < num_rqst; i++) { if (rc < 0) --=20 2.39.2 From nobody Sun Oct 5 00:10:01 2025 Received: from dggsgout11.his.huawei.com (dggsgout11.his.huawei.com [45.249.212.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A1B911A83F8; Mon, 11 Aug 2025 14:15:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754921723; cv=none; b=mOfaWApp3ug21yGl1SpOW/xOMO3VsohTE0xMGTH56le8rBXHwgiZPz8NrkqLyNSFwVk97vOSB7I2FdzdcIlmqCSRH2bPqIpyHZ81OTLwEcb9xMFqONAKyKpHAC8Jz+ZjUK2E9GvnAHbZQ6CuXHyOq6NuU2CAxYt4FI4d/zyGrug= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754921723; c=relaxed/simple; bh=ZHPBXXARkxfMnIeg1ZiMsgZlLUb6UJTzndMVRLNHEUg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=OPhe6vOGHbb30HURCUZvGRO4fxPyvbeM9SNfLOtZt0gydb7q0I42G0zTY45fDX2uKP24zAzU4mavgYXNFvXhFmkn8c89en6z+rSvxII6iA8gwNJMJyYm7vhRWs2UxV6yt3Au8sjoE2mKoivyM2Yy1WlctzT9hVVD13FBb/JKfi4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=45.249.212.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.19.163.216]) by dggsgout11.his.huawei.com (SkyGuard) with ESMTPS id 4c0xVZ5g6RzYQvCD; Mon, 11 Aug 2025 22:15:18 +0800 (CST) Received: from mail02.huawei.com (unknown [10.116.40.128]) by mail.maildlp.com (Postfix) with ESMTP id 69F8E1A177F; Mon, 11 Aug 2025 22:15:17 +0800 (CST) Received: from huaweicloud.com (unknown [10.175.104.67]) by APP4 (Coremail) with SMTP id gCh0CgBXIBHw+plocdNUDQ--.57266S6; Mon, 11 Aug 2025 22:15:17 +0800 (CST) From: Wang Zhaolong To: sfrench@samba.org, pshilov@microsoft.com Cc: linux-cifs@vger.kernel.org, samba-technical@lists.samba.org, linux-kernel@vger.kernel.org, chengzhihao1@huawei.com, yi.zhang@huawei.com, yangerkun@huawei.com Subject: [PATCH V3 2/2] smb: client: Clean up mid_queue_lock usage and standardize mid_state access Date: Mon, 11 Aug 2025 22:07:38 +0800 Message-Id: <20250811140738.1141817-3-wangzhaolong@huaweicloud.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20250811140738.1141817-1-wangzhaolong@huaweicloud.com> References: <20250811140738.1141817-1-wangzhaolong@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: gCh0CgBXIBHw+plocdNUDQ--.57266S6 X-Coremail-Antispam: 1UD129KBjvAXoWfZFy7Zr1UGF1xKFWrJr17trb_yoW8tFWfGo Z3W345Ar4UXr9YkFyYyrn3JF4v9r4q939FqF4FyrW5Aa4Ika10qr18tr45Jay5ZF4ft390 9aykJFn5ta97Jwn3n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYL7kC6x804xWl14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK 8VAvwI8IcIk0rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_Jr yl82xGYIkIc2x26xkF7I0E14v26r4j6ryUM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Ar0_tr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AK xVW0oVCq3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ew Av7VC0I7IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY 6r1j6r4UM4x0Y48IcxkI7VAKI48JMxkF7I0En4kS14v26r126r1DMxAIw28IcxkI7VAKI4 8JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xv wVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUtVW8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjx v20xvE14v26r1j6r1xMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw20E Y4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267 AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7IU89NVDUUUUU== X-CM-SenderInfo: pzdqw6xkdrz0tqj6x35dzhxuhorxvhhfrp/ Content-Type: text/plain; charset="utf-8" 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 --- 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 =3D 1, .instance =3D 0, .rreq_debug_id =3D rdata->rreq->debug_id, .rreq_debug_index =3D rdata->subreq.debug_index, }; + int mid_state =3D READ_ONCE(mid->mid_state); =20 cifs_dbg(FYI, "%s: mid=3D%llu state=3D%d result=3D%d bytes=3D%zu\n", - __func__, mid->mid, mid->mid_state, rdata->result, + __func__, mid->mid, mid_state, rdata->result, rdata->subreq.len); =20 - switch (mid->mid_state) { + switch (mid_state) { case MID_RESPONSE_RECEIVED: /* result already set, check signature */ if (server->sign) { int rc =3D 0; =20 @@ -1694,12 +1695,13 @@ cifs_writev_callback(struct mid_q_entry *mid) .rreq_debug_id =3D wdata->rreq->debug_id, .rreq_debug_index =3D wdata->subreq.debug_index, }; ssize_t result; size_t written; + int mid_state =3D READ_ONCE(mid->mid_state); =20 - switch (mid->mid_state) { + switch (mid_state) { case MID_RESPONSE_RECEIVED: result =3D cifs_check_receive(mid, tcon->ses->server, 0); if (result !=3D 0) break; =20 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 =3D current; temp->callback =3D cifs_wake_up_task; temp->callback_data =3D current; =20 atomic_inc(&mid_count); - temp->mid_state =3D MID_REQUEST_ALLOCATED; + WRITE_ONCE(temp->mid_state, MID_REQUEST_ALLOCATED); return temp; } =20 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; } =20 - midQ->mid_state =3D MID_REQUEST_SUBMITTED; + WRITE_ONCE(midQ->mid_state, MID_REQUEST_SUBMITTED); =20 rc =3D smb_send(server, in_buf, len); cifs_save_when_sent(midQ); =20 if (rc < 0) @@ -362,11 +362,11 @@ SendReceive(const unsigned int xid, struct cifs_ses *= ses, add_credits(server, &credits, 0); return rc; } =20 if (!midQ->resp_buf || !out_buf || - midQ->mid_state !=3D MID_RESPONSE_READY) { + READ_ONCE(midQ->mid_state) !=3D MID_RESPONSE_READY) { rc =3D -EIO; cifs_server_dbg(VFS, "Bad MID state?\n"); goto out; } =20 @@ -403,10 +403,40 @@ send_lock_cancel(const unsigned int xid, struct cifs_= tcon *tcon, =20 return SendReceive(xid, ses, in_buf, out_buf, &bytes_returned, 0); } =20 +static inline bool cifs_blocking_lock_should_exit(struct mid_q_entry *midQ, + struct TCP_Server_Info *server) +{ + int mid_state =3D READ_ONCE(midQ->mid_state); + int tcp_status =3D READ_ONCE(server->tcpStatus); + + if (mid_state !=3D MID_REQUEST_SUBMITTED && + mid_state !=3D MID_RESPONSE_RECEIVED) + return true; + + if (tcp_status !=3D CifsGood && tcp_status !=3D 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 =3D READ_ONCE(midQ->mid_state); + int tcp_status =3D READ_ONCE(server->tcpStatus); + /* Can only cancel if still pending */ + bool still_pending =3D (mid_state =3D=3D MID_REQUEST_SUBMITTED || + mid_state =3D=3D MID_RESPONSE_RECEIVED); + /* Can only cancel if server connection is good */ + bool server_good =3D (tcp_status =3D=3D CifsGood || tcp_status =3D=3D Cif= sNew); + + 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, struc= t cifs_tcon *tcon, delete_mid(midQ); cifs_server_unlock(server); return rc; } =20 - midQ->mid_state =3D MID_REQUEST_SUBMITTED; + WRITE_ONCE(midQ->mid_state, MID_REQUEST_SUBMITTED); rc =3D smb_send(server, in_buf, len); cifs_save_when_sent(midQ); =20 if (rc < 0) server->sequence_number -=3D 2; @@ -486,22 +516,16 @@ SendReceiveBlockingLock(const unsigned int xid, struc= t cifs_tcon *tcon, return rc; } =20 /* Wait for a reply - allow signals to interrupt. */ rc =3D wait_event_interruptible(server->response_q, - (!(midQ->mid_state =3D=3D MID_REQUEST_SUBMITTED || - midQ->mid_state =3D=3D MID_RESPONSE_RECEIVED)) || - ((server->tcpStatus !=3D CifsGood) && - (server->tcpStatus !=3D CifsNew))); + cifs_blocking_lock_should_exit(midQ, server)); =20 /* Were we interrupted by a signal ? */ spin_lock(&server->srv_lock); if ((rc =3D=3D -ERESTARTSYS) && - (midQ->mid_state =3D=3D MID_REQUEST_SUBMITTED || - midQ->mid_state =3D=3D MID_RESPONSE_RECEIVED) && - ((server->tcpStatus =3D=3D CifsGood) || - (server->tcpStatus =3D=3D CifsNew))) { + cifs_blocking_lock_can_cancel(midQ, server)) { spin_unlock(&server->srv_lock); =20 if (in_buf->Command =3D=3D 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, struc= t cifs_tcon *tcon, rc =3D cifs_sync_mid_result(midQ, server); if (rc !=3D 0) return rc; =20 /* rcvd frame is ok */ - if (out_buf =3D=3D NULL || midQ->mid_state !=3D MID_RESPONSE_READY) { + if (out_buf =3D=3D NULL || READ_ONCE(midQ->mid_state) !=3D MID_RESPONSE_R= EADY) { rc =3D -EIO; cifs_tcon_dbg(VFS, "Bad MID state?\n"); goto out; } =20 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 =3D=3D MID_REQUEST_SUBMITTED) - mid->mid_state =3D MID_RETRY_NEEDED; + if (READ_ONCE(mid->mid_state) =3D=3D MID_REQUEST_SUBMITTED) + WRITE_ONCE(mid->mid_state, MID_RETRY_NEEDED); list_move(&mid->qhead, &retry_list); mid->deleted_from_q =3D true; } spin_unlock(&server->mid_queue_lock); cifs_server_unlock(server); @@ -916,11 +916,11 @@ is_smb_response(struct TCP_Server_Info *server, unsig= ned 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 =3D mid_rc; - mid->mid_state =3D MID_RC; + WRITE_ONCE(mid->mid_state, MID_RC); mid_execute_callback(mid); release_mid(mid); } =20 /* @@ -955,19 +955,18 @@ void dequeue_mid(struct mid_q_entry *mid, bool malformed) { #ifdef CONFIG_CIFS_STATS2 mid->when_received =3D jiffies; #endif - spin_lock(&mid->server->mid_queue_lock); - if (!malformed) - mid->mid_state =3D MID_RESPONSE_RECEIVED; - else - mid->mid_state =3D 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 =3D=3D 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 *serv= er) spin_lock(&server->mid_queue_lock); list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { mid_entry =3D 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 =3D MID_SHUTDOWN; + WRITE_ONCE(mid_entry->mid_state, MID_SHUTDOWN); list_move(&mid_entry->qhead, &dispose_list); mid_entry->deleted_from_q =3D true; } spin_unlock(&server->mid_queue_lock); =20 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 *buf= fer) struct mid_q_entry *mid; =20 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 =3D=3D MID_REQUEST_SUBMITTED && + READ_ONCE(mid->mid_state) =3D=3D MID_REQUEST_SUBMITTED && le16_to_cpu(mid->command) =3D=3D 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 =3D 0; spin_lock(&server->mid_queue_lock); list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { ++num_mids; if (mid_entry->mid =3D=3D cur_mid && - mid_entry->mid_state =3D=3D MID_REQUEST_SUBMITTED) { + READ_ONCE(mid_entry->mid_state) =3D=3D + MID_REQUEST_SUBMITTED) { /* This mid is in use, try a different one */ collision =3D 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) } =20 spin_lock(&server->mid_queue_lock); list_for_each_entry(mid, &server->pending_mid_q, qhead) { if ((mid->mid =3D=3D wire_mid) && - (mid->mid_state =3D=3D MID_REQUEST_SUBMITTED) && + (READ_ONCE(mid->mid_state) =3D=3D MID_REQUEST_SUBMITTED) && (mid->command =3D=3D shdr->Command)) { kref_get(&mid->refcount); if (dequeue) { list_del_init(&mid->qhead); mid->deleted_from_q =3D true; @@ -4661,11 +4661,11 @@ handle_read_data(struct TCP_Server_Info *server, st= ruct mid_q_entry *mid, if (rdata->result !=3D 0) { cifs_dbg(FYI, "%s: server returned error %d\n", __func__, rdata->result); /* normal error on read response */ if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_RECEIVED; + WRITE_ONCE(mid->mid_state, MID_RESPONSE_RECEIVED); else dequeue_mid(mid, false); return 0; } =20 @@ -4688,11 +4688,11 @@ handle_read_data(struct TCP_Server_Info *server, st= ruct 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 =3D -EIO; if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED); else dequeue_mid(mid, rdata->result); return 0; } =20 @@ -4707,32 +4707,32 @@ handle_read_data(struct TCP_Server_Info *server, st= ruct 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 =3D -EIO; if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED); else dequeue_mid(mid, rdata->result); return 0; } =20 if (data_len > buffer_len - pad_len) { /* data_len is corrupt -- discard frame */ rdata->result =3D -EIO; if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED); else dequeue_mid(mid, rdata->result); return 0; } =20 /* Copy the data to the output I/O iterator. */ rdata->result =3D cifs_copy_folioq_to_iter(buffer, buffer_len, cur_off, &rdata->subreq.io_iter); if (rdata->result !=3D 0) { if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED); else dequeue_mid(mid, rdata->result); return 0; } rdata->got_bytes =3D buffer_len; @@ -4747,18 +4747,18 @@ handle_read_data(struct TCP_Server_Info *server, st= ruct 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 =3D -EIO; if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + WRITE_ONCE(mid->mid_state, MID_RESPONSE_MALFORMED); else dequeue_mid(mid, rdata->result); return 0; } =20 if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_RECEIVED; + WRITE_ONCE(mid->mid_state, MID_RESPONSE_RECEIVED); else dequeue_mid(mid, false); return 0; } =20 @@ -4807,18 +4807,16 @@ static void smb2_decrypt_offload(struct work_struct= *work) =20 mid_execute_callback(mid); } else { spin_lock(&dw->server->srv_lock); if (dw->server->tcpStatus =3D=3D CifsNeedReconnect) { - spin_lock(&dw->server->mid_queue_lock); - mid->mid_state =3D 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 =3D MID_REQUEST_SUBMITTED; + WRITE_ONCE(mid->mid_state, MID_REQUEST_SUBMITTED); mid->deleted_from_q =3D 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 =3D mid->callback_data; struct smb2_echo_rsp *rsp =3D (struct smb2_echo_rsp *)mid->resp_buf; struct cifs_credits credits =3D { .value =3D 0, .instance =3D 0 }; + int mid_state =3D READ_ONCE(mid->mid_state); =20 - if (mid->mid_state =3D=3D MID_RESPONSE_RECEIVED - || mid->mid_state =3D=3D MID_RESPONSE_MALFORMED) { + if (mid_state =3D=3D MID_RESPONSE_RECEIVED + || mid_state =3D=3D MID_RESPONSE_MALFORMED) { credits.value =3D le16_to_cpu(rsp->hdr.CreditRequest); credits.instance =3D server->reconnect_instance; } =20 release_mid(mid); @@ -4531,24 +4532,25 @@ smb2_readv_callback(struct mid_q_entry *mid) .rreq_debug_index =3D rdata->subreq.debug_index, }; struct smb_rqst rqst =3D { .rq_iov =3D &rdata->iov[1], .rq_nvec =3D 1 }; unsigned int rreq_debug_id =3D rdata->rreq->debug_id; unsigned int subreq_debug_index =3D rdata->subreq.debug_index; + int mid_state =3D READ_ONCE(mid->mid_state); =20 if (rdata->got_bytes) { rqst.rq_iter =3D rdata->subreq.io_iter; } =20 WARN_ONCE(rdata->server !=3D mid->server, "rdata server %p !=3D mid server %p", rdata->server, mid->server); =20 cifs_dbg(FYI, "%s: mid=3D%llu state=3D%d result=3D%d bytes=3D%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); =20 - switch (mid->mid_state) { + switch (mid_state) { case MID_RESPONSE_RECEIVED: credits.value =3D le16_to_cpu(shdr->CreditRequest); credits.instance =3D 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 =3D current; temp->callback =3D cifs_wake_up_task; temp->callback_data =3D current; =20 atomic_inc(&mid_count); - temp->mid_state =3D 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" =20 void cifs_wake_up_task(struct mid_q_entry *mid) { - if (mid->mid_state =3D=3D MID_RESPONSE_RECEIVED) - mid->mid_state =3D MID_RESPONSE_READY; + if (READ_ONCE(mid->mid_state) =3D=3D MID_RESPONSE_RECEIVED) + WRITE_ONCE(mid->mid_state, MID_RESPONSE_READY); wake_up_process(mid->callback_data); } =20 void __release_mid(struct kref *refcount) { @@ -47,18 +47,19 @@ void __release_mid(struct kref *refcount) __u16 smb_cmd =3D le16_to_cpu(midEntry->command); unsigned long now; unsigned long roundtrip_time; #endif struct TCP_Server_Info *server =3D midEntry->server; + int mid_state =3D READ_ONCE(midEntry->mid_state); =20 if (midEntry->resp_buf && (midEntry->wait_cancelled) && - (midEntry->mid_state =3D=3D MID_RESPONSE_RECEIVED || - midEntry->mid_state =3D=3D MID_RESPONSE_READY) && + (mid_state =3D=3D MID_RESPONSE_RECEIVED || + mid_state =3D=3D MID_RESPONSE_READY) && server->ops->handle_cancelled_mid) server->ops->handle_cancelled_mid(midEntry, server); =20 - midEntry->mid_state =3D 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 =3D 0; credits->instance =3D server->reconnect_instance; return 0; } =20 +static inline bool cifs_mid_response_ready(struct mid_q_entry *mid) +{ + int mid_state =3D READ_ONCE(mid->mid_state); + + return (mid_state !=3D MID_REQUEST_SUBMITTED && + mid_state !=3D MID_RESPONSE_RECEIVED); +} + int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *= midQ) { int error; =20 error =3D wait_event_state(server->response_q, - midQ->mid_state !=3D MID_REQUEST_SUBMITTED && - midQ->mid_state !=3D MID_RESPONSE_RECEIVED, + cifs_mid_response_ready(midQ), (TASK_KILLABLE|TASK_FREEZABLE_UNSAFE)); if (error < 0) return -ERESTARTSYS; =20 return 0; @@ -696,11 +704,11 @@ cifs_call_async(struct TCP_Server_Info *server, struc= t smb_rqst *rqst, =20 mid->receive =3D receive; mid->callback =3D callback; mid->callback_data =3D cbdata; mid->handle =3D handle; - mid->mid_state =3D MID_REQUEST_SUBMITTED; + WRITE_ONCE(mid->mid_state, MID_REQUEST_SUBMITTED); =20 /* 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, struc= t smb_rqst *rqst, } =20 int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *= server) { int rc =3D 0; + int state =3D READ_ONCE(mid->mid_state); =20 cifs_dbg(FYI, "%s: cmd=3D%d mid=3D%llu state=3D%d\n", - __func__, le16_to_cpu(mid->command), mid->mid, mid->mid_state); + __func__, le16_to_cpu(mid->command), mid->mid, state); =20 - 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 =3D -EAGAIN; break; case MID_RESPONSE_MALFORMED: @@ -750,21 +757,21 @@ int cifs_sync_mid_result(struct mid_q_entry *mid, str= uct TCP_Server_Info *server break; case MID_RC: rc =3D mid->mid_rc; break; default: + spin_lock(&server->mid_queue_lock); if (mid->deleted_from_q =3D=3D false) { list_del_init(&mid->qhead); mid->deleted_from_q =3D true; } spin_unlock(&server->mid_queue_lock); cifs_server_dbg(VFS, "%s: invalid mid state mid=3D%llu state=3D%d\n", - __func__, mid->mid, mid->mid_state); + __func__, mid->mid, state); rc =3D -EIO; goto sync_mid_done; } - spin_unlock(&server->mid_queue_lock); =20 sync_mid_done: release_mid(mid); return rc; } @@ -778,12 +785,12 @@ cifs_compound_callback(struct mid_q_entry *mid) .instance =3D server->reconnect_instance, }; =20 add_credits(server, &credits, mid->optype); =20 - if (mid->mid_state =3D=3D MID_RESPONSE_RECEIVED) - mid->mid_state =3D MID_RESPONSE_READY; + if (READ_ONCE(mid->mid_state) =3D=3D MID_RESPONSE_RECEIVED) + WRITE_ONCE(mid->mid_state, MID_RESPONSE_READY); } =20 static void cifs_compound_last_callback(struct mid_q_entry *mid) { @@ -936,11 +943,11 @@ compound_send_recv(const unsigned int xid, struct cif= s_ses *ses, for (j =3D 0; j < num_rqst; j++) add_credits(server, &credits[j], optype); return PTR_ERR(midQ[i]); } =20 - midQ[i]->mid_state =3D MID_REQUEST_SUBMITTED; + WRITE_ONCE(midQ[i]->mid_state, MID_REQUEST_SUBMITTED); midQ[i]->optype =3D 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 c= ifs_ses *ses, cancelled_mid[i] =3D true; goto out; } =20 if (!midQ[i]->resp_buf || - midQ[i]->mid_state !=3D MID_RESPONSE_READY) { + READ_ONCE(midQ[i]->mid_state) !=3D MID_RESPONSE_READY) { rc =3D -EIO; cifs_dbg(FYI, "Bad MID state?\n"); goto out; } =20 --=20 2.39.2