{"workers", required_argument, NULL, 520},
#endif
{"zfeature-bits", required_argument, NULL, 521},
+ {"clean", optional_argument, NULL, 522},
+ {"incremental", optional_argument, NULL, 523},
{0, 0, 0, 0},
};
" --all-root make all files owned by root\n"
" --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"
+ " --incremental=X run incremental build\n"
+ " (X = data|rvsp; data=full data, rvsp=space is allocated\n"
+ " and filled with zeroes)\n"
" --compress-hints=X specify a file to configure per-file compression strategy\n"
" --exclude-path=X avoid including file X (X = exact literal path)\n"
" --exclude-regex=X avoid including files that match X (X = regular expression)\n"
static struct erofs_tarfile erofstar = {
.global.xattrs = LIST_HEAD_INIT(erofstar.global.xattrs)
};
-static bool tar_mode, rebuild_mode;
+static bool tar_mode, rebuild_mode, incremental_mode;
+
+enum {
+ EROFS_MKFS_DATA_IMPORT_DEFAULT,
+ EROFS_MKFS_DATA_IMPORT_FULLDATA,
+ EROFS_MKFS_DATA_IMPORT_RVSP,
+ EROFS_MKFS_DATA_IMPORT_SPARSE,
+} dataimport_mode;
static unsigned int rebuild_src_count;
static LIST_HEAD(rebuild_src_list);
if (err)
return err;
break;
+ case 522:
+ case 523:
+ if (!optarg || !strcmp(optarg, "data")) {
+ dataimport_mode = EROFS_MKFS_DATA_IMPORT_FULLDATA;
+ } else if (!strcmp(optarg, "rvsp")) {
+ dataimport_mode = EROFS_MKFS_DATA_IMPORT_RVSP;
+ } else {
+ dataimport_mode = strtol(optarg, &endptr, 0);
+ if (errno || *endptr != '\0') {
+ erofs_err("invalid --%s=%s",
+ opt == 523 ? "incremental" : "clean", optarg);
+ return -EINVAL;
+ }
+ }
+ incremental_mode = (opt == 523);
+ break;
case 'V':
version();
exit(0);
sbi.feature_incompat = EROFS_FEATURE_INCOMPAT_ZERO_PADDING;
sbi.feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM |
EROFS_FEATURE_COMPAT_MTIME;
-
- /* generate a default uuid first */
- erofs_uuid_generate(sbi.uuid);
}
/* https://reproducible-builds.org/specs/source-date-epoch/ for more details */
return root;
}
-static int erofs_rebuild_load_trees(struct erofs_inode *root)
+static int erofs_mkfs_rebuild_load_trees(struct erofs_inode *root)
{
struct erofs_sb_info *src;
unsigned int extra_devices = 0;
erofs_blk_t nblocks;
int ret, idx;
+ enum erofs_rebuild_datamode datamode;
+
+ switch (dataimport_mode) {
+ case EROFS_MKFS_DATA_IMPORT_DEFAULT:
+ datamode = EROFS_REBUILD_DATA_BLOB_INDEX;
+ break;
+ case EROFS_MKFS_DATA_IMPORT_FULLDATA:
+ datamode = EROFS_REBUILD_DATA_FULL;
+ break;
+ case EROFS_MKFS_DATA_IMPORT_RVSP:
+ datamode = EROFS_REBUILD_DATA_RESVSP;
+ break;
+ default:
+ return -EINVAL;
+ }
list_for_each_entry(src, &rebuild_src_list, list) {
- ret = erofs_rebuild_load_tree(root, src,
- EROFS_REBUILD_DATA_BLOB_INDEX);
+ ret = erofs_rebuild_load_tree(root, src, datamode);
if (ret) {
erofs_err("failed to load %s", src->devname);
return ret;
extra_devices += src->extra_devices;
}
- if (extra_devices && extra_devices != rebuild_src_count) {
+ if (datamode != EROFS_REBUILD_DATA_BLOB_INDEX)
+ return 0;
+
+ if (extra_devices != rebuild_src_count) {
erofs_err("extra_devices(%u) is mismatched with source images(%u)",
extra_devices, rebuild_src_count);
return -EOPNOTSUPP;
static void erofs_mkfs_showsummaries(erofs_blk_t nblocks)
{
char uuid_str[37] = {};
+ char *incr = incremental_mode ? "new" : "total";
if (!(cfg.c_dbg_lvl > EROFS_ERR && cfg.c_showprogress))
return;
fprintf(stdout, "------\nFilesystem UUID: %s\n"
"Filesystem total blocks: %u (of %u-byte blocks)\n"
"Filesystem total inodes: %llu\n"
- "Filesystem total metadata blocks: %u\n"
- "Filesystem total deduplicated bytes (of source files): %llu\n",
+ "Filesystem %s metadata blocks: %u\n"
+ "Filesystem %s deduplicated bytes (of source files): %llu\n",
uuid_str, nblocks, 1U << sbi.blkszbits, sbi.inos | 0ULL,
- erofs_total_metablocks(),
- sbi.saved_by_deduplication | 0ULL);
+ incr, erofs_total_metablocks(),
+ incr, sbi.saved_by_deduplication | 0ULL);
}
int main(int argc, char **argv)
sbi.build_time_nsec = t.tv_usec;
}
- err = erofs_dev_open(&sbi, cfg.c_img_path, O_RDWR | O_TRUNC);
+ err = erofs_dev_open(&sbi, cfg.c_img_path, O_RDWR |
+ (incremental_mode ? 0 : O_TRUNC));
if (err) {
fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
return 1;
}
- if (tar_mode && !erofstar.index_mode) {
- err = erofs_diskbuf_init(1);
- if (err) {
- erofs_err("failed to initialize diskbuf: %s",
- strerror(-err));
- goto exit;
- }
- }
#ifdef WITH_ANDROID
if (cfg.fs_config_file &&
load_canned_fs_config(cfg.fs_config_file) < 0) {
if (cfg.c_random_pclusterblks)
srand(time(NULL));
#endif
- if (tar_mode && erofstar.index_mode) {
+ if (tar_mode) {
+ if (dataimport_mode == EROFS_MKFS_DATA_IMPORT_RVSP)
+ erofstar.rvsp_mode = true;
+ erofstar.dev = rebuild_src_count + 1;
+
if (erofstar.mapfile) {
err = erofs_blocklist_open(erofstar.mapfile, true);
if (err) {
erofs_err("failed to open %s", erofstar.mapfile);
goto exit;
}
- } else {
+ } else if (erofstar.index_mode) {
+ /*
+ * If mapfile is unspecified for tarfs index mode,
+ * 512-byte block size is enforced here.
+ */
sbi.blkszbits = 9;
}
}
sbi.blkszbits = src->blkszbits;
}
- sb_bh = erofs_reserve_sb();
- if (IS_ERR(sb_bh)) {
- err = PTR_ERR(sb_bh);
- goto exit;
+ if (!incremental_mode) {
+ sb_bh = erofs_reserve_sb();
+ if (IS_ERR(sb_bh)) {
+ err = PTR_ERR(sb_bh);
+ goto exit;
+ }
+ /* generate new UUIDs for clean builds */
+ erofs_uuid_generate(sbi.uuid);
+ } else {
+ union {
+ struct stat st;
+ erofs_blk_t startblk;
+ } u;
+
+ erofs_warn("EXPERIMENTAL incremental build in use. Use at your own risk!");
+ err = erofs_read_superblock(&sbi);
+ if (err) {
+ erofs_err("failed to read superblock of %s", sbi.devname);
+ goto exit;
+ }
+
+ err = erofs_io_fstat(&sbi.bdev, &u.st);
+ if (!err && S_ISREG(u.st.st_mode))
+ u.startblk = DIV_ROUND_UP(u.st.st_size, erofs_blksiz(&sbi));
+ else
+ u.startblk = sbi.primarydevice_blocks;
+ erofs_buffer_init(u.startblk);
+ sb_bh = NULL;
+ }
+
+ if (tar_mode && !erofstar.index_mode) {
+ err = erofs_diskbuf_init(1);
+ if (err) {
+ erofs_err("failed to initialize diskbuf: %s",
+ strerror(-err));
+ goto exit;
+ }
}
err = erofs_load_compress_hints(&sbi);
if (err < 0)
goto exit;
- err = erofs_rebuild_dump_tree(root, false);
+ err = erofs_rebuild_dump_tree(root, incremental_mode);
if (err < 0)
goto exit;
} else if (rebuild_mode) {
goto exit;
}
- err = erofs_rebuild_load_trees(root);
+ err = erofs_mkfs_rebuild_load_trees(root);
if (err)
goto exit;
- err = erofs_rebuild_dump_tree(root, false);
+ err = erofs_rebuild_dump_tree(root, incremental_mode);
if (err)
goto exit;
} else {