erofs-utils: generate preallocated extents for tarerofs
authorGao Xiang <hsiangkao@linux.alibaba.com>
Tue, 1 Aug 2023 13:27:55 +0000 (21:27 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 2 Aug 2023 02:22:50 +0000 (10:22 +0800)
It is also useful to fill data blocks from tarballs at runtime in
order to implement image lazy pulling.

Let's generate an additional mapfile for such use cases:
   mkfs.erofs --tar=0,MAPFILE IMAGE TARBALL

Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Reviewed-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230801132755.23997-1-hsiangkao@linux.alibaba.com
include/erofs/blobchunk.h
include/erofs/block_list.h
include/erofs/tar.h
lib/Makefile.am
lib/blobchunk.c
lib/block_list.c
lib/tar.c
mkfs/main.c

index 7c5645eb8d290bc2b4b7e12acf5274eb235866a8..010aee1ef9b86417ed1cee5a7b08891af8b9429d 100644 (file)
@@ -14,14 +14,13 @@ extern "C"
 
 #include "erofs/internal.h"
 
-struct erofs_blobchunk *erofs_get_unhashed_chunk(erofs_off_t chunksize,
-                       unsigned int device_id, erofs_blk_t blkaddr);
 int erofs_blob_write_chunk_indexes(struct erofs_inode *inode, erofs_off_t off);
 int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd);
-int erofs_blob_remap(struct erofs_sb_info *sbi);
+int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset);
+int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi);
 void erofs_blob_exit(void);
 int erofs_blob_init(const char *blobfile_path);
-int erofs_generate_devtable(struct erofs_sb_info *sbi);
+int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices);
 
 #ifdef __cplusplus
 }
index 78fab44ff941a007d1c852816443f8c5862ccb67..9f9975ebfee169c38140d51e20de835f4cb579c3 100644 (file)
@@ -13,9 +13,12 @@ extern "C"
 
 #include "internal.h"
 
+int erofs_blocklist_open(char *filename, bool srcmap);
+void erofs_blocklist_close(void);
+
+void tarerofs_blocklist_write(erofs_blk_t blkaddr, erofs_blk_t nblocks,
+                             erofs_off_t srcoff);
 #ifdef WITH_ANDROID
-int erofs_droid_blocklist_fopen(void);
-void erofs_droid_blocklist_fclose(void);
 void erofs_droid_blocklist_write(struct erofs_inode *inode,
                                 erofs_blk_t blk_start, erofs_blk_t nblocks);
 void erofs_droid_blocklist_write_tail_end(struct erofs_inode *inode,
index a14f8ac5f4dd23061a10000714fcd1f1134265ac..8d3f8decfc9b493a48c2bc48ab1e90d8edd4b6fd 100644 (file)
@@ -15,6 +15,7 @@ struct erofs_pax_header {
 
 struct erofs_tarfile {
        struct erofs_pax_header global;
+       char *mapfile;
 
        int fd;
        u64 offset;
index ebe466b8b30c468b6c18a4d7d9282b9647492c6c..7a5dc03a8f1a3301811abf5d4bf20b01a0aac4d9 100644 (file)
@@ -30,7 +30,8 @@ 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 \
-                     fragments.c rb_tree.c dedupe.c uuid_unparse.c uuid.c tar.c
+                     fragments.c rb_tree.c dedupe.c uuid_unparse.c uuid.c tar.c \
+                     block_list.c
 
 liberofs_la_CFLAGS = -Wall ${libuuid_CFLAGS} -I$(top_srcdir)/include
 if ENABLE_LZ4
index 4e4295eb317ff9bcb738ae2186404c244434f07e..cada5bb1f43a7c26b8ededb150f67cabd286336b 100644 (file)
@@ -20,13 +20,17 @@ struct erofs_blobchunk {
        };
        char            sha256[32];
        unsigned int    device_id;
-       erofs_off_t     chunksize;
+       union {
+               erofs_off_t     chunksize;
+               erofs_off_t     sourceoffset;
+       };
        erofs_blk_t     blkaddr;
 };
 
 static struct hashmap blob_hashmap;
 static FILE *blobfile;
 static erofs_blk_t remapped_base;
+static erofs_off_t datablob_size;
 static bool multidev;
 static struct erofs_buffer_head *bh_devt;
 struct erofs_blobchunk erofs_holechunk = {
@@ -34,8 +38,8 @@ struct erofs_blobchunk erofs_holechunk = {
 };
 static LIST_HEAD(unhashed_blobchunks);
 
-struct erofs_blobchunk *erofs_get_unhashed_chunk(erofs_off_t chunksize,
-               unsigned int device_id, erofs_blk_t blkaddr)
+static struct erofs_blobchunk *erofs_get_unhashed_chunk(unsigned int device_id,
+               erofs_blk_t blkaddr, erofs_off_t sourceoffset)
 {
        struct erofs_blobchunk *chunk;
 
@@ -43,9 +47,9 @@ struct erofs_blobchunk *erofs_get_unhashed_chunk(erofs_off_t chunksize,
        if (!chunk)
                return ERR_PTR(-ENOMEM);
 
-       chunk->chunksize = chunksize;
        chunk->device_id = device_id;
        chunk->blkaddr = blkaddr;
+       chunk->sourceoffset = sourceoffset;
        list_add_tail(&chunk->list, &unhashed_blobchunks);
        return chunk;
 }
@@ -78,7 +82,7 @@ static struct erofs_blobchunk *erofs_blob_getchunk(struct erofs_sb_info *sbi,
        blkpos = ftell(blobfile);
        DBG_BUGON(erofs_blkoff(sbi, blkpos));
 
-       if (multidev)
+       if (sbi->extra_devices)
                chunk->device_id = 1;
        else
                chunk->device_id = 0;
@@ -125,6 +129,7 @@ int erofs_blob_write_chunk_indexes(struct erofs_inode *inode,
        struct erofs_inode_chunk_index idx = {0};
        erofs_blk_t extent_start = EROFS_NULL_ADDR;
        erofs_blk_t extent_end, chunkblks;
+       erofs_off_t source_offset;
        unsigned int dst, src, unit;
        bool first_extent = true;
 
@@ -153,6 +158,9 @@ int erofs_blob_write_chunk_indexes(struct erofs_inode *inode,
                if (extent_start == EROFS_NULL_ADDR ||
                    idx.blkaddr != extent_end) {
                        if (extent_start != EROFS_NULL_ADDR) {
+                               tarerofs_blocklist_write(extent_start,
+                                               extent_end - extent_start,
+                                               source_offset);
                                erofs_droid_blocklist_write_extent(inode,
                                        extent_start,
                                        extent_end - extent_start,
@@ -160,6 +168,7 @@ int erofs_blob_write_chunk_indexes(struct erofs_inode *inode,
                                first_extent = false;
                        }
                        extent_start = idx.blkaddr;
+                       source_offset = chunk->sourceoffset;
                }
                extent_end = idx.blkaddr + chunkblks;
                idx.device_id = cpu_to_le16(chunk->device_id);
@@ -171,6 +180,9 @@ int erofs_blob_write_chunk_indexes(struct erofs_inode *inode,
                        memcpy(inode->chunkindexes + dst, &idx, sizeof(idx));
        }
        off = roundup(off, unit);
+       if (extent_start != EROFS_NULL_ADDR)
+               tarerofs_blocklist_write(extent_start, extent_end - extent_start,
+                                        source_offset);
        erofs_droid_blocklist_write_extent(inode, extent_start,
                        extent_start == EROFS_NULL_ADDR ?
                                        0 : extent_end - extent_start,
@@ -236,7 +248,7 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd)
        chunksize = 1ULL << chunkbits;
        count = DIV_ROUND_UP(inode->i_size, chunksize);
 
-       if (multidev)
+       if (sbi->extra_devices)
                inode->u.chunkformat |= EROFS_CHUNK_FORMAT_INDEXES;
        if (inode->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)
                unit = sizeof(struct erofs_inode_chunk_index);
@@ -320,46 +332,123 @@ err:
        return ret;
 }
 
-int erofs_blob_remap(struct erofs_sb_info *sbi)
+int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset)
+{
+       struct erofs_sb_info *sbi = inode->sbi;
+       unsigned int chunkbits = ilog2(inode->i_size - 1) + 1;
+       unsigned int count, unit, device_id;
+       erofs_off_t chunksize, len, pos;
+       erofs_blk_t blkaddr;
+       struct erofs_inode_chunk_index *idx;
+
+       if (chunkbits < sbi->blkszbits)
+               chunkbits = sbi->blkszbits;
+       if (chunkbits - sbi->blkszbits > EROFS_CHUNK_FORMAT_BLKBITS_MASK)
+               chunkbits = EROFS_CHUNK_FORMAT_BLKBITS_MASK + sbi->blkszbits;
+
+       inode->u.chunkformat |= chunkbits - sbi->blkszbits;
+       if (sbi->extra_devices) {
+               device_id = 1;
+               inode->u.chunkformat |= EROFS_CHUNK_FORMAT_INDEXES;
+               unit = sizeof(struct erofs_inode_chunk_index);
+               DBG_BUGON(erofs_blkoff(sbi, data_offset));
+               blkaddr = erofs_blknr(sbi, data_offset);
+       } else {
+               device_id = 0;
+               unit = EROFS_BLOCK_MAP_ENTRY_SIZE;
+               DBG_BUGON(erofs_blkoff(sbi, datablob_size));
+               blkaddr = erofs_blknr(sbi, datablob_size);
+               datablob_size += round_up(inode->i_size, erofs_blksiz(sbi));
+       }
+       chunksize = 1ULL << chunkbits;
+       count = DIV_ROUND_UP(inode->i_size, chunksize);
+
+       inode->extent_isize = count * unit;
+       idx = calloc(count, max(sizeof(*idx), sizeof(void *)));
+       if (!idx)
+               return -ENOMEM;
+       inode->chunkindexes = idx;
+
+       for (pos = 0; pos < inode->i_size; pos += len) {
+               struct erofs_blobchunk *chunk;
+
+               len = min_t(erofs_off_t, inode->i_size - pos, chunksize);
+
+               chunk = erofs_get_unhashed_chunk(device_id, blkaddr,
+                                                data_offset);
+               if (IS_ERR(chunk)) {
+                       free(inode->chunkindexes);
+                       inode->chunkindexes = NULL;
+                       return PTR_ERR(chunk);
+               }
+
+               *(void **)idx++ = chunk;
+               blkaddr += erofs_blknr(sbi, len);
+               data_offset += len;
+       }
+       inode->datalayout = EROFS_INODE_CHUNK_BASED;
+       return 0;
+}
+
+int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi)
 {
        struct erofs_buffer_head *bh;
        ssize_t length;
        erofs_off_t pos_in, pos_out;
        ssize_t ret;
 
-       fflush(blobfile);
-       length = ftell(blobfile);
-       if (length < 0)
-               return -errno;
-       if (multidev) {
-               struct erofs_deviceslot dis = {
-                       .blocks = erofs_blknr(sbi, length),
-               };
+       if (blobfile) {
+               fflush(blobfile);
+               length = ftell(blobfile);
+               if (length < 0)
+                       return -errno;
 
-               pos_out = erofs_btell(bh_devt, false);
-               ret = dev_write(sbi, &dis, pos_out, sizeof(dis));
-               if (ret)
-                       return ret;
+               if (sbi->extra_devices)
+                       sbi->devs[0].blocks = erofs_blknr(sbi, length);
+               else
+                       datablob_size = length;
+       }
+
+       if (sbi->extra_devices) {
+               unsigned int i;
 
+               pos_out = erofs_btell(bh_devt, false);
+               i = 0;
+               do {
+                       struct erofs_deviceslot dis = {
+                               .blocks = cpu_to_le32(sbi->devs[i].blocks),
+                       };
+                       int ret;
+
+                       ret = dev_write(sbi, &dis, pos_out, sizeof(dis));
+                       if (ret)
+                               return ret;
+                       pos_out += sizeof(dis);
+               } while (++i < sbi->extra_devices);
                bh_devt->op = &erofs_drop_directly_bhops;
                erofs_bdrop(bh_devt, false);
                return 0;
        }
-       if (!length)    /* bail out if there is no chunked data */
-               return 0;
-       bh = erofs_balloc(DATA, length, 0, 0);
+
+       bh = erofs_balloc(DATA, blobfile ? datablob_size : 0, 0, 0);
        if (IS_ERR(bh))
                return PTR_ERR(bh);
 
        erofs_mapbh(bh->block);
+
        pos_out = erofs_btell(bh, false);
-       pos_in = 0;
        remapped_base = erofs_blknr(sbi, pos_out);
-       ret = erofs_copy_file_range(fileno(blobfile), &pos_in,
-                                   sbi->devfd, &pos_out, length);
+       if (blobfile) {
+               pos_in = 0;
+               ret = erofs_copy_file_range(fileno(blobfile), &pos_in,
+                               sbi->devfd, &pos_out, datablob_size);
+               ret = ret < datablob_size ? -EIO : 0;
+       } else {
+               ret = 0;
+       }
        bh->op = &erofs_drop_directly_bhops;
        erofs_bdrop(bh, false);
-       return ret < length ? -EIO : 0;
+       return ret;
 }
 
 void erofs_blob_exit(void)
@@ -405,22 +494,25 @@ int erofs_blob_init(const char *blobfile_path)
        return 0;
 }
 
-int erofs_generate_devtable(struct erofs_sb_info *sbi)
+int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices)
 {
-       struct erofs_deviceslot dis;
-
-       if (!multidev)
+       if (!devices)
                return 0;
 
-       bh_devt = erofs_balloc(DEVT, sizeof(dis), 0, 0);
-       if (IS_ERR(bh_devt))
-               return PTR_ERR(bh_devt);
+       sbi->devs = calloc(devices, sizeof(sbi->devs[0]));
+       if (!sbi->devs)
+               return -ENOMEM;
 
-       dis = (struct erofs_deviceslot) {};
+       bh_devt = erofs_balloc(DEVT,
+               sizeof(struct erofs_deviceslot) * devices, 0, 0);
+       if (IS_ERR(bh_devt)) {
+               free(sbi->devs);
+               return PTR_ERR(bh_devt);
+       }
        erofs_mapbh(bh_devt->block);
        bh_devt->op = &erofs_skip_write_bhops;
        sbi->devt_slotoff = erofs_btell(bh_devt, false) / EROFS_DEVT_SLOT_SIZE;
-       sbi->extra_devices = 1;
+       sbi->extra_devices = devices;
        erofs_sb_set_device_table(sbi);
        return 0;
 }
index 896fb018945baec66fc98d6eb0e1bb7047f2f143..b45b553a72fa610d3df78ce187ad7119636af4a6 100644 (file)
@@ -3,7 +3,6 @@
  * Copyright (C), 2021, Coolpad Group Limited.
  * Created by Yue Hu <huyue2@yulong.com>
  */
-#ifdef WITH_ANDROID
 #include <stdio.h>
 #include <sys/stat.h>
 #include "erofs/block_list.h"
 #include "erofs/print.h"
 
 static FILE *block_list_fp;
+bool srcmap_enabled;
 
-int erofs_droid_blocklist_fopen(void)
+int erofs_blocklist_open(char *filename, bool srcmap)
 {
-       block_list_fp = fopen(cfg.block_list_file, "w");
+       block_list_fp = fopen(filename, "w");
 
        if (!block_list_fp)
-               return -1;
+               return -errno;
+       srcmap_enabled = srcmap;
        return 0;
 }
 
-void erofs_droid_blocklist_fclose(void)
+void erofs_blocklist_close(void)
 {
        if (!block_list_fp)
                return;
@@ -31,6 +32,18 @@ void erofs_droid_blocklist_fclose(void)
        block_list_fp = NULL;
 }
 
+/* XXX: really need to be cleaned up */
+void tarerofs_blocklist_write(erofs_blk_t blkaddr, erofs_blk_t nblocks,
+                             erofs_off_t srcoff)
+{
+       if (!block_list_fp || !nblocks || !srcmap_enabled)
+               return;
+
+       fprintf(block_list_fp, "%08x %8x %08" PRIx64 "\n",
+               blkaddr, nblocks, srcoff);
+}
+
+#ifdef WITH_ANDROID
 static void blocklist_write(const char *path, erofs_blk_t blk_start,
                            erofs_blk_t nblocks, bool first_extent,
                            bool last_extent)
index 3c145e57ced6df039ac144d7d5caca53f0052505..54ee33fd24237b6ca33a26890ea0cd53b3691012 100644 (file)
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -341,44 +341,6 @@ out:
        return ret;
 }
 
-int tarerofs_write_chunk_indexes(struct erofs_inode *inode, erofs_blk_t blkaddr)
-{
-       struct erofs_sb_info *sbi = inode->sbi;
-       unsigned int chunkbits = ilog2(inode->i_size - 1) + 1;
-       unsigned int count, unit;
-       erofs_off_t chunksize, len, pos;
-       struct erofs_inode_chunk_index *idx;
-
-       if (chunkbits < sbi->blkszbits)
-               chunkbits = sbi->blkszbits;
-       inode->u.chunkformat |= chunkbits - sbi->blkszbits;
-       inode->u.chunkformat |= EROFS_CHUNK_FORMAT_INDEXES;
-       chunksize = 1ULL << chunkbits;
-       count = DIV_ROUND_UP(inode->i_size, chunksize);
-
-       unit = sizeof(struct erofs_inode_chunk_index);
-       inode->extent_isize = count * unit;
-       idx = calloc(count, max(sizeof(*idx), sizeof(void *)));
-       if (!idx)
-               return -ENOMEM;
-       inode->chunkindexes = idx;
-
-       for (pos = 0; pos < inode->i_size; pos += len) {
-               struct erofs_blobchunk *chunk;
-
-               len = min_t(erofs_off_t, inode->i_size - pos, chunksize);
-
-               chunk = erofs_get_unhashed_chunk(chunksize, 1, blkaddr);
-               if (IS_ERR(chunk))
-                       return PTR_ERR(chunk);
-
-               *(void **)idx++ = chunk;
-               blkaddr += erofs_blknr(sbi, len);
-       }
-       inode->datalayout = EROFS_INODE_CHUNK_BASED;
-       return 0;
-}
-
 void tarerofs_remove_inode(struct erofs_inode *inode)
 {
        struct erofs_dentry *d;
@@ -608,7 +570,8 @@ restart:
                        eh.link = strndup(th.linkname, sizeof(th.linkname));
        }
 
-       if (tar->index_mode && erofs_blkoff(sbi, tar_offset + sizeof(th))) {
+       if (tar->index_mode && !tar->mapfile &&
+           erofs_blkoff(sbi, data_offset)) {
                erofs_err("invalid tar data alignment @ %llu", tar_offset);
                ret = -EIO;
                goto out;
@@ -710,8 +673,7 @@ new_inode:
                        inode->i_link = malloc(inode->i_size + 1);
                        memcpy(inode->i_link, eh.link, inode->i_size + 1);
                } else if (tar->index_mode) {
-                       ret = tarerofs_write_chunk_indexes(inode,
-                                       erofs_blknr(sbi, data_offset));
+                       ret = tarerofs_write_chunkes(inode, data_offset);
                        if (ret)
                                goto out;
                        if (erofs_lskip(tar->fd, inode->i_size)) {
@@ -763,47 +725,3 @@ invalid_tar:
        ret = -EIO;
        goto out;
 }
-
-static struct erofs_buffer_head *bh_devt;
-
-int tarerofs_reserve_devtable(struct erofs_sb_info *sbi, unsigned int devices)
-{
-       if (!devices)
-               return 0;
-
-       bh_devt = erofs_balloc(DEVT,
-               sizeof(struct erofs_deviceslot) * devices, 0, 0);
-       if (IS_ERR(bh_devt))
-               return PTR_ERR(bh_devt);
-
-       erofs_mapbh(bh_devt->block);
-       bh_devt->op = &erofs_skip_write_bhops;
-       sbi->devt_slotoff = erofs_btell(bh_devt, false) / EROFS_DEVT_SLOT_SIZE;
-       sbi->extra_devices = devices;
-       erofs_sb_set_device_table(sbi);
-       return 0;
-}
-
-int tarerofs_write_devtable(struct erofs_sb_info *sbi, struct erofs_tarfile *tar)
-{
-       erofs_off_t pos_out;
-       unsigned int i;
-
-       if (!sbi->extra_devices)
-               return 0;
-       pos_out = erofs_btell(bh_devt, false);
-       for (i = 0; i < sbi->extra_devices; ++i) {
-               struct erofs_deviceslot dis = {
-                       .blocks = erofs_blknr(sbi, tar->offset),
-               };
-               int ret;
-
-               ret = dev_write(sbi, &dis, pos_out, sizeof(dis));
-               if (ret)
-                       return ret;
-               pos_out += sizeof(dis);
-       }
-       bh_devt->op = &erofs_drop_directly_bhops;
-       erofs_bdrop(bh_devt, false);
-       return 0;
-}
index bc5ed877f0a46de65826a36a1832c3eacaaaa0a7..3809c71328d2491a2b7eb674ca2c9123bbc2ead6 100644 (file)
@@ -484,8 +484,11 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        break;
                case 20:
                        if (optarg && (!strcmp(optarg, "i") ||
-                                       !strcmp(optarg, "0")))
+                               !strcmp(optarg, "0") || !memcmp(optarg, "0,", 2))) {
                                erofstar.index_mode = true;
+                               if (!memcmp(optarg, "0,", 2))
+                                       erofstar.mapfile = strdup(optarg + 2);
+                       }
                        tar_mode = true;
                        break;
                case 21:
@@ -795,7 +798,8 @@ int main(int argc, char **argv)
                return 1;
        }
 
-       if (cfg.block_list_file && erofs_droid_blocklist_fopen() < 0) {
+       if (cfg.block_list_file &&
+           erofs_blocklist_open(cfg.block_list_file, false)) {
                erofs_err("failed to open %s", cfg.block_list_file);
                return 1;
        }
@@ -827,8 +831,18 @@ int main(int argc, char **argv)
        if (cfg.c_random_pclusterblks)
                srand(time(NULL));
 #endif
-       if (tar_mode && erofstar.index_mode)
-               sbi.blkszbits = 9;
+       if (tar_mode && erofstar.index_mode) {
+               if (erofstar.mapfile) {
+                       err = erofs_blocklist_open(erofstar.mapfile, true);
+                       if (err) {
+                               erofs_err("failed to open %s", erofstar.mapfile);
+                               goto exit;
+                       }
+               } else {
+                       sbi.blkszbits = 9;
+               }
+       }
+
        sb_bh = erofs_buffer_init();
        if (IS_ERR(sb_bh)) {
                err = PTR_ERR(sb_bh);
@@ -884,10 +898,8 @@ int main(int argc, char **argv)
                        return 1;
        }
 
-       if (tar_mode && erofstar.index_mode)
-               err = tarerofs_reserve_devtable(&sbi, 1);
-       else
-               err = erofs_generate_devtable(&sbi);
+       if ((erofstar.index_mode && !erofstar.mapfile) || cfg.c_blobdev_path)
+               err = erofs_mkfs_init_devices(&sbi, 1);
        if (err) {
                erofs_err("failed to generate device table: %s",
                          erofs_strerror(err));
@@ -942,11 +954,12 @@ int main(int argc, char **argv)
        root_nid = erofs_lookupnid(root_inode);
        erofs_iput(root_inode);
 
-       if (tar_mode)
-               tarerofs_write_devtable(&sbi, &erofstar);
-       if (cfg.c_chunkbits) {
+       if (erofstar.index_mode || cfg.c_chunkbits) {
                erofs_info("total metadata: %u blocks", erofs_mapbh(NULL));
-               err = erofs_blob_remap(&sbi);
+               if (erofstar.index_mode && !erofstar.mapfile)
+                       sbi.devs[0].blocks =
+                               BLK_ROUND_UP(&sbi, erofstar.offset);
+               err = erofs_mkfs_dump_blobs(&sbi);
                if (err)
                        goto exit;
        }
@@ -980,9 +993,7 @@ int main(int argc, char **argv)
 exit:
        z_erofs_compress_exit();
        z_erofs_dedupe_exit();
-#ifdef WITH_ANDROID
-       erofs_droid_blocklist_fclose();
-#endif
+       erofs_blocklist_close();
        dev_close(&sbi);
        erofs_cleanup_compress_hints();
        erofs_cleanup_exclude_rules();