diff options
author | Enzo Matsumiya <ematsumiya@suse.de> | 2024-07-29 15:39:26 -0300 |
---|---|---|
committer | Enzo Matsumiya <ematsumiya@suse.de> | 2024-08-15 13:35:06 -0300 |
commit | 7ce34289b7dfa5ab025b48816c69fad966202879 (patch) | |
tree | c9c5b069723e4fb4f0e12220aed52cb9f3ba5b4a | |
parent | f88976e507284bd37819355e08965f44a148be35 (diff) | |
download | linux-7ce34289b7dfa5ab025b48816c69fad966202879.tar.gz linux-7ce34289b7dfa5ab025b48816c69fad966202879.tar.bz2 linux-7ce34289b7dfa5ab025b48816c69fad966202879.zip |
smb: client: compress: allocate dest buffer inside smb_compress()
Change smb_compress() to take as arguments: server, uncompressed
smb_rqst, and the function to send the request (used only with
__smb_send_rqst for now, but maybe take an encryption function,
when support is implemented).
Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-rw-r--r-- | fs/smb/client/compress.c | 77 | ||||
-rw-r--r-- | fs/smb/client/compress.h | 56 |
2 files changed, 83 insertions, 50 deletions
diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c index dcb563a9dde6..645edde6e328 100644 --- a/fs/smb/client/compress.c +++ b/fs/smb/client/compress.c @@ -319,27 +319,68 @@ bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq) return (shdr->Command == SMB2_READ); } -int smb_compress(void *buf, const void *data, size_t *len) +int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_send_fn send_fn) { - struct smb2_compression_hdr *hdr; - size_t buf_len, data_len; + struct iov_iter iter; + size_t slen, dlen; + void *src, *dst; int ret; - buf_len = sizeof(struct smb2_write_req); - data_len = *len; - *len = 0; - - hdr = buf; - hdr->ProtocolId = SMB2_COMPRESSION_TRANSFORM_ID; - hdr->OriginalCompressedSegmentSize = cpu_to_le32(data_len); - hdr->Offset = cpu_to_le32(buf_len); - hdr->Flags = SMB2_COMPRESSION_FLAG_NONE; - hdr->CompressionAlgorithm = SMB3_COMPRESS_LZ77; - - /* XXX: add other algs here as they're implemented */ - ret = lz77_compress(data, data_len, buf + SMB_COMPRESS_HDR_LEN + buf_len, &data_len); - if (!ret) - *len = SMB_COMPRESS_HDR_LEN + buf_len + data_len; + if (!server || !rq || !rq->rq_iov || !rq->rq_iov->iov_base) + return -EINVAL; + + if (rq->rq_iov->iov_len != sizeof(struct smb2_write_req)) + return -EINVAL; + + slen = rq->rq_iter_size; + src = kvzalloc(slen, GFP_KERNEL); + if (!src) { + ret = -ENOMEM; + goto err_free; + } + + /* Keep the original iter intact. */ + iter = rq->rq_iter; + + if (!copy_from_iter_full(src, slen, &iter)) { + ret = -EIO; + goto err_free; + } + + dlen = round_up(slen, PAGE_SIZE); + dst = kvzalloc(dlen, GFP_KERNEL); + if (!dst) { + ret = -ENOMEM; + goto err_free; + } + + ret = lz77_compress(src, slen, dst, &dlen); + if (!ret) { + struct smb2_compression_hdr hdr = { 0 }; + struct smb_rqst comp_rq = { .rq_nvec = 3, }; + struct kvec iov[3]; + + hdr.ProtocolId = SMB2_COMPRESSION_TRANSFORM_ID; + hdr.OriginalCompressedSegmentSize = cpu_to_le32(slen); + hdr.CompressionAlgorithm = SMB3_COMPRESS_LZ77; + hdr.Flags = SMB2_COMPRESSION_FLAG_NONE; + hdr.Offset = cpu_to_le32(rq->rq_iov[0].iov_len); + + iov[0].iov_base = &hdr; + iov[0].iov_len = sizeof(hdr); + iov[1] = rq->rq_iov[0]; + iov[2].iov_base = dst; + iov[2].iov_len = dlen; + + comp_rq.rq_iov = iov; + + ret = send_fn(server, 1, &comp_rq); + } else if (ret == -EMSGSIZE || dlen >= slen) { + ret = send_fn(server, 1, rq); + } +err_free: + kvfree(dst); + kvfree(src); return ret; } diff --git a/fs/smb/client/compress.h b/fs/smb/client/compress.h index 316bb43cb277..f3ed1d3e52fb 100644 --- a/fs/smb/client/compress.h +++ b/fs/smb/client/compress.h @@ -26,18 +26,27 @@ #define SMB_COMPRESS_PAYLOAD_HDR_LEN 8 #define SMB_COMPRESS_MIN_LEN PAGE_SIZE -struct smb_compress_ctx { - struct TCP_Server_Info *server; - struct work_struct work; - struct mid_q_entry *mid; +#ifdef CONFIG_CIFS_COMPRESSION +typedef int (*compress_send_fn)(struct TCP_Server_Info *, int, struct smb_rqst *); - void *buf; /* compressed data */ - void *data; /* uncompressed data */ - size_t len; -}; +int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_send_fn send_fn); -#ifdef CONFIG_CIFS_COMPRESSION -int smb_compress(void *buf, const void *data, size_t *len); +/** + * should_compress() - Determines if a request (write) or the response to a + * request (read) should be compressed. + * @tcon: tcon of the request is being sent to + * @rqst: request to evaluate + * + * Return: true iff: + * - compression was successfully negotiated with server + * - server has enabled compression for the share + * - it's a read or write request + * - (write only) request length is >= SMB_COMPRESS_MIN_LEN + * - (write only) is_compressible() returns 1 + * + * Return false otherwise. + */ +bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq); /** * smb_compress_alg_valid() - Validate a compression algorithm. @@ -62,37 +71,20 @@ static __always_inline int smb_compress_alg_valid(__le16 alg, bool valid_none) return false; } - -/** - * should_compress() - Determines if a request (write) or the response to a - * request (read) should be compressed. - * @tcon: tcon of the request is being sent to - * @rqst: request to evaluate - * - * Return: true iff: - * - compression was successfully negotiated with server - * - server has enabled compression for the share - * - it's a read or write request - * - (write only) request length is >= SMB_COMPRESS_MIN_LEN - * - (write only) is_compressible() returns 1 - * - * Return false otherwise. - */ -bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq); #else /* !CONFIG_CIFS_COMPRESSION */ -static inline int smb_compress(...) +static inline int smb_compress(void *unused1, void *unused2, void *unused3) { return -EOPNOTSUPP; } -static inline int smb_compress_alg_valid(__le16 unused1, bool unused2) +static inline bool should_compress(void *unused1, void *unused2) { - return -EOPNOTSUPP; + return false; } -static inline bool should_compress(void *unused1, void *unused2) +static inline int smb_compress_alg_valid(__le16 unused1, bool unused2) { - return false; + return -EOPNOTSUPP; } #endif /* !CONFIG_CIFS_COMPRESSION */ #endif /* _SMB_COMPRESS_H */ |