summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2024-07-29 15:39:26 -0300
committerEnzo Matsumiya <ematsumiya@suse.de>2024-08-15 13:35:06 -0300
commit7ce34289b7dfa5ab025b48816c69fad966202879 (patch)
treec9c5b069723e4fb4f0e12220aed52cb9f3ba5b4a
parentf88976e507284bd37819355e08965f44a148be35 (diff)
downloadlinux-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.c77
-rw-r--r--fs/smb/client/compress.h56
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 */