The underlay block storage could work in a stripe-like manner to improve performance and space efficiency.
EROFS on-disk layout is flexible enough for such use cases. Cc: Changpeng Liu <changpe...@tencent.com> Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com> --- include/erofs/cache.h | 3 +++ lib/cache.c | 25 ++++++++++++++++++++----- man/mkfs.erofs.1 | 3 +++ mkfs/main.c | 11 +++++++++++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/include/erofs/cache.h b/include/erofs/cache.h index d8559a8..6ff80ab 100644 --- a/include/erofs/cache.h +++ b/include/erofs/cache.h @@ -67,6 +67,9 @@ struct erofs_bufmgr { /* last mapped buffer block to accelerate erofs_mapbh() */ struct erofs_buffer_block *last_mapped_block; + + /* align data block addresses to multiples of `dsunit` */ + unsigned int dsunit; }; static inline const int get_alignsize(struct erofs_sb_info *sbi, int type, diff --git a/lib/cache.c b/lib/cache.c index cb05466..d3e2e62 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -156,10 +156,15 @@ static int erofs_bfind_for_attach(struct erofs_bufmgr *bmgr, bb = NULL; /* try to find a most-fit mapped buffer block first */ - if (size + inline_ext >= blksiz) + + if (__erofs_unlikely(bmgr->dsunit > 1)) { + used_before = blksiz - alignsize; + } else if (size + inline_ext >= blksiz) { goto skip_mapped; + } else { + used_before = rounddown(blksiz - (size + inline_ext), alignsize); + } - used_before = rounddown(blksiz - (size + inline_ext), alignsize); for (; used_before; --used_before) { struct list_head *bt = bmgr->mapped_buckets[type] + used_before; @@ -181,7 +186,7 @@ static int erofs_bfind_for_attach(struct erofs_bufmgr *bmgr, ret = __erofs_battach(cur, NULL, size, alignsize, inline_ext, true); if (ret < 0) { - DBG_BUGON(1); + DBG_BUGON(!(bmgr->dsunit > 1)); continue; } @@ -324,10 +329,20 @@ struct erofs_buffer_head *erofs_battach(struct erofs_buffer_head *bh, static void __erofs_mapbh(struct erofs_buffer_block *bb) { struct erofs_bufmgr *bmgr = bb->buffers.fsprivate; - erofs_blk_t blkaddr; + erofs_blk_t blkaddr = bmgr->tail_blkaddr; if (bb->blkaddr == NULL_ADDR) { - bb->blkaddr = bmgr->tail_blkaddr; + bb->blkaddr = blkaddr; + if (__erofs_unlikely(bmgr->dsunit > 1) && bb->type == DATA) { + struct erofs_buffer_block *pb = list_prev_entry(bb, list); + + bb->blkaddr = roundup(blkaddr, bmgr->dsunit); + if (pb != &bmgr->blkh && + pb->blkaddr + pb->buffers.nblocks >= blkaddr) { + DBG_BUGON(pb->blkaddr + pb->buffers.nblocks > blkaddr); + pb->buffers.nblocks = bb->blkaddr - pb->blkaddr; + } + } bmgr->last_mapped_block = bb; erofs_bupdate_mapped(bb); } diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1 index 0093839..ee84163 100644 --- a/man/mkfs.erofs.1 +++ b/man/mkfs.erofs.1 @@ -149,6 +149,9 @@ the given primary algorithm, alternative algorithms can be specified with are extended regular expressions, matched against absolute paths within the output filesystem, with no leading /. .TP +.BI "\-\-dsunit=" # +Align all data block addresses to multiples of #. +.TP .BI "\-\-exclude-path=" path Ignore file that matches the exact literal path. You may give multiple diff --git a/mkfs/main.c b/mkfs/main.c index 9ca7dad..1f4b7c6 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -86,6 +86,7 @@ static struct option long_options[] = { {"all-time", no_argument, NULL, 526}, {"sort", required_argument, NULL, 527}, {"hard-dereference", no_argument, NULL, 528}, + {"dsunit", required_argument, NULL, 529}, {0, 0, 0, 0}, }; @@ -162,6 +163,7 @@ static void usage(int argc, char **argv) " --blobdev=X specify an extra device X to store chunked data\n" " --chunksize=# generate chunk-based files with #-byte chunks\n" " --clean=X run full clean build (default) or:\n" + " --dsunit=# align all data block addresses to multiples of #\n" " --incremental=X run incremental build\n" " (X = data|rvsp; data=full data, rvsp=space is allocated\n" " and filled with zeroes)\n" @@ -243,6 +245,7 @@ static unsigned int rebuild_src_count; static LIST_HEAD(rebuild_src_list); static u8 fixeduuid[16]; static bool valid_fixeduuid; +static unsigned int dsunit; static int erofs_mkfs_feat_set_legacy_compress(bool en, const char *val, unsigned int vallen) @@ -856,6 +859,13 @@ static int mkfs_parse_options_cfg(int argc, char *argv[]) case 528: cfg.c_hard_dereference = true; break; + case 529: + dsunit = strtoul(optarg, &endptr, 0); + if (*endptr != '\0') { + erofs_err("invalid dsunit %s", optarg); + return -EINVAL; + } + break; case 'V': version(); exit(0); @@ -1318,6 +1328,7 @@ int main(int argc, char **argv) } sb_bh = NULL; } + g_sbi.bmgr->dsunit = dsunit; /* Use the user-defined UUID or generate one for clean builds */ if (valid_fixeduuid) -- 2.43.5