From ad60a0a1245a84e15088c4c68cd8af626102208a Mon Sep 17 00:00:00 2001 From: Artem Blagodarenko Date: Sun, 3 Sep 2023 17:38:18 +0100 Subject: [PATCH] EX-7601 osc: move common CSDC code to the library CSDC repacks a chunk on the server side in case of the partial rewrite. There are routines that can be shared between client and server. This patch moves common compression code to the libcfs. Signed-off-by: Artem Blagodarenko Change-Id: I824211a3435b0479f7a3b8f08598a5b567b67d3c Reviewed-on: https://review.whamcloud.com/c/ex/lustre-release/+/52262 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger --- lustre/include/Makefile.am | 1 + lustre/include/lustre_compr.h | 50 ++++++++ lustre/obdclass/Makefile.in | 1 + lustre/obdclass/lustre_compr.c | 254 +++++++++++++++++++++++++++++++++++++++++ lustre/osc/osc_compress.c | 220 +++-------------------------------- lustre/osc/osc_internal.h | 21 +--- 6 files changed, 323 insertions(+), 224 deletions(-) create mode 100644 lustre/include/lustre_compr.h create mode 100644 lustre/obdclass/lustre_compr.c diff --git a/lustre/include/Makefile.am b/lustre/include/Makefile.am index 584b646..a73a052 100644 --- a/lustre/include/Makefile.am +++ b/lustre/include/Makefile.am @@ -47,6 +47,7 @@ EXTRA_DIST = \ lustre_acl.h \ lustre_barrier.h \ lustre_compat.h \ + lustre_compr.h \ lustre_crypto.h \ lustre_debug.h \ lustre_disk.h \ diff --git a/lustre/include/lustre_compr.h b/lustre/include/lustre_compr.h new file mode 100644 index 0000000..15edfa4 --- /dev/null +++ b/lustre/include/lustre_compr.h @@ -0,0 +1,50 @@ +/* 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 + */ + +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); diff --git a/lustre/obdclass/Makefile.in b/lustre/obdclass/Makefile.in index 50b4c46..53401d5 100644 --- a/lustre/obdclass/Makefile.in +++ b/lustre/obdclass/Makefile.in @@ -14,6 +14,7 @@ obdclass-all-objs += kernelcomm.o jobid.o 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 diff --git a/lustre/obdclass/lustre_compr.c b/lustre/obdclass/lustre_compr.c new file mode 100644 index 0000000..37c3805 --- /dev/null +++ b/lustre/obdclass/lustre_compr.c @@ -0,0 +1,254 @@ +/* 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 + */ + +#define DEBUG_SUBSYSTEM S_SEC + +#include +#include +#include + +#include + +/* "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); diff --git a/lustre/osc/osc_compress.c b/lustre/osc/osc_compress.c index 6f63c6b..e8a181d 100644 --- a/lustre/osc/osc_compress.c +++ b/lustre/osc/osc_compress.c @@ -30,12 +30,7 @@ #include #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 enum cpga_fill_bits { CPGA_FILL_DIRECTIO = 0x0001, @@ -95,147 +90,6 @@ static void unmerge_chunk(struct brw_page **pga, int first, int count, } } -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; @@ -385,13 +239,22 @@ int compress_request(const char *obd_name, struct obdo *oa, */ 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; @@ -435,58 +298,6 @@ out: 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; @@ -504,6 +315,7 @@ int decompress_request(struct osc_brw_async_args *aa, int page_count) 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])); @@ -554,7 +366,7 @@ int decompress_request(struct osc_brw_async_args *aa, int page_count) 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, diff --git a/lustre/osc/osc_internal.h b/lustre/osc/osc_internal.h index ee068f1..b96d02e 100644 --- a/lustre/osc/osc_internal.h +++ b/lustre/osc/osc_internal.h @@ -224,25 +224,6 @@ static inline void osc_set_io_portal(struct ptlrpc_request *req) 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 */ -- 1.8.3.1