Hi Xiang, On Wed, 24 Aug 2022 17:00:07 +0800 Gao Xiang <[email protected]> wrote:
> On Sun, Aug 21, 2022 at 09:57:25PM +0800, [email protected] wrote: > > From: Yue Hu <[email protected]> > > > > This approach can merge tail pclusters or the whole files into a special > > inode in order to achieve greater compression ratio. And an option of > > pcluster size is provided for different compression requirments. > > > > Meanwhile, we change to write the uncompressed data from 'clusterofs' > > when compressing files since it can benefit from in-place I/O. For now, > > this change goes with the fragments. > > > > Signed-off-by: Yue Hu <[email protected]> > > --- > > include/erofs/compress.h | 3 +- > > include/erofs/config.h | 3 +- > > include/erofs/fragments.h | 25 +++++++++ > > include/erofs/inode.h | 1 + > > include/erofs/internal.h | 1 + > > include/erofs_fs.h | 1 + > > lib/Makefile.am | 4 +- > > lib/compress.c | 108 ++++++++++++++++++++++++++++---------- > > lib/fragments.c | 58 ++++++++++++++++++++ > > lib/inode.c | 59 ++++++++++++++++----- > > mkfs/main.c | 64 +++++++++++++++++++--- > > 11 files changed, 277 insertions(+), 50 deletions(-) > > create mode 100644 include/erofs/fragments.h > > create mode 100644 lib/fragments.c > > > > diff --git a/include/erofs/compress.h b/include/erofs/compress.h > > index 24f6204..d17aadb 100644 > > --- a/include/erofs/compress.h > > +++ b/include/erofs/compress.h > > @@ -18,7 +18,8 @@ extern "C" > > #define EROFS_CONFIG_COMPR_MIN_SZ (32 * 1024) > > > > void z_erofs_drop_inline_pcluster(struct erofs_inode *inode); > > -int erofs_write_compressed_file(struct erofs_inode *inode); > > +int erofs_write_compressed_file_from_fd(struct erofs_inode *inode, int fd, > > + bool is_src); > > > > int z_erofs_compress_init(struct erofs_buffer_head *bh); > > int z_erofs_compress_exit(void); > > diff --git a/include/erofs/config.h b/include/erofs/config.h > > index 539d813..764b0f7 100644 > > --- a/include/erofs/config.h > > +++ b/include/erofs/config.h > > @@ -44,6 +44,7 @@ struct erofs_configure { > > char c_chunkbits; > > bool c_noinline_data; > > bool c_ztailpacking; > > + bool c_fragments; > > bool c_ignore_mtime; > > bool c_showprogress; > > > > @@ -62,7 +63,7 @@ struct erofs_configure { > > /* < 0, xattr disabled and INT_MAX, always use inline xattrs */ > > int c_inline_xattr_tolerance; > > > > - u32 c_pclusterblks_max, c_pclusterblks_def; > > + u32 c_pclusterblks_max, c_pclusterblks_def, c_pclusterblks_packed; > > u32 c_max_decompressed_extent_bytes; > > u32 c_dict_size; > > u64 c_unix_timestamp; > > diff --git a/include/erofs/fragments.h b/include/erofs/fragments.h > > new file mode 100644 > > index 0000000..913aa99 > > --- /dev/null > > +++ b/include/erofs/fragments.h > > @@ -0,0 +1,25 @@ > > +/* SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 */ > > +/* > > + * Copyright (C), 2022, Coolpad Group Limited. > > + */ > > +#ifndef __EROFS_FRAGMENTS_H > > +#define __EROFS_FRAGMENTS_H > > + > > +#ifdef __cplusplus > > +extern "C" > > +{ > > +#endif > > + > > +#include "erofs/internal.h" > > + > > +int z_erofs_pack_fragments(struct erofs_inode *inode, void *data, > > + unsigned int len); > > +struct erofs_inode *erofs_mkfs_build_fragments(void); > > +int erofs_fragments_init(void); > > +void erofs_fragments_exit(void); > > + > > +#ifdef __cplusplus > > +} > > +#endif > > + > > +#endif > > diff --git a/include/erofs/inode.h b/include/erofs/inode.h > > index 79b8d89..bf20cd3 100644 > > --- a/include/erofs/inode.h > > +++ b/include/erofs/inode.h > > @@ -22,6 +22,7 @@ unsigned int erofs_iput(struct erofs_inode *inode); > > erofs_nid_t erofs_lookupnid(struct erofs_inode *inode); > > struct erofs_inode *erofs_mkfs_build_tree_from_path(struct erofs_inode > > *parent, > > const char *path); > > +struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char > > *name); > > > > #ifdef __cplusplus > > } > > diff --git a/include/erofs/internal.h b/include/erofs/internal.h > > index 58590ed..2e834e5 100644 > > --- a/include/erofs/internal.h > > +++ b/include/erofs/internal.h > > @@ -212,6 +212,7 @@ struct erofs_inode { > > uint64_t capabilities; > > #endif > > erofs_off_t fragmentoff; > > + unsigned int fragment_size; > > }; > > > > static inline bool is_inode_layout_compression(struct erofs_inode *inode) > > diff --git a/include/erofs_fs.h b/include/erofs_fs.h > > index 2422e1c..997ac0c 100644 > > --- a/include/erofs_fs.h > > +++ b/include/erofs_fs.h > > @@ -267,6 +267,7 @@ struct erofs_inode_chunk_index { > > > > /* maximum supported size of a physical compression cluster */ > > #define Z_EROFS_PCLUSTER_MAX_SIZE (1024 * 1024) > > +#define Z_EROFS_PCLUSTER_MAX_BLKS (Z_EROFS_PCLUSTER_MAX_SIZE / > > EROFS_BLKSIZ) > > > > /* available compression algorithm types (for h_algorithmtype) */ > > enum { > > diff --git a/lib/Makefile.am b/lib/Makefile.am > > index 3fad357..95f1d55 100644 > > --- a/lib/Makefile.am > > +++ b/lib/Makefile.am > > @@ -22,12 +22,14 @@ noinst_HEADERS = $(top_srcdir)/include/erofs_fs.h \ > > $(top_srcdir)/include/erofs/trace.h \ > > $(top_srcdir)/include/erofs/xattr.h \ > > $(top_srcdir)/include/erofs/compress_hints.h \ > > + $(top_srcdir)/include/erofs/fragments.h \ > > $(top_srcdir)/lib/liberofs_private.h > > > > noinst_HEADERS += compressor.h > > liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c > > exclude.c \ > > namei.c data.c compress.c compressor.c zmap.c > > decompress.c \ > > - compress_hints.c hashmap.c sha256.c blobchunk.c dir.c > > + compress_hints.c hashmap.c sha256.c blobchunk.c dir.c \ > > + fragments.c > > liberofs_la_CFLAGS = -Wall -I$(top_srcdir)/include > > if ENABLE_LZ4 > > liberofs_la_CFLAGS += ${LZ4_CFLAGS} > > diff --git a/lib/compress.c b/lib/compress.c > > index fd02053..fde14f6 100644 > > --- a/lib/compress.c > > +++ b/lib/compress.c > > @@ -18,6 +18,7 @@ > > #include "compressor.h" > > #include "erofs/block_list.h" > > #include "erofs/compress_hints.h" > > +#include "erofs/fragments.h" > > > > static struct erofs_compress compresshandle; > > static unsigned int algorithmtype[2]; > > @@ -74,9 +75,9 @@ static void vle_write_indexes(struct > > z_erofs_vle_compress_ctx *ctx, > > if (!d1) { > > /* > > * A lcluster cannot have three parts with the middle one which > > - * is well-compressed for !ztailpacking cases. > > + * is well-compressed for !ztailpacking and !fragments cases. > > */ > > - DBG_BUGON(!raw && !cfg.c_ztailpacking); > > + DBG_BUGON(!raw && !cfg.c_ztailpacking && !cfg.c_fragments); > > This should be per-inode? Thanks for reviewing the patch, let me check this and below. Thanks. > > > type = raw ? Z_EROFS_VLE_CLUSTER_TYPE_PLAIN : > > Z_EROFS_VLE_CLUSTER_TYPE_HEAD; > > advise = cpu_to_le16(type << Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT); > > @@ -143,7 +144,7 @@ static int write_uncompressed_extent(struct > > z_erofs_vle_compress_ctx *ctx, > > unsigned int *len, char *dst) > > { > > int ret; > > - unsigned int count; > > + unsigned int count, offset, rcopied, rzeroed; > > > > /* reset clusterofs to 0 if permitted */ > > if (!erofs_sb_has_lz4_0padding() && ctx->clusterofs && > > @@ -153,11 +154,21 @@ static int write_uncompressed_extent(struct > > z_erofs_vle_compress_ctx *ctx, > > ctx->clusterofs = 0; > > } > > > > - /* write uncompressed data */ > > + /* > > + * write uncompressed data from clusterofs which can benefit from > > + * in-place I/O, loop shift right when to exceed EROFS_BLKSIZ. > > + */ > > count = min(EROFS_BLKSIZ, *len); > > > > - memcpy(dst, ctx->queue + ctx->head, count); > > - memset(dst + count, 0, EROFS_BLKSIZ - count); > > + offset = cfg.c_fragments ? ctx->clusterofs : 0; > > interlaced_offset; > > > + rcopied = min(EROFS_BLKSIZ - offset, count); > > + rzeroed = EROFS_BLKSIZ - offset - rcopied; > > + > > + memcpy(dst + offset, ctx->queue + ctx->head, rcopied); > > + memcpy(dst, ctx->queue + ctx->head + rcopied, count - rcopied); > > + > > + memset(dst + offset + rcopied, 0, rzeroed); > > + memset(dst + count - rcopied, 0, EROFS_BLKSIZ - count - rzeroed); > > > > erofs_dbg("Writing %u uncompressed data to block %u", > > count, ctx->blkaddr); > > @@ -167,8 +178,11 @@ static int write_uncompressed_extent(struct > > z_erofs_vle_compress_ctx *ctx, > > return count; > > } > > > > -static unsigned int z_erofs_get_max_pclusterblks(struct erofs_inode *inode) > > +static unsigned int z_erofs_get_max_pclusterblks(struct erofs_inode *inode, > > + bool is_src) > > is_src should be in erofs_inode as, for example, bool is_packed_inode, > or other likewise rather than passing another argument here. > > > { > > + if (cfg.c_fragments && !is_src) > > + return cfg.c_pclusterblks_packed; > > #ifndef NDEBUG > > if (cfg.c_random_pclusterblks) > > return 1 + rand() % cfg.c_pclusterblks_max; > > @@ -224,7 +238,7 @@ static void tryrecompress_trailing(void *in, unsigned > > int *insize, > > > > static int vle_compress_one(struct erofs_inode *inode, > > struct z_erofs_vle_compress_ctx *ctx, > > - bool final) > > + bool final, bool is_src) > > { > > struct erofs_compress *const h = &compresshandle; > > unsigned int len = ctx->tail - ctx->head; > > @@ -234,14 +248,19 @@ static int vle_compress_one(struct erofs_inode *inode, > > char *const dst = dstbuf + EROFS_BLKSIZ; > > > > while (len) { > > - unsigned int pclustersize = > > - z_erofs_get_max_pclusterblks(inode) * EROFS_BLKSIZ; > > + unsigned int pclustersize = EROFS_BLKSIZ * > > + z_erofs_get_max_pclusterblks(inode, is_src); > > bool may_inline = (cfg.c_ztailpacking && final); > > + bool may_packing = (cfg.c_fragments && final && is_src); > > bool raw; > > > > if (len <= pclustersize) { > > if (!final) > > break; > > + if (may_packing) { > > + count = len; > > + goto frag_packing; > > + } > > if (!may_inline && len <= EROFS_BLKSIZ) > > goto nocompression; > > } > > @@ -294,6 +313,19 @@ nocompression: > > return ret; > > ctx->compressedblks = 1; > > raw = false; > > + } else if (may_packing && len == count && ret < pclustersize) { > > +frag_packing: > > + ret = z_erofs_pack_fragments(inode, > > + ctx->queue + ctx->head, > > + len); > > + if (ret < 0) > > + return ret; > > + if (inode->i_size == inode->fragment_size) { > > + ctx->head += len; > > + return 0; > > + } > > + ctx->compressedblks = 0; > > + raw = false; > > } else { > > unsigned int tailused, padding; > > > > @@ -546,13 +578,20 @@ static void z_erofs_write_mapheader(struct > > erofs_inode *inode, > > { > > struct z_erofs_map_header h = { > > .h_advise = cpu_to_le16(inode->z_advise), > > - .h_idata_size = cpu_to_le16(inode->idata_size), > > .h_algorithmtype = inode->z_algorithmtype[1] << 4 | > > inode->z_algorithmtype[0], > > /* lclustersize */ > > .h_clusterbits = inode->z_logical_clusterbits - 12, > > }; > > > > + if (cfg.c_fragments) > > + h.h_fragmentoff = cpu_to_le32(inode->fragmentoff); > > + else > > + h.h_idata_size = cpu_to_le16(inode->idata_size); > > + > > + if (inode->fragment_size && inode->i_size == inode->fragment_size) > > + h.h_clusterbits |= 1 << Z_EROFS_FRAGMENT_INODE_BIT; > > + > > memset(compressmeta, 0, Z_EROFS_LEGACY_MAP_HEADER_SIZE); > > /* write out map header */ > > memcpy(compressmeta, &h, sizeof(struct z_erofs_map_header)); > > @@ -605,30 +644,25 @@ void z_erofs_drop_inline_pcluster(struct erofs_inode > > *inode) > > inode->eof_tailraw = NULL; > > } > > > > -int erofs_write_compressed_file(struct erofs_inode *inode) > > +int erofs_write_compressed_file_from_fd(struct erofs_inode *inode, int fd, > > + bool is_src) > > same here. > > > { > > struct erofs_buffer_head *bh; > > static struct z_erofs_vle_compress_ctx ctx; > > erofs_off_t remaining; > > erofs_blk_t blkaddr, compressed_blocks; > > unsigned int legacymetasize; > > - int ret, fd; > > + int ret; > > u8 *compressmeta = malloc(vle_compressmeta_capacity(inode->i_size)); > > > > if (!compressmeta) > > return -ENOMEM; > > > > - fd = open(inode->i_srcpath, O_RDONLY | O_BINARY); > > - if (fd < 0) { > > - ret = -errno; > > - goto err_free_meta; > > - } > > - > > /* allocate main data buffer */ > > bh = erofs_balloc(DATA, 0, 0, 0); > > if (IS_ERR(bh)) { > > ret = PTR_ERR(bh); > > - goto err_close; > > + goto err_free_meta; > > } > > > > /* initialize per-file compression setting */ > > @@ -649,6 +683,9 @@ int erofs_write_compressed_file(struct erofs_inode > > *inode) > > inode->z_algorithmtype[1] = algorithmtype[1]; > > inode->z_logical_clusterbits = LOG_BLOCK_SIZE; > > > > + inode->idata_size = 0; > > + inode->fragment_size = 0; > > + > > blkaddr = erofs_mapbh(bh->block); /* start_blkaddr */ > > ctx.blkaddr = blkaddr; > > ctx.metacur = compressmeta + Z_EROFS_LEGACY_MAP_HEADER_SIZE; > > @@ -668,7 +705,7 @@ int erofs_write_compressed_file(struct erofs_inode > > *inode) > > remaining -= readcount; > > ctx.tail += readcount; > > > > - ret = vle_compress_one(inode, &ctx, !remaining); > > + ret = vle_compress_one(inode, &ctx, !remaining, is_src); > > if (ret) > > goto err_free_idata; > > } > > @@ -682,19 +719,20 @@ int erofs_write_compressed_file(struct erofs_inode > > *inode) > > vle_write_indexes_final(&ctx); > > legacymetasize = ctx.metacur - compressmeta; > > /* estimate if data compression saves space or not */ > > - if (compressed_blocks * EROFS_BLKSIZ + inode->idata_size + > > + if (!inode->fragment_size && > > + compressed_blocks * EROFS_BLKSIZ + inode->idata_size + > > legacymetasize >= inode->i_size) { > > ret = -ENOSPC; > > goto err_free_idata; > > } > > z_erofs_write_mapheader(inode, compressmeta); > > > > - close(fd); > > if (compressed_blocks) { > > ret = erofs_bh_balloon(bh, blknr_to_addr(compressed_blocks)); > > DBG_BUGON(ret != EROFS_BLKSIZ); > > } else { > > - DBG_BUGON(!inode->idata_size); > > + if (!cfg.c_fragments) > > + DBG_BUGON(!inode->idata_size); > > } > > > > erofs_info("compressed %s (%llu bytes) into %u blocks", > > @@ -717,7 +755,8 @@ int erofs_write_compressed_file(struct erofs_inode > > *inode) > > DBG_BUGON(ret); > > } > > inode->compressmeta = compressmeta; > > - erofs_droid_blocklist_write(inode, blkaddr, compressed_blocks); > > + if (is_src) > > + erofs_droid_blocklist_write(inode, blkaddr, compressed_blocks); > > return 0; > > > > err_free_idata: > > @@ -727,8 +766,6 @@ err_free_idata: > > } > > err_bdrop: > > erofs_bdrop(bh, true); /* revoke buffer */ > > -err_close: > > - close(fd); > > err_free_meta: > > free(compressmeta); > > return ret; > > @@ -834,14 +871,27 @@ int z_erofs_compress_init(struct erofs_buffer_head > > *sb_bh) > > * to be loaded in order to get those compressed block counts. > > */ > > if (cfg.c_pclusterblks_max > 1) { > > - if (cfg.c_pclusterblks_max > > > - Z_EROFS_PCLUSTER_MAX_SIZE / EROFS_BLKSIZ) { > > + if (cfg.c_pclusterblks_max > Z_EROFS_PCLUSTER_MAX_BLKS) { > > erofs_err("unsupported clusterblks %u (too large)", > > cfg.c_pclusterblks_max); > > return -EINVAL; > > } > > + if (cfg.c_pclusterblks_packed > Z_EROFS_PCLUSTER_MAX_BLKS) { > > c_pclusterblks_packed should be smaller than > c_pclusterblks_max > > > + erofs_err("unsupported clusterblks %u (too large for > > fragments)", > > + cfg.c_pclusterblks_packed); > > + return -EINVAL; > > + } > > + if (cfg.c_pclusterblks_packed == 1) { > > + erofs_err("physical cluster size of fragments should > > > 4096 bytes"); > > + return -EINVAL; > > + } > > How can this happen? why judging this here? > > > erofs_sb_set_big_pcluster(); > > } > > + if (!erofs_sb_has_big_pcluster() && cfg.c_pclusterblks_packed > 1) { > > + erofs_err("invalid clusterblks %u (for fragments)", > > + cfg.c_pclusterblks_packed); > > + return -EINVAL; > > + } > > The only condition I think would be > > if (c_pclusterblks_packed > cfg.c_pclusterblks_max) { > erofs_err("invalid physical cluster size for the packed file"); > } > > > > > > > if (ret != Z_EROFS_COMPRESSION_LZ4) > > erofs_sb_set_compr_cfgs(); > > diff --git a/lib/fragments.c b/lib/fragments.c > > new file mode 100644 > > index 0000000..73c0d1b > > --- /dev/null > > +++ b/lib/fragments.c > > @@ -0,0 +1,58 @@ > > +// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 > > +/* > > + * Copyright (C), 2022, Coolpad Group Limited. > > + * Created by Yue Hu <[email protected]> > > + */ > > +#define _GNU_SOURCE > > +#include <stdlib.h> > > +#include <unistd.h> > > +#include "erofs/err.h" > > +#include "erofs/inode.h" > > +#include "erofs/compress.h" > > +#include "erofs/print.h" > > +#include "erofs/fragments.h" > > + > > +static FILE *packedfile; > > + > > +int z_erofs_pack_fragments(struct erofs_inode *inode, void *data, > > + unsigned int len) > > +{ > > + inode->z_advise |= Z_EROFS_ADVISE_FRAGMENT_PCLUSTER; > > + inode->fragmentoff = ftell(packedfile); > > + inode->fragment_size = len; > > + > > + if (write(fileno(packedfile), data, len) < 0) > > + return -EIO; > > + > > + erofs_sb_set_fragments(); > > + > > + erofs_dbg("Recording %u fragment data at %lu", inode->fragment_size, > > + inode->fragmentoff); > > + return len; > > +} > > + > > +struct erofs_inode *erofs_mkfs_build_fragments(void) > > +{ > > + fseek(packedfile, 0, SEEK_SET); > > + > > + return erofs_mkfs_build_special_from_fd(fileno(packedfile), > > + "packed_file"); > > +} > > + > > +void erofs_fragments_exit(void) > > +{ > > + if (packedfile) > > + fclose(packedfile); > > +} > > + > > +int erofs_fragments_init(void) > > +{ > > +#ifdef HAVE_TMPFILE64 > > + packedfile = tmpfile64(); > > +#else > > + packedfile = tmpfile(); > > +#endif > > + if (!packedfile) > > + return -ENOMEM; > > + return 0; > > +} > > diff --git a/lib/inode.c b/lib/inode.c > > index 4da28b3..e6f3dfa 100644 > > --- a/lib/inode.c > > +++ b/lib/inode.c > > @@ -424,7 +424,11 @@ int erofs_write_file(struct erofs_inode *inode) > > } > > > > if (cfg.c_compr_alg_master && erofs_file_is_compressible(inode)) { > > - ret = erofs_write_compressed_file(inode); > > + fd = open(inode->i_srcpath, O_RDONLY | O_BINARY); > > + if (fd < 0) > > + return -errno; > > + ret = erofs_write_compressed_file_from_fd(inode, fd, true); > > + close(fd); > > > > if (!ret || ret != -ENOSPC) > > return ret; > > @@ -935,6 +939,24 @@ static struct erofs_inode *erofs_new_inode(void) > > return inode; > > } > > > > +static struct erofs_inode *erofs_generate_inode(struct stat64 *st, > > + const char *path) > > let's avoid such helper, since it doesn't simplify a lot. > > Thanks, > Gao Xiang > > > +{ > > + struct erofs_inode *inode; > > + int ret; > > + > > + inode = erofs_new_inode(); > > + if (IS_ERR(inode)) > > + return inode; > > + > > + ret = erofs_fill_inode(inode, st, path); > > + if (ret) { > > + free(inode); > > + return ERR_PTR(ret); > > + } > > + return inode; > > +} > > + > > /* get the inode from the (source) path */ > > static struct erofs_inode *erofs_iget_from_path(const char *path, bool > > is_src) > > { > > @@ -962,17 +984,7 @@ static struct erofs_inode *erofs_iget_from_path(const > > char *path, bool is_src) > > } > > > > /* cannot find in the inode cache */ > > - inode = erofs_new_inode(); > > - if (IS_ERR(inode)) > > - return inode; > > - > > - ret = erofs_fill_inode(inode, &st, path); > > - if (ret) { > > - free(inode); > > - return ERR_PTR(ret); > > - } > > - > > - return inode; > > + return erofs_generate_inode(&st, path); > > } > > > > static void erofs_fixup_meta_blkaddr(struct erofs_inode *rootdir) > > @@ -1180,3 +1192,26 @@ struct erofs_inode > > *erofs_mkfs_build_tree_from_path(struct erofs_inode *parent, > > > > return erofs_mkfs_build_tree(inode); > > } > > + > > +struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char > > *name) > > +{ > > + struct stat64 st; > > + struct erofs_inode *inode; > > + int ret; > > + > > + ret = fstat64(fd, &st); > > + if (ret) > > + return ERR_PTR(-errno); > > + > > + inode = erofs_generate_inode(&st, name); > > + if (IS_ERR(inode)) > > + return inode; > > + > > + /* only for compressed file now */ > > + ret = erofs_write_compressed_file_from_fd(inode, fd, false); > > + if (ret) > > + return ERR_PTR(ret); > > + > > + erofs_prepare_inode_buffer(inode); > > + return inode; > > +} > > diff --git a/mkfs/main.c b/mkfs/main.c > > index b969b35..cfc2c4a 100644 > > --- a/mkfs/main.c > > +++ b/mkfs/main.c > > @@ -23,6 +23,7 @@ > > #include "erofs/block_list.h" > > #include "erofs/compress_hints.h" > > #include "erofs/blobchunk.h" > > +#include "erofs/fragments.h" > > #include "../lib/liberofs_private.h" > > > > #ifdef HAVE_LIBUUID > > @@ -133,9 +134,9 @@ static int parse_extended_opts(const char *opts) > > const char *p = strchr(token, ','); > > > > next = NULL; > > - if (p) > > + if (p) { > > next = p + 1; > > - else { > > + } else { > > p = token + strlen(token); > > next = p; > > } > > @@ -202,7 +203,34 @@ static int parse_extended_opts(const char *opts) > > return -EINVAL; > > cfg.c_ztailpacking = true; > > } > > + > > + if (MATCH_EXTENTED_OPT("fragments", token, keylen)) { > > + char *endptr; > > + u64 i; > > + > > + if (vallen || cfg.c_ztailpacking) > > + return -EINVAL; > > + cfg.c_fragments = true; > > + > > + i = strtoull(next, &endptr, 0); > > + if (i == 0 || (*endptr != ',' && *endptr != '\0')) { > > + cfg.c_pclusterblks_packed = 1; > > + continue; > > + } > > + if (i % EROFS_BLKSIZ) { > > + erofs_err("invalid physical clustersize %llu", > > + i); > > + return -EINVAL; > > + } > > + cfg.c_pclusterblks_packed = i / EROFS_BLKSIZ; > > + > > + if (*endptr == ',') > > + next = strchr(next, ',') + 1; > > + else > > + goto out; > > + } > > } > > +out: > > return 0; > > } > > > > @@ -458,7 +486,8 @@ static int mkfs_parse_options_cfg(int argc, char > > *argv[]) > > > > int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh, > > erofs_nid_t root_nid, > > - erofs_blk_t *blocks) > > + erofs_blk_t *blocks, > > + erofs_nid_t packed_nid) > > { > > struct erofs_super_block sb = { > > .magic = cpu_to_le32(EROFS_SUPER_MAGIC_V1), > > @@ -482,6 +511,7 @@ int erofs_mkfs_update_super_block(struct > > erofs_buffer_head *bh, > > *blocks = erofs_mapbh(NULL); > > sb.blocks = cpu_to_le32(*blocks); > > sb.root_nid = cpu_to_le16(root_nid); > > + sb.packed_nid = cpu_to_le64(packed_nid); > > memcpy(sb.uuid, sbi.uuid, sizeof(sb.uuid)); > > > > if (erofs_sb_has_compr_cfgs()) > > @@ -599,8 +629,8 @@ int main(int argc, char **argv) > > { > > int err = 0; > > struct erofs_buffer_head *sb_bh; > > - struct erofs_inode *root_inode; > > - erofs_nid_t root_nid; > > + struct erofs_inode *root_inode, *packed_inode; > > + erofs_nid_t root_nid, packed_nid; > > struct stat64 st; > > erofs_blk_t nblocks; > > struct timeval t; > > @@ -670,6 +700,14 @@ int main(int argc, char **argv) > > erofs_warn("EXPERIMENTAL chunked file feature in use. Use at > > your own risk!"); > > if (cfg.c_ztailpacking) > > erofs_warn("EXPERIMENTAL compressed inline data feature in use. > > Use at your own risk!"); > > + if (cfg.c_fragments) { > > + err = erofs_fragments_init(); > > + if (err) { > > + erofs_err("failed to initialize fragments"); > > + return 1; > > + } > > + erofs_warn("EXPERIMENTAL compressed fragments feature in use. > > Use at your own risk!"); > > + } > > erofs_set_fs_root(cfg.c_src_path); > > #ifndef NDEBUG > > if (cfg.c_random_pclusterblks) > > @@ -739,7 +777,19 @@ int main(int argc, char **argv) > > goto exit; > > } > > > > - err = erofs_mkfs_update_super_block(sb_bh, root_nid, &nblocks); > > + packed_nid = 0; > > + if (cfg.c_fragments) { > > + packed_inode = erofs_mkfs_build_fragments(); > > + if (IS_ERR(packed_inode)) { > > + err = PTR_ERR(packed_inode); > > + goto exit; > > + } > > + packed_nid = erofs_lookupnid(packed_inode); > > + erofs_iput(packed_inode); > > + } > > + > > + err = erofs_mkfs_update_super_block(sb_bh, root_nid, &nblocks, > > + packed_nid); > > if (err) > > goto exit; > > > > @@ -761,6 +811,8 @@ exit: > > erofs_cleanup_exclude_rules(); > > if (cfg.c_chunkbits) > > erofs_blob_exit(); > > + if (cfg.c_fragments) > > + erofs_fragments_exit(); > > erofs_exit_configure(); > > > > if (err) { > > -- > > 2.17.1
