summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2026-04-13 16:07:08 -0300
committerSteve French <stfrench@microsoft.com>2026-04-22 09:55:34 -0500
commit20d4f9efe008be1b673f43d38d3d99fb1fd4cd68 (patch)
tree688a12e9c7c521e24c91a67fe7c546048f80a2c9
parent4c221711b23745e2fb961ee517e9ed96ce76f9cb (diff)
smb: client: compress: fix counting in LZ77 match finding
- lz77_match_len() increments @cur before checking for equality, leading to off-by-one match len in some cases. Fix by moving pointers increment to inside the loop. Also rename @wnd arg to @match (more accurate name). - both lz77_match_len() and lz77_compress() checked for "buf + step < end" when the correct is "<=" for such cases. Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/smb/client/compress/lz77.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c
index c1e7fada6e61..61cdf1c14612 100644
--- a/fs/smb/client/compress/lz77.c
+++ b/fs/smb/client/compress/lz77.c
@@ -48,17 +48,17 @@ static __always_inline void lz77_write32(u32 *ptr, u32 v)
put_unaligned_le32(v, ptr);
}
-static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, const void *end)
+static __always_inline u32 lz77_match_len(const void *match, const void *cur, const void *end)
{
const void *start = cur;
u64 diff;
/* Safe for a do/while because otherwise we wouldn't reach here from the main loop. */
do {
- diff = lz77_read64(cur) ^ lz77_read64(wnd);
+ diff = lz77_read64(cur) ^ lz77_read64(match);
if (!diff) {
cur += LZ77_STEP_SIZE;
- wnd += LZ77_STEP_SIZE;
+ match += LZ77_STEP_SIZE;
continue;
}
@@ -67,10 +67,13 @@ static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, cons
cur += count_trailing_zeros(diff) >> 3;
return (cur - start);
- } while (likely(cur + LZ77_STEP_SIZE < end));
+ } while (likely(cur + LZ77_STEP_SIZE <= end));
- while (cur < end && lz77_read8(cur++) == lz77_read8(wnd++))
- ;
+ /* Fallback to byte-by-byte comparison for last <8 bytes. */
+ while (cur < end && lz77_read8(cur) == lz77_read8(match)) {
+ cur++;
+ match++;
+ }
return (cur - start);
}
@@ -195,7 +198,7 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen)
flag_pos = dstp;
dstp += 4;
}
- } while (likely(srcp + LZ77_STEP_SIZE < end));
+ } while (likely(srcp + LZ77_STEP_SIZE <= end));
while (srcp < end) {
u32 c = umin(end - srcp, 32 - flag_count);