lustre_acl.h \
lustre_barrier.h \
lustre_compat.h \
+ lustre_compr.h \
lustre_crypto.h \
lustre_debug.h \
lustre_disk.h \
--- /dev/null
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright (c) 2023, DataDirect Networks Inc, all rights reserved.
+ * Author: Artem Blagodarenko <ablagodarenko@whamcloud.com>
+ */
+
+int alloc_compr(enum ll_compr_type *type, unsigned int lvl,
+ struct crypto_comp **cc);
+
+int compress_chunk(const char *obd_name, const unsigned char *in,
+ unsigned int in_len, unsigned char *out,
+ unsigned int *out_len, void *wrkmem,
+ enum ll_compr_type type, unsigned int lvl,
+ unsigned int chunk_log_bit,
+ enum ll_compr_type *applied_type);
+
+static inline struct page *mem_to_page(void *addr)
+{
+ if (!is_vmalloc_addr(addr))
+ return virt_to_page(addr);
+
+ return vmalloc_to_page(addr);
+}
+
+int is_chunk_start(struct page *page, struct ll_compr_hdr **ret_header);
+
+int decompress_chunk(const char *obd_name,
+ unsigned char *in, unsigned int in_len,
+ unsigned char *out, unsigned int *out_len,
+ enum ll_compr_type type, unsigned int lvl);
obdclass-all-objs += integrity.o obd_cksum.o
obdclass-all-objs += lu_tgt_descs.o
obdclass-all-objs += range_lock.o interval_tree.o
+obdclass-all-objs += lustre_compr.o
@SERVER_TRUE@obdclass-all-objs += acl.o
@SERVER_TRUE@obdclass-all-objs += idmap.o
--- /dev/null
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright (c) 2023, DataDirect Networks Inc, all rights reserved.
+ * Author: Artem Blagodarenko <ablagodarenko@whamcloud.com>
+ */
+
+#define DEBUG_SUBSYSTEM S_SEC
+
+#include <lustre_debug.h>
+#include <linux/falloc.h>
+#include <lustre_crypto.h>
+
+#include <lustre_compr.h>
+
+/* "one-shot" try to load our own compression modules
+ * the first time that a compressed file is accessed
+ */
+static bool tried_llz4_load = false;
+static bool tried_lgzip_load = false;
+
+static inline const char *crypto_name_from_type(enum ll_compr_type type,
+ unsigned int level)
+{
+ switch (type) {
+ case LL_COMPR_TYPE_NONE:
+ return "none";
+ case LL_COMPR_TYPE_GZIP:
+ return "deflate";
+ case LL_COMPR_TYPE_LZ4FAST:
+ return "lz4";
+ case LL_COMPR_TYPE_LZ4HC:
+ if (level < LZ4HC_MIN_CLEVEL - 1)
+ return "lz4";
+ return "lz4hc";
+ case LL_COMPR_TYPE_LZO:
+ return "lzo";
+ default:
+ return "unknown";
+ }
+}
+
+int alloc_compr(enum ll_compr_type *type, unsigned int lvl,
+ struct crypto_comp **cc)
+{
+ if (OBD_FAIL_CHECK(OBD_FAIL_OSC_WRONG_COMP_ALG))
+ return -EIO;
+
+ /*
+ * We should never have a chunk that is actually compressed with BEST
+ * or FAST type, so it should never apply during decompression.
+ * For compression path these types are changed to the appropriate algo
+ * in the compress_chunk().
+ */
+ LASSERT(*type != LL_COMPR_TYPE_BEST);
+ LASSERT(*type != LL_COMPR_TYPE_FAST);
+
+ /* Always try to use our built-in modules.
+ * Do not check request_module ret code, this is best effort
+ * as it will fail back to kernel's modules.
+ */
+ if ((*type == LL_COMPR_TYPE_LZ4FAST || *type == LL_COMPR_TYPE_LZ4HC) &&
+ unlikely(!tried_llz4_load)) {
+ /* lz4 and lz4hc are siblings, treat them together */
+ request_module(LLZ4FAST_MOD_NAME);
+ request_module(LLZ4HC_MOD_NAME);
+ tried_llz4_load = true;
+ } else if (*type == LL_COMPR_TYPE_GZIP && unlikely(!tried_lgzip_load)) {
+ request_module(LGZIP_MOD_NAME);
+ tried_lgzip_load = true;
+ }
+ *cc = crypto_alloc_comp(crypto_name_from_type(*type, lvl), 0, 0);
+ if (IS_ERR(*cc)) {
+ int ret = PTR_ERR(*cc);
+ CERROR("Cannot initialize compressor %i, error %i\n", *type,
+ ret);
+ /*
+ * This shouldn't return "ENOENT" to the caller when the crypto
+ * type is missing. That will be confusing to see "no such file
+ * or directory" message, so let's change it to "Can not access
+ * a needed shared library" here.
+ */
+ if (ret == -ENOENT)
+ ret = -ELIBACC;
+ *cc = NULL;
+ return ret;
+ }
+
+ if (lvl != -1)
+ ll_crypto_comp_set_level(*cc, lvl);
+
+ return 0;
+
+}
+EXPORT_SYMBOL(alloc_compr);
+
+/*
+ * The minimum delta between compressed and plain data to
+ * use the compressed one.
+ */
+#define COMP_GAP 4096
+int compress_chunk(const char *obd_name, const unsigned char *in,
+ unsigned int in_len, unsigned char *out,
+ unsigned int *out_len, void *wrkmem,
+ enum ll_compr_type type, unsigned int lvl,
+ unsigned int chunk_log_bits,
+ enum ll_compr_type *applied_type)
+{
+ struct ll_compr_hdr *llch;
+ unsigned int len = *out_len - sizeof(*llch);
+ struct crypto_comp *cc = NULL;
+ enum ll_compr_type compr_type_fast = LL_COMPR_TYPE_LZ4FAST;
+ enum ll_compr_type compr_type_best = LL_COMPR_TYPE_GZIP;
+ int rc;
+
+ /*
+ * Once compress_chunk() faced with unsupported compression
+ * algorithm, it replaces algorithm used for whole request.
+ */
+ if (*applied_type != LL_COMPR_TYPE_UNCHANGED)
+ type = *applied_type;
+
+ if (type == LL_COMPR_TYPE_BEST)
+ type = compr_type_best;
+ else if (type == LL_COMPR_TYPE_FAST)
+ type = compr_type_fast;
+
+again:
+ rc = alloc_compr(&type, lvl, &cc);
+ if (!rc) {
+ CDEBUG(D_SEC, "%s: crypto_comp allocated, type %i, level %i\n",
+ obd_name, type, lvl);
+ } else if (type == LL_COMPR_TYPE_LZO) {
+ CWARN("%s: LZO(%i) unsupported, left plain: rc = %d\n",
+ obd_name, type, rc);
+ *out_len = in_len;
+ *applied_type = LL_COMPR_TYPE_NONE;
+ return 0;
+ } else if (type != compr_type_fast) {
+ CWARN("%s: type %i unsupported, try FAST(%i): rc = %d\n",
+ obd_name, type, compr_type_fast, rc);
+ type = compr_type_fast;
+ goto again;
+ } else {
+ CWARN("%s: type %i unsupported, try LZO(%i): rc = %d\n",
+ obd_name, type, LL_COMPR_TYPE_LZO, rc);
+ type = LL_COMPR_TYPE_LZO;
+ goto again;
+ }
+
+ rc = crypto_comp_compress(cc, in, in_len,
+ out + sizeof(*llch),
+ &len);
+ if (rc) {
+ crypto_free_comp(cc);
+ return 0;
+ }
+
+ if (len + sizeof(*llch) + COMP_GAP > in_len) {
+ CDEBUG(D_SEC, ", compressed %u, plain %u, leaving uncompressed\n",
+ len, in_len);
+ *out_len = in_len;
+ crypto_free_comp(cc);
+ return 0;
+ }
+
+ llch = (struct ll_compr_hdr *)out;
+ llch->llch_magic = LLCH_MAGIC;
+ llch->llch_header_size = sizeof(*llch);
+ llch->llch_compr_type = type;
+ llch->llch_compr_level = lvl;
+ llch->llch_chunk_log_bits = chunk_log_bits;
+ llch->llch_flags = 0;
+ llch->llch_compr_size = len;
+ llch->llch_compr_csum = 0;
+ llch->llch_uncompr_csum = 0;
+ llch->llch_reserved = 0;
+ llch->llch_hdr_csum = 0;
+
+ *out_len = len + sizeof(*llch);
+
+ if (cc)
+ crypto_free_comp(cc);
+
+ return 1;
+}
+EXPORT_SYMBOL(compress_chunk);
+
+int is_chunk_start(struct page *page, struct ll_compr_hdr **ret_header)
+{
+ struct ll_compr_hdr *header;
+ int rc = 1;
+ ENTRY;
+
+ if (page == NULL)
+ RETURN(0);
+
+ header = (struct ll_compr_hdr *)kmap_atomic(page);
+ if (header->llch_magic != LLCH_MAGIC)
+ rc = 0;
+ *ret_header = header;
+
+ kunmap_atomic(header);
+
+ RETURN(rc);
+}
+EXPORT_SYMBOL(is_chunk_start);
+
+int decompress_chunk(const char *obd_name,
+ unsigned char *in, unsigned int in_len,
+ unsigned char *out, unsigned int *out_len,
+ enum ll_compr_type type, unsigned int lvl)
+{
+ int rc = 0;
+ struct crypto_comp *cc = NULL;
+
+ rc = alloc_compr(&type, lvl, &cc);
+ if (rc) {
+ CERROR("%s: Unsupported compression type %i: rc = %d\n",
+ obd_name, type, rc);
+ goto fail;
+ }
+
+ rc = crypto_comp_decompress(cc, in, in_len, out, out_len);
+ if (rc) {
+ CERROR("%s: Compression error : rc = %d\n", obd_name, rc);
+ goto fail;
+ }
+
+fail:
+ if (cc)
+ crypto_free_comp(cc);
+ return rc;
+}
+EXPORT_SYMBOL(decompress_chunk);
#include <linux/falloc.h>
#include "osc_internal.h"
#include "osc_compress.h"
-
-/* "one-shot" try to load our own compression modules
- * the first time that a compressed file is accessed
- */
-static bool tried_llz4_load = false;
-static bool tried_lgzip_load = false;
+#include <lustre_compr.h>
enum cpga_fill_bits {
CPGA_FILL_DIRECTIO = 0x0001,
}
}
-static int alloc_comp(enum ll_compr_type *type, unsigned int lvl,
- struct crypto_comp **cc)
-{
- if (OBD_FAIL_CHECK(OBD_FAIL_OSC_WRONG_COMP_ALG))
- return -EIO;
-
- /*
- * TDB: At some point we will probably want to allow "fast" and "best"
- * to be configurable and/or dynamically selected by CPU speed.
- */
-
- if (*type == LL_COMPR_TYPE_BEST)
- *type = LL_COMPR_TYPE_GZIP;
- else if (*type == LL_COMPR_TYPE_FAST)
- *type = LL_COMPR_TYPE_LZ4FAST;
-
- /* Always try to use our built-in modules.
- * Do not check request_module ret code, this is best effort
- * as it will fail back to kernel's modules.
- */
- if ((*type == LL_COMPR_TYPE_LZ4FAST || *type == LL_COMPR_TYPE_LZ4HC) &&
- unlikely(!tried_llz4_load)) {
- /* lz4 and lz4hc are siblings, treat them together */
- request_module(LLZ4FAST_MOD_NAME);
- request_module(LLZ4HC_MOD_NAME);
- tried_llz4_load = true;
- } else if (*type == LL_COMPR_TYPE_GZIP && unlikely(!tried_lgzip_load)) {
- request_module(LGZIP_MOD_NAME);
- tried_lgzip_load = true;
- }
- *cc = crypto_alloc_comp(crypto_name_from_type(*type, lvl), 0, 0);
- if (IS_ERR(*cc)) {
- int ret = PTR_ERR(*cc);
- CERROR("Cannot initialize compressor %i, error %i\n", *type,
- ret);
- *cc = NULL;
- return ret;
- }
-
- if (lvl != -1)
- ll_crypto_comp_set_level(*cc, lvl);
-
- return 0;
-
-}
-/*
- * The minimum delta between compressed and plain data to
- * use the compressed one.
- */
-#define COMP_GAP 4096
-static int compress_chunk(const char *obd_name, struct obdo *oa,
- const unsigned char *in, unsigned int in_len,
- unsigned char *out, unsigned int *out_len,
- void *wrkmem, struct cl_page *clpage,
- enum ll_compr_type *applied_type)
-{
- struct ll_compr_hdr *llch;
- unsigned int len = *out_len - sizeof(*llch);
- struct crypto_comp *cc = NULL;
- enum ll_compr_type type = clpage->cp_comp_type;
- int rc;
-
- /*
- * Once compress_chunk() faced with unsupported compression
- * algorithm, it replaces algorithm used for whole request.
- */
- if (*applied_type != LL_COMPR_TYPE_UNCHANGED)
- type = *applied_type;
-
-again:
- rc = alloc_comp(&type, clpage->cp_comp_level, &cc);
- if (!rc) {
- CDEBUG(D_SEC, "%s: crypto_comp allocated, type %i, level %i\n",
- obd_name, type, clpage->cp_comp_level);
- } else if (type == LL_COMPR_TYPE_LZO) {
- CWARN("%s: LZO(%i) unsupported, left plain: rc = %d\n",
- obd_name, type, rc);
- *out_len = in_len;
- *applied_type = 0;
- return 0;
- } else if (type == LL_COMPR_TYPE_FAST) {
- CWARN("%s: %i unsupported, try LZO(%i): rc = %d\n",
- obd_name, type, LL_COMPR_TYPE_LZO, rc);
- *applied_type = type = LL_COMPR_TYPE_LZO;
- goto again;
- } else {
- CWARN("%s: %i unsupported, try FAST(%i): rc = %d\n",
- obd_name, type, LL_COMPR_TYPE_FAST, rc);
- *applied_type = type = LL_COMPR_TYPE_FAST;
- goto again;
- }
-
- rc = crypto_comp_compress(cc, in, in_len,
- out + sizeof(*llch),
- &len);
- if (rc) {
- CERROR("%s: Compression error %d: inode "DFID"\n",
- obd_name, rc, oa->o_parent_seq, oa->o_parent_oid,
- oa->o_parent_ver);
- crypto_free_comp(cc);
- return 0;
- }
-
- if (len + sizeof(*llch) + COMP_GAP > in_len) {
- CDEBUG(D_SEC, "Inode "DFID", compressed %u, plain %u, leaving uncompressed\n",
- oa->o_parent_seq, oa->o_parent_oid, oa->o_parent_ver,
- len, in_len);
- *out_len = in_len;
- crypto_free_comp(cc);
- return 0;
- }
-
- llch = (struct ll_compr_hdr *)out;
- llch->llch_magic = LLCH_MAGIC;
- llch->llch_header_size = sizeof(*llch);
- llch->llch_compr_type = type;
- llch->llch_compr_level = clpage->cp_comp_level;
- llch->llch_chunk_log_bits = clpage->cp_chunk_log_bits;
- llch->llch_flags = 0;
- llch->llch_compr_size = len;
- llch->llch_compr_csum = 0;
- llch->llch_uncompr_csum = 0;
- llch->llch_reserved = 0;
- llch->llch_hdr_csum = 0;
-
- *out_len = len + sizeof(*llch);
-
- if (cc)
- crypto_free_comp(cc);
-
- return 1;
-}
-
-static inline struct page *mem_to_page(void *addr)
-{
- if (!is_vmalloc_addr(addr))
- return virt_to_page(addr);
-
- return vmalloc_to_page(addr);
-}
-
void free_cpga(struct brw_page **cpga, u32 page_count)
{
int i;
*/
if (clpage->cp_comp_type != LL_COMPR_TYPE_NONE &&
applied_type && (pga_i != *page_count - 1)) {
- done = compress_chunk(obd_name, oa, src,
+ done = compress_chunk(obd_name, src,
src_size, dst, &dst_size,
- wrkmem, clpage,
+ wrkmem,
+ clpage->cp_comp_type,
+ clpage->cp_comp_level,
+ clpage->cp_chunk_log_bits,
&applied_type);
CDEBUG(D_SEC,
- "Compressed %u, plain %u, rc %i\n",
- dst_size, src_size, done);
+ "%s: rc %d: inode "DFID"\n",
+ obd_name, rc, oa->o_parent_seq,
+ oa->o_parent_oid,
+ oa->o_parent_ver);
+
+ CDEBUG(D_SEC,
+ "Compressed %u, plain %u\n",
+ dst_size, src_size);
} else {
done = 0;
dst_size = src_size;
RETURN(rc);
}
-int is_chunk_start(struct page *page, struct ll_compr_hdr **ret_header)
-{
- struct ll_compr_hdr *header;
- int rc = 1;
- ENTRY;
-
- if (page == NULL)
- RETURN(0);
-
- header = (struct ll_compr_hdr *)kmap_atomic(page);
-
- if (header->llch_magic != LLCH_MAGIC)
- rc = 0;
- *ret_header = header;
-
- kunmap_atomic(header);
-
- RETURN(rc);
-}
-
-static int decompress_chunk(struct osc_brw_async_args *aa,
- unsigned char *in, unsigned int in_len,
- unsigned char *out, unsigned int *out_len,
- enum ll_compr_type type, unsigned int lvl)
-{
- int rc = 0;
- struct crypto_comp *cc = NULL;
- struct obdo *oa = aa->aa_oa;
- char *obd_name = aa->aa_cli->cl_import->imp_obd->obd_name;
-
- rc = alloc_comp(&type, lvl, &cc);
- if (rc) {
- CERROR("%s: Unsupported compression type %i: rc = %d\n",
- obd_name, type, rc);
- goto fail;
- }
-
- rc = crypto_comp_decompress(cc, in, in_len, out, out_len);
- if (rc) {
- CERROR("%s: Compression error : rc = %d\n", obd_name, rc);
- goto fail;
- }
-
-fail:
- if (rc)
- CERROR("%s: inode "DFID"\n", obd_name, oa->o_parent_seq,
- oa->o_parent_oid, oa->o_parent_ver);
- if (cc)
- crypto_free_comp(cc);
- return rc;
-}
-
int decompress_request(struct osc_brw_async_args *aa, int page_count)
{
struct brw_page **pga = aa->aa_ppga;
int buf_bits;
int rc = 0;
int i = 0;
+ char *obd_name = aa->aa_cli->cl_import->imp_obd->obd_name;
ENTRY;
clpage = oap2cl_page(brw_page2oap(pga[0]));
llch->llch_compr_size + sizeof(*llch),
llch->llch_compr_type);
- rc = decompress_chunk(aa,
+ rc = decompress_chunk(obd_name,
src + llch->llch_header_size,
llch->llch_compr_size,
dst, &dst_size,
req->rq_request_portal = OST_IO_PORTAL;
}
-static inline const char *crypto_name_from_type(enum ll_compr_type type,
- unsigned int level)
-{
- switch (type) {
- case LL_COMPR_TYPE_NONE:
- return "none";
- case LL_COMPR_TYPE_GZIP:
- return "deflate";
- case LL_COMPR_TYPE_LZ4FAST:
- return "lz4";
- case LL_COMPR_TYPE_LZ4HC:
- if (level < LZ4HC_MIN_CLEVEL - 1)
- return "lz4";
- return "lz4hc";
- case LL_COMPR_TYPE_LZO:
- return "lzo";
- default:
- return "unknown";
- }
-}
+
#endif /* OSC_INTERNAL_H */