--- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # -*- sh -*- -CPPFLAGS += -I./include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS) -I./include/linux/lzma +CPPFLAGS += -I./include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS) $(XZCPPFLAGS) -I./include/linux/lzma ifeq ($(WITHOUT_XATTR), 1) CPPFLAGS += -DWITHOUT_XATTR --- a/mkfs.ubifs/compr.c +++ b/mkfs.ubifs/compr.c @@ -127,6 +127,114 @@ static inline int lzo_init(void) { retur static inline void lzo_fini(void) { } #endif +#ifndef WITHOUT_XZ + +#include + +struct xz_ctx { + lzma_filter filters[3]; + lzma_options_lzma opts; +}; + +static struct xz_ctx *xz_ctx; + +#define LZMA_COMPRESSION_LEVEL 9 + +static struct xz_ctx *xz_ctx_init(void) +{ + struct xz_ctx *ctx; + lzma_options_lzma *opts_lzma; + uint32_t preset; + int ret; + + ctx = malloc(sizeof(struct xz_ctx)); + if (ctx == NULL) + goto err; + + memset(ctx, 0, sizeof(struct xz_ctx)); + + opts_lzma = &ctx->opts; + + preset = LZMA_COMPRESSION_LEVEL | LZMA_PRESET_EXTREME; + ret = lzma_lzma_preset(opts_lzma, preset); + if (ret) + goto err_free_ctx; + + /* TODO: allow to specify LZMA options via command line */ +#if 0 + opts_lzma->lc = 3; + opts_lzma->lp = 0; + opts_lzma->pb = 2; + opts_lzma->nice_len = 64; +#else + opts_lzma->lc = 0; + opts_lzma->lp = 2; + opts_lzma->pb = 2; + opts_lzma->nice_len = 64; +#endif + + ctx->filters[0].id = LZMA_FILTER_LZMA2; + ctx->filters[0].options = opts_lzma; + ctx->filters[1].id = LZMA_VLI_UNKNOWN; + + return ctx; + +err_free_ctx: + free(ctx); +err: + return NULL; +} + +static void xz_ctx_free(struct xz_ctx *ctx) +{ + free(ctx); +} + +static int xz_init(void) +{ + xz_ctx = xz_ctx_init(); + if (xz_ctx == NULL) + return -1; + + return 0; +} + +static void xz_fini(void) +{ + xz_ctx_free(xz_ctx); +} + +static int xz_compress(void *in_buf, size_t in_len, void *out_buf, + size_t *out_len) +{ + size_t ret_len; + lzma_ret ret_xz; + int ret; + + ret = -1; + + ret_len = 0; + ret_xz = lzma_stream_buffer_encode(xz_ctx->filters, LZMA_CHECK_CRC32, + NULL, in_buf, in_len, out_buf, + &ret_len, *out_len); + if (ret_xz != LZMA_OK) { + fprintf(stderr, "XZ error: %d\n", (int) ret_xz); + goto out; + } + + *out_len = ret_len; + + ret = 0; +out: + return ret; +} +#else +static inline int xz_init(void) { return 0; } +static inline void xz_fini(void) { } +static inline int xz_compress(void *in_buf, size_t in_len, void *out_buf, + size_t *out_len) { return -1; } +#endif + static int no_compress(void *in_buf, size_t in_len, void *out_buf, size_t *out_len) { @@ -199,6 +307,9 @@ int compress_data(void *in_buf, size_t i case MKFS_UBIFS_COMPR_LZO: ret = lzo_compress(in_buf, in_len, out_buf, out_len); break; + case MKFS_UBIFS_COMPR_XZ: + ret = xz_compress(in_buf, in_len, out_buf, out_len); + break; case MKFS_UBIFS_COMPR_ZLIB: ret = zlib_deflate(in_buf, in_len, out_buf, out_len); break; @@ -226,12 +337,18 @@ int init_compression(void) if (ret) goto err; + ret = xz_init(); + if (ret) + goto err_lzo; + zlib_buf = malloc(UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR); if (!zlib_buf) - goto err_lzo; + goto err_xz; return 0; +err_xz: + xz_fini(); err_lzo: lzo_fini(); err: @@ -241,6 +358,7 @@ err: void destroy_compression(void) { free(zlib_buf); + xz_fini(); lzo_fini(); if (errcnt) fprintf(stderr, "%llu compression errors occurred\n", errcnt); --- a/mkfs.ubifs/compr.h +++ b/mkfs.ubifs/compr.h @@ -36,6 +36,7 @@ enum compression_type MKFS_UBIFS_COMPR_NONE, MKFS_UBIFS_COMPR_LZO, MKFS_UBIFS_COMPR_ZLIB, + MKFS_UBIFS_COMPR_XZ, }; int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len, --- a/mkfs.ubifs/Makefile +++ b/mkfs.ubifs/Makefile @@ -6,21 +6,33 @@ ALL_SOURCES=*.[ch] hashtable/*.[ch] TARGETS = mkfs.ubifs +MKFS_UBIFS_OBJS = $(addprefix $(BUILDDIR)/,\ + crc16.o lpt.o compr.o devtable.o \ + hashtable/hashtable.o hashtable/hashtable_itr.o) + ifeq ($(WITHOUT_LZO), 1) CPPFLAGS += -DWITHOUT_LZO else LZOLDLIBS = -llzo2 endif -LDLIBS_mkfs.ubifs = -lz $(LZOLDLIBS) -lm -luuid -L$(BUILDDIR)/../ubi-utils/ -lubi +ifeq ($(WITHOUT_XZ), 1) + CPPFLAGS += -DWITHOUT_XZ +else +ifneq ($(LZMA_STATIC_LIB),) + MKFS_UBIFS_OBJS += $(LZMA_STATIC_LIB) +else + XZLDLIBS = -llzma +endif +endif + +LDLIBS_mkfs.ubifs = -lz $(LZOLDLIBS) $(XZLDLIBS) -lm -luuid -L$(BUILDDIR)/../ubi-utils/ -lubi LDLIBS_mkfs.ubifs += -L$(BUILDDIR)/../lib -lmtd -LDLIBS_mkfs.ubifs += $(ZLIBLDFLAGS) $(LZOLDFLAGS) +LDLIBS_mkfs.ubifs += $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(XZLDFLAGS) include ../common.mk -$(BUILDDIR)/mkfs.ubifs: $(addprefix $(BUILDDIR)/,\ - crc16.o lpt.o compr.o devtable.o \ - hashtable/hashtable.o hashtable/hashtable_itr.o) +$(BUILDDIR)/mkfs.ubifs: $(MKFS_UBIFS_OBJS) clean:: rm -f $(BUILDDIR)/hashtable/*.o cscope.* --- a/mkfs.ubifs/mkfs.ubifs.c +++ b/mkfs.ubifs/mkfs.ubifs.c @@ -98,6 +98,9 @@ struct ubifs_info info_; static struct ubifs_info *c = &info_; static libubi_t ubi; +static int force_compr_set; +static int force_compr; + /* Debug levels are: 0 (none), 1 (statistics), 2 (files) ,3 (more details) */ int debug_level; int verbose; @@ -132,7 +135,7 @@ static struct inum_mapping **hash_table; /* Inode creation sequence number */ static unsigned long long creat_sqnum; -static const char *optstring = "d:r:m:o:D:h?vVe:c:g:f:Fp:k:x:X:j:R:l:j:UQq"; +static const char *optstring = "d:r:m:o:D:h?vVe:c:g:f:Fp:k:x:X:y:j:R:l:j:UQq"; static const struct option longopts[] = { {"root", 1, NULL, 'r'}, @@ -149,6 +152,7 @@ static const struct option longopts[] = {"reserved", 1, NULL, 'R'}, {"compr", 1, NULL, 'x'}, {"favor-percent", 1, NULL, 'X'}, + {"force-compr", 1, NULL, 'y'}, {"fanout", 1, NULL, 'f'}, {"space-fixup", 0, NULL, 'F'}, {"keyhash", 1, NULL, 'k'}, @@ -178,11 +182,13 @@ static const char *helptext = "-o, --output=FILE output to FILE\n" "-j, --jrn-size=SIZE journal size\n" "-R, --reserved=SIZE how much space should be reserved for the super-user\n" -"-x, --compr=TYPE compression type - \"lzo\", \"favor_lzo\", \"zlib\" or\n" -" \"none\" (default: \"lzo\")\n" +"-x, --compr=TYPE default compression type - \"lzo\", \"favor_lzo\",\n" +" \"zlib\" or \"none\" (default: \"lzo\")\n" "-X, --favor-percent may only be used with favor LZO compression and defines\n" " how many percent better zlib should compress to make\n" " mkfs.ubifs use zlib instead of LZO (default 20%)\n" +"-y, --force-compr=TYPE force to build the fs with different compression -\n" +" \"lzo\", \"zlib\" or \"none\"\n" "-f, --fanout=NUM fanout NUM (default: 8)\n" "-F, --space-fixup file-system free space has to be fixed up on first mount\n" " (requires kernel version 3.0 or greater)\n" @@ -530,6 +536,43 @@ static int open_ubi(const char *node) return 0; } +static const char *get_compr_str(int compr) +{ + switch (compr) { + case UBIFS_COMPR_LZO: + return "lzo"; + case UBIFS_COMPR_ZLIB: + return "zlib"; + case UBIFS_COMPR_XZ: + return "xz"; + case UBIFS_COMPR_NONE: + return "none"; + } + + return "unknown"; +} + +static int get_compr_option(char *opt, int *compr_type, int *favor_lzo) +{ + *compr_type = UBIFS_COMPR_LZO; + + if (favor_lzo) + *favor_lzo = 0; + + if (favor_lzo && strcmp(optarg, "favor_lzo") == 0) + *favor_lzo = 1; + else if (strcmp(optarg, "zlib") == 0) + *compr_type = UBIFS_COMPR_ZLIB; + else if (strcmp(optarg, "xz") == 0) + *compr_type = UBIFS_COMPR_XZ; + else if (strcmp(optarg, "none") == 0) + *compr_type = UBIFS_COMPR_NONE; + else if (strcmp(optarg, "lzo") != 0) + return -1; + + return 0; +} + static int get_options(int argc, char**argv) { int opt, i; @@ -649,14 +692,13 @@ static int get_options(int argc, char**a return err_msg("bad key hash"); break; case 'x': - if (strcmp(optarg, "favor_lzo") == 0) - c->favor_lzo = 1; - else if (strcmp(optarg, "zlib") == 0) - c->default_compr = UBIFS_COMPR_ZLIB; - else if (strcmp(optarg, "none") == 0) - c->default_compr = UBIFS_COMPR_NONE; - else if (strcmp(optarg, "lzo") != 0) - return err_msg("bad compressor name"); + if (get_compr_option(optarg, &c->default_compr, + &c->favor_lzo)) + return err_msg("bad compressor name '%s'", + optarg); + if (c->default_compr == UBIFS_COMPR_XZ) + return err_msg("'%s' can't be used as default compressor", + optarg); break; case 'X': c->favor_percent = strtol(optarg, &endp, 0); @@ -665,6 +707,12 @@ static int get_options(int argc, char**a return err_msg("bad favor LZO percent '%s'", optarg); break; + case 'y': + if (get_compr_option(optarg, &force_compr, NULL)) + return err_msg("bad forced compressor name '%s'", + optarg); + force_compr_set = 1; + break; case 'j': c->max_bud_bytes = get_bytes(optarg); if (c->max_bud_bytes <= 0) @@ -749,6 +797,9 @@ static int get_options(int argc, char**a c->min_io_size = 8; c->rp_size = add_space_overhead(c->rp_size); + if (force_compr_set == 0) + force_compr = c->default_compr; + if (verbose) { printf("mkfs.ubifs\n"); printf("\troot: %s\n", root); @@ -758,17 +809,10 @@ static int get_options(int argc, char**a printf("\toutput: %s\n", output); printf("\tjrn_size: %llu\n", c->max_bud_bytes); printf("\treserved: %llu\n", c->rp_size); - switch (c->default_compr) { - case UBIFS_COMPR_LZO: - printf("\tcompr: lzo\n"); - break; - case UBIFS_COMPR_ZLIB: - printf("\tcompr: zlib\n"); - break; - case UBIFS_COMPR_NONE: - printf("\tcompr: none\n"); - break; - } + printf("\tcompr: %s\n", get_compr_str(c->default_compr)); + if (force_compr_set) + printf("\tforced compr: %s\n", + get_compr_str(force_compr)); printf("\tkeyhash: %s\n", (c->key_hash == key_r5_hash) ? "r5" : "test"); printf("\tfanout: %d\n", c->fanout); @@ -1353,7 +1397,7 @@ static int add_file(const char *path_nam use_compr = UBIFS_COMPR_LZO; else #endif - use_compr = c->default_compr; + use_compr = force_compr; compr_type = compress_data(buf, bytes_read, &dn->data, &out_len, use_compr); dn->compr_type = cpu_to_le16(compr_type); --- a/mkfs.ubifs/mkfs.ubifs.h +++ b/mkfs.ubifs/mkfs.ubifs.h @@ -77,6 +77,9 @@ #if MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB #error MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB #endif +#if MKFS_UBIFS_COMPR_XZ != UBIFS_COMPR_XZ +#error MKFS_UBIFS_COMPR_XZ != UBIFS_COMPR_XZ +#endif extern int verbose; extern int debug_level; --- a/mkfs.ubifs/ubifs-media.h +++ b/mkfs.ubifs/ubifs-media.h @@ -303,6 +303,7 @@ enum { UBIFS_COMPR_NONE, UBIFS_COMPR_LZO, UBIFS_COMPR_ZLIB, + UBIFS_COMPR_XZ, UBIFS_COMPR_TYPES_CNT, };