[bionic:linux-azure-4.15][PATCH 2/2] cifs: Fix potential softlockups while refreshing DFS cache
Marcelo Henrique Cerri
marcelo.cerri at canonical.com
Mon Oct 26 14:34:43 UTC 2020
From: Paulo Alcantara (SUSE) <pc at cjr.nz>
BugLink: https://bugs.launchpad.net/bugs/1882268
We used to skip reconnects on all SMB2_IOCTL commands due to SMB3+
FSCTL_VALIDATE_NEGOTIATE_INFO - which made sense since we're still
establishing a SMB session.
However, when refresh_cache_worker() calls smb2_get_dfs_refer() and
we're under reconnect, SMB2_ioctl() will not be able to get a proper
status error (e.g. -EHOSTDOWN in case we failed to reconnect) but an
-EAGAIN from cifs_send_recv() thus looping forever in
refresh_cache_worker().
Fixes: e99c63e4d86d ("SMB3: Fix deadlock in validate negotiate hits reconnect")
Signed-off-by: Paulo Alcantara (SUSE) <pc at cjr.nz>
Suggested-by: Aurelien Aptel <aaptel at suse.com>
Reviewed-by: Aurelien Aptel <aaptel at suse.com>
Signed-off-by: Steve French <stfrench at microsoft.com>
(backported from commit 84a1f5b1cc6fd7f6cd99fc5630c36f631b19fa60)
[marcelo.cerri: Adapted the changes from smb2_plain_req_init() to
small_smb2_init() to avoid picking too many unrelated changes]
Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri at canonical.com>
---
fs/cifs/smb2pdu.c | 38 ++++++++++++++++++++++++++++----------
1 file changed, 28 insertions(+), 10 deletions(-)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index ec2f7c377a2b..ab1df4311a6d 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -166,7 +166,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
if (tcon == NULL)
return 0;
- if (smb2_command == SMB2_TREE_CONNECT || smb2_command == SMB2_IOCTL)
+ if (smb2_command == SMB2_TREE_CONNECT)
return 0;
if (tcon->tidStatus == CifsExiting) {
@@ -372,18 +372,13 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
* function must have filled in request_buf pointer. The returned buffer
* has RFC1001 length at the beginning.
*/
-static int
-small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
- void **request_buf)
+static int __small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
+ void **request_buf)
{
- int rc;
+ int rc = 0;
unsigned int total_len;
struct smb2_pdu *pdu;
- rc = smb2_reconnect(smb2_command, tcon);
- if (rc)
- return rc;
-
/* BB eventually switch this to SMB2 specific small buf size */
*request_buf = cifs_small_buf_get();
if (*request_buf == NULL) {
@@ -409,6 +404,29 @@ small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
return rc;
}
+static int small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
+ void **request_buf)
+{
+ int rc;
+
+ rc = smb2_reconnect(smb2_command, tcon);
+ if (rc)
+ return rc;
+
+ return __small_smb2_init(smb2_command, tcon, request_buf);
+}
+
+static int small_smb2_ioctl_init(u32 opcode, struct cifs_tcon *tcon,
+ void **request_buf)
+{
+ /* Skip reconnect only for FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs */
+ if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) {
+ return __small_smb2_init(SMB2_IOCTL, tcon, request_buf);
+ }
+ return small_smb2_init(SMB2_IOCTL, tcon, request_buf);
+}
+
+
#ifdef CONFIG_CIFS_SMB311
/* offset is sizeof smb2_negotiate_req - 4 but rounded up to 8 bytes */
#define OFFSET_OF_NEG_CONTEXT 0x68 /* sizeof(struct smb2_negotiate_req) - 4 */
@@ -1937,7 +1955,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
if (!ses || !(ses->server))
return -EIO;
- rc = small_smb2_init(SMB2_IOCTL, tcon, (void **) &req);
+ rc = small_smb2_ioctl_init(opcode, tcon, (void **) &req);
if (rc)
return rc;
--
2.25.1
More information about the kernel-team
mailing list