[PATCH v2 03/14] smb: client: compress: disable compression on reconnects

Enzo Matsumiya <[email protected]> Mon, 20 Jul 2026 16:49:14 -0300
Newsgroups org.kernel.vger.linux-cifs
Message-ID <[email protected]>
Windows Server resets the connection if it gets a compressed request
that it couldn't decompress.

Some encoded payloads might decode differently on the server, or
vice-versa, due to different implementation details (not really a bug),
or an actual bug on either implementation.

To prevent an infinite retry on such failed sends, simply disable
compression for that server when a reconnect is about to happen.

Other:
- add disable_compression() helper (cifsglob.h)

Signed-off-by: Enzo Matsumiya <[email protected]>
---
 fs/smb/client/cifsglob.h | 20 ++++++++++++++++++++
 fs/smb/client/connect.c  | 11 +++++++++++
 2 files changed, 31 insertions(+)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 99f9e6dca62b..5a397499dcb0 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -835,6 +835,26 @@ struct TCP_Server_Info {
 	char dns_dom[CIFS_MAX_DOMAINNAME_LEN + 1];
 };
 
+static __always_inline void disable_compression(struct TCP_Server_Info *server)
+{
+	/*
+	 * should_compress() checks the primary server compression state, so disable it only
+	 * on primary server.
+	 */
+	if (SERVER_IS_CHAN(server))
+		server = server->primary_server;
+
+	if (server->compression.enabled) {
+		pr_warn("%s: disabling compression (failsafe)\n", server->hostname);
+
+		/*
+		 * We must keep ->requested as true, in case new channels are added, so server
+		 * capabilities are kept in sync (even though no further compression will be done).
+		 */
+		server->compression.enabled = false;
+	}
+}
+
 static inline bool is_smb1(const struct TCP_Server_Info *server)
 {
 	return server->vals->protocol_id == SMB10_PROT_ID;
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 85aec302c89e..6a4afefe337d 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -401,6 +401,17 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
 		try_to_freeze();
 		cifs_server_lock(server);
 
+		/*
+		 * Servers might disconnect us when they can't decompress a compressed request we
+		 * sent.
+		 * When this happens, as a failsafe measure, disable compression entirely to avoid
+		 * an endless retry.
+		 *
+		 * TODO: implement a more flexible alternative, e.g. identify and retry sending
+		 * the failed request uncompressed, without having to disable compression entirely.
+		 */
+		disable_compression(server);
+
 		if (!cifs_swn_set_server_dstaddr(server) &&
 		    !SERVER_IS_CHAN(server)) {
 			/* resolve the hostname again to make sure that IP address is up-to-date */
-- 
2.54.0