erofs-utils: fix up root inode for incremental builds
authorGao Xiang <hsiangkao@linux.alibaba.com>
Tue, 18 Jun 2024 08:24:08 +0000 (16:24 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 19 Jun 2024 03:11:32 +0000 (11:11 +0800)
Move the new root inode to the original location if it cannot
be accessed by the super block.

Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20240618082414.47876-3-hsiangkao@linux.alibaba.com
include/erofs/inode.h
lib/inode.c
mkfs/main.c

index 557150c49a71bb434d3d3eacb1ab22621fc0659a..0fc9b80e20f54d6dabf03fce519b6b58b28a9890 100644 (file)
@@ -34,7 +34,7 @@ erofs_nid_t erofs_lookupnid(struct erofs_inode *inode);
 int erofs_iflush(struct erofs_inode *inode);
 struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent,
                                   const char *name);
-int erofs_rebuild_dump_tree(struct erofs_inode *dir);
+int erofs_rebuild_dump_tree(struct erofs_inode *dir, bool incremental);
 int erofs_init_empty_dir(struct erofs_inode *dir);
 int __erofs_fill_inode(struct erofs_inode *inode, struct stat *st,
                       const char *path);
@@ -43,6 +43,7 @@ struct erofs_inode *erofs_mkfs_build_tree_from_path(struct erofs_sb_info *sbi,
                                                    const char *path);
 struct erofs_inode *erofs_mkfs_build_special_from_fd(struct erofs_sb_info *sbi,
                                                     int fd, const char *name);
+int erofs_fixup_root_inode(struct erofs_inode *root);
 
 #ifdef __cplusplus
 }
index 0bfaa5678f506154115310de1e888704b4388f7b..a4f61ab759b7d27fd0f1e8e9b66b60ea8a8cda47 100644 (file)
@@ -311,17 +311,18 @@ erofs_nid_t erofs_lookupnid(struct erofs_inode *inode)
        struct erofs_sb_info *sbi = inode->sbi;
        erofs_off_t off, meta_offset;
 
-       if (!bh || (long long)inode->nid > 0)
-               return inode->nid;
-
-       erofs_mapbh(bh->block);
-       off = erofs_btell(bh, false);
-
-       meta_offset = erofs_pos(sbi, sbi->meta_blkaddr);
-       DBG_BUGON(off < meta_offset);
-       inode->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
-       erofs_dbg("Assign nid %llu to file %s (mode %05o)",
-                 inode->nid, inode->i_srcpath, inode->i_mode);
+       if (bh && (long long)inode->nid <= 0) {
+               erofs_mapbh(bh->block);
+               off = erofs_btell(bh, false);
+
+               meta_offset = erofs_pos(sbi, sbi->meta_blkaddr);
+               DBG_BUGON(off < meta_offset);
+               inode->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
+               erofs_dbg("Assign nid %llu to file %s (mode %05o)",
+                         inode->nid, inode->i_srcpath, inode->i_mode);
+       }
+       if (unlikely(IS_ROOT(inode)) && inode->nid > 0xffff)
+               return sbi->root_nid;
        return inode->nid;
 }
 
@@ -739,7 +740,6 @@ static int erofs_bh_flush_write_inline(struct erofs_buffer_head *bh)
        if (ret)
                return ret;
 
-       inode->idata_size = 0;
        free(inode->idata);
        inode->idata = NULL;
 
@@ -1531,7 +1531,8 @@ static void erofs_mark_parent_inode(struct erofs_inode *inode,
        inode->i_parent = (void *)((unsigned long)dir | 1);
 }
 
-static int erofs_mkfs_dump_tree(struct erofs_inode *root, bool rebuild)
+static int erofs_mkfs_dump_tree(struct erofs_inode *root, bool rebuild,
+                               bool incremental)
 {
        struct erofs_sb_info *sbi = root->sbi;
        struct erofs_inode *dumpdir = erofs_igrab(root);
@@ -1545,9 +1546,12 @@ static int erofs_mkfs_dump_tree(struct erofs_inode *root, bool rebuild)
        if (err)
                return err;
 
-       erofs_mkfs_flushjobs(sbi);
-       erofs_fixup_meta_blkaddr(root);         /* assign root NID */
-       sbi->root_nid = root->nid;
+       /* assign root NID immediately for non-incremental builds */
+       if (!incremental) {
+               erofs_mkfs_flushjobs(sbi);
+               erofs_fixup_meta_blkaddr(root);
+               sbi->root_nid = root->nid;
+       }
 
        do {
                int err;
@@ -1600,6 +1604,7 @@ struct erofs_mkfs_buildtree_ctx {
                const char *path;
                struct erofs_inode *root;
        } u;
+       bool incremental;
 };
 #ifndef EROFS_MT_ENABLED
 #define __erofs_mkfs_build_tree erofs_mkfs_build_tree
@@ -1619,7 +1624,7 @@ static int __erofs_mkfs_build_tree(struct erofs_mkfs_buildtree_ctx *ctx)
                root = ctx->u.root;
        }
 
-       err = erofs_mkfs_dump_tree(root, !from_path);
+       err = erofs_mkfs_dump_tree(root, !from_path, ctx->incremental);
        if (err) {
                if (from_path)
                        erofs_iput(root);
@@ -1692,11 +1697,12 @@ struct erofs_inode *erofs_mkfs_build_tree_from_path(struct erofs_sb_info *sbi,
        return ctx.u.root;
 }
 
-int erofs_rebuild_dump_tree(struct erofs_inode *root)
+int erofs_rebuild_dump_tree(struct erofs_inode *root, bool incremental)
 {
        return erofs_mkfs_build_tree(&((struct erofs_mkfs_buildtree_ctx) {
                .sbi = NULL,
                .u.root = root,
+               .incremental = incremental,
        }));
 }
 
@@ -1758,3 +1764,56 @@ struct erofs_inode *erofs_mkfs_build_special_from_fd(struct erofs_sb_info *sbi,
        erofs_write_tail_end(inode);
        return inode;
 }
+
+int erofs_fixup_root_inode(struct erofs_inode *root)
+{
+       struct erofs_sb_info *sbi = root->sbi;
+       struct erofs_inode oi;
+       unsigned int ondisk_capacity, ondisk_size;
+       char *ibuf;
+       int err;
+
+       if (sbi->root_nid == root->nid)
+               return 0;
+
+       if (root->nid <= 0xffff) {
+               sbi->root_nid = root->nid;
+               return 0;
+       }
+
+       oi = (struct erofs_inode){ .sbi = sbi, .nid = sbi->root_nid };
+       err = erofs_read_inode_from_disk(&oi);
+       if (err) {
+               erofs_err("failed to read root inode: %s",
+                         erofs_strerror(err));
+               return err;
+       }
+
+       if (oi.datalayout != EROFS_INODE_FLAT_INLINE &&
+           oi.datalayout != EROFS_INODE_FLAT_PLAIN)
+               return -EOPNOTSUPP;
+
+       ondisk_capacity = oi.inode_isize + oi.xattr_isize;
+       if (oi.datalayout == EROFS_INODE_FLAT_INLINE)
+               ondisk_capacity += erofs_blkoff(sbi, oi.i_size);
+
+       ondisk_size = root->inode_isize + root->xattr_isize;
+       if (root->extent_isize)
+               ondisk_size = roundup(ondisk_size, 8) + root->extent_isize;
+       ondisk_size += root->idata_size;
+
+       if (ondisk_size > ondisk_capacity) {
+               erofs_err("no enough room for the root inode from nid %llu",
+                         root->nid);
+               return -ENOSPC;
+       }
+
+       ibuf = malloc(ondisk_size);
+       if (!ibuf)
+               return -ENOMEM;
+       err = erofs_dev_read(sbi, 0, ibuf, erofs_iloc(root), ondisk_size);
+       if (err >= 0)
+               err = erofs_dev_write(sbi, ibuf, erofs_iloc(&oi), ondisk_size);
+       free(ibuf);
+       return err;
+}
index d15b790c2f200b84805c2a2f35aa4fb3a6cd2c4c..cb6dfe6023eeb3beacbf5b1567b07566de7e41aa 100644 (file)
@@ -1136,7 +1136,7 @@ int main(int argc, char **argv)
 {
        int err = 0;
        struct erofs_buffer_head *sb_bh;
-       struct erofs_inode *root;
+       struct erofs_inode *root = NULL;
        erofs_blk_t nblocks;
        struct timeval t;
        FILE *packedfile = NULL;
@@ -1309,7 +1309,7 @@ int main(int argc, char **argv)
                if (err < 0)
                        goto exit;
 
-               err = erofs_rebuild_dump_tree(root);
+               err = erofs_rebuild_dump_tree(root, false);
                if (err < 0)
                        goto exit;
        } else if (rebuild_mode) {
@@ -1322,7 +1322,7 @@ int main(int argc, char **argv)
                err = erofs_rebuild_load_trees(root);
                if (err)
                        goto exit;
-               err = erofs_rebuild_dump_tree(root);
+               err = erofs_rebuild_dump_tree(root, false);
                if (err)
                        goto exit;
        } else {
@@ -1342,7 +1342,6 @@ int main(int argc, char **argv)
                        goto exit;
                }
        }
-       erofs_iput(root);
 
        if (erofstar.index_mode && sbi.extra_devices && !erofstar.mapfile)
                sbi.devs[0].blocks = BLK_ROUND_UP(&sbi, erofstar.offset);
@@ -1365,6 +1364,10 @@ int main(int argc, char **argv)
        if (err)
                goto exit;
 
+       erofs_fixup_root_inode(root);
+       erofs_iput(root);
+       root = NULL;
+
        err = erofs_writesb(&sbi, sb_bh, &nblocks);
        if (err)
                goto exit;
@@ -1379,6 +1382,8 @@ int main(int argc, char **argv)
        if (!err && erofs_sb_has_sb_chksum(&sbi))
                err = erofs_mkfs_superblock_csum_set();
 exit:
+       if (root)
+               erofs_iput(root);
        z_erofs_compress_exit();
        z_erofs_dedupe_exit();
        erofs_blocklist_close();