A new mode is prepared in order to preallocate/reserve data blocks only
since some applications tend to fill data after EROFS images are built.

Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com>
---
 include/erofs/internal.h |  7 +++-
 include/erofs/rebuild.h  |  9 ++++-
 lib/inode.c              | 45 +++++++++++++++++----
 lib/rebuild.c            | 84 ++++++++++++++++++++++++----------------
 lib/tar.c                |  2 +-
 mkfs/main.c              |  3 +-
 6 files changed, 104 insertions(+), 46 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 39cf066..1d6496a 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -170,6 +170,11 @@ EROFS_FEATURE_FUNCS(xattr_filter, compat, 
COMPAT_XATTR_FILTER)
 
 struct erofs_diskbuf;
 
+#define EROFS_INODE_DATA_SOURCE_NONE           0
+#define EROFS_INODE_DATA_SOURCE_LOCALPATH      1
+#define EROFS_INODE_DATA_SOURCE_DISKBUF                2
+#define EROFS_INODE_DATA_SOURCE_RESVSP         3
+
 struct erofs_inode {
        struct list_head i_hash, i_subdirs, i_xattrs;
 
@@ -216,9 +221,9 @@ struct erofs_inode {
        unsigned char inode_isize;
        /* inline tail-end packing size */
        unsigned short idata_size;
+       char datasource;
        bool compressed_idata;
        bool lazy_tailblock;
-       bool with_diskbuf;
        bool opaque;
        /* OVL: non-merge dir that may contain whiteout entries */
        bool whiteouts;
diff --git a/include/erofs/rebuild.h b/include/erofs/rebuild.h
index e99ce74..59b2f6f 100644
--- a/include/erofs/rebuild.h
+++ b/include/erofs/rebuild.h
@@ -9,10 +9,17 @@ extern "C"
 
 #include "internal.h"
 
+enum erofs_rebuild_datamode {
+       EROFS_REBUILD_DATA_BLOB_INDEX,
+       EROFS_REBUILD_DATA_RESVSP,
+       EROFS_REBUILD_DATA_FULL,
+};
+
 struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
                char *path, bool aufs, bool *whout, bool *opq, bool to_head);
 
-int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_sb_info 
*sbi);
+int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_sb_info 
*sbi,
+                           enum erofs_rebuild_datamode mode);
 
 #ifdef __cplusplus
 }
diff --git a/lib/inode.c b/lib/inode.c
index 6c4fa2a..60a076a 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -143,7 +143,8 @@ unsigned int erofs_iput(struct erofs_inode *inode)
        list_del(&inode->i_hash);
        if (inode->i_srcpath)
                free(inode->i_srcpath);
-       if (inode->with_diskbuf) {
+
+       if (inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF) {
                erofs_diskbuf_close(inode->i_diskbuf);
                free(inode->i_diskbuf);
        } else if (inode->i_link) {
@@ -1175,6 +1176,30 @@ static void erofs_fixup_meta_blkaddr(struct erofs_inode 
*rootdir)
        rootdir->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
 }
 
+static int erofs_inode_reserve_data_blocks(struct erofs_inode *inode)
+{
+       struct erofs_sb_info *sbi = inode->sbi;
+       erofs_off_t alignedsz = round_up(inode->i_size, erofs_blksiz(sbi));
+       erofs_blk_t nblocks = alignedsz >> sbi->blkszbits;
+       struct erofs_buffer_head *bh;
+
+       /* allocate data blocks */
+       bh = erofs_balloc(DATA, alignedsz, 0, 0);
+       if (IS_ERR(bh))
+               return PTR_ERR(bh);
+
+       /* get blkaddr of the bh */
+       (void)erofs_mapbh(bh->block);
+
+       /* write blocks except for the tail-end block */
+       inode->u.i_blkaddr = bh->block->blkaddr;
+       erofs_bdrop(bh, false);
+
+       inode->datalayout = EROFS_INODE_FLAT_PLAIN;
+       tarerofs_blocklist_write(inode->u.i_blkaddr, nblocks, inode->i_ino[1]);
+       return 0;
+}
+
 struct erofs_mkfs_job_ndir_ctx {
        struct erofs_inode *inode;
        void *ictx;
@@ -1187,7 +1212,8 @@ static int erofs_mkfs_job_write_file(struct 
erofs_mkfs_job_ndir_ctx *ctx)
        struct erofs_inode *inode = ctx->inode;
        int ret;
 
-       if (inode->with_diskbuf && lseek(ctx->fd, ctx->fpos, SEEK_SET) < 0) {
+       if (inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF &&
+           lseek(ctx->fd, ctx->fpos, SEEK_SET) < 0) {
                ret = -errno;
                goto out;
        }
@@ -1204,11 +1230,11 @@ static int erofs_mkfs_job_write_file(struct 
erofs_mkfs_job_ndir_ctx *ctx)
        /* fallback to all data uncompressed */
        ret = erofs_write_unencoded_file(inode, ctx->fd, ctx->fpos);
 out:
-       if (inode->with_diskbuf) {
+       if (inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF) {
                erofs_diskbuf_close(inode->i_diskbuf);
                free(inode->i_diskbuf);
                inode->i_diskbuf = NULL;
-               inode->with_diskbuf = false;
+               inode->datasource = EROFS_INODE_DATA_SOURCE_NONE;
        } else {
                close(ctx->fd);
        }
@@ -1236,8 +1262,11 @@ static int erofs_mkfs_handle_nondirectory(struct 
erofs_mkfs_job_ndir_ctx *ctx)
                ret = erofs_write_file_from_buffer(inode, symlink);
                free(symlink);
                inode->i_link = NULL;
-       } else if (inode->i_size && ctx->fd >= 0) {
-               ret = erofs_mkfs_job_write_file(ctx);
+       } else if (inode->i_size) {
+               if (inode->datasource == EROFS_INODE_DATA_SOURCE_RESVSP)
+                       ret = erofs_inode_reserve_data_blocks(inode);
+               else if (ctx->fd >= 0)
+                       ret = erofs_mkfs_job_write_file(ctx);
        }
        if (ret)
                return ret;
@@ -1628,8 +1657,8 @@ static int erofs_rebuild_handle_inode(struct erofs_inode 
*inode,
                struct erofs_mkfs_job_ndir_ctx ctx =
                        { .inode = inode, .fd = -1 };
 
-               if (!S_ISLNK(inode->i_mode) && inode->i_size &&
-                   inode->with_diskbuf) {
+               if (S_ISREG(inode->i_mode) && inode->i_size &&
+                   inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF) {
                        ctx.fd = erofs_diskbuf_getfd(inode->i_diskbuf, 
&ctx.fpos);
                        if (ctx.fd < 0)
                                return ret;
diff --git a/lib/rebuild.c b/lib/rebuild.c
index 6f2e301..9c1e8f8 100644
--- a/lib/rebuild.c
+++ b/lib/rebuild.c
@@ -128,7 +128,8 @@ struct erofs_dentry *erofs_rebuild_get_dentry(struct 
erofs_inode *pwd,
        return d;
 }
 
-static int erofs_rebuild_fixup_inode_index(struct erofs_inode *inode)
+static int erofs_rebuild_write_blob_index(struct erofs_sb_info *dst_sb,
+                                         struct erofs_inode *inode)
 {
        int ret;
        unsigned int count, unit, chunkbits, i;
@@ -137,26 +138,26 @@ static int erofs_rebuild_fixup_inode_index(struct 
erofs_inode *inode)
        erofs_blk_t blkaddr;
 
        /* TODO: fill data map in other layouts */
-       if (inode->datalayout != EROFS_INODE_CHUNK_BASED &&
-           inode->datalayout != EROFS_INODE_FLAT_PLAIN) {
-               erofs_err("%s: unsupported datalayout %d", inode->i_srcpath, 
inode->datalayout);
-               return -EOPNOTSUPP;
-       }
-
-       if (inode->sbi->extra_devices) {
+       if (inode->datalayout == EROFS_INODE_CHUNK_BASED) {
                chunkbits = inode->u.chunkbits;
-               if (chunkbits < sbi.blkszbits) {
-                       erofs_err("%s: chunk size %u is too small to fit the 
target block size %u",
-                                 inode->i_srcpath, 1U << chunkbits, 1U << 
sbi.blkszbits);
+               if (chunkbits < dst_sb->blkszbits) {
+                       erofs_err("%s: chunk size %u is smaller than the target 
block size %u",
+                                 inode->i_srcpath, 1U << chunkbits,
+                                 1U << dst_sb->blkszbits);
                        return -EINVAL;
                }
-       } else {
+       } else if (inode->datalayout == EROFS_INODE_FLAT_PLAIN) {
                chunkbits = ilog2(inode->i_size - 1) + 1;
-               if (chunkbits < sbi.blkszbits)
-                       chunkbits = sbi.blkszbits;
-               if (chunkbits - sbi.blkszbits > EROFS_CHUNK_FORMAT_BLKBITS_MASK)
-                       chunkbits = EROFS_CHUNK_FORMAT_BLKBITS_MASK + 
sbi.blkszbits;
+               if (chunkbits < dst_sb->blkszbits)
+                       chunkbits = dst_sb->blkszbits;
+               if (chunkbits - dst_sb->blkszbits > 
EROFS_CHUNK_FORMAT_BLKBITS_MASK)
+                       chunkbits = EROFS_CHUNK_FORMAT_BLKBITS_MASK + 
dst_sb->blkszbits;
+       } else {
+               erofs_err("%s: unsupported datalayout %d ", inode->i_srcpath,
+                         inode->datalayout);
+               return -EOPNOTSUPP;
        }
+
        chunksize = 1ULL << chunkbits;
        count = DIV_ROUND_UP(inode->i_size, chunksize);
 
@@ -178,7 +179,7 @@ static int erofs_rebuild_fixup_inode_index(struct 
erofs_inode *inode)
                if (ret)
                        goto err;
 
-               blkaddr = erofs_blknr(&sbi, map.m_pa);
+               blkaddr = erofs_blknr(dst_sb, map.m_pa);
                chunk = erofs_get_unhashed_chunk(inode->dev, blkaddr, 0);
                if (IS_ERR(chunk)) {
                        ret = PTR_ERR(chunk);
@@ -189,7 +190,7 @@ static int erofs_rebuild_fixup_inode_index(struct 
erofs_inode *inode)
        }
        inode->datalayout = EROFS_INODE_CHUNK_BASED;
        inode->u.chunkformat = EROFS_CHUNK_FORMAT_INDEXES;
-       inode->u.chunkformat |= chunkbits - sbi.blkszbits;
+       inode->u.chunkformat |= chunkbits - dst_sb->blkszbits;
        return 0;
 err:
        free(inode->chunkindexes);
@@ -197,8 +198,12 @@ err:
        return ret;
 }
 
-static int erofs_rebuild_fill_inode(struct erofs_inode *inode)
+static int erofs_rebuild_update_inode(struct erofs_sb_info *dst_sb,
+                                     struct erofs_inode *inode,
+                                     enum erofs_rebuild_datamode datamode)
 {
+       int err = 0;
+
        switch (inode->i_mode & S_IFMT) {
        case S_IFCHR:
                if (erofs_inode_is_whiteout(inode))
@@ -211,36 +216,44 @@ static int erofs_rebuild_fill_inode(struct erofs_inode 
*inode)
                erofs_dbg("\tdev: %d %d", major(inode->u.i_rdev),
                          minor(inode->u.i_rdev));
                inode->u.i_rdev = erofs_new_encode_dev(inode->u.i_rdev);
-               return 0;
+               break;
        case S_IFDIR:
-               return erofs_init_empty_dir(inode);
-       case S_IFLNK: {
-               int ret;
-
+               err = erofs_init_empty_dir(inode);
+               break;
+       case S_IFLNK:
                inode->i_link = malloc(inode->i_size + 1);
                if (!inode->i_link)
                        return -ENOMEM;
-               ret = erofs_pread(inode, inode->i_link, inode->i_size, 0);
+               err = erofs_pread(inode, inode->i_link, inode->i_size, 0);
                erofs_dbg("\tsymlink: %s -> %s", inode->i_srcpath, 
inode->i_link);
-               return ret;
-       }
+               break;
        case S_IFREG:
-               if (inode->i_size)
-                       return erofs_rebuild_fixup_inode_index(inode);
-               return 0;
-       default:
+               if (!inode->i_size) {
+                       inode->u.i_blkaddr = NULL_ADDR;
+                       break;
+               }
+               if (datamode == EROFS_REBUILD_DATA_BLOB_INDEX)
+                       err = erofs_rebuild_write_blob_index(dst_sb, inode);
+               else if (datamode == EROFS_REBUILD_DATA_RESVSP)
+                       inode->datasource = EROFS_INODE_DATA_SOURCE_RESVSP;
+               else
+                       err = -EOPNOTSUPP;
                break;
+       default:
+               return -EINVAL;
        }
-       return -EINVAL;
+       return err;
 }
 
 /*
  * @mergedir: parent directory in the merged tree
  * @ctx.dir:  parent directory when itering erofs_iterate_dir()
+ * @datamode: indicate how to import inode data
  */
 struct erofs_rebuild_dir_context {
        struct erofs_dir_context ctx;
        struct erofs_inode *mergedir;
+       enum erofs_rebuild_datamode datamode;
 };
 
 static int erofs_rebuild_dirent_iter(struct erofs_dir_context *ctx)
@@ -340,7 +353,8 @@ static int erofs_rebuild_dirent_iter(struct 
erofs_dir_context *ctx)
                        inode->i_ino[1] = inode->nid;
                        inode->i_nlink = 1;
 
-                       ret = erofs_rebuild_fill_inode(inode);
+                       ret = erofs_rebuild_update_inode(&sbi, inode,
+                                                        rctx->datamode);
                        if (ret) {
                                erofs_iput(inode);
                                goto out;
@@ -372,7 +386,8 @@ out:
        return ret;
 }
 
-int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_sb_info 
*sbi)
+int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_sb_info 
*sbi,
+                           enum erofs_rebuild_datamode mode)
 {
        struct erofs_inode inode = {};
        struct erofs_rebuild_dir_context ctx;
@@ -403,6 +418,7 @@ int erofs_rebuild_load_tree(struct erofs_inode *root, 
struct erofs_sb_info *sbi)
                .ctx.dir = &inode,
                .ctx.cb = erofs_rebuild_dirent_iter,
                .mergedir = root,
+               .datamode = mode,
        };
        ret = erofs_iterate_dir(&ctx.ctx, false);
        free(inode.i_srcpath);
diff --git a/lib/tar.c b/lib/tar.c
index 3a5d484..53a1188 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -607,7 +607,7 @@ static int tarerofs_write_file_data(struct erofs_inode 
*inode,
                j -= nread;
        }
        erofs_diskbuf_commit(inode->i_diskbuf, inode->i_size);
-       inode->with_diskbuf = true;
+       inode->datasource = EROFS_INODE_DATA_SOURCE_DISKBUF;
        return 0;
 }
 
diff --git a/mkfs/main.c b/mkfs/main.c
index cb6dfe6..425fe00 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -1060,7 +1060,8 @@ static int erofs_rebuild_load_trees(struct erofs_inode 
*root)
        int ret, idx;
 
        list_for_each_entry(src, &rebuild_src_list, list) {
-               ret = erofs_rebuild_load_tree(root, src);
+               ret = erofs_rebuild_load_tree(root, src,
+                                             EROFS_REBUILD_DATA_BLOB_INDEX);
                if (ret) {
                        erofs_err("failed to load %s", src->devname);
                        return ret;
-- 
2.39.3

Reply via email to