From b569147c823fa0fdbf597eba178beb475f9cc9b2 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Thu, 20 Jul 2023 15:31:04 +0800 Subject: [PATCH 01/17] erofs-utils: lib: avoid global sbi dependencies (take 1) Later mkfs is going to be able to convert multiple erofs images into one merged erofs image, in which case there are multiple device contexts and sbi instances. In preparation for that, remove global device context and sbi if possible except the buffer cache implementation, as there's still only one erofs output image. The device context is now folded into sbi. Global sbi still exists but it is only used by binaries directly, e.g. mkfs/dump/fsck. Signed-off-by: Jingbo Xu Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20230720073104.116439-1-hsiangkao@linux.alibaba.com --- dump/main.c | 28 ++--- fsck/main.c | 38 +++---- fuse/main.c | 20 ++-- include/erofs/blobchunk.h | 4 +- include/erofs/cache.h | 6 +- include/erofs/compress.h | 9 +- include/erofs/compress_hints.h | 2 +- include/erofs/decompress.h | 1 + include/erofs/dir.h | 3 +- include/erofs/internal.h | 48 +++++---- include/erofs/io.h | 38 +++---- include/erofs/tar.h | 4 +- include/erofs/xattr.h | 16 +-- lib/blobchunk.c | 46 ++++---- lib/cache.c | 47 +++++---- lib/compress.c | 187 ++++++++++++++++++--------------- lib/compress_hints.c | 10 +- lib/compressor.c | 15 +-- lib/compressor.h | 4 +- lib/compressor_lz4.c | 2 +- lib/compressor_lz4hc.c | 2 +- lib/data.c | 66 +++++++----- lib/decompress.c | 36 ++++--- lib/dir.c | 25 +++-- lib/fragments.c | 2 +- lib/inode.c | 118 +++++++++++---------- lib/io.c | 119 ++++++++++----------- lib/namei.c | 31 +++--- lib/super.c | 51 ++++----- lib/tar.c | 36 ++++--- lib/xattr.c | 75 +++++++------ lib/zmap.c | 37 ++++--- mkfs/main.c | 62 +++++------ 33 files changed, 644 insertions(+), 544 deletions(-) diff --git a/dump/main.c b/dump/main.c index 7e757191..409c851d 100644 --- a/dump/main.c +++ b/dump/main.c @@ -154,7 +154,7 @@ static int erofsdump_parse_options_cfg(int argc, char **argv) usage(); exit(0); case 3: - err = blob_open_ro(optarg); + err = blob_open_ro(&sbi, optarg); if (err) return err; ++sbi.extra_devices; @@ -202,7 +202,7 @@ static int erofsdump_get_occupied_size(struct erofs_inode *inode, case EROFS_INODE_COMPRESSED_FULL: case EROFS_INODE_COMPRESSED_COMPACT: stats.compressed_files++; - *size = inode->u.i_blocks * erofs_blksiz(); + *size = inode->u.i_blocks * erofs_blksiz(inode->sbi); break; default: erofs_err("unknown datalayout"); @@ -270,9 +270,9 @@ static int erofsdump_read_packed_inode(void) { int err; erofs_off_t occupied_size = 0; - struct erofs_inode vi = { .nid = sbi.packed_nid }; + struct erofs_inode vi = { .sbi = &sbi, .nid = sbi.packed_nid }; - if (!(erofs_sb_has_fragments() && sbi.packed_nid > 0)) + if (!(erofs_sb_has_fragments(&sbi) && sbi.packed_nid > 0)) return 0; err = erofs_read_inode_from_disk(&vi); @@ -296,7 +296,7 @@ static int erofsdump_readdir(struct erofs_dir_context *ctx) { int err; erofs_off_t occupied_size = 0; - struct erofs_inode vi = { .nid = ctx->de_nid }; + struct erofs_inode vi = { .sbi = &sbi, .nid = ctx->de_nid }; err = erofs_read_inode_from_disk(&vi); if (err) { @@ -351,7 +351,7 @@ static void erofsdump_show_fileinfo(bool show_extent) int err, i; erofs_off_t size; u16 access_mode; - struct erofs_inode inode = { .nid = dumpcfg.nid }; + struct erofs_inode inode = { .sbi = &sbi, .nid = dumpcfg.nid }; char path[PATH_MAX]; char access_mode_str[] = "rwxrwxrwx"; char timebuf[128] = {0}; @@ -382,7 +382,7 @@ static void erofsdump_show_fileinfo(bool show_extent) return; } - err = erofs_get_pathname(inode.nid, path, sizeof(path)); + err = erofs_get_pathname(inode.sbi, inode.nid, path, sizeof(path)); if (err < 0) { strncpy(path, "(not found)", sizeof(path) - 1); path[sizeof(path) - 1] = '\0'; @@ -447,7 +447,7 @@ static void erofsdump_show_fileinfo(bool show_extent) .m_deviceid = map.m_deviceid, .m_pa = map.m_pa, }; - err = erofs_map_dev(&mdev); + err = erofs_map_dev(inode.sbi, &mdev); if (err) { erofs_err("failed to map device"); return; @@ -604,7 +604,7 @@ static void erofsdump_show_superblock(void) sbi.xattr_blkaddr); fprintf(stdout, "Filesystem root nid: %llu\n", sbi.root_nid | 0ULL); - if (erofs_sb_has_fragments() && sbi.packed_nid > 0) + if (erofs_sb_has_fragments(&sbi) && sbi.packed_nid > 0) fprintf(stdout, "Filesystem packed nid: %llu\n", sbi.packed_nid | 0ULL); fprintf(stdout, "Filesystem inode count: %llu\n", @@ -636,13 +636,13 @@ int main(int argc, char **argv) goto exit; } - err = dev_open_ro(cfg.c_img_path); + err = dev_open_ro(&sbi, cfg.c_img_path); if (err) { erofs_err("failed to open image file"); goto exit; } - err = erofs_read_superblock(); + err = erofs_read_superblock(&sbi); if (err) { erofs_err("failed to read superblock"); goto exit_dev_close; @@ -667,11 +667,11 @@ int main(int argc, char **argv) erofsdump_show_fileinfo(dumpcfg.show_extent); exit_put_super: - erofs_put_super(); + erofs_put_super(&sbi); exit_dev_close: - dev_close(); + dev_close(&sbi); exit: - blob_closeall(); + blob_closeall(&sbi); erofs_exit_configure(); return err; } diff --git a/fsck/main.c b/fsck/main.c index aabfda4d..39a55341 100644 --- a/fsck/main.c +++ b/fsck/main.c @@ -158,7 +158,7 @@ static int erofsfsck_parse_options_cfg(int argc, char **argv) } break; case 3: - ret = blob_open_ro(optarg); + ret = blob_open_ro(&sbi, optarg); if (ret) return ret; ++sbi.extra_devices; @@ -279,7 +279,7 @@ static int erofs_check_sb_chksum(void) struct erofs_super_block *sb; int ret; - ret = blk_read(0, buf, 0, 1); + ret = blk_read(&sbi, 0, buf, 0, 1); if (ret) { erofs_err("failed to read superblock to check checksum: %d", ret); @@ -289,7 +289,7 @@ static int erofs_check_sb_chksum(void) sb = (struct erofs_super_block *)(buf + EROFS_SUPER_OFFSET); sb->checksum = 0; - crc = erofs_crc32c(~0, (u8 *)sb, erofs_blksiz() - EROFS_SUPER_OFFSET); + crc = erofs_crc32c(~0, (u8 *)sb, erofs_blksiz(&sbi) - EROFS_SUPER_OFFSET); if (crc != sbi.checksum) { erofs_err("superblock chksum doesn't match: saved(%08xh) calculated(%08xh)", sbi.checksum, crc); @@ -302,6 +302,7 @@ static int erofs_check_sb_chksum(void) static int erofs_verify_xattr(struct erofs_inode *inode) { + struct erofs_sb_info *sbi = inode->sbi; unsigned int xattr_hdr_size = sizeof(struct erofs_xattr_ibody_header); unsigned int xattr_entry_size = sizeof(struct erofs_xattr_entry); erofs_off_t addr; @@ -326,7 +327,7 @@ static int erofs_verify_xattr(struct erofs_inode *inode) } addr = erofs_iloc(inode) + inode->inode_isize; - ret = dev_read(0, buf, addr, xattr_hdr_size); + ret = dev_read(sbi, 0, buf, addr, xattr_hdr_size); if (ret < 0) { erofs_err("failed to read xattr header @ nid %llu: %d", inode->nid | 0ULL, ret); @@ -335,12 +336,12 @@ static int erofs_verify_xattr(struct erofs_inode *inode) ih = (struct erofs_xattr_ibody_header *)buf; xattr_shared_count = ih->h_shared_count; - ofs = erofs_blkoff(addr) + xattr_hdr_size; + ofs = erofs_blkoff(sbi, addr) + xattr_hdr_size; addr += xattr_hdr_size; remaining -= xattr_hdr_size; for (i = 0; i < xattr_shared_count; ++i) { - if (ofs >= erofs_blksiz()) { - if (ofs != erofs_blksiz()) { + if (ofs >= erofs_blksiz(sbi)) { + if (ofs != erofs_blksiz(sbi)) { erofs_err("unaligned xattr entry in xattr shared area @ nid %llu", inode->nid | 0ULL); ret = -EFSCORRUPTED; @@ -356,7 +357,7 @@ static int erofs_verify_xattr(struct erofs_inode *inode) while (remaining > 0) { unsigned int entry_sz; - ret = dev_read(0, buf, addr, xattr_entry_size); + ret = dev_read(sbi, 0, buf, addr, xattr_entry_size); if (ret) { erofs_err("failed to read xattr entry @ nid %llu: %d", inode->nid | 0ULL, ret); @@ -483,7 +484,7 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd) u64 count = min_t(u64, alloc_rawsize, map.m_llen); - ret = erofs_read_one_data(&map, raw, p, count); + ret = erofs_read_one_data(inode, &map, raw, p, count); if (ret) goto out; @@ -497,8 +498,8 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd) if (fsckcfg.print_comp_ratio) { if (!erofs_is_packed_inode(inode)) - fsckcfg.logical_blocks += BLK_ROUND_UP(inode->i_size); - fsckcfg.physical_blocks += BLK_ROUND_UP(pchunk_len); + fsckcfg.logical_blocks += BLK_ROUND_UP(inode->sbi, inode->i_size); + fsckcfg.physical_blocks += BLK_ROUND_UP(inode->sbi, pchunk_len); } out: if (raw) @@ -845,6 +846,7 @@ static int erofsfsck_check_inode(erofs_nid_t pnid, erofs_nid_t nid) erofs_dbg("check inode: nid(%llu)", nid | 0ULL); inode.nid = nid; + inode.sbi = &sbi; ret = erofs_read_inode_from_disk(&inode); if (ret) { if (ret == -EIO) @@ -920,19 +922,19 @@ int main(int argc, char *argv[]) cfg.c_dbg_lvl = -1; #endif - err = dev_open_ro(cfg.c_img_path); + err = dev_open_ro(&sbi, cfg.c_img_path); if (err) { erofs_err("failed to open image file"); goto exit; } - err = erofs_read_superblock(); + err = erofs_read_superblock(&sbi); if (err) { erofs_err("failed to read superblock"); goto exit_dev_close; } - if (erofs_sb_has_sb_chksum() && erofs_check_sb_chksum()) { + if (erofs_sb_has_sb_chksum(&sbi) && erofs_check_sb_chksum()) { erofs_err("failed to verify superblock checksum"); goto exit_put_super; } @@ -940,7 +942,7 @@ int main(int argc, char *argv[]) if (fsckcfg.extract_path) erofsfsck_hardlink_init(); - if (erofs_sb_has_fragments() && sbi.packed_nid > 0) { + if (erofs_sb_has_fragments(&sbi) && sbi.packed_nid > 0) { err = erofsfsck_check_inode(sbi.packed_nid, sbi.packed_nid); if (err) { erofs_err("failed to verify packed file"); @@ -974,11 +976,11 @@ int main(int argc, char *argv[]) if (fsckcfg.extract_path) erofsfsck_hardlink_exit(); exit_put_super: - erofs_put_super(); + erofs_put_super(&sbi); exit_dev_close: - dev_close(); + dev_close(&sbi); exit: - blob_closeall(); + blob_closeall(&sbi); erofs_exit_configure(); return err ? 1 : 0; } diff --git a/fuse/main.c b/fuse/main.c index b060e06c..821d98cc 100644 --- a/fuse/main.c +++ b/fuse/main.c @@ -49,6 +49,7 @@ int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, }; erofs_dbg("readdir:%s offset=%llu", path, (long long)offset); + dir.sbi = &sbi; ret = erofs_ilookup(path, &dir); if (ret) return ret; @@ -84,7 +85,7 @@ static int erofsfuse_open(const char *path, struct fuse_file_info *fi) static int erofsfuse_getattr(const char *path, struct stat *stbuf) { - struct erofs_inode vi = {}; + struct erofs_inode vi = { .sbi = &sbi }; int ret; erofs_dbg("getattr(%s)", path); @@ -95,7 +96,7 @@ static int erofsfuse_getattr(const char *path, struct stat *stbuf) stbuf->st_mode = vi.i_mode; stbuf->st_nlink = vi.i_nlink; stbuf->st_size = vi.i_size; - stbuf->st_blocks = roundup(vi.i_size, erofs_blksiz()) >> 9; + stbuf->st_blocks = roundup(vi.i_size, erofs_blksiz(vi.sbi)) >> 9; stbuf->st_uid = vi.i_uid; stbuf->st_gid = vi.i_gid; if (S_ISBLK(vi.i_mode) || S_ISCHR(vi.i_mode)) @@ -115,6 +116,7 @@ static int erofsfuse_read(const char *path, char *buffer, erofs_dbg("path:%s size=%zd offset=%llu", path, size, (long long)offset); + vi.sbi = &sbi; ret = erofs_ilookup(path, &vi); if (ret) return ret; @@ -155,6 +157,7 @@ static int erofsfuse_getxattr(const char *path, const char *name, char *value, erofs_dbg("getxattr(%s): name=%s size=%llu", path, name, size); + vi.sbi = &sbi; ret = erofs_ilookup(path, &vi); if (ret) return ret; @@ -169,6 +172,7 @@ static int erofsfuse_listxattr(const char *path, char *list, size_t size) erofs_dbg("listxattr(%s): size=%llu", path, size); + vi.sbi = &sbi; ret = erofs_ilookup(path, &vi); if (ret) return ret; @@ -244,7 +248,7 @@ static int optional_opt_func(void *data, const char *arg, int key, switch (key) { case 1: - ret = blob_open_ro(arg + sizeof("--device=") - 1); + ret = blob_open_ro(&sbi, arg + sizeof("--device=") - 1); if (ret) return -1; ++sbi.extra_devices; @@ -325,13 +329,13 @@ int main(int argc, char *argv[]) cfg.c_offset = fusecfg.offset; erofsfuse_dumpcfg(); - ret = dev_open_ro(fusecfg.disk); + ret = dev_open_ro(&sbi, fusecfg.disk); if (ret) { fprintf(stderr, "failed to open: %s\n", fusecfg.disk); goto err_fuse_free_args; } - ret = erofs_read_superblock(); + ret = erofs_read_superblock(&sbi); if (ret) { fprintf(stderr, "failed to read erofs super block\n"); goto err_dev_close; @@ -339,10 +343,10 @@ int main(int argc, char *argv[]) ret = fuse_main(args.argc, args.argv, &erofs_ops, NULL); - erofs_put_super(); + erofs_put_super(&sbi); err_dev_close: - blob_closeall(); - dev_close(); + blob_closeall(&sbi); + dev_close(&sbi); err_fuse_free_args: fuse_opt_free_args(&args); err: diff --git a/include/erofs/blobchunk.h b/include/erofs/blobchunk.h index 4269d822..7c5645eb 100644 --- a/include/erofs/blobchunk.h +++ b/include/erofs/blobchunk.h @@ -18,10 +18,10 @@ 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(void); +int erofs_blob_remap(struct erofs_sb_info *sbi); void erofs_blob_exit(void); int erofs_blob_init(const char *blobfile_path); -int erofs_generate_devtable(void); +int erofs_generate_devtable(struct erofs_sb_info *sbi); #ifdef __cplusplus } diff --git a/include/erofs/cache.h b/include/erofs/cache.h index 8c3bd46b..dc299852 100644 --- a/include/erofs/cache.h +++ b/include/erofs/cache.h @@ -57,14 +57,14 @@ struct erofs_buffer_block { static inline const int get_alignsize(int type, int *type_ret) { if (type == DATA) - return erofs_blksiz(); + return erofs_blksiz(&sbi); if (type == INODE) { *type_ret = META; return sizeof(struct erofs_inode_compact); } else if (type == DIRA) { *type_ret = META; - return erofs_blksiz(); + return erofs_blksiz(&sbi); } else if (type == XATTR) { *type_ret = META; return sizeof(struct erofs_xattr_entry); @@ -88,7 +88,7 @@ static inline erofs_off_t erofs_btell(struct erofs_buffer_head *bh, bool end) if (bb->blkaddr == NULL_ADDR) return NULL_ADDR_UL; - return erofs_pos(bb->blkaddr) + + return erofs_pos(&sbi, bb->blkaddr) + (end ? list_next_entry(bh, list)->off : bh->off); } diff --git a/include/erofs/compress.h b/include/erofs/compress.h index 08af9e30..f1ad84aa 100644 --- a/include/erofs/compress.h +++ b/include/erofs/compress.h @@ -19,18 +19,21 @@ extern "C" void z_erofs_drop_inline_pcluster(struct erofs_inode *inode); int erofs_write_compressed_file(struct erofs_inode *inode, int fd); -int z_erofs_compress_init(struct erofs_buffer_head *bh); +int z_erofs_compress_init(struct erofs_sb_info *sbi, + struct erofs_buffer_head *bh); int z_erofs_compress_exit(void); const char *z_erofs_list_available_compressors(unsigned int i); static inline bool erofs_is_packed_inode(struct erofs_inode *inode) { + erofs_nid_t packed_nid = inode->sbi->packed_nid; + if (inode->nid == EROFS_PACKED_NID_UNALLOCATED) { - DBG_BUGON(sbi.packed_nid != EROFS_PACKED_NID_UNALLOCATED); + DBG_BUGON(packed_nid != EROFS_PACKED_NID_UNALLOCATED); return true; } - return (sbi.packed_nid > 0 && inode->nid == sbi.packed_nid); + return (packed_nid > 0 && inode->nid == packed_nid); } #ifdef __cplusplus diff --git a/include/erofs/compress_hints.h b/include/erofs/compress_hints.h index d836f229..9f0d8ae4 100644 --- a/include/erofs/compress_hints.h +++ b/include/erofs/compress_hints.h @@ -25,7 +25,7 @@ struct erofs_compress_hints { bool z_erofs_apply_compress_hints(struct erofs_inode *inode); void erofs_cleanup_compress_hints(void); -int erofs_load_compress_hints(void); +int erofs_load_compress_hints(struct erofs_sb_info *sbi); #ifdef __cplusplus } diff --git a/include/erofs/decompress.h b/include/erofs/decompress.h index a9067cbd..0d554832 100644 --- a/include/erofs/decompress.h +++ b/include/erofs/decompress.h @@ -14,6 +14,7 @@ extern "C" #include "internal.h" struct z_erofs_decompress_req { + struct erofs_sb_info *sbi; char *in, *out; /* diff --git a/include/erofs/dir.h b/include/erofs/dir.h index 74bffb53..5460ac48 100644 --- a/include/erofs/dir.h +++ b/include/erofs/dir.h @@ -62,7 +62,8 @@ struct erofs_dir_context { /* Iterate over inodes that are in directory */ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck); /* Get a full pathname of the inode NID */ -int erofs_get_pathname(erofs_nid_t nid, char *buf, size_t size); +int erofs_get_pathname(struct erofs_sb_info *sbi, erofs_nid_t nid, + char *buf, size_t size); #ifdef __cplusplus } diff --git a/include/erofs/internal.h b/include/erofs/internal.h index 93e3a0ba..04a9a695 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -44,12 +44,11 @@ typedef u32 erofs_blk_t; /* global sbi */ extern struct erofs_sb_info sbi; -#define erofs_blksiz() (1u << sbi.blkszbits) -#define erofs_blknr(addr) ((addr) >> sbi.blkszbits) -#define erofs_blkoff(addr) ((addr) & (erofs_blksiz() - 1)) -#define erofs_pos(nr) ((erofs_off_t)(nr) << sbi.blkszbits) - -#define BLK_ROUND_UP(addr) DIV_ROUND_UP(addr, 1u << sbi.blkszbits) +#define erofs_blksiz(sbi) (1u << (sbi)->blkszbits) +#define erofs_blknr(sbi, addr) ((addr) >> (sbi)->blkszbits) +#define erofs_blkoff(sbi, addr) ((addr) & (erofs_blksiz(sbi) - 1)) +#define erofs_pos(sbi, nr) ((erofs_off_t)(nr) << (sbi)->blkszbits) +#define BLK_ROUND_UP(sbi, addr) DIV_ROUND_UP(addr, erofs_blksiz(sbi)) struct erofs_buffer_head; @@ -62,6 +61,7 @@ struct erofs_device_info { struct erofs_sb_info { struct erofs_device_info *devs; + const char *devname; u64 total_blocks; u64 primarydevice_blocks; @@ -98,23 +98,28 @@ struct erofs_sb_info { u32 xattr_prefix_start; u8 xattr_prefix_count; + + int devfd; + u64 devsz; + unsigned int nblobs; + unsigned int blobfd[256]; }; /* make sure that any user of the erofs headers has atleast 64bit off_t type */ extern int erofs_assert_largefile[sizeof(off_t)-8]; #define EROFS_FEATURE_FUNCS(name, compat, feature) \ -static inline bool erofs_sb_has_##name(void) \ +static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \ { \ - return sbi.feature_##compat & EROFS_FEATURE_##feature; \ + return sbi->feature_##compat & EROFS_FEATURE_##feature; \ } \ -static inline void erofs_sb_set_##name(void) \ +static inline void erofs_sb_set_##name(struct erofs_sb_info *sbi) \ { \ - sbi.feature_##compat |= EROFS_FEATURE_##feature; \ + sbi->feature_##compat |= EROFS_FEATURE_##feature; \ } \ -static inline void erofs_sb_clear_##name(void) \ +static inline void erofs_sb_clear_##name(struct erofs_sb_info *sbi) \ { \ - sbi.feature_##compat &= ~EROFS_FEATURE_##feature; \ + sbi->feature_##compat &= ~EROFS_FEATURE_##feature; \ } EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_ZERO_PADDING) @@ -143,6 +148,7 @@ struct erofs_inode { u32 subdirs_queued; }; unsigned int i_count; + struct erofs_sb_info *sbi; struct erofs_inode *i_parent; umode_t i_mode; @@ -216,7 +222,10 @@ struct erofs_inode { static inline erofs_off_t erofs_iloc(struct erofs_inode *inode) { - return erofs_pos(sbi.meta_blkaddr) + (inode->nid << sbi.islotbits); + struct erofs_sb_info *sbi = inode->sbi; + + return erofs_pos(sbi, sbi->meta_blkaddr) + + (inode->nid << sbi->islotbits); } static inline bool is_inode_layout_compression(struct erofs_inode *inode) @@ -336,22 +345,21 @@ struct erofs_map_dev { }; /* super.c */ -int erofs_read_superblock(void); -void erofs_put_super(void); +int erofs_read_superblock(struct erofs_sb_info *sbi); +void erofs_put_super(struct erofs_sb_info *sbi); /* namei.c */ int erofs_read_inode_from_disk(struct erofs_inode *vi); int erofs_ilookup(const char *path, struct erofs_inode *vi); -int erofs_read_inode_from_disk(struct erofs_inode *vi); /* data.c */ int erofs_pread(struct erofs_inode *inode, char *buf, erofs_off_t count, erofs_off_t offset); int erofs_map_blocks(struct erofs_inode *inode, struct erofs_map_blocks *map, int flags); -int erofs_map_dev(struct erofs_map_dev *map); -int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset, - size_t len); +int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map); +int erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map, + char *buffer, u64 offset, size_t len); int z_erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map, char *raw, char *buffer, erofs_off_t skip, erofs_off_t length, bool trimmed); @@ -368,7 +376,7 @@ static inline int erofs_get_occupied_size(const struct erofs_inode *inode, break; case EROFS_INODE_COMPRESSED_FULL: case EROFS_INODE_COMPRESSED_COMPACT: - *size = inode->u.i_blocks * erofs_blksiz(); + *size = inode->u.i_blocks * erofs_blksiz(inode->sbi); break; default: return -EOPNOTSUPP; diff --git a/include/erofs/io.h b/include/erofs/io.h index 36210a35..4db5716d 100644 --- a/include/erofs/io.h +++ b/include/erofs/io.h @@ -22,34 +22,36 @@ extern "C" #define O_BINARY 0 #endif -void blob_closeall(void); -int blob_open_ro(const char *dev); -int dev_open(const char *devname); -int dev_open_ro(const char *dev); -void dev_close(void); -int dev_write(const void *buf, u64 offset, size_t len); -int dev_read(int device_id, void *buf, u64 offset, size_t len); -int dev_fillzero(u64 offset, size_t len, bool padding); -int dev_fsync(void); -int dev_resize(erofs_blk_t nblocks); -u64 dev_length(void); - -extern int erofs_devfd; +void blob_closeall(struct erofs_sb_info *sbi); +int blob_open_ro(struct erofs_sb_info *sbi, const char *dev); +int dev_open(struct erofs_sb_info *sbi, const char *devname); +int dev_open_ro(struct erofs_sb_info *sbi, const char *dev); +void dev_close(struct erofs_sb_info *sbi); +int dev_write(struct erofs_sb_info *sbi, const void *buf, + u64 offset, size_t len); +int dev_read(struct erofs_sb_info *sbi, int device_id, + void *buf, u64 offset, size_t len); +int dev_fillzero(struct erofs_sb_info *sbi, u64 offset, + size_t len, bool padding); +int dev_fsync(struct erofs_sb_info *sbi); +int dev_resize(struct erofs_sb_info *sbi, erofs_blk_t nblocks); ssize_t erofs_copy_file_range(int fd_in, erofs_off_t *off_in, int fd_out, erofs_off_t *off_out, size_t length); -static inline int blk_write(const void *buf, erofs_blk_t blkaddr, - u32 nblocks) +static inline int blk_write(struct erofs_sb_info *sbi, const void *buf, + erofs_blk_t blkaddr, u32 nblocks) { - return dev_write(buf, erofs_pos(blkaddr), erofs_pos(nblocks)); + return dev_write(sbi, buf, erofs_pos(sbi, blkaddr), + erofs_pos(sbi, nblocks)); } -static inline int blk_read(int device_id, void *buf, +static inline int blk_read(struct erofs_sb_info *sbi, int device_id, void *buf, erofs_blk_t start, u32 nblocks) { - return dev_read(device_id, buf, erofs_pos(start), erofs_pos(nblocks)); + return dev_read(sbi, device_id, buf, erofs_pos(sbi, start), + erofs_pos(sbi, nblocks)); } #ifdef __cplusplus diff --git a/include/erofs/tar.h b/include/erofs/tar.h index 268c57b0..a14f8ac5 100644 --- a/include/erofs/tar.h +++ b/include/erofs/tar.h @@ -23,7 +23,7 @@ struct erofs_tarfile { int tarerofs_init_empty_dir(struct erofs_inode *inode); int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar); -int tarerofs_reserve_devtable(unsigned int devices); -int tarerofs_write_devtable(struct erofs_tarfile *tar); +int tarerofs_reserve_devtable(struct erofs_sb_info *sbi, unsigned int devices); +int tarerofs_write_devtable(struct erofs_sb_info *sbi, struct erofs_tarfile *tar); #endif diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h index 27e14bf0..dc27cf6e 100644 --- a/include/erofs/xattr.h +++ b/include/erofs/xattr.h @@ -24,15 +24,17 @@ static inline unsigned int inlinexattr_header_size(struct erofs_inode *vi) sizeof(u32) * vi->xattr_shared_count; } -static inline erofs_blk_t xattrblock_addr(unsigned int xattr_id) +static inline erofs_blk_t xattrblock_addr(struct erofs_inode *vi, + unsigned int xattr_id) { - return sbi.xattr_blkaddr + - ((xattr_id * sizeof(__u32)) >> sbi.blkszbits); + return vi->sbi->xattr_blkaddr + + erofs_blknr(vi->sbi, xattr_id * sizeof(__u32)); } -static inline unsigned int xattrblock_offset(unsigned int xattr_id) +static inline unsigned int xattrblock_offset(struct erofs_inode *vi, + unsigned int xattr_id) { - return (xattr_id * sizeof(__u32)) & (erofs_blksiz() - 1); + return erofs_blkoff(vi->sbi, xattr_id * sizeof(__u32)); } #define EROFS_INODE_XATTR_ICOUNT(_size) ({\ @@ -75,11 +77,11 @@ static inline unsigned int xattrblock_offset(unsigned int xattr_id) int erofs_scan_file_xattrs(struct erofs_inode *inode); int erofs_prepare_xattr_ibody(struct erofs_inode *inode); char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size); -int erofs_build_shared_xattrs_from_path(const char *path); +int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *path); int erofs_xattr_insert_name_prefix(const char *prefix); void erofs_xattr_cleanup_name_prefixes(void); -int erofs_xattr_write_name_prefixes(FILE *f); +int erofs_xattr_write_name_prefixes(struct erofs_sb_info *sbi, FILE *f); int erofs_setxattr(struct erofs_inode *inode, char *key, const void *value, size_t size); diff --git a/lib/blobchunk.c b/lib/blobchunk.c index 1d91a67d..56077dc7 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -50,8 +50,8 @@ struct erofs_blobchunk *erofs_get_unhashed_chunk(erofs_off_t chunksize, return chunk; } -static struct erofs_blobchunk *erofs_blob_getchunk(int fd, - erofs_off_t chunksize) +static struct erofs_blobchunk *erofs_blob_getchunk(struct erofs_sb_info *sbi, + int fd, erofs_off_t chunksize) { static u8 zeroed[EROFS_MAX_BLOCK_SIZE]; u8 *chunkdata, sha256[32]; @@ -84,17 +84,18 @@ static struct erofs_blobchunk *erofs_blob_getchunk(int fd, chunk->chunksize = chunksize; blkpos = ftell(blobfile); - DBG_BUGON(erofs_blkoff(blkpos)); + DBG_BUGON(erofs_blkoff(sbi, blkpos)); chunk->device_id = 0; - chunk->blkaddr = erofs_blknr(blkpos); + chunk->blkaddr = erofs_blknr(sbi, blkpos); memcpy(chunk->sha256, sha256, sizeof(sha256)); hashmap_entry_init(&chunk->ent, hash); hashmap_add(&blob_hashmap, chunk); erofs_dbg("Writing chunk (%u bytes) to %u", chunksize, chunk->blkaddr); ret = fwrite(chunkdata, chunksize, 1, blobfile); - if (ret == 1 && erofs_blkoff(chunksize)) - ret = fwrite(zeroed, erofs_blksiz() - erofs_blkoff(chunksize), + if (ret == 1 && erofs_blkoff(sbi, chunksize)) + ret = fwrite(zeroed, + erofs_blksiz(sbi) - erofs_blkoff(sbi, chunksize), 1, blobfile); if (ret < 1) { hashmap_remove(&blob_hashmap, &chunk->ent); @@ -182,11 +183,12 @@ int erofs_blob_write_chunk_indexes(struct erofs_inode *inode, erofs_droid_blocklist_write_extent(inode, extent_start, extents_blks, first_extent, true); - return dev_write(inode->chunkindexes, off, inode->extent_isize); + return dev_write(inode->sbi, inode->chunkindexes, off, inode->extent_isize); } int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) { + struct erofs_sb_info *sbi = inode->sbi; unsigned int chunkbits = cfg.c_chunkbits; unsigned int count, unit; struct erofs_inode_chunk_index *idx; @@ -197,15 +199,15 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) /* if the file is fully sparsed, use one big chunk instead */ if (lseek(fd, 0, SEEK_DATA) < 0 && errno == ENXIO) { chunkbits = ilog2(inode->i_size - 1) + 1; - if (chunkbits < sbi.blkszbits) - chunkbits = sbi.blkszbits; + if (chunkbits < sbi->blkszbits) + chunkbits = sbi->blkszbits; } #endif - if (chunkbits - sbi.blkszbits > EROFS_CHUNK_FORMAT_BLKBITS_MASK) - chunkbits = EROFS_CHUNK_FORMAT_BLKBITS_MASK + sbi.blkszbits; + if (chunkbits - sbi->blkszbits > EROFS_CHUNK_FORMAT_BLKBITS_MASK) + chunkbits = EROFS_CHUNK_FORMAT_BLKBITS_MASK + sbi->blkszbits; chunksize = 1ULL << chunkbits; count = DIV_ROUND_UP(inode->i_size, chunksize); - inode->u.chunkformat |= chunkbits - sbi.blkszbits; + inode->u.chunkformat |= chunkbits - sbi->blkszbits; if (multidev) inode->u.chunkformat |= EROFS_CHUNK_FORMAT_INDEXES; @@ -246,7 +248,7 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) #endif len = min_t(u64, inode->i_size - pos, chunksize); - chunk = erofs_blob_getchunk(fd, len); + chunk = erofs_blob_getchunk(sbi, fd, len); if (IS_ERR(chunk)) { ret = PTR_ERR(chunk); goto err; @@ -263,7 +265,7 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) return ret; } -int erofs_blob_remap(void) +int erofs_blob_remap(struct erofs_sb_info *sbi) { struct erofs_buffer_head *bh; ssize_t length; @@ -276,11 +278,11 @@ int erofs_blob_remap(void) return -errno; if (multidev) { struct erofs_deviceslot dis = { - .blocks = erofs_blknr(length), + .blocks = erofs_blknr(sbi, length), }; pos_out = erofs_btell(bh_devt, false); - ret = dev_write(&dis, pos_out, sizeof(dis)); + ret = dev_write(sbi, &dis, pos_out, sizeof(dis)); if (ret) return ret; @@ -297,9 +299,9 @@ int erofs_blob_remap(void) erofs_mapbh(bh->block); pos_out = erofs_btell(bh, false); pos_in = 0; - remapped_base = erofs_blknr(pos_out); + remapped_base = erofs_blknr(sbi, pos_out); ret = erofs_copy_file_range(fileno(blobfile), &pos_in, - erofs_devfd, &pos_out, length); + sbi->devfd, &pos_out, length); bh->op = &erofs_drop_directly_bhops; erofs_bdrop(bh, false); return ret < length ? -EIO : 0; @@ -348,7 +350,7 @@ int erofs_blob_init(const char *blobfile_path) return 0; } -int erofs_generate_devtable(void) +int erofs_generate_devtable(struct erofs_sb_info *sbi) { struct erofs_deviceslot dis; @@ -362,8 +364,8 @@ int erofs_generate_devtable(void) dis = (struct erofs_deviceslot) {}; 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; - erofs_sb_set_device_table(); + sbi->devt_slotoff = erofs_btell(bh_devt, false) / EROFS_DEVT_SLOT_SIZE; + sbi->extra_devices = 1; + erofs_sb_set_device_table(sbi); return 0; } diff --git a/lib/cache.c b/lib/cache.c index 178bd5aa..d6e9b470 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -63,7 +63,7 @@ static void erofs_bupdate_mapped(struct erofs_buffer_block *bb) if (bb->blkaddr == NULL_ADDR) return; - bkt = mapped_buckets[bb->type] + bb->buffers.off % erofs_blksiz(); + bkt = mapped_buckets[bb->type] + bb->buffers.off % erofs_blksiz(&sbi); list_del(&bb->mapped_list); list_add_tail(&bb->mapped_list, bkt); } @@ -76,10 +76,10 @@ static int __erofs_battach(struct erofs_buffer_block *bb, unsigned int extrasize, bool dryrun) { + const unsigned int blksiz = erofs_blksiz(&sbi); const erofs_off_t alignedoffset = roundup(bb->buffers.off, alignsize); - const int oob = cmpsgn(roundup((bb->buffers.off - 1) % erofs_blksiz() + 1, - alignsize) + incr + extrasize, - erofs_blksiz()); + const int oob = cmpsgn(roundup((bb->buffers.off - 1) % blksiz + 1, + alignsize) + incr + extrasize, blksiz); bool tailupdate = false; erofs_blk_t blkaddr; @@ -91,7 +91,7 @@ static int __erofs_battach(struct erofs_buffer_block *bb, blkaddr = bb->blkaddr; if (blkaddr != NULL_ADDR) { tailupdate = (tail_blkaddr == blkaddr + - BLK_ROUND_UP(bb->buffers.off)); + DIV_ROUND_UP(bb->buffers.off, blksiz)); if (oob && !tailupdate) return -EINVAL; } @@ -106,10 +106,11 @@ static int __erofs_battach(struct erofs_buffer_block *bb, bb->buffers.off = alignedoffset + incr; /* need to update the tail_blkaddr */ if (tailupdate) - tail_blkaddr = blkaddr + BLK_ROUND_UP(bb->buffers.off); + tail_blkaddr = blkaddr + + DIV_ROUND_UP(bb->buffers.off, blksiz); erofs_bupdate_mapped(bb); } - return (alignedoffset + incr - 1) % erofs_blksiz() + 1; + return ((alignedoffset + incr - 1) & (blksiz - 1)) + 1; } int erofs_bh_balloon(struct erofs_buffer_head *bh, erofs_off_t incr) @@ -129,16 +130,17 @@ static int erofs_bfind_for_attach(int type, erofs_off_t size, unsigned int alignsize, struct erofs_buffer_block **bbp) { + const unsigned int blksiz = erofs_blksiz(&sbi); struct erofs_buffer_block *cur, *bb; unsigned int used0, used_before, usedmax, used; int ret; - used0 = (size + required_ext) % erofs_blksiz() + inline_ext; + used0 = ((size + required_ext) & (blksiz - 1)) + inline_ext; /* inline data should be in the same fs block */ - if (used0 > erofs_blksiz()) + if (used0 > blksiz) return -ENOSPC; - if (!used0 || alignsize == erofs_blksiz()) { + if (!used0 || alignsize == blksiz) { *bbp = NULL; return 0; } @@ -147,10 +149,10 @@ static int erofs_bfind_for_attach(int type, erofs_off_t size, bb = NULL; /* try to find a most-fit mapped buffer block first */ - if (size + required_ext + inline_ext >= erofs_blksiz()) + if (size + required_ext + inline_ext >= blksiz) goto skip_mapped; - used_before = rounddown(erofs_blksiz() - + used_before = rounddown(blksiz - (size + required_ext + inline_ext), alignsize); for (; used_before; --used_before) { struct list_head *bt = mapped_buckets[type] + used_before; @@ -168,7 +170,7 @@ static int erofs_bfind_for_attach(int type, erofs_off_t size, DBG_BUGON(cur->type != type); DBG_BUGON(cur->blkaddr == NULL_ADDR); - DBG_BUGON(used_before != cur->buffers.off % erofs_blksiz()); + DBG_BUGON(used_before != cur->buffers.off % blksiz); ret = __erofs_battach(cur, NULL, size, alignsize, required_ext + inline_ext, true); @@ -179,7 +181,7 @@ static int erofs_bfind_for_attach(int type, erofs_off_t size, /* should contain all data in the current block */ used = ret + required_ext + inline_ext; - DBG_BUGON(used > erofs_blksiz()); + DBG_BUGON(used > blksiz); bb = cur; usedmax = used; @@ -192,7 +194,7 @@ static int erofs_bfind_for_attach(int type, erofs_off_t size, if (cur == &blkh) cur = list_next_entry(cur, list); for (; cur != &blkh; cur = list_next_entry(cur, list)) { - used_before = cur->buffers.off % erofs_blksiz(); + used_before = cur->buffers.off & (blksiz - 1); /* skip if buffer block is just full */ if (!used_before) @@ -207,10 +209,10 @@ static int erofs_bfind_for_attach(int type, erofs_off_t size, if (ret < 0) continue; - used = (ret + required_ext) % erofs_blksiz() + inline_ext; + used = ((ret + required_ext) & (blksiz - 1)) + inline_ext; /* should contain inline data in current block */ - if (used > erofs_blksiz()) + if (used > blksiz) continue; /* @@ -323,7 +325,7 @@ static erofs_blk_t __erofs_mapbh(struct erofs_buffer_block *bb) erofs_bupdate_mapped(bb); } - blkaddr = bb->blkaddr + BLK_ROUND_UP(bb->buffers.off); + blkaddr = bb->blkaddr + BLK_ROUND_UP(&sbi, bb->buffers.off); if (blkaddr > tail_blkaddr) tail_blkaddr = blkaddr; @@ -349,6 +351,7 @@ erofs_blk_t erofs_mapbh(struct erofs_buffer_block *bb) bool erofs_bflush(struct erofs_buffer_block *bb) { + const unsigned int blksiz = erofs_blksiz(&sbi); struct erofs_buffer_block *p, *n; erofs_blk_t blkaddr; @@ -376,9 +379,9 @@ bool erofs_bflush(struct erofs_buffer_block *bb) if (skip) continue; - padding = erofs_blksiz() - p->buffers.off % erofs_blksiz(); - if (padding != erofs_blksiz()) - dev_fillzero(erofs_pos(blkaddr) - padding, + padding = blksiz - (p->buffers.off & (blksiz - 1)); + if (padding != blksiz) + dev_fillzero(&sbi, erofs_pos(&sbi, blkaddr) - padding, padding, true); DBG_BUGON(!list_empty(&p->buffers.list)); @@ -400,7 +403,7 @@ void erofs_bdrop(struct erofs_buffer_head *bh, bool tryrevoke) /* tail_blkaddr could be rolled back after revoking all bhs */ if (tryrevoke && blkaddr != NULL_ADDR && - tail_blkaddr == blkaddr + BLK_ROUND_UP(bb->buffers.off)) + tail_blkaddr == blkaddr + BLK_ROUND_UP(&sbi, bb->buffers.off)) rollback = true; bh->op = &erofs_drop_directly_bhops; diff --git a/lib/compress.c b/lib/compress.c index a8713225..b43b077c 100644 --- a/lib/compress.c +++ b/lib/compress.c @@ -68,9 +68,10 @@ static void z_erofs_write_indexes_final(struct z_erofs_vle_compress_ctx *ctx) static void z_erofs_write_indexes(struct z_erofs_vle_compress_ctx *ctx) { struct erofs_inode *inode = ctx->inode; + struct erofs_sb_info *sbi = inode->sbi; unsigned int clusterofs = ctx->clusterofs; unsigned int count = ctx->e.length; - unsigned int d0 = 0, d1 = (clusterofs + count) / erofs_blksiz(); + unsigned int d0 = 0, d1 = (clusterofs + count) / erofs_blksiz(sbi); struct z_erofs_lcluster_index di; unsigned int type, advise; @@ -109,7 +110,7 @@ static void z_erofs_write_indexes(struct z_erofs_vle_compress_ctx *ctx) do { advise = 0; /* XXX: big pcluster feature should be per-inode */ - if (d0 == 1 && erofs_sb_has_big_pcluster()) { + if (d0 == 1 && erofs_sb_has_big_pcluster(sbi)) { type = Z_EROFS_LCLUSTER_TYPE_NONHEAD; di.di_u.delta[0] = cpu_to_le16(ctx->e.compressedblks | Z_EROFS_LI_D0_CBLKCNT); @@ -155,12 +156,12 @@ static void z_erofs_write_indexes(struct z_erofs_vle_compress_ctx *ctx) memcpy(ctx->metacur, &di, sizeof(di)); ctx->metacur += sizeof(di); - count -= erofs_blksiz() - clusterofs; + count -= erofs_blksiz(sbi) - clusterofs; clusterofs = 0; ++d0; --d1; - } while (clusterofs + count >= erofs_blksiz()); + } while (clusterofs + count >= erofs_blksiz(sbi)); ctx->clusterofs = clusterofs + count; } @@ -169,6 +170,7 @@ static int z_erofs_compress_dedupe(struct z_erofs_vle_compress_ctx *ctx, unsigned int *len) { struct erofs_inode *inode = ctx->inode; + struct erofs_sb_info *sbi = inode->sbi; int ret = 0; /* @@ -181,12 +183,12 @@ static int z_erofs_compress_dedupe(struct z_erofs_vle_compress_ctx *ctx, do { struct z_erofs_dedupe_ctx dctx = { .start = ctx->queue + ctx->head - ({ int rc; - if (ctx->e.length <= erofs_blksiz()) + if (ctx->e.length <= erofs_blksiz(sbi)) rc = 0; - else if (ctx->e.length - erofs_blksiz() >= ctx->head) + else if (ctx->e.length - erofs_blksiz(sbi) >= ctx->head) rc = ctx->head; else - rc = ctx->e.length - erofs_blksiz(); + rc = ctx->e.length - erofs_blksiz(sbi); rc; }), .end = ctx->queue + ctx->head + *len, .cur = ctx->queue + ctx->head, @@ -203,14 +205,14 @@ static int z_erofs_compress_dedupe(struct z_erofs_vle_compress_ctx *ctx, * decompresssion could be done as another try in practice. */ if (dctx.e.compressedblks > 1 && - (ctx->clusterofs + ctx->e.length - delta) % erofs_blksiz() + - dctx.e.length < 2 * erofs_blksiz()) + (ctx->clusterofs + ctx->e.length - delta) % erofs_blksiz(sbi) + + dctx.e.length < 2 * erofs_blksiz(sbi)) break; /* fall back to noncompact indexes for deduplication */ inode->z_advise &= ~Z_EROFS_ADVISE_COMPACTED_2B; inode->datalayout = EROFS_INODE_COMPRESSED_FULL; - erofs_sb_set_dedupe(); + erofs_sb_set_dedupe(sbi); if (delta) { DBG_BUGON(delta < 0); @@ -230,7 +232,7 @@ static int z_erofs_compress_dedupe(struct z_erofs_vle_compress_ctx *ctx, if (ctx->head >= EROFS_CONFIG_COMPR_MAX_SZ) { const unsigned int qh_aligned = - round_down(ctx->head, erofs_blksiz()); + round_down(ctx->head, erofs_blksiz(sbi)); const unsigned int qh_after = ctx->head - qh_aligned; memmove(ctx->queue, ctx->queue + qh_aligned, @@ -251,52 +253,57 @@ static int write_uncompressed_extent(struct z_erofs_vle_compress_ctx *ctx, unsigned int *len, char *dst) { int ret; + struct erofs_sb_info *sbi = ctx->inode->sbi; unsigned int count, interlaced_offset, rightpart; /* reset clusterofs to 0 if permitted */ - if (!erofs_sb_has_lz4_0padding() && ctx->clusterofs && + if (!erofs_sb_has_lz4_0padding(sbi) && ctx->clusterofs && ctx->head >= ctx->clusterofs) { ctx->head -= ctx->clusterofs; *len += ctx->clusterofs; ctx->clusterofs = 0; } - count = min(erofs_blksiz(), *len); + count = min(erofs_blksiz(sbi), *len); /* write interlaced uncompressed data if needed */ if (ctx->inode->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER) interlaced_offset = ctx->clusterofs; else interlaced_offset = 0; - rightpart = min(erofs_blksiz() - interlaced_offset, count); + rightpart = min(erofs_blksiz(sbi) - interlaced_offset, count); - memset(dst, 0, erofs_blksiz()); + memset(dst, 0, erofs_blksiz(sbi)); memcpy(dst + interlaced_offset, ctx->queue + ctx->head, rightpart); memcpy(dst, ctx->queue + ctx->head + rightpart, count - rightpart); erofs_dbg("Writing %u uncompressed data to block %u", count, ctx->blkaddr); - ret = blk_write(dst, ctx->blkaddr, 1); + ret = blk_write(sbi, dst, ctx->blkaddr, 1); if (ret) return ret; return count; } -static unsigned int z_erofs_get_max_pclusterblks(struct erofs_inode *inode) +static unsigned int z_erofs_get_max_pclustersize(struct erofs_inode *inode) { + unsigned int pclusterblks; + if (erofs_is_packed_inode(inode)) - return cfg.c_pclusterblks_packed; + pclusterblks = cfg.c_pclusterblks_packed; #ifndef NDEBUG - if (cfg.c_random_pclusterblks) - return 1 + rand() % cfg.c_pclusterblks_max; + else if (cfg.c_random_pclusterblks) + pclusterblks = 1 + rand() % cfg.c_pclusterblks_max; #endif - if (cfg.c_compress_hints_file) { + else if (cfg.c_compress_hints_file) { z_erofs_apply_compress_hints(inode); DBG_BUGON(!inode->z_physical_clusterblks); - return inode->z_physical_clusterblks; + pclusterblks = inode->z_physical_clusterblks; + } else { + pclusterblks = cfg.c_pclusterblks_def; } - return cfg.c_pclusterblks_def; + return pclusterblks * erofs_blksiz(inode->sbi); } static int z_erofs_fill_inline_data(struct erofs_inode *inode, void *data, @@ -315,23 +322,25 @@ static int z_erofs_fill_inline_data(struct erofs_inode *inode, void *data, return len; } -static void tryrecompress_trailing(struct erofs_compress *ec, +static void tryrecompress_trailing(struct z_erofs_vle_compress_ctx *ctx, + struct erofs_compress *ec, void *in, unsigned int *insize, void *out, int *compressedsize) { + struct erofs_sb_info *sbi = ctx->inode->sbi; static char tmp[Z_EROFS_PCLUSTER_MAX_SIZE]; unsigned int count; int ret = *compressedsize; /* no need to recompress */ - if (!(ret & (erofs_blksiz() - 1))) + if (!(ret & (erofs_blksiz(sbi) - 1))) return; count = *insize; ret = erofs_compress_destsize(ec, in, &count, (void *)tmp, - rounddown(ret, erofs_blksiz()), false); + rounddown(ret, erofs_blksiz(sbi)), false); if (ret <= 0 || ret + (*insize - count) >= - roundup(*compressedsize, erofs_blksiz())) + roundup(*compressedsize, erofs_blksiz(sbi))) return; /* replace the original compressed data if any gain */ @@ -344,15 +353,16 @@ static bool z_erofs_fixup_deduped_fragment(struct z_erofs_vle_compress_ctx *ctx, unsigned int len) { struct erofs_inode *inode = ctx->inode; + struct erofs_sb_info *sbi = inode->sbi; const unsigned int newsize = ctx->remaining + len; DBG_BUGON(!inode->fragment_size); /* try to fix again if it gets larger (should be rare) */ if (inode->fragment_size < newsize) { - ctx->pclustersize = min(z_erofs_get_max_pclusterblks(inode) * erofs_blksiz(), + ctx->pclustersize = min(z_erofs_get_max_pclustersize(inode), roundup(newsize - inode->fragment_size, - erofs_blksiz())); + erofs_blksiz(sbi))); return false; } @@ -373,7 +383,8 @@ static int vle_compress_one(struct z_erofs_vle_compress_ctx *ctx) { static char dstbuf[EROFS_CONFIG_COMPR_MAX_SZ + EROFS_MAX_BLOCK_SIZE]; struct erofs_inode *inode = ctx->inode; - char *const dst = dstbuf + erofs_blksiz(); + struct erofs_sb_info *sbi = inode->sbi; + char *const dst = dstbuf + erofs_blksiz(sbi); struct erofs_compress *const h = &ctx->ccfg->handle; unsigned int len = ctx->tail - ctx->head; bool is_packed_inode = erofs_is_packed_inode(inode); @@ -396,13 +407,13 @@ static int vle_compress_one(struct z_erofs_vle_compress_ctx *ctx) if (may_packing) { if (inode->fragment_size && !fix_dedupedfrag) { ctx->pclustersize = - roundup(len, erofs_blksiz()); + roundup(len, erofs_blksiz(sbi)); goto fix_dedupedfrag; } ctx->e.length = len; goto frag_packing; } - if (!may_inline && len <= erofs_blksiz()) + if (!may_inline && len <= erofs_blksiz(sbi)) goto nocompression; } @@ -418,7 +429,7 @@ static int vle_compress_one(struct z_erofs_vle_compress_ctx *ctx) erofs_strerror(ret)); } - if (may_inline && len < erofs_blksiz()) { + if (may_inline && len < erofs_blksiz(sbi)) { ret = z_erofs_fill_inline_data(inode, ctx->queue + ctx->head, len, true); @@ -455,8 +466,8 @@ static int vle_compress_one(struct z_erofs_vle_compress_ctx *ctx) fix_dedupedfrag = false; /* tailpcluster should be less than 1 block */ } else if (may_inline && len == ctx->e.length && - ret < erofs_blksiz()) { - if (ctx->clusterofs + len <= erofs_blksiz()) { + ret < erofs_blksiz(sbi)) { + if (ctx->clusterofs + len <= erofs_blksiz(sbi)) { inode->eof_tailraw = malloc(len); if (!inode->eof_tailraw) return -ENOMEM; @@ -482,36 +493,37 @@ static int vle_compress_one(struct z_erofs_vle_compress_ctx *ctx) * Otherwise, just drop it and go to packing. */ if (may_packing && len == ctx->e.length && - (ret & (erofs_blksiz() - 1)) && + (ret & (erofs_blksiz(sbi) - 1)) && ctx->tail < sizeof(ctx->queue)) { - ctx->pclustersize = - BLK_ROUND_UP(ret) * erofs_blksiz(); + ctx->pclustersize = BLK_ROUND_UP(sbi, ret) * + erofs_blksiz(sbi); goto fix_dedupedfrag; } if (may_inline && len == ctx->e.length) - tryrecompress_trailing(h, ctx->queue + ctx->head, + tryrecompress_trailing(ctx, h, + ctx->queue + ctx->head, &ctx->e.length, dst, &ret); - tailused = ret & (erofs_blksiz() - 1); + tailused = ret & (erofs_blksiz(sbi) - 1); padding = 0; - ctx->e.compressedblks = BLK_ROUND_UP(ret); - DBG_BUGON(ctx->e.compressedblks * erofs_blksiz() >= + ctx->e.compressedblks = BLK_ROUND_UP(sbi, ret); + DBG_BUGON(ctx->e.compressedblks * erofs_blksiz(sbi) >= ctx->e.length); /* zero out garbage trailing data for non-0padding */ - if (!erofs_sb_has_lz4_0padding()) + if (!erofs_sb_has_lz4_0padding(sbi)) memset(dst + ret, 0, - roundup(ret, erofs_blksiz()) - ret); + roundup(ret, erofs_blksiz(sbi)) - ret); else if (tailused) - padding = erofs_blksiz() - tailused; + padding = erofs_blksiz(sbi) - tailused; /* write compressed data */ erofs_dbg("Writing %u compressed data to %u of %u blocks", ctx->e.length, ctx->blkaddr, ctx->e.compressedblks); - ret = blk_write(dst - padding, ctx->blkaddr, + ret = blk_write(sbi, dst - padding, ctx->blkaddr, ctx->e.compressedblks); if (ret) return ret; @@ -534,7 +546,7 @@ static int vle_compress_one(struct z_erofs_vle_compress_ctx *ctx) if (!final && ctx->head >= EROFS_CONFIG_COMPR_MAX_SZ) { const unsigned int qh_aligned = - round_down(ctx->head, erofs_blksiz()); + round_down(ctx->head, erofs_blksiz(sbi)); const unsigned int qh_after = ctx->head - qh_aligned; memmove(ctx->queue, ctx->queue + qh_aligned, @@ -592,10 +604,10 @@ static void *write_compacted_indexes(u8 *out, erofs_blk_t *blkaddr_ret, unsigned int destsize, unsigned int logical_clusterbits, - bool final, bool *dummy_head) + bool final, bool *dummy_head, + bool update_blkaddr) { unsigned int vcnt, encodebits, pos, i, cblks; - bool update_blkaddr; erofs_blk_t blkaddr; if (destsize == 4) @@ -606,7 +618,6 @@ static void *write_compacted_indexes(u8 *out, return ERR_PTR(-EINVAL); encodebits = (vcnt * destsize * 8 - 32) / vcnt; blkaddr = *blkaddr_ret; - update_blkaddr = erofs_sb_has_big_pcluster(); pos = 0; for (i = 0; i < vcnt; ++i) { @@ -669,12 +680,14 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode, const unsigned int logical_clusterbits = inode->z_logical_clusterbits; u8 *out, *in; struct z_erofs_compressindex_vec cv[16]; + struct erofs_sb_info *sbi = inode->sbi; /* # of 8-byte units so that it can be aligned with 32 bytes */ unsigned int compacted_4b_initial, compacted_4b_end; unsigned int compacted_2b; bool dummy_head; + bool big_pcluster = erofs_sb_has_big_pcluster(sbi); - if (logical_clusterbits < sbi.blkszbits || sbi.blkszbits < 12) + if (logical_clusterbits < sbi->blkszbits || sbi->blkszbits < 12) return -EINVAL; if (logical_clusterbits > 14) { erofs_err("compact format is unsupported for lcluster size %u", @@ -714,7 +727,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode, dummy_head = false; /* prior to bigpcluster, blkaddr was bumped up once coming into HEAD */ - if (!erofs_sb_has_big_pcluster()) { + if (!big_pcluster) { --blkaddr; dummy_head = true; } @@ -724,7 +737,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode, in = parse_legacy_indexes(cv, 2, in); out = write_compacted_indexes(out, cv, &blkaddr, 4, logical_clusterbits, false, - &dummy_head); + &dummy_head, big_pcluster); compacted_4b_initial -= 2; } DBG_BUGON(compacted_4b_initial); @@ -734,7 +747,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode, in = parse_legacy_indexes(cv, 16, in); out = write_compacted_indexes(out, cv, &blkaddr, 2, logical_clusterbits, false, - &dummy_head); + &dummy_head, big_pcluster); compacted_2b -= 16; } DBG_BUGON(compacted_2b); @@ -744,7 +757,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode, in = parse_legacy_indexes(cv, 2, in); out = write_compacted_indexes(out, cv, &blkaddr, 4, logical_clusterbits, false, - &dummy_head); + &dummy_head, big_pcluster); compacted_4b_end -= 2; } @@ -754,7 +767,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode, in = parse_legacy_indexes(cv, 1, in); out = write_compacted_indexes(out, cv, &blkaddr, 4, logical_clusterbits, true, - &dummy_head); + &dummy_head, big_pcluster); } inode->extent_isize = out - (u8 *)compressmeta; return 0; @@ -763,12 +776,13 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode, static void z_erofs_write_mapheader(struct erofs_inode *inode, void *compressmeta) { + struct erofs_sb_info *sbi = inode->sbi; struct z_erofs_map_header h = { .h_advise = cpu_to_le16(inode->z_advise), .h_algorithmtype = inode->z_algorithmtype[1] << 4 | inode->z_algorithmtype[0], /* lclustersize */ - .h_clusterbits = inode->z_logical_clusterbits - sbi.blkszbits, + .h_clusterbits = inode->z_logical_clusterbits - sbi->blkszbits, }; if (inode->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) @@ -783,6 +797,7 @@ static void z_erofs_write_mapheader(struct erofs_inode *inode, void z_erofs_drop_inline_pcluster(struct erofs_inode *inode) { + struct erofs_sb_info *sbi = inode->sbi; const unsigned int type = Z_EROFS_LCLUSTER_TYPE_PLAIN; struct z_erofs_map_header *h = inode->compressmeta; @@ -808,12 +823,12 @@ void z_erofs_drop_inline_pcluster(struct erofs_inode *inode) u8 *out; eofs = inode->extent_isize - - (4 << (BLK_ROUND_UP(inode->i_size) & 1)); + (4 << (BLK_ROUND_UP(sbi, inode->i_size) & 1)); base = round_down(eofs, 8); pos = 16 /* encodebits */ * ((eofs - base) / 4); out = inode->compressmeta + base; - lo = get_unaligned_le32(out + pos / 8) & (erofs_blksiz() - 1); - v = (type << sbi.blkszbits) | lo; + lo = erofs_blkoff(sbi, get_unaligned_le32(out + pos / 8)); + v = (type << sbi->blkszbits) | lo; out[pos / 8] = v & 0xff; out[pos / 8 + 1] = v >> 8; } else { @@ -835,7 +850,8 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd) erofs_blk_t blkaddr, compressed_blocks; unsigned int legacymetasize; int ret; - u8 *compressmeta = malloc(BLK_ROUND_UP(inode->i_size) * + struct erofs_sb_info *sbi = inode->sbi; + u8 *compressmeta = malloc(BLK_ROUND_UP(sbi, inode->i_size) * sizeof(struct z_erofs_lcluster_index) + Z_EROFS_LEGACY_MAP_HEADER_SIZE); @@ -851,7 +867,7 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd) /* initialize per-file compression setting */ inode->z_advise = 0; - inode->z_logical_clusterbits = sbi.blkszbits; + inode->z_logical_clusterbits = sbi->blkszbits; if (!cfg.c_legacy_compress && inode->z_logical_clusterbits <= 14) { if (inode->z_logical_clusterbits <= 12) inode->z_advise |= Z_EROFS_ADVISE_COMPACTED_2B; @@ -860,7 +876,7 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd) inode->datalayout = EROFS_INODE_COMPRESSED_FULL; } - if (erofs_sb_has_big_pcluster()) { + if (erofs_sb_has_big_pcluster(sbi)) { inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_1; if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT) inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_2; @@ -897,7 +913,7 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd) blkaddr = erofs_mapbh(bh->block); /* start_blkaddr */ ctx.inode = inode; - ctx.pclustersize = z_erofs_get_max_pclusterblks(inode) * erofs_blksiz(); + ctx.pclustersize = z_erofs_get_max_pclustersize(inode); ctx.blkaddr = blkaddr; ctx.metacur = compressmeta + Z_EROFS_LEGACY_MAP_HEADER_SIZE; ctx.head = ctx.tail = 0; @@ -950,7 +966,7 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd) legacymetasize = ctx.metacur - compressmeta; /* estimate if data compression saves space or not */ if (!inode->fragment_size && - compressed_blocks * erofs_blksiz() + inode->idata_size + + compressed_blocks * erofs_blksiz(sbi) + inode->idata_size + legacymetasize >= inode->i_size) { z_erofs_dedupe_commit(true); ret = -ENOSPC; @@ -969,8 +985,8 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd) } if (compressed_blocks) { - ret = erofs_bh_balloon(bh, erofs_pos(compressed_blocks)); - DBG_BUGON(ret != erofs_blksiz()); + ret = erofs_bh_balloon(bh, erofs_pos(sbi, compressed_blocks)); + DBG_BUGON(ret != erofs_blksiz(sbi)); } else { if (!cfg.c_fragments && !cfg.c_dedupe) DBG_BUGON(!inode->idata_size); @@ -1025,12 +1041,13 @@ static int erofs_get_compress_algorithm_id(const char *name) return -ENOTSUP; } -int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh) +static int z_erofs_build_compr_cfgs(struct erofs_sb_info *sbi, + struct erofs_buffer_head *sb_bh) { struct erofs_buffer_head *bh = sb_bh; int ret = 0; - if (sbi.available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4)) { + if (sbi->available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4)) { struct { __le16 size; struct z_erofs_lz4_cfgs lz4; @@ -1038,7 +1055,7 @@ int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh) .size = cpu_to_le16(sizeof(struct z_erofs_lz4_cfgs)), .lz4 = { .max_distance = - cpu_to_le16(sbi.lz4_max_distance), + cpu_to_le16(sbi->lz4_max_distance), .max_pclusterblks = cfg.c_pclusterblks_max, } }; @@ -1049,12 +1066,12 @@ int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh) return PTR_ERR(bh); } erofs_mapbh(bh->block); - ret = dev_write(&lz4alg, erofs_btell(bh, false), + ret = dev_write(sbi, &lz4alg, erofs_btell(bh, false), sizeof(lz4alg)); bh->op = &erofs_drop_directly_bhops; } #ifdef HAVE_LIBLZMA - if (sbi.available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZMA)) { + if (sbi->available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZMA)) { struct { __le16 size; struct z_erofs_lzma_cfgs lzma; @@ -1071,12 +1088,12 @@ int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh) return PTR_ERR(bh); } erofs_mapbh(bh->block); - ret = dev_write(&lzmaalg, erofs_btell(bh, false), + ret = dev_write(sbi, &lzmaalg, erofs_btell(bh, false), sizeof(lzmaalg)); bh->op = &erofs_drop_directly_bhops; } #endif - if (sbi.available_compr_algs & (1 << Z_EROFS_COMPRESSION_DEFLATE)) { + if (sbi->available_compr_algs & (1 << Z_EROFS_COMPRESSION_DEFLATE)) { struct { __le16 size; struct z_erofs_deflate_cfgs z; @@ -1094,19 +1111,19 @@ int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh) return PTR_ERR(bh); } erofs_mapbh(bh->block); - ret = dev_write(&zalg, erofs_btell(bh, false), + ret = dev_write(sbi, &zalg, erofs_btell(bh, false), sizeof(zalg)); bh->op = &erofs_drop_directly_bhops; } return ret; } -int z_erofs_compress_init(struct erofs_buffer_head *sb_bh) +int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh) { int i, ret; for (i = 0; cfg.c_compr_alg[i]; ++i) { - ret = erofs_compressor_init(&erofs_ccfg[i].handle, + ret = erofs_compressor_init(sbi, &erofs_ccfg[i].handle, cfg.c_compr_alg[i]); if (ret) return ret; @@ -1121,9 +1138,9 @@ int z_erofs_compress_init(struct erofs_buffer_head *sb_bh) return ret; erofs_ccfg[i].algorithmtype = ret; erofs_ccfg[i].enable = true; - sbi.available_compr_algs |= 1 << ret; + sbi->available_compr_algs |= 1 << ret; if (ret != Z_EROFS_COMPRESSION_LZ4) - erofs_sb_set_compr_cfgs(); + erofs_sb_set_compr_cfgs(sbi); } /* @@ -1132,7 +1149,7 @@ int z_erofs_compress_init(struct erofs_buffer_head *sb_bh) */ if (!cfg.c_compr_alg[0] || (cfg.c_legacy_compress && !strncmp(cfg.c_compr_alg[0], "lz4", 3))) - erofs_sb_clear_lz4_0padding(); + erofs_sb_clear_lz4_0padding(sbi); if (!cfg.c_compr_alg[0]) return 0; @@ -1143,21 +1160,21 @@ int z_erofs_compress_init(struct erofs_buffer_head *sb_bh) */ if (cfg.c_pclusterblks_max > 1) { if (cfg.c_pclusterblks_max > - Z_EROFS_PCLUSTER_MAX_SIZE / erofs_blksiz()) { + Z_EROFS_PCLUSTER_MAX_SIZE / erofs_blksiz(sbi)) { erofs_err("unsupported clusterblks %u (too large)", cfg.c_pclusterblks_max); return -EINVAL; } - erofs_sb_set_big_pcluster(); + erofs_sb_set_big_pcluster(sbi); } if (cfg.c_pclusterblks_packed > cfg.c_pclusterblks_max) { erofs_err("invalid physical cluster size for the packed file"); return -EINVAL; } - if (erofs_sb_has_compr_cfgs()) { - sbi.available_compr_algs |= 1 << ret; - return z_erofs_build_compr_cfgs(sb_bh); + if (erofs_sb_has_compr_cfgs(sbi)) { + sbi->available_compr_algs |= 1 << ret; + return z_erofs_build_compr_cfgs(sbi, sb_bh); } return 0; } diff --git a/lib/compress_hints.c b/lib/compress_hints.c index 0182e93b..afc9f8f3 100644 --- a/lib/compress_hints.c +++ b/lib/compress_hints.c @@ -86,7 +86,7 @@ void erofs_cleanup_compress_hints(void) } } -int erofs_load_compress_hints(void) +int erofs_load_compress_hints(struct erofs_sb_info *sbi) { char buf[PATH_MAX + 100]; FILE *f; @@ -133,21 +133,21 @@ int erofs_load_compress_hints(void) } } - if (pclustersize % erofs_blksiz()) { + if (pclustersize % erofs_blksiz(sbi)) { erofs_warn("invalid physical clustersize %u, " "use default pclusterblks %u", pclustersize, cfg.c_pclusterblks_def); continue; } erofs_insert_compress_hints(pattern, - pclustersize / erofs_blksiz(), ccfg); + pclustersize / erofs_blksiz(sbi), ccfg); if (pclustersize > max_pclustersize) max_pclustersize = pclustersize; } - if (cfg.c_pclusterblks_max * erofs_blksiz() < max_pclustersize) { - cfg.c_pclusterblks_max = max_pclustersize / erofs_blksiz(); + if (cfg.c_pclusterblks_max * erofs_blksiz(sbi) < max_pclustersize) { + cfg.c_pclusterblks_max = max_pclustersize / erofs_blksiz(sbi); erofs_warn("update max pclusterblks to %u", cfg.c_pclusterblks_max); } out: diff --git a/lib/compressor.c b/lib/compressor.c index f81db5bb..4333f26f 100644 --- a/lib/compressor.c +++ b/lib/compressor.c @@ -42,10 +42,10 @@ int erofs_compress_destsize(const struct erofs_compress *c, if (ret < 0) return ret; - /* XXX: ret >= erofs_blksiz() is a temporary hack for ztailpacking */ - if (inblocks || ret >= erofs_blksiz() || + /* XXX: ret >= destsize_alignsize is a temporary hack for ztailpacking */ + if (inblocks || ret >= c->destsize_alignsize || uncompressed_capacity != *srcsize) - compressed_size = roundup(ret, erofs_blksiz()); + compressed_size = roundup(ret, c->destsize_alignsize); else compressed_size = ret; DBG_BUGON(c->compress_threshold < 100); @@ -72,16 +72,19 @@ int erofs_compressor_setlevel(struct erofs_compress *c, int compression_level) return 0; } -int erofs_compressor_init(struct erofs_compress *c, char *alg_name) +int erofs_compressor_init(struct erofs_sb_info *sbi, + struct erofs_compress *c, char *alg_name) { int ret, i; + c->sbi = sbi; + /* should be written in "minimum compression ratio * 100" */ c->compress_threshold = 100; /* optimize for 4k size page */ - c->destsize_alignsize = erofs_blksiz(); - c->destsize_redzone_begin = erofs_blksiz() - 16; + c->destsize_alignsize = erofs_blksiz(sbi); + c->destsize_redzone_begin = erofs_blksiz(sbi) - 16; c->destsize_redzone_end = EROFS_CONFIG_COMPR_DEF_BOUNDARY; if (!alg_name) { diff --git a/lib/compressor.h b/lib/compressor.h index f699fe7e..08a3988f 100644 --- a/lib/compressor.h +++ b/lib/compressor.h @@ -27,6 +27,7 @@ struct erofs_compressor { }; struct erofs_compress { + struct erofs_sb_info *sbi; const struct erofs_compressor *alg; unsigned int compress_threshold; @@ -52,7 +53,8 @@ int erofs_compress_destsize(const struct erofs_compress *c, void *dst, unsigned int dstsize, bool inblocks); int erofs_compressor_setlevel(struct erofs_compress *c, int compression_level); -int erofs_compressor_init(struct erofs_compress *c, char *alg_name); +int erofs_compressor_init(struct erofs_sb_info *sbi, + struct erofs_compress *c, char *alg_name); int erofs_compressor_exit(struct erofs_compress *c); #endif diff --git a/lib/compressor_lz4.c b/lib/compressor_lz4.c index b6f6e7e8..e507b709 100644 --- a/lib/compressor_lz4.c +++ b/lib/compressor_lz4.c @@ -33,7 +33,7 @@ static int compressor_lz4_exit(struct erofs_compress *c) static int compressor_lz4_init(struct erofs_compress *c) { c->alg = &erofs_compressor_lz4; - sbi.lz4_max_distance = LZ4_DISTANCE_MAX; + c->sbi->lz4_max_distance = LZ4_DISTANCE_MAX; return 0; } diff --git a/lib/compressor_lz4hc.c b/lib/compressor_lz4hc.c index eec1c849..f2120d88 100644 --- a/lib/compressor_lz4hc.c +++ b/lib/compressor_lz4hc.c @@ -44,7 +44,7 @@ static int compressor_lz4hc_init(struct erofs_compress *c) if (!c->private_data) return -ENOMEM; - sbi.lz4_max_distance = LZ4_DISTANCE_MAX; + c->sbi->lz4_max_distance = LZ4_DISTANCE_MAX; return 0; } diff --git a/lib/data.c b/lib/data.c index 86e28d9f..a172bb57 100644 --- a/lib/data.c +++ b/lib/data.c @@ -18,27 +18,29 @@ static int erofs_map_blocks_flatmode(struct erofs_inode *inode, erofs_blk_t nblocks, lastblk; u64 offset = map->m_la; struct erofs_inode *vi = inode; + struct erofs_sb_info *sbi = inode->sbi; bool tailendpacking = (vi->datalayout == EROFS_INODE_FLAT_INLINE); trace_erofs_map_blocks_flatmode_enter(inode, map, flags); - nblocks = BLK_ROUND_UP(inode->i_size); + nblocks = BLK_ROUND_UP(sbi, inode->i_size); lastblk = nblocks - tailendpacking; /* there is no hole in flatmode */ map->m_flags = EROFS_MAP_MAPPED; - if (offset < erofs_pos(lastblk)) { - map->m_pa = erofs_pos(vi->u.i_blkaddr) + map->m_la; - map->m_plen = erofs_pos(lastblk) - offset; + if (offset < erofs_pos(sbi, lastblk)) { + map->m_pa = erofs_pos(sbi, vi->u.i_blkaddr) + map->m_la; + map->m_plen = erofs_pos(sbi, lastblk) - offset; } else if (tailendpacking) { /* 2 - inode inline B: inode, [xattrs], inline last blk... */ map->m_pa = erofs_iloc(vi) + vi->inode_isize + - vi->xattr_isize + erofs_blkoff(map->m_la); + vi->xattr_isize + erofs_blkoff(sbi, map->m_la); map->m_plen = inode->i_size - offset; /* inline data should be located in the same meta block */ - if (erofs_blkoff(map->m_pa) + map->m_plen > erofs_blksiz()) { + if (erofs_blkoff(sbi, map->m_pa) + map->m_plen > + erofs_blksiz(sbi)) { erofs_err("inline data cross block boundary @ nid %" PRIu64, vi->nid); DBG_BUGON(1); @@ -65,6 +67,7 @@ int erofs_map_blocks(struct erofs_inode *inode, struct erofs_map_blocks *map, int flags) { struct erofs_inode *vi = inode; + struct erofs_sb_info *sbi = inode->sbi; struct erofs_inode_chunk_index *idx; u8 buf[EROFS_MAX_BLOCK_SIZE]; u64 chunknr; @@ -92,36 +95,36 @@ int erofs_map_blocks(struct erofs_inode *inode, pos = roundup(erofs_iloc(vi) + vi->inode_isize + vi->xattr_isize, unit) + unit * chunknr; - err = blk_read(0, buf, erofs_blknr(pos), 1); + err = blk_read(sbi, 0, buf, erofs_blknr(sbi, pos), 1); if (err < 0) return -EIO; map->m_la = chunknr << vi->u.chunkbits; map->m_plen = min_t(erofs_off_t, 1UL << vi->u.chunkbits, - roundup(inode->i_size - map->m_la, erofs_blksiz())); + roundup(inode->i_size - map->m_la, erofs_blksiz(sbi))); /* handle block map */ if (!(vi->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)) { - __le32 *blkaddr = (void *)buf + erofs_blkoff(pos); + __le32 *blkaddr = (void *)buf + erofs_blkoff(sbi, pos); if (le32_to_cpu(*blkaddr) == EROFS_NULL_ADDR) { map->m_flags = 0; } else { - map->m_pa = erofs_pos(le32_to_cpu(*blkaddr)); + map->m_pa = erofs_pos(sbi, le32_to_cpu(*blkaddr)); map->m_flags = EROFS_MAP_MAPPED; } goto out; } /* parse chunk indexes */ - idx = (void *)buf + erofs_blkoff(pos); + idx = (void *)buf + erofs_blkoff(sbi, pos); switch (le32_to_cpu(idx->blkaddr)) { case EROFS_NULL_ADDR: map->m_flags = 0; break; default: map->m_deviceid = le16_to_cpu(idx->device_id) & - sbi.device_id_mask; - map->m_pa = erofs_pos(le32_to_cpu(idx->blkaddr)); + sbi->device_id_mask; + map->m_pa = erofs_pos(sbi, le32_to_cpu(idx->blkaddr)); map->m_flags = EROFS_MAP_MAPPED; break; } @@ -130,23 +133,23 @@ int erofs_map_blocks(struct erofs_inode *inode, return err; } -int erofs_map_dev(struct erofs_map_dev *map) +int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map) { struct erofs_device_info *dif; int id; if (map->m_deviceid) { - if (sbi.extra_devices < map->m_deviceid) + if (sbi->extra_devices < map->m_deviceid) return -ENODEV; - } else if (sbi.extra_devices) { - for (id = 0; id < sbi.extra_devices; ++id) { + } else if (sbi->extra_devices) { + for (id = 0; id < sbi->extra_devices; ++id) { erofs_off_t startoff, length; - dif = sbi.devs + id; + dif = sbi->devs + id; if (!dif->mapped_blkaddr) continue; - startoff = erofs_pos(dif->mapped_blkaddr); - length = erofs_pos(dif->blocks); + startoff = erofs_pos(sbi, dif->mapped_blkaddr); + length = erofs_pos(sbi, dif->blocks); if (map->m_pa >= startoff && map->m_pa < startoff + length) { @@ -158,9 +161,10 @@ int erofs_map_dev(struct erofs_map_dev *map) return 0; } -int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset, - size_t len) +int erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map, + char *buffer, u64 offset, size_t len) { + struct erofs_sb_info *sbi = inode->sbi; struct erofs_map_dev mdev; int ret; @@ -168,11 +172,11 @@ int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset, .m_deviceid = map->m_deviceid, .m_pa = map->m_pa, }; - ret = erofs_map_dev(&mdev); + ret = erofs_map_dev(sbi, &mdev); if (ret) return ret; - ret = dev_read(mdev.m_deviceid, buffer, mdev.m_pa + offset, len); + ret = dev_read(sbi, mdev.m_deviceid, buffer, mdev.m_pa + offset, len); if (ret < 0) return -EIO; return 0; @@ -219,7 +223,8 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer, map.m_la = ptr; } - ret = erofs_read_one_data(&map, estart, moff, eend - map.m_la); + ret = erofs_read_one_data(inode, &map, estart, moff, + eend - map.m_la); if (ret) return ret; ptr = eend; @@ -231,12 +236,14 @@ int z_erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map, char *raw, char *buffer, erofs_off_t skip, erofs_off_t length, bool trimmed) { + struct erofs_sb_info *sbi = inode->sbi; struct erofs_map_dev mdev; int ret = 0; if (map->m_flags & EROFS_MAP_FRAGMENT) { struct erofs_inode packed_inode = { - .nid = sbi.packed_nid, + .sbi = sbi, + .nid = sbi->packed_nid, }; ret = erofs_read_inode_from_disk(&packed_inode); @@ -253,23 +260,24 @@ int z_erofs_read_one_data(struct erofs_inode *inode, mdev = (struct erofs_map_dev) { .m_pa = map->m_pa, }; - ret = erofs_map_dev(&mdev); + ret = erofs_map_dev(sbi, &mdev); if (ret) { DBG_BUGON(1); return ret; } - ret = dev_read(mdev.m_deviceid, raw, mdev.m_pa, map->m_plen); + ret = dev_read(sbi, mdev.m_deviceid, raw, mdev.m_pa, map->m_plen); if (ret < 0) return ret; ret = z_erofs_decompress(&(struct z_erofs_decompress_req) { + .sbi = sbi, .in = raw, .out = buffer, .decodedskip = skip, .interlaced_offset = map->m_algorithmformat == Z_EROFS_COMPRESSION_INTERLACED ? - erofs_blkoff(map->m_la) : 0, + erofs_blkoff(sbi, map->m_la) : 0, .inputsize = map->m_plen, .decodedlength = length, .alg = map->m_algorithmformat, diff --git a/lib/decompress.c b/lib/decompress.c index 0b41ff46..01f0141b 100644 --- a/lib/decompress.c +++ b/lib/decompress.c @@ -15,6 +15,7 @@ static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq) { + struct erofs_sb_info *sbi = rq->sbi; u8 *dest = (u8 *)rq->out; u8 *src = (u8 *)rq->in; u8 *buff = NULL; @@ -23,8 +24,8 @@ static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq) struct libdeflate_decompressor *inf; enum libdeflate_result ret; - while (!src[inputmargin & (erofs_blksiz() - 1)]) - if (!(++inputmargin & (erofs_blksiz() - 1))) + while (!src[inputmargin & (erofs_blksiz(sbi) - 1)]) + if (!(++inputmargin & (erofs_blksiz(sbi) - 1))) break; if (inputmargin >= rq->inputsize) @@ -96,15 +97,16 @@ static int zerr(int ret) static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq) { - int ret = 0; + struct erofs_sb_info *sbi = rq->sbi; u8 *dest = (u8 *)rq->out; u8 *src = (u8 *)rq->in; u8 *buff = NULL; unsigned int inputmargin = 0; z_stream strm; + int ret; - while (!src[inputmargin & (erofs_blksiz() - 1)]) - if (!(++inputmargin & (erofs_blksiz() - 1))) + while (!src[inputmargin & (erofs_blksiz(sbi) - 1)]) + if (!(++inputmargin & (erofs_blksiz(sbi) - 1))) break; if (inputmargin >= rq->inputsize) @@ -158,6 +160,7 @@ static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq) static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq) { int ret = 0; + struct erofs_sb_info *sbi = rq->sbi; u8 *dest = (u8 *)rq->out; u8 *src = (u8 *)rq->in; u8 *buff = NULL; @@ -165,8 +168,8 @@ static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq) lzma_stream strm; lzma_ret ret2; - while (!src[inputmargin & (erofs_blksiz() - 1)]) - if (!(++inputmargin & (erofs_blksiz() - 1))) + while (!src[inputmargin & (erofs_blksiz(sbi) - 1)]) + if (!(++inputmargin & (erofs_blksiz(sbi) - 1))) break; if (inputmargin >= rq->inputsize) @@ -224,12 +227,13 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq) char *buff = NULL; bool support_0padding = false; unsigned int inputmargin = 0; + struct erofs_sb_info *sbi = rq->sbi; - if (erofs_sb_has_lz4_0padding()) { + if (erofs_sb_has_lz4_0padding(sbi)) { support_0padding = true; - while (!src[inputmargin & (erofs_blksiz() - 1)]) - if (!(++inputmargin & (erofs_blksiz() - 1))) + while (!src[inputmargin & (erofs_blksiz(sbi) - 1)]) + if (!(++inputmargin & (erofs_blksiz(sbi) - 1))) break; if (inputmargin >= rq->inputsize) @@ -274,22 +278,24 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq) int z_erofs_decompress(struct z_erofs_decompress_req *rq) { + struct erofs_sb_info *sbi = rq->sbi; + if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) { unsigned int count, rightpart, skip; - /* XXX: should support inputsize >= erofs_blksiz() later */ - if (rq->inputsize > erofs_blksiz()) + /* XXX: should support inputsize >= erofs_blksiz(sbi) later */ + if (rq->inputsize > erofs_blksiz(sbi)) return -EFSCORRUPTED; - if (rq->decodedlength > erofs_blksiz()) + if (rq->decodedlength > erofs_blksiz(sbi)) return -EFSCORRUPTED; if (rq->decodedlength < rq->decodedskip) return -EFSCORRUPTED; count = rq->decodedlength - rq->decodedskip; - skip = erofs_blkoff(rq->interlaced_offset + rq->decodedskip); - rightpart = min(erofs_blksiz() - skip, count); + skip = erofs_blkoff(sbi, rq->interlaced_offset + rq->decodedskip); + rightpart = min(erofs_blksiz(sbi) - skip, count); memcpy(rq->out, rq->in + skip, rightpart); memcpy(rq->out + rightpart, rq->in, count - rightpart); return 0; diff --git a/lib/dir.c b/lib/dir.c index abbf27a3..e8df9f70 100644 --- a/lib/dir.c +++ b/lib/dir.c @@ -9,6 +9,7 @@ static int traverse_dirents(struct erofs_dir_context *ctx, unsigned int next_nameoff, unsigned int maxsize, bool fsck) { + struct erofs_sb_info *sbi = ctx->dir->sbi; struct erofs_dirent *de = dentry_blk; const struct erofs_dirent *end = dentry_blk + next_nameoff; const char *prev_name = NULL; @@ -76,8 +77,8 @@ static int traverse_dirents(struct erofs_dir_context *ctx, goto out; } ctx->flags |= EROFS_READDIR_DOTDOT_FOUND; - if (sbi.root_nid == ctx->dir->nid) { - ctx->pnid = sbi.root_nid; + if (sbi->root_nid == ctx->dir->nid) { + ctx->pnid = sbi->root_nid; ctx->flags |= EROFS_READDIR_VALID_PNID; } if (fsck && @@ -123,6 +124,7 @@ static int traverse_dirents(struct erofs_dir_context *ctx, int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck) { struct erofs_inode *dir = ctx->dir; + struct erofs_sb_info *sbi = dir->sbi; int err = 0; erofs_off_t pos; char buf[EROFS_MAX_BLOCK_SIZE]; @@ -133,9 +135,9 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck) ctx->flags &= ~EROFS_READDIR_ALL_SPECIAL_FOUND; pos = 0; while (pos < dir->i_size) { - erofs_blk_t lblk = erofs_blknr(pos); + erofs_blk_t lblk = erofs_blknr(sbi, pos); erofs_off_t maxsize = min_t(erofs_off_t, - dir->i_size - pos, erofs_blksiz()); + dir->i_size - pos, erofs_blksiz(sbi)); const struct erofs_dirent *de = (const void *)buf; unsigned int nameoff; @@ -148,7 +150,7 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck) nameoff = le16_to_cpu(de->nameoff); if (nameoff < sizeof(struct erofs_dirent) || - nameoff >= erofs_blksiz()) { + nameoff >= erofs_blksiz(sbi)) { erofs_err("invalid de[0].nameoff %u @ nid %llu, lblk %u", nameoff, dir->nid | 0ULL, lblk); return -EFSCORRUPTED; @@ -203,7 +205,10 @@ static int erofs_get_pathname_iter(struct erofs_dir_context *ctx) } if (ctx->de_ftype == EROFS_FT_DIR || ctx->de_ftype == EROFS_FT_UNKNOWN) { - struct erofs_inode dir = { .nid = ctx->de_nid }; + struct erofs_inode dir = { + .sbi = ctx->dir->sbi, + .nid = ctx->de_nid + }; ret = erofs_read_inode_from_disk(&dir); if (ret) { @@ -229,10 +234,14 @@ static int erofs_get_pathname_iter(struct erofs_dir_context *ctx) return 0; } -int erofs_get_pathname(erofs_nid_t nid, char *buf, size_t size) +int erofs_get_pathname(struct erofs_sb_info *sbi, erofs_nid_t nid, + char *buf, size_t size) { int ret; - struct erofs_inode root = { .nid = sbi.root_nid }; + struct erofs_inode root = { + .sbi = sbi, + .nid = sbi->root_nid, + }; struct erofs_get_pathname_context pathctx = { .ctx.flags = 0, .ctx.dir = &root, diff --git a/lib/fragments.c b/lib/fragments.c index 1d243d35..d4f6be19 100644 --- a/lib/fragments.c +++ b/lib/fragments.c @@ -229,7 +229,7 @@ void z_erofs_fragments_commit(struct erofs_inode *inode) inode->datalayout = EROFS_INODE_COMPRESSED_FULL; inode->z_advise |= Z_EROFS_ADVISE_FRAGMENT_PCLUSTER; - erofs_sb_set_fragments(); + erofs_sb_set_fragments(inode->sbi); } int z_erofs_pack_file_from_fd(struct erofs_inode *inode, int fd, diff --git a/lib/inode.c b/lib/inode.c index 0d14441d..c4d14767 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -153,7 +153,7 @@ static int __allocate_inode_bh_data(struct erofs_inode *inode, } /* allocate main data buffer */ - bh = erofs_balloc(type, erofs_pos(nblocks), 0, 0); + bh = erofs_balloc(type, erofs_pos(inode->sbi, nblocks), 0, 0); if (IS_ERR(bh)) return PTR_ERR(bh); @@ -181,6 +181,7 @@ static int comp_subdir(const void *a, const void *b) static int erofs_prepare_dir_layout(struct erofs_inode *dir, unsigned int nr_subdirs) { + struct erofs_sb_info *sbi = dir->sbi; struct erofs_dentry *d, *n, **sorted_d; unsigned int i; unsigned int d_size = 0; @@ -203,8 +204,8 @@ static int erofs_prepare_dir_layout(struct erofs_inode *dir, list_for_each_entry(d, &dir->i_subdirs, d_child) { int len = strlen(d->name) + sizeof(struct erofs_dirent); - if ((d_size & (erofs_blksiz() - 1)) + len > erofs_blksiz()) - d_size = round_up(d_size, erofs_blksiz()); + if (erofs_blkoff(sbi, d_size) + len > erofs_blksiz(sbi)) + d_size = round_up(d_size, erofs_blksiz(sbi)); d_size += len; } dir->i_size = d_size; @@ -213,7 +214,7 @@ static int erofs_prepare_dir_layout(struct erofs_inode *dir, dir->datalayout = EROFS_INODE_FLAT_INLINE; /* it will be used in erofs_prepare_inode_buffer */ - dir->idata_size = d_size % erofs_blksiz(); + dir->idata_size = d_size % erofs_blksiz(sbi); return 0; } @@ -274,18 +275,20 @@ static void fill_dirblock(char *buf, unsigned int size, unsigned int q, memset(buf + q, 0, size - q); } -static int write_dirblock(unsigned int q, struct erofs_dentry *head, +static int write_dirblock(struct erofs_sb_info *sbi, + unsigned int q, struct erofs_dentry *head, struct erofs_dentry *end, erofs_blk_t blkaddr) { char buf[EROFS_MAX_BLOCK_SIZE]; - fill_dirblock(buf, erofs_blksiz(), q, head, end); - return blk_write(buf, blkaddr, 1); + fill_dirblock(buf, erofs_blksiz(sbi), q, head, end); + return blk_write(sbi, buf, blkaddr, 1); } erofs_nid_t erofs_lookupnid(struct erofs_inode *inode) { struct erofs_buffer_head *const bh = inode->bh; + struct erofs_sb_info *sbi = inode->sbi; erofs_off_t off, meta_offset; if (!bh || (long long)inode->nid > 0) @@ -294,7 +297,7 @@ erofs_nid_t erofs_lookupnid(struct erofs_inode *inode) erofs_mapbh(bh->block); off = erofs_btell(bh, false); - meta_offset = erofs_pos(sbi.meta_blkaddr); + 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)", @@ -315,6 +318,7 @@ static int erofs_write_dir_file(struct erofs_inode *dir) struct erofs_dentry *head = list_first_entry(&dir->i_subdirs, struct erofs_dentry, d_child); + struct erofs_sb_info *sbi = dir->sbi; struct erofs_dentry *d; int ret; unsigned int q, used, blkno; @@ -322,7 +326,7 @@ static int erofs_write_dir_file(struct erofs_inode *dir) q = used = blkno = 0; /* allocate dir main data */ - ret = __allocate_inode_bh_data(dir, erofs_blknr(dir->i_size), DIRA); + ret = __allocate_inode_bh_data(dir, erofs_blknr(sbi, dir->i_size), DIRA); if (ret) return ret; @@ -331,8 +335,8 @@ static int erofs_write_dir_file(struct erofs_inode *dir) sizeof(struct erofs_dirent); erofs_d_invalidate(d); - if (used + len > erofs_blksiz()) { - ret = write_dirblock(q, head, d, + if (used + len > erofs_blksiz(sbi)) { + ret = write_dirblock(sbi, q, head, d, dir->u.i_blkaddr + blkno); if (ret) return ret; @@ -345,13 +349,13 @@ static int erofs_write_dir_file(struct erofs_inode *dir) q += sizeof(struct erofs_dirent); } - DBG_BUGON(used > erofs_blksiz()); - if (used == erofs_blksiz()) { - DBG_BUGON(dir->i_size % erofs_blksiz()); + DBG_BUGON(used > erofs_blksiz(sbi)); + if (used == erofs_blksiz(sbi)) { + DBG_BUGON(dir->i_size % erofs_blksiz(sbi)); DBG_BUGON(dir->idata_size); - return write_dirblock(q, head, d, dir->u.i_blkaddr + blkno); + return write_dirblock(sbi, q, head, d, dir->u.i_blkaddr + blkno); } - DBG_BUGON(used != dir->i_size % erofs_blksiz()); + DBG_BUGON(used != dir->i_size % erofs_blksiz(sbi)); if (used) { /* fill tail-end dir block */ dir->idata = malloc(used); @@ -365,7 +369,8 @@ static int erofs_write_dir_file(struct erofs_inode *dir) int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf) { - const unsigned int nblocks = erofs_blknr(inode->i_size); + struct erofs_sb_info *sbi = inode->sbi; + const unsigned int nblocks = erofs_blknr(sbi, inode->i_size); int ret; inode->datalayout = EROFS_INODE_FLAT_INLINE; @@ -375,13 +380,13 @@ int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf) return ret; if (nblocks) - blk_write(buf, inode->u.i_blkaddr, nblocks); - inode->idata_size = inode->i_size % erofs_blksiz(); + blk_write(sbi, buf, inode->u.i_blkaddr, nblocks); + inode->idata_size = inode->i_size % erofs_blksiz(sbi); if (inode->idata_size) { inode->idata = malloc(inode->idata_size); if (!inode->idata) return -ENOMEM; - memcpy(inode->idata, buf + erofs_pos(nblocks), + memcpy(inode->idata, buf + erofs_pos(sbi, nblocks), inode->idata_size); } return 0; @@ -399,9 +404,10 @@ static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd) { int ret; unsigned int nblocks, i; + struct erofs_sb_info *sbi = inode->sbi; inode->datalayout = EROFS_INODE_FLAT_INLINE; - nblocks = inode->i_size / erofs_blksiz(); + nblocks = inode->i_size / erofs_blksiz(sbi); ret = __allocate_inode_bh_data(inode, nblocks, DATA); if (ret) @@ -410,20 +416,20 @@ static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd) for (i = 0; i < nblocks; ++i) { char buf[EROFS_MAX_BLOCK_SIZE]; - ret = read(fd, buf, erofs_blksiz()); - if (ret != erofs_blksiz()) { + ret = read(fd, buf, erofs_blksiz(sbi)); + if (ret != erofs_blksiz(sbi)) { if (ret < 0) return -errno; return -EAGAIN; } - ret = blk_write(buf, inode->u.i_blkaddr + i, 1); + ret = blk_write(sbi, buf, inode->u.i_blkaddr + i, 1); if (ret) return ret; } /* read the tail-end data */ - inode->idata_size = inode->i_size % erofs_blksiz(); + inode->idata_size = inode->i_size % erofs_blksiz(sbi); if (inode->idata_size) { inode->idata = malloc(inode->idata_size); if (!inode->idata) @@ -473,6 +479,7 @@ int erofs_write_file(struct erofs_inode *inode, int fd) static bool erofs_bh_flush_write_inode(struct erofs_buffer_head *bh) { struct erofs_inode *const inode = bh->fsprivate; + struct erofs_sb_info *sbi = inode->sbi; const u16 icount = EROFS_INODE_XATTR_ICOUNT(inode->xattr_isize); erofs_off_t off = erofs_btell(bh, false); union { @@ -559,7 +566,7 @@ static bool erofs_bh_flush_write_inode(struct erofs_buffer_head *bh) BUG_ON(1); } - ret = dev_write(&u, off, inode->inode_isize); + ret = dev_write(sbi, &u, off, inode->inode_isize); if (ret) return false; off += inode->inode_isize; @@ -570,7 +577,7 @@ static bool erofs_bh_flush_write_inode(struct erofs_buffer_head *bh) if (IS_ERR(xattrs)) return false; - ret = dev_write(xattrs, off, inode->xattr_isize); + ret = dev_write(sbi, xattrs, off, inode->xattr_isize); free(xattrs); if (ret) return false; @@ -586,7 +593,7 @@ static bool erofs_bh_flush_write_inode(struct erofs_buffer_head *bh) } else { /* write compression metadata */ off = roundup(off, 8); - ret = dev_write(inode->compressmeta, off, + ret = dev_write(sbi, inode->compressmeta, off, inode->extent_isize); if (ret) return false; @@ -605,6 +612,7 @@ static struct erofs_bhops erofs_write_inode_bhops = { static int erofs_prepare_tail_block(struct erofs_inode *inode) { + struct erofs_sb_info *sbi = inode->sbi; struct erofs_buffer_head *bh; int ret; @@ -614,8 +622,8 @@ static int erofs_prepare_tail_block(struct erofs_inode *inode) bh = inode->bh_data; if (bh) { /* expend a block as the tail block (should be successful) */ - ret = erofs_bh_balloon(bh, erofs_blksiz()); - if (ret != erofs_blksiz()) { + ret = erofs_bh_balloon(bh, erofs_blksiz(sbi)); + if (ret != erofs_blksiz(sbi)) { DBG_BUGON(1); return -EIO; } @@ -678,7 +686,7 @@ static int erofs_prepare_inode_buffer(struct erofs_inode *inode) erofs_dbg("Inline %scompressed data (%u bytes) to %s", inode->compressed_idata ? "" : "un", inode->idata_size, inode->i_srcpath); - erofs_sb_set_ztailpacking(); + erofs_sb_set_ztailpacking(inode->sbi); } else { inode->datalayout = EROFS_INODE_FLAT_INLINE; erofs_dbg("Inline tail-end data (%u bytes) to %s", @@ -706,7 +714,7 @@ static bool erofs_bh_flush_write_inline(struct erofs_buffer_head *bh) const erofs_off_t off = erofs_btell(bh, false); int ret; - ret = dev_write(inode->idata, off, inode->idata_size); + ret = dev_write(inode->sbi, inode->idata, off, inode->idata_size); if (ret) return false; @@ -724,6 +732,7 @@ static struct erofs_bhops erofs_write_inline_bhops = { static int erofs_write_tail_end(struct erofs_inode *inode) { + struct erofs_sb_info *sbi = inode->sbi; struct erofs_buffer_head *bh, *ibh; bh = inode->bh_data; @@ -744,7 +753,7 @@ static int erofs_write_tail_end(struct erofs_inode *inode) erofs_off_t pos, zero_pos; if (!bh) { - bh = erofs_balloc(DATA, erofs_blksiz(), 0, 0); + bh = erofs_balloc(DATA, erofs_blksiz(sbi), 0, 0); if (IS_ERR(bh)) return PTR_ERR(bh); bh->op = &erofs_skip_write_bhops; @@ -756,8 +765,8 @@ static int erofs_write_tail_end(struct erofs_inode *inode) } else { if (inode->lazy_tailblock) { /* expend a tail block (should be successful) */ - ret = erofs_bh_balloon(bh, erofs_blksiz()); - if (ret != erofs_blksiz()) { + ret = erofs_bh_balloon(bh, erofs_blksiz(sbi)); + if (ret != erofs_blksiz(sbi)) { DBG_BUGON(1); return -EIO; } @@ -766,24 +775,24 @@ static int erofs_write_tail_end(struct erofs_inode *inode) ret = erofs_mapbh(bh->block); } DBG_BUGON(ret < 0); - pos = erofs_btell(bh, true) - erofs_blksiz(); + pos = erofs_btell(bh, true) - erofs_blksiz(sbi); /* 0'ed data should be padded at head for 0padding conversion */ - if (erofs_sb_has_lz4_0padding() && inode->compressed_idata) { + if (erofs_sb_has_lz4_0padding(sbi) && inode->compressed_idata) { zero_pos = pos; - pos += erofs_blksiz() - inode->idata_size; + pos += erofs_blksiz(sbi) - inode->idata_size; } else { /* pad 0'ed data for the other cases */ zero_pos = pos + inode->idata_size; } - ret = dev_write(inode->idata, pos, inode->idata_size); + ret = dev_write(sbi, inode->idata, pos, inode->idata_size); if (ret) return ret; - DBG_BUGON(inode->idata_size > erofs_blksiz()); - if (inode->idata_size < erofs_blksiz()) { - ret = dev_fillzero(zero_pos, - erofs_blksiz() - inode->idata_size, + DBG_BUGON(inode->idata_size > erofs_blksiz(sbi)); + if (inode->idata_size < erofs_blksiz(sbi)) { + ret = dev_fillzero(sbi, zero_pos, + erofs_blksiz(sbi) - inode->idata_size, false); if (ret) return ret; @@ -792,7 +801,7 @@ static int erofs_write_tail_end(struct erofs_inode *inode) free(inode->idata); inode->idata = NULL; - erofs_droid_blocklist_write_tail_end(inode, erofs_blknr(pos)); + erofs_droid_blocklist_write_tail_end(inode, erofs_blknr(sbi, pos)); } out: /* now bh_data can drop directly */ @@ -821,8 +830,8 @@ static bool erofs_should_use_inode_extended(struct erofs_inode *inode) return true; if (inode->i_nlink > USHRT_MAX) return true; - if ((inode->i_mtime != sbi.build_time || - inode->i_mtime_nsec != sbi.build_time_nsec) && + if ((inode->i_mtime != inode->sbi->build_time || + inode->i_mtime_nsec != inode->sbi->build_time_nsec) && !cfg.c_ignore_mtime) return true; return false; @@ -897,6 +906,7 @@ static int erofs_fill_inode(struct erofs_inode *inode, struct stat *st, const char *path) { int err = erofs_droid_inode_fsconfig(inode, st, path); + struct erofs_sb_info *sbi = inode->sbi; if (err) return err; @@ -917,11 +927,11 @@ static int erofs_fill_inode(struct erofs_inode *inode, struct stat *st, switch (cfg.c_timeinherit) { case TIMESTAMP_CLAMPING: - if (inode->i_mtime < sbi.build_time) + if (inode->i_mtime < sbi->build_time) break; case TIMESTAMP_FIXED: - inode->i_mtime = sbi.build_time; - inode->i_mtime_nsec = sbi.build_time_nsec; + inode->i_mtime = sbi->build_time; + inode->i_mtime_nsec = sbi->build_time_nsec; default: break; } @@ -978,6 +988,7 @@ struct erofs_inode *erofs_new_inode(void) if (!inode) return ERR_PTR(-ENOMEM); + inode->sbi = &sbi; inode->i_ino[0] = sbi.inos++; /* inode serial number */ inode->i_count = 1; inode->datalayout = EROFS_INODE_FLAT_PLAIN; @@ -1031,16 +1042,17 @@ static void erofs_fixup_meta_blkaddr(struct erofs_inode *rootdir) { const erofs_off_t rootnid_maxoffset = 0xffff << EROFS_ISLOTBITS; struct erofs_buffer_head *const bh = rootdir->bh; + struct erofs_sb_info *sbi = rootdir->sbi; erofs_off_t off, meta_offset; erofs_mapbh(bh->block); off = erofs_btell(bh, false); if (off > rootnid_maxoffset) - meta_offset = round_up(off - rootnid_maxoffset, erofs_blksiz()); + meta_offset = round_up(off - rootnid_maxoffset, erofs_blksiz(sbi)); else meta_offset = 0; - sbi.meta_blkaddr = erofs_blknr(meta_offset); + sbi->meta_blkaddr = erofs_blknr(sbi, meta_offset); rootdir->nid = (off - meta_offset) >> EROFS_ISLOTBITS; } @@ -1283,8 +1295,8 @@ struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char *name) } if (name == EROFS_PACKED_INODE) { - sbi.packed_nid = EROFS_PACKED_NID_UNALLOCATED; - inode->nid = sbi.packed_nid; + inode->sbi->packed_nid = EROFS_PACKED_NID_UNALLOCATED; + inode->nid = inode->sbi->packed_nid; } ret = erofs_write_compressed_file(inode, fd); diff --git a/lib/io.c b/lib/io.c index 1d266a5e..8d84de23 100644 --- a/lib/io.c +++ b/lib/io.c @@ -23,12 +23,7 @@ #define EROFS_MODNAME "erofs_io" #include "erofs/print.h" -static const char *erofs_devname; -int erofs_devfd = -1; -static u64 erofs_devsz; -static unsigned int erofs_nblobs, erofs_blobfd[256]; - -int dev_get_blkdev_size(int fd, u64 *bytes) +static int dev_get_blkdev_size(int fd, u64 *bytes) { errno = ENOTSUP; #ifdef BLKGETSIZE64 @@ -48,15 +43,15 @@ int dev_get_blkdev_size(int fd, u64 *bytes) return -errno; } -void dev_close(void) +void dev_close(struct erofs_sb_info *sbi) { - close(erofs_devfd); - erofs_devname = NULL; - erofs_devfd = -1; - erofs_devsz = 0; + close(sbi->devfd); + sbi->devname = NULL; + sbi->devfd = -1; + sbi->devsz = 0; } -int dev_open(const char *dev) +int dev_open(struct erofs_sb_info *sbi, const char *dev) { struct stat st; int fd, ret; @@ -76,13 +71,13 @@ int dev_open(const char *dev) switch (st.st_mode & S_IFMT) { case S_IFBLK: - ret = dev_get_blkdev_size(fd, &erofs_devsz); + ret = dev_get_blkdev_size(fd, &sbi->devsz); if (ret) { erofs_err("failed to get block device size(%s).", dev); close(fd); return ret; } - erofs_devsz = round_down(erofs_devsz, erofs_blksiz()); + sbi->devsz = round_down(sbi->devsz, erofs_blksiz(sbi)); break; case S_IFREG: ret = ftruncate(fd, 0); @@ -92,7 +87,7 @@ int dev_open(const char *dev) return -errno; } /* INT64_MAX is the limit of kernel vfs */ - erofs_devsz = INT64_MAX; + sbi->devsz = INT64_MAX; break; default: erofs_err("bad file type (%s, %o).", dev, st.st_mode); @@ -100,23 +95,23 @@ int dev_open(const char *dev) return -EINVAL; } - erofs_devname = dev; - erofs_devfd = fd; + sbi->devname = dev; + sbi->devfd = fd; erofs_info("successfully to open %s", dev); return 0; } -void blob_closeall(void) +void blob_closeall(struct erofs_sb_info *sbi) { unsigned int i; - for (i = 0; i < erofs_nblobs; ++i) - close(erofs_blobfd[i]); - erofs_nblobs = 0; + for (i = 0; i < sbi->nblobs; ++i) + close(sbi->blobfd[i]); + sbi->nblobs = 0; } -int blob_open_ro(const char *dev) +int blob_open_ro(struct erofs_sb_info *sbi, const char *dev) { int fd = open(dev, O_RDONLY | O_BINARY); @@ -125,14 +120,14 @@ int blob_open_ro(const char *dev) return -errno; } - erofs_blobfd[erofs_nblobs] = fd; - erofs_info("successfully to open blob%u %s", erofs_nblobs, dev); - ++erofs_nblobs; + sbi->blobfd[sbi->nblobs] = fd; + erofs_info("successfully to open blob%u %s", sbi->nblobs, dev); + ++sbi->nblobs; return 0; } /* XXX: temporary soluation. Disk I/O implementation needs to be refactored. */ -int dev_open_ro(const char *dev) +int dev_open_ro(struct erofs_sb_info *sbi, const char *dev) { int fd = open(dev, O_RDONLY | O_BINARY); @@ -141,18 +136,13 @@ int dev_open_ro(const char *dev) return -errno; } - erofs_devfd = fd; - erofs_devname = dev; - erofs_devsz = INT64_MAX; + sbi->devfd = fd; + sbi->devname = dev; + sbi->devsz = INT64_MAX; return 0; } -u64 dev_length(void) -{ - return erofs_devsz; -} - -int dev_write(const void *buf, u64 offset, size_t len) +int dev_write(struct erofs_sb_info *sbi, const void *buf, u64 offset, size_t len) { int ret; @@ -164,33 +154,33 @@ int dev_write(const void *buf, u64 offset, size_t len) return -EINVAL; } - if (offset >= erofs_devsz || len > erofs_devsz || - offset > erofs_devsz - len) { + if (offset >= sbi->devsz || len > sbi->devsz || + offset > sbi->devsz - len) { erofs_err("Write posion[%" PRIu64 ", %zd] is too large beyond the end of device(%" PRIu64 ").", - offset, len, erofs_devsz); + offset, len, sbi->devsz); return -EINVAL; } #ifdef HAVE_PWRITE64 - ret = pwrite64(erofs_devfd, buf, len, (off64_t)offset); + ret = pwrite64(sbi->devfd, buf, len, (off64_t)offset); #else - ret = pwrite(erofs_devfd, buf, len, (off_t)offset); + ret = pwrite(sbi->devfd, buf, len, (off_t)offset); #endif if (ret != (int)len) { if (ret < 0) { erofs_err("Failed to write data into device - %s:[%" PRIu64 ", %zd].", - erofs_devname, offset, len); + sbi->devname, offset, len); return -errno; } erofs_err("Writing data into device - %s:[%" PRIu64 ", %zd] - was truncated.", - erofs_devname, offset, len); + sbi->devname, offset, len); return -ERANGE; } return 0; } -int dev_fillzero(u64 offset, size_t len, bool padding) +int dev_fillzero(struct erofs_sb_info *sbi, u64 offset, size_t len, bool padding) { static const char zero[EROFS_MAX_BLOCK_SIZE] = {0}; int ret; @@ -199,25 +189,25 @@ int dev_fillzero(u64 offset, size_t len, bool padding) return 0; #if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE) - if (!padding && fallocate(erofs_devfd, FALLOC_FL_PUNCH_HOLE | + if (!padding && fallocate(sbi->devfd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, len) >= 0) return 0; #endif - while (len > erofs_blksiz()) { - ret = dev_write(zero, offset, erofs_blksiz()); + while (len > erofs_blksiz(sbi)) { + ret = dev_write(sbi, zero, offset, erofs_blksiz(sbi)); if (ret) return ret; - len -= erofs_blksiz(); - offset += erofs_blksiz(); + len -= erofs_blksiz(sbi); + offset += erofs_blksiz(sbi); } - return dev_write(zero, offset, len); + return dev_write(sbi, zero, offset, len); } -int dev_fsync(void) +int dev_fsync(struct erofs_sb_info *sbi) { int ret; - ret = fsync(erofs_devfd); + ret = fsync(sbi->devfd); if (ret) { erofs_err("Could not fsync device!!!"); return -EIO; @@ -225,36 +215,37 @@ int dev_fsync(void) return 0; } -int dev_resize(unsigned int blocks) +int dev_resize(struct erofs_sb_info *sbi, unsigned int blocks) { int ret; struct stat st; u64 length; - if (cfg.c_dry_run || erofs_devsz != INT64_MAX) + if (cfg.c_dry_run || sbi->devsz != INT64_MAX) return 0; - ret = fstat(erofs_devfd, &st); + ret = fstat(sbi->devfd, &st); if (ret) { erofs_err("failed to fstat."); return -errno; } - length = (u64)blocks * erofs_blksiz(); + length = (u64)blocks * erofs_blksiz(sbi); if (st.st_size == length) return 0; if (st.st_size > length) - return ftruncate(erofs_devfd, length); + return ftruncate(sbi->devfd, length); length = length - st.st_size; #if defined(HAVE_FALLOCATE) - if (fallocate(erofs_devfd, 0, st.st_size, length) >= 0) + if (fallocate(sbi->devfd, 0, st.st_size, length) >= 0) return 0; #endif - return dev_fillzero(st.st_size, length, true); + return dev_fillzero(sbi, st.st_size, length, true); } -int dev_read(int device_id, void *buf, u64 offset, size_t len) +int dev_read(struct erofs_sb_info *sbi, int device_id, + void *buf, u64 offset, size_t len) { int read_count, fd; @@ -269,13 +260,13 @@ int dev_read(int device_id, void *buf, u64 offset, size_t len) } if (!device_id) { - fd = erofs_devfd; + fd = sbi->devfd; } else { - if (device_id > erofs_nblobs) { + if (device_id > sbi->nblobs) { erofs_err("invalid device id %d", device_id); return -ENODEV; } - fd = erofs_blobfd[device_id - 1]; + fd = sbi->blobfd[device_id - 1]; } while (len > 0) { @@ -287,12 +278,12 @@ int dev_read(int device_id, void *buf, u64 offset, size_t len) if (read_count < 1) { if (!read_count) { erofs_info("Reach EOF of device - %s:[%" PRIu64 ", %zd].", - erofs_devname, offset, len); + sbi->devname, offset, len); memset(buf, 0, len); return 0; } else if (errno != EINTR) { erofs_err("Failed to read data from device - %s:[%" PRIu64 ", %zd].", - erofs_devname, offset, len); + sbi->devname, offset, len); return -errno; } } diff --git a/lib/namei.c b/lib/namei.c index 423c1ddc..1023a9aa 100644 --- a/lib/namei.c +++ b/lib/namei.c @@ -26,11 +26,15 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi) { int ret, ifmt; char buf[sizeof(struct erofs_inode_extended)]; + struct erofs_sb_info *sbi = vi->sbi; struct erofs_inode_compact *dic; struct erofs_inode_extended *die; - const erofs_off_t inode_loc = erofs_iloc(vi); + erofs_off_t inode_loc; - ret = dev_read(0, buf, inode_loc, sizeof(*dic)); + DBG_BUGON(!sbi); + inode_loc = erofs_iloc(vi); + + ret = dev_read(sbi, 0, buf, inode_loc, sizeof(*dic)); if (ret < 0) return -EIO; @@ -47,7 +51,8 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi) case EROFS_INODE_LAYOUT_EXTENDED: vi->inode_isize = sizeof(struct erofs_inode_extended); - ret = dev_read(0, buf + sizeof(*dic), inode_loc + sizeof(*dic), + ret = dev_read(sbi, 0, buf + sizeof(*dic), + inode_loc + sizeof(*dic), sizeof(*die) - sizeof(*dic)); if (ret < 0) return -EIO; @@ -114,8 +119,8 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi) vi->i_gid = le16_to_cpu(dic->i_gid); vi->i_nlink = le16_to_cpu(dic->i_nlink); - vi->i_mtime = sbi.build_time; - vi->i_mtime_nsec = sbi.build_time_nsec; + vi->i_mtime = sbi->build_time; + vi->i_mtime_nsec = sbi->build_time_nsec; vi->i_size = le32_to_cpu(dic->i_size); if (vi->datalayout == EROFS_INODE_CHUNK_BASED) @@ -134,10 +139,10 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi) vi->u.chunkformat, vi->nid | 0ULL); return -EOPNOTSUPP; } - vi->u.chunkbits = sbi.blkszbits + + vi->u.chunkbits = sbi->blkszbits + (vi->u.chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK); } else if (erofs_inode_is_data_compressed(vi->datalayout)) { - if (erofs_blksiz() != EROFS_MAX_BLOCK_SIZE) + if (erofs_blksiz(vi->sbi) != EROFS_MAX_BLOCK_SIZE) return -EOPNOTSUPP; return z_erofs_fill_inode(vi); } @@ -185,6 +190,7 @@ struct erofs_dirent *find_target_dirent(erofs_nid_t pnid, } struct nameidata { + struct erofs_sb_info *sbi; erofs_nid_t nid; unsigned int ftype; }; @@ -194,7 +200,8 @@ int erofs_namei(struct nameidata *nd, const char *name, unsigned int len) erofs_nid_t nid = nd->nid; int ret; char buf[EROFS_MAX_BLOCK_SIZE]; - struct erofs_inode vi = { .nid = nid }; + struct erofs_sb_info *sbi = nd->sbi; + struct erofs_inode vi = { .sbi = sbi, .nid = nid }; erofs_off_t offset; ret = erofs_read_inode_from_disk(&vi); @@ -204,7 +211,7 @@ int erofs_namei(struct nameidata *nd, const char *name, unsigned int len) offset = 0; while (offset < vi.i_size) { erofs_off_t maxsize = min_t(erofs_off_t, - vi.i_size - offset, erofs_blksiz()); + vi.i_size - offset, erofs_blksiz(sbi)); struct erofs_dirent *de = (void *)buf; unsigned int nameoff; @@ -214,7 +221,7 @@ int erofs_namei(struct nameidata *nd, const char *name, unsigned int len) nameoff = le16_to_cpu(de->nameoff); if (nameoff < sizeof(struct erofs_dirent) || - nameoff >= erofs_blksiz()) { + nameoff >= erofs_blksiz(sbi)) { erofs_err("invalid de[0].nameoff %u @ nid %llu", nameoff, nid | 0ULL); return -EFSCORRUPTED; @@ -236,7 +243,7 @@ int erofs_namei(struct nameidata *nd, const char *name, unsigned int len) static int link_path_walk(const char *name, struct nameidata *nd) { - nd->nid = sbi.root_nid; + nd->nid = nd->sbi->root_nid; while (*name == '/') name++; @@ -266,7 +273,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) int erofs_ilookup(const char *path, struct erofs_inode *vi) { int ret; - struct nameidata nd; + struct nameidata nd = { .sbi = vi->sbi }; ret = link_path_walk(path, &nd); if (ret) diff --git a/lib/super.c b/lib/super.c index 820c8834..16a1d62a 100644 --- a/lib/super.c +++ b/lib/super.c @@ -31,7 +31,7 @@ static int erofs_init_devices(struct erofs_sb_info *sbi, sbi->total_blocks = sbi->primarydevice_blocks; - if (!erofs_sb_has_device_table()) + if (!erofs_sb_has_device_table(sbi)) ondisk_extradevs = 0; else ondisk_extradevs = le16_to_cpu(dsb->extra_devices); @@ -53,7 +53,7 @@ static int erofs_init_devices(struct erofs_sb_info *sbi, struct erofs_deviceslot dis; int ret; - ret = dev_read(0, &dis, pos, sizeof(dis)); + ret = dev_read(sbi, 0, &dis, pos, sizeof(dis)); if (ret < 0) { free(sbi->devs); return ret; @@ -66,13 +66,14 @@ static int erofs_init_devices(struct erofs_sb_info *sbi, return 0; } -int erofs_read_superblock(void) +int erofs_read_superblock(struct erofs_sb_info *sbi) { u8 data[EROFS_MAX_BLOCK_SIZE]; struct erofs_super_block *dsb; int ret; - ret = blk_read(0, data, 0, erofs_blknr(sizeof(data))); + sbi->blkszbits = ilog2(EROFS_MAX_BLOCK_SIZE); + ret = blk_read(sbi, 0, data, 0, erofs_blknr(sbi, sizeof(data))); if (ret < 0) { erofs_err("cannot read erofs superblock: %d", ret); return -EIO; @@ -85,36 +86,36 @@ int erofs_read_superblock(void) return ret; } - sbi.feature_compat = le32_to_cpu(dsb->feature_compat); + sbi->feature_compat = le32_to_cpu(dsb->feature_compat); - sbi.blkszbits = dsb->blkszbits; - if (sbi.blkszbits < 9 || - sbi.blkszbits > ilog2(EROFS_MAX_BLOCK_SIZE)) { + sbi->blkszbits = dsb->blkszbits; + if (sbi->blkszbits < 9 || + sbi->blkszbits > ilog2(EROFS_MAX_BLOCK_SIZE)) { erofs_err("blksize %llu isn't supported on this platform", - erofs_blksiz() | 0ULL); + erofs_blksiz(sbi) | 0ULL); return ret; - } else if (!check_layout_compatibility(&sbi, dsb)) { + } else if (!check_layout_compatibility(sbi, dsb)) { return ret; } - sbi.primarydevice_blocks = le32_to_cpu(dsb->blocks); - sbi.meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr); - sbi.xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr); - sbi.islotbits = EROFS_ISLOTBITS; - sbi.root_nid = le16_to_cpu(dsb->root_nid); - sbi.packed_nid = le64_to_cpu(dsb->packed_nid); - sbi.inos = le64_to_cpu(dsb->inos); - sbi.checksum = le32_to_cpu(dsb->checksum); + sbi->primarydevice_blocks = le32_to_cpu(dsb->blocks); + sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr); + sbi->xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr); + sbi->islotbits = EROFS_ISLOTBITS; + sbi->root_nid = le16_to_cpu(dsb->root_nid); + sbi->packed_nid = le64_to_cpu(dsb->packed_nid); + sbi->inos = le64_to_cpu(dsb->inos); + sbi->checksum = le32_to_cpu(dsb->checksum); - sbi.build_time = le64_to_cpu(dsb->build_time); - sbi.build_time_nsec = le32_to_cpu(dsb->build_time_nsec); + sbi->build_time = le64_to_cpu(dsb->build_time); + sbi->build_time_nsec = le32_to_cpu(dsb->build_time_nsec); - memcpy(&sbi.uuid, dsb->uuid, sizeof(dsb->uuid)); - return erofs_init_devices(&sbi, dsb); + memcpy(&sbi->uuid, dsb->uuid, sizeof(dsb->uuid)); + return erofs_init_devices(sbi, dsb); } -void erofs_put_super(void) +void erofs_put_super(struct erofs_sb_info *sbi) { - if (sbi.devs) - free(sbi.devs); + if (sbi->devs) + free(sbi->devs); } diff --git a/lib/tar.c b/lib/tar.c index b62e562b..76ba69d5 100644 --- a/lib/tar.c +++ b/lib/tar.c @@ -161,8 +161,8 @@ static struct erofs_dentry *tarerofs_mkdir(struct erofs_inode *dir, const char * inode->i_parent = dir; inode->i_uid = getuid(); inode->i_gid = getgid(); - inode->i_mtime = sbi.build_time; - inode->i_mtime_nsec = sbi.build_time_nsec; + inode->i_mtime = inode->sbi->build_time; + inode->i_mtime_nsec = inode->sbi->build_time_nsec; tarerofs_init_empty_dir(inode); d = erofs_d_alloc(dir, s); @@ -353,14 +353,15 @@ int tarerofs_parse_pax_header(int fd, struct erofs_pax_header *eh, u32 size) 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; + 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); @@ -382,7 +383,7 @@ int tarerofs_write_chunk_indexes(struct erofs_inode *inode, erofs_blk_t blkaddr) return PTR_ERR(chunk); *(void **)idx++ = chunk; - blkaddr += erofs_blknr(len); + blkaddr += erofs_blknr(sbi, len); } inode->datalayout = EROFS_INODE_CHUNK_BASED; return 0; @@ -410,6 +411,7 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar) { char path[PATH_MAX]; struct erofs_pax_header eh = tar->global; + struct erofs_sb_info *sbi = root->sbi; bool e, whout, opq; struct stat st; erofs_off_t tar_offset, data_offset; @@ -616,7 +618,7 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar) eh.link = strndup(th.linkname, sizeof(th.linkname)); } - if (tar->index_mode && erofs_blkoff(tar_offset + sizeof(th))) { + if (tar->index_mode && erofs_blkoff(sbi, tar_offset + sizeof(th))) { erofs_err("invalid tar data alignment @ %llu", tar_offset); ret = -EIO; goto out; @@ -719,7 +721,7 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar) memcpy(inode->i_link, eh.link, inode->i_size + 1); } else if (tar->index_mode) { ret = tarerofs_write_chunk_indexes(inode, - erofs_blknr(data_offset)); + erofs_blknr(sbi, data_offset)); if (ret) goto out; if (erofs_lskip(tar->fd, inode->i_size)) { @@ -774,7 +776,7 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar) static struct erofs_buffer_head *bh_devt; -int tarerofs_reserve_devtable(unsigned int devices) +int tarerofs_reserve_devtable(struct erofs_sb_info *sbi, unsigned int devices) { if (!devices) return 0; @@ -786,27 +788,27 @@ int tarerofs_reserve_devtable(unsigned int devices) 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->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_tarfile *tar) +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) + if (!sbi->extra_devices) return 0; pos_out = erofs_btell(bh_devt, false); - for (i = 0; i < sbi.extra_devices; ++i) { + for (i = 0; i < sbi->extra_devices; ++i) { struct erofs_deviceslot dis = { - .blocks = erofs_blknr(tar->offset), + .blocks = erofs_blknr(sbi, tar->offset), }; int ret; - ret = dev_write(&dis, pos_out, sizeof(dis)); + ret = dev_write(sbi, &dis, pos_out, sizeof(dis)); if (ret) return ret; pos_out += sizeof(dis); diff --git a/lib/xattr.c b/lib/xattr.c index 9e839353..12f580e7 100644 --- a/lib/xattr.c +++ b/lib/xattr.c @@ -636,7 +636,7 @@ static inline int erofs_xattr_index_by_prefix(const char *prefix, int *len) return -ENODATA; } -int erofs_xattr_write_name_prefixes(FILE *f) +int erofs_xattr_write_name_prefixes(struct erofs_sb_info *sbi, FILE *f) { struct ea_type_node *tnode; struct xattr_prefix *p; @@ -653,8 +653,8 @@ int erofs_xattr_write_name_prefixes(FILE *f) offset = round_up(offset, 4); if (fseek(f, offset, SEEK_SET)) return -errno; - sbi.xattr_prefix_start = (u32)offset >> 2; - sbi.xattr_prefix_count = ea_prefix_count; + sbi->xattr_prefix_start = (u32)offset >> 2; + sbi->xattr_prefix_count = ea_prefix_count; list_for_each_entry(tnode, &ea_name_prefixes, list) { union { @@ -682,12 +682,12 @@ int erofs_xattr_write_name_prefixes(FILE *f) if (fseek(f, offset, SEEK_SET)) return -errno; } - erofs_sb_set_fragments(); - erofs_sb_set_xattr_prefixes(); + erofs_sb_set_fragments(sbi); + erofs_sb_set_xattr_prefixes(sbi); return 0; } -int erofs_build_shared_xattrs_from_path(const char *path) +int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *path) { int ret; struct erofs_buffer_head *bh; @@ -746,8 +746,8 @@ int erofs_build_shared_xattrs_from_path(const char *path) erofs_mapbh(bh->block); off = erofs_btell(bh, false); - sbi.xattr_blkaddr = off / erofs_blksiz(); - off %= erofs_blksiz(); + sbi->xattr_blkaddr = off / erofs_blksiz(sbi); + off %= erofs_blksiz(sbi); p = 0; for (i = 0; i < shared_xattrs_count; i++) { struct xattr_item *item = sorted_n[i]; @@ -768,7 +768,7 @@ int erofs_build_shared_xattrs_from_path(const char *path) shared_xattrs_list = sorted_n[0]; free(sorted_n); bh->op = &erofs_drop_directly_bhops; - ret = dev_write(buf, erofs_btell(bh, false), shared_xattrs_size); + ret = dev_write(sbi, buf, erofs_btell(bh, false), shared_xattrs_size); free(buf); erofs_bdrop(bh, false); out: @@ -837,10 +837,12 @@ struct xattr_iter { erofs_blk_t blkaddr; unsigned int ofs; + struct erofs_sb_info *sbi; }; static int init_inode_xattrs(struct erofs_inode *vi) { + struct erofs_sb_info *sbi = vi->sbi; struct xattr_iter it; unsigned int i; struct erofs_xattr_ibody_header *ih; @@ -871,10 +873,10 @@ static int init_inode_xattrs(struct erofs_inode *vi) return -ENOATTR; } - it.blkaddr = erofs_blknr(erofs_iloc(vi) + vi->inode_isize); - it.ofs = erofs_blkoff(erofs_iloc(vi) + vi->inode_isize); + it.blkaddr = erofs_blknr(sbi, erofs_iloc(vi) + vi->inode_isize); + it.ofs = erofs_blkoff(sbi, erofs_iloc(vi) + vi->inode_isize); - ret = blk_read(0, it.page, it.blkaddr, 1); + ret = blk_read(sbi, 0, it.page, it.blkaddr, 1); if (ret < 0) return -EIO; @@ -890,11 +892,11 @@ static int init_inode_xattrs(struct erofs_inode *vi) it.ofs += sizeof(struct erofs_xattr_ibody_header); for (i = 0; i < vi->xattr_shared_count; ++i) { - if (it.ofs >= erofs_blksiz()) { + if (it.ofs >= erofs_blksiz(sbi)) { /* cannot be unaligned */ - DBG_BUGON(it.ofs != erofs_blksiz()); + DBG_BUGON(it.ofs != erofs_blksiz(sbi)); - ret = blk_read(0, it.page, ++it.blkaddr, 1); + ret = blk_read(sbi, 0, it.page, ++it.blkaddr, 1); if (ret < 0) { free(vi->xattr_shared_xattrs); vi->xattr_shared_xattrs = NULL; @@ -932,25 +934,27 @@ struct xattr_iter_handlers { static inline int xattr_iter_fixup(struct xattr_iter *it) { + struct erofs_sb_info *sbi = it->sbi; int ret; - if (it->ofs < erofs_blksiz()) + if (it->ofs < erofs_blksiz(sbi)) return 0; - it->blkaddr += erofs_blknr(it->ofs); + it->blkaddr += erofs_blknr(sbi, it->ofs); - ret = blk_read(0, it->page, it->blkaddr, 1); + ret = blk_read(sbi, 0, it->page, it->blkaddr, 1); if (ret < 0) return -EIO; it->kaddr = it->page; - it->ofs = erofs_blkoff(it->ofs); + it->ofs = erofs_blkoff(sbi, it->ofs); return 0; } static int inline_xattr_iter_pre(struct xattr_iter *it, struct erofs_inode *vi) { + struct erofs_sb_info *sbi = vi->sbi; unsigned int xattr_header_sz, inline_xattr_ofs; int ret; @@ -962,10 +966,10 @@ static int inline_xattr_iter_pre(struct xattr_iter *it, inline_xattr_ofs = vi->inode_isize + xattr_header_sz; - it->blkaddr = erofs_blknr(erofs_iloc(vi) + inline_xattr_ofs); - it->ofs = erofs_blkoff(erofs_iloc(vi) + inline_xattr_ofs); + it->blkaddr = erofs_blknr(sbi, erofs_iloc(vi) + inline_xattr_ofs); + it->ofs = erofs_blkoff(sbi, erofs_iloc(vi) + inline_xattr_ofs); - ret = blk_read(0, it->page, it->blkaddr, 1); + ret = blk_read(sbi, 0, it->page, it->blkaddr, 1); if (ret < 0) return -EIO; @@ -981,6 +985,7 @@ static int xattr_foreach(struct xattr_iter *it, const struct xattr_iter_handlers *op, unsigned int *tlimit) { + struct erofs_sb_info *sbi = it->sbi; struct erofs_xattr_entry entry; unsigned int value_sz, processed, slice; int err; @@ -1021,8 +1026,8 @@ static int xattr_foreach(struct xattr_iter *it, processed = 0; while (processed < entry.e_name_len) { - if (it->ofs >= erofs_blksiz()) { - DBG_BUGON(it->ofs > erofs_blksiz()); + if (it->ofs >= erofs_blksiz(sbi)) { + DBG_BUGON(it->ofs > erofs_blksiz(sbi)); err = xattr_iter_fixup(it); if (err) @@ -1030,7 +1035,7 @@ static int xattr_foreach(struct xattr_iter *it, it->ofs = 0; } - slice = min_t(unsigned int, erofs_blksiz() - it->ofs, + slice = min_t(unsigned int, erofs_blksiz(sbi) - it->ofs, entry.e_name_len - processed); /* handle name */ @@ -1056,8 +1061,8 @@ static int xattr_foreach(struct xattr_iter *it, } while (processed < value_sz) { - if (it->ofs >= erofs_blksiz()) { - DBG_BUGON(it->ofs > erofs_blksiz()); + if (it->ofs >= erofs_blksiz(sbi)) { + DBG_BUGON(it->ofs > erofs_blksiz(sbi)); err = xattr_iter_fixup(it); if (err) @@ -1065,7 +1070,7 @@ static int xattr_foreach(struct xattr_iter *it, it->ofs = 0; } - slice = min_t(unsigned int, erofs_blksiz() - it->ofs, + slice = min_t(unsigned int, erofs_blksiz(sbi) - it->ofs, value_sz - processed); op->value(it, processed, it->kaddr + it->ofs, slice); it->ofs += slice; @@ -1157,12 +1162,12 @@ static int shared_getxattr(struct erofs_inode *vi, struct getxattr_iter *it) for (i = 0; i < vi->xattr_shared_count; ++i) { erofs_blk_t blkaddr = - xattrblock_addr(vi->xattr_shared_xattrs[i]); + xattrblock_addr(vi, vi->xattr_shared_xattrs[i]); - it->it.ofs = xattrblock_offset(vi->xattr_shared_xattrs[i]); + it->it.ofs = xattrblock_offset(vi, vi->xattr_shared_xattrs[i]); if (!i || blkaddr != it->it.blkaddr) { - ret = blk_read(0, it->it.page, blkaddr, 1); + ret = blk_read(vi->sbi, 0, it->it.page, blkaddr, 1); if (ret < 0) return -EIO; @@ -1196,6 +1201,7 @@ int erofs_getxattr(struct erofs_inode *vi, const char *name, char *buffer, if (!match_prefix(name, &prefix, &prefixlen)) return -ENODATA; + it.it.sbi = vi->sbi; it.index = prefix; it.name = name + prefixlen; it.len = strlen(it.name); @@ -1297,11 +1303,11 @@ static int shared_listxattr(struct erofs_inode *vi, struct listxattr_iter *it) for (i = 0; i < vi->xattr_shared_count; ++i) { erofs_blk_t blkaddr = - xattrblock_addr(vi->xattr_shared_xattrs[i]); + xattrblock_addr(vi, vi->xattr_shared_xattrs[i]); - it->it.ofs = xattrblock_offset(vi->xattr_shared_xattrs[i]); + it->it.ofs = xattrblock_offset(vi, vi->xattr_shared_xattrs[i]); if (!i || blkaddr != it->it.blkaddr) { - ret = blk_read(0, it->it.page, blkaddr, 1); + ret = blk_read(vi->sbi, 0, it->it.page, blkaddr, 1); if (ret < 0) return -EIO; @@ -1328,6 +1334,7 @@ int erofs_listxattr(struct erofs_inode *vi, char *buffer, size_t buffer_size) if (ret) return ret; + it.it.sbi = vi->sbi; it.buffer = buffer; it.buffer_size = buffer_size; it.buffer_ofs = 0; diff --git a/lib/zmap.c b/lib/zmap.c index 7428d115..cd91ca5f 100644 --- a/lib/zmap.c +++ b/lib/zmap.c @@ -16,13 +16,15 @@ static int z_erofs_do_map_blocks(struct erofs_inode *vi, int z_erofs_fill_inode(struct erofs_inode *vi) { - if (!erofs_sb_has_big_pcluster() && - !erofs_sb_has_ztailpacking() && !erofs_sb_has_fragments() && + struct erofs_sb_info *sbi = vi->sbi; + + if (!erofs_sb_has_big_pcluster(sbi) && + !erofs_sb_has_ztailpacking(sbi) && !erofs_sb_has_fragments(sbi) && vi->datalayout == EROFS_INODE_COMPRESSED_FULL) { vi->z_advise = 0; vi->z_algorithmtype[0] = 0; vi->z_algorithmtype[1] = 0; - vi->z_logical_clusterbits = sbi.blkszbits; + vi->z_logical_clusterbits = sbi->blkszbits; vi->flags |= EROFS_I_Z_INITED; } @@ -35,12 +37,13 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi) erofs_off_t pos; struct z_erofs_map_header *h; char buf[sizeof(struct z_erofs_map_header)]; + struct erofs_sb_info *sbi = vi->sbi; if (vi->flags & EROFS_I_Z_INITED) return 0; pos = round_up(erofs_iloc(vi) + vi->inode_isize + vi->xattr_isize, 8); - ret = dev_read(0, buf, pos, sizeof(buf)); + ret = dev_read(sbi, 0, buf, pos, sizeof(buf)); if (ret < 0) return -EIO; @@ -66,7 +69,7 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi) return -EOPNOTSUPP; } - vi->z_logical_clusterbits = sbi.blkszbits + (h->h_clusterbits & 7); + vi->z_logical_clusterbits = sbi->blkszbits + (h->h_clusterbits & 7); if (vi->datalayout == EROFS_INODE_COMPRESSED_COMPACT && !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^ !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2)) { @@ -82,7 +85,7 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi) ret = z_erofs_do_map_blocks(vi, &map, EROFS_GET_BLOCKS_FINDTAIL); if (!map.m_plen || - erofs_blkoff(map.m_pa) + map.m_plen > erofs_blksiz()) { + erofs_blkoff(sbi, map.m_pa) + map.m_plen > erofs_blksiz(sbi)) { erofs_err("invalid tail-packing pclustersize %llu", map.m_plen | 0ULL); return -EFSCORRUPTED; @@ -130,7 +133,7 @@ static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m, if (map->index == eblk) return 0; - ret = blk_read(0, mpage, eblk, 1); + ret = blk_read(m->inode->sbi, 0, mpage, eblk, 1); if (ret < 0) return -EIO; @@ -143,6 +146,7 @@ static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m, unsigned long lcn) { struct erofs_inode *const vi = m->inode; + struct erofs_sb_info *sbi = vi->sbi; const erofs_off_t ibase = erofs_iloc(vi); const erofs_off_t pos = Z_EROFS_FULL_INDEX_ALIGN(ibase + vi->inode_isize + vi->xattr_isize) + @@ -151,13 +155,13 @@ static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m, unsigned int advise, type; int err; - err = z_erofs_reload_indexes(m, erofs_blknr(pos)); + err = z_erofs_reload_indexes(m, erofs_blknr(sbi, pos)); if (err) return err; m->nextpackoff = pos + sizeof(struct z_erofs_lcluster_index); m->lcn = lcn; - di = m->kaddr + erofs_blkoff(pos); + di = m->kaddr + erofs_blkoff(sbi, pos); advise = le16_to_cpu(di->di_advise); type = (advise >> Z_EROFS_LI_LCLUSTER_TYPE_BIT) & @@ -252,7 +256,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m, (vcnt << amortizedshift); big_pcluster = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1; encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt; - eofs = erofs_blkoff(pos); + eofs = erofs_blkoff(vi->sbi, pos); base = round_down(eofs, vcnt << amortizedshift); in = m->kaddr + base; @@ -341,11 +345,12 @@ static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m, unsigned long lcn, bool lookahead) { struct erofs_inode *const vi = m->inode; + struct erofs_sb_info *sbi = vi->sbi; const unsigned int lclusterbits = vi->z_logical_clusterbits; const erofs_off_t ebase = round_up(erofs_iloc(vi) + vi->inode_isize + vi->xattr_isize, 8) + sizeof(struct z_erofs_map_header); - const unsigned int totalidx = BLK_ROUND_UP(vi->i_size); + const unsigned int totalidx = BLK_ROUND_UP(sbi, vi->i_size); unsigned int compacted_4b_initial, compacted_2b; unsigned int amortizedshift; erofs_off_t pos; @@ -386,7 +391,7 @@ static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m, amortizedshift = 2; out: pos += lcn * (1 << amortizedshift); - err = z_erofs_reload_indexes(m, erofs_blknr(pos)); + err = z_erofs_reload_indexes(m, erofs_blknr(sbi, pos)); if (err) return err; return unpack_compacted_index(m, amortizedshift, pos, lookahead); @@ -455,6 +460,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, unsigned int initial_lcn) { struct erofs_inode *const vi = m->inode; + struct erofs_sb_info *sbi = vi->sbi; struct erofs_map_blocks *const map = m->map; const unsigned int lclusterbits = vi->z_logical_clusterbits; unsigned long lcn; @@ -495,7 +501,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type * rather than CBLKCNT, it's a 1 lcluster-sized pcluster. */ - m->compressedblks = 1 << (lclusterbits - sbi.blkszbits); + m->compressedblks = 1 << (lclusterbits - sbi->blkszbits); break; case Z_EROFS_LCLUSTER_TYPE_NONHEAD: if (m->delta[0] != 1) @@ -510,7 +516,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, return -EFSCORRUPTED; } out: - map->m_plen = m->compressedblks << sbi.blkszbits; + map->m_plen = m->compressedblks << sbi->blkszbits; return 0; err_bonus_cblkcnt: erofs_err("bogus CBLKCNT @ lcn %lu of nid %llu", @@ -565,6 +571,7 @@ static int z_erofs_do_map_blocks(struct erofs_inode *vi, struct erofs_map_blocks *map, int flags) { + struct erofs_sb_info *sbi = vi->sbi; bool ztailpacking = vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER; bool fragment = vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER; struct z_erofs_maprecorder m = { @@ -645,7 +652,7 @@ static int z_erofs_do_map_blocks(struct erofs_inode *vi, } else if (fragment && m.lcn == vi->z_tailextent_headlcn) { map->m_flags |= EROFS_MAP_FRAGMENT; } else { - map->m_pa = erofs_pos(m.pblk); + map->m_pa = erofs_pos(sbi, m.pblk); err = z_erofs_get_extent_compressedlen(&m, initial_lcn); if (err) goto out; diff --git a/mkfs/main.c b/mkfs/main.c index 7369b908..92a07fda 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -189,7 +189,7 @@ static int parse_extended_opts(const char *opts) if (MATCH_EXTENTED_OPT("nosbcrc", token, keylen)) { if (vallen) return -EINVAL; - erofs_sb_clear_sb_chksum(); + erofs_sb_clear_sb_chksum(&sbi); } if (MATCH_EXTENTED_OPT("noinline_data", token, keylen)) { @@ -442,7 +442,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[]) optarg); return -EINVAL; } - erofs_sb_set_chunked_file(); + erofs_sb_set_chunked_file(&sbi); break; case 12: quiet = true; @@ -545,14 +545,14 @@ static int mkfs_parse_options_cfg(int argc, char *argv[]) cfg.c_dbg_lvl = EROFS_ERR; cfg.c_showprogress = false; } - if (cfg.c_compr_alg[0] && erofs_blksiz() != EROFS_MAX_BLOCK_SIZE) { + if (cfg.c_compr_alg[0] && erofs_blksiz(&sbi) != EROFS_MAX_BLOCK_SIZE) { erofs_err("compression is unsupported for now with block size %u", - erofs_blksiz()); + erofs_blksiz(&sbi)); return -EINVAL; } if (pclustersize_max) { - if (pclustersize_max < erofs_blksiz() || - pclustersize_max % erofs_blksiz()) { + if (pclustersize_max < erofs_blksiz(&sbi) || + pclustersize_max % erofs_blksiz(&sbi)) { erofs_err("invalid physical clustersize %u", pclustersize_max); return -EINVAL; @@ -567,8 +567,8 @@ static int mkfs_parse_options_cfg(int argc, char *argv[]) } if (pclustersize_packed) { - if (pclustersize_max < erofs_blksiz() || - pclustersize_max % erofs_blksiz()) { + if (pclustersize_max < erofs_blksiz(&sbi) || + pclustersize_max % erofs_blksiz(&sbi)) { erofs_err("invalid pcluster size for the packed file %u", pclustersize_packed); return -EINVAL; @@ -600,7 +600,7 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh, .extra_devices = cpu_to_le16(sbi.extra_devices), .devt_slotoff = cpu_to_le16(sbi.devt_slotoff), }; - const u32 sb_blksize = round_up(EROFS_SUPER_END, erofs_blksiz()); + const u32 sb_blksize = round_up(EROFS_SUPER_END, erofs_blksiz(&sbi)); char *buf; int ret; @@ -611,7 +611,7 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh, memcpy(sb.uuid, sbi.uuid, sizeof(sb.uuid)); memcpy(sb.volume_name, sbi.volume_name, sizeof(sb.volume_name)); - if (erofs_sb_has_compr_cfgs()) + if (erofs_sb_has_compr_cfgs(&sbi)) sb.u1.available_compr_algs = cpu_to_le16(sbi.available_compr_algs); else sb.u1.lz4_max_distance = cpu_to_le16(sbi.lz4_max_distance); @@ -624,7 +624,7 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh, } memcpy(buf + EROFS_SUPER_OFFSET, &sb, sizeof(sb)); - ret = dev_write(buf, erofs_btell(bh, false), EROFS_SUPER_END); + ret = dev_write(&sbi, buf, erofs_btell(bh, false), EROFS_SUPER_END); free(buf); erofs_bdrop(bh, false); return ret; @@ -638,7 +638,7 @@ static int erofs_mkfs_superblock_csum_set(void) unsigned int len; struct erofs_super_block *sb; - ret = blk_read(0, buf, 0, erofs_blknr(EROFS_SUPER_END) + 1); + ret = blk_read(&sbi, 0, buf, 0, erofs_blknr(&sbi, EROFS_SUPER_END) + 1); if (ret) { erofs_err("failed to read superblock to set checksum: %s", erofs_strerror(ret)); @@ -659,16 +659,16 @@ static int erofs_mkfs_superblock_csum_set(void) /* turn on checksum feature */ sb->feature_compat = cpu_to_le32(le32_to_cpu(sb->feature_compat) | EROFS_FEATURE_COMPAT_SB_CHKSUM); - if (erofs_blksiz() > EROFS_SUPER_OFFSET) - len = erofs_blksiz() - EROFS_SUPER_OFFSET; + if (erofs_blksiz(&sbi) > EROFS_SUPER_OFFSET) + len = erofs_blksiz(&sbi) - EROFS_SUPER_OFFSET; else - len = erofs_blksiz(); + len = erofs_blksiz(&sbi); crc = erofs_crc32c(~0, (u8 *)sb, len); /* set up checksum field to erofs_super_block */ sb->checksum = cpu_to_le32(crc); - ret = blk_write(buf, 0, 1); + ret = blk_write(&sbi, buf, 0, 1); if (ret) { erofs_err("failed to write checksummed superblock: %s", erofs_strerror(ret)); @@ -782,7 +782,7 @@ int main(int argc, char **argv) sbi.build_time_nsec = t.tv_usec; } - err = dev_open(cfg.c_img_path); + err = dev_open(&sbi, cfg.c_img_path); if (err) { usage(); return 1; @@ -850,14 +850,14 @@ int main(int argc, char **argv) goto exit; } - err = erofs_load_compress_hints(); + err = erofs_load_compress_hints(&sbi); if (err) { erofs_err("failed to load compress hints %s", cfg.c_compress_hints_file); goto exit; } - err = z_erofs_compress_init(sb_bh); + err = z_erofs_compress_init(&sbi, sb_bh); if (err) { erofs_err("failed to initialize compressor: %s", erofs_strerror(err)); @@ -869,7 +869,7 @@ int main(int argc, char **argv) erofs_err("Compression is not enabled. Turn on chunk-based data deduplication instead."); cfg.c_chunkbits = sbi.blkszbits; } else { - err = z_erofs_dedupe_init(erofs_blksiz()); + err = z_erofs_dedupe_init(erofs_blksiz(&sbi)); if (err) { erofs_err("failed to initialize deduplication: %s", erofs_strerror(err)); @@ -885,9 +885,9 @@ int main(int argc, char **argv) } if (tar_mode && erofstar.index_mode) - err = tarerofs_reserve_devtable(1); + err = tarerofs_reserve_devtable(&sbi, 1); else - err = erofs_generate_devtable(); + err = erofs_generate_devtable(&sbi); if (err) { erofs_err("failed to generate device table: %s", erofs_strerror(err)); @@ -899,10 +899,10 @@ int main(int argc, char **argv) erofs_inode_manager_init(); if (cfg.c_extra_ea_name_prefixes) - erofs_xattr_write_name_prefixes(packedfile); + erofs_xattr_write_name_prefixes(&sbi, packedfile); if (!tar_mode) { - err = erofs_build_shared_xattrs_from_path(cfg.c_src_path); + err = erofs_build_shared_xattrs_from_path(&sbi, cfg.c_src_path); if (err) { erofs_err("failed to build shared xattrs: %s", erofs_strerror(err)); @@ -910,7 +910,7 @@ int main(int argc, char **argv) } if (cfg.c_extra_ea_name_prefixes) - erofs_xattr_write_name_prefixes(packedfile); + erofs_xattr_write_name_prefixes(&sbi, packedfile); root_inode = erofs_mkfs_build_tree_from_path(cfg.c_src_path); if (IS_ERR(root_inode)) { @@ -943,17 +943,17 @@ int main(int argc, char **argv) erofs_iput(root_inode); if (tar_mode) - tarerofs_write_devtable(&erofstar); + tarerofs_write_devtable(&sbi, &erofstar); if (cfg.c_chunkbits) { erofs_info("total metadata: %u blocks", erofs_mapbh(NULL)); - err = erofs_blob_remap(); + err = erofs_blob_remap(&sbi); if (err) goto exit; } packed_nid = 0; if ((cfg.c_fragments || cfg.c_extra_ea_name_prefixes) && - erofs_sb_has_fragments()) { + erofs_sb_has_fragments(&sbi)) { erofs_update_progressinfo("Handling packed_file ..."); packed_inode = erofs_mkfs_build_packedfile(); if (IS_ERR(packed_inode)) { @@ -973,9 +973,9 @@ int main(int argc, char **argv) if (!erofs_bflush(NULL)) err = -EIO; else - err = dev_resize(nblocks); + err = dev_resize(&sbi, nblocks); - if (!err && erofs_sb_has_sb_chksum()) + if (!err && erofs_sb_has_sb_chksum(&sbi)) err = erofs_mkfs_superblock_csum_set(); exit: z_erofs_compress_exit(); @@ -983,7 +983,7 @@ int main(int argc, char **argv) #ifdef WITH_ANDROID erofs_droid_blocklist_fclose(); #endif - dev_close(); + dev_close(&sbi); erofs_cleanup_compress_hints(); erofs_cleanup_exclude_rules(); if (cfg.c_chunkbits) From b557485942f4e6802451bb3158459b98efd5521e Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Fri, 21 Jul 2023 13:07:55 +0800 Subject: [PATCH 02/17] AOSP: erofs-utils: mkfs: fix block list support for chunked files chunksize may not always equal to blocksize (e.g. 4KiB). Also it can lead to unexpected behaviors when the consecutive chunk merging is implemented later since the chunksize is also on a per-file basis. Fixes: d9a01943f8c5 ("AOSP: erofs-utils: mkfs: add block list support for chunked files") Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20230721050755.82122-1-hsiangkao@linux.alibaba.com --- lib/blobchunk.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/blobchunk.c b/lib/blobchunk.c index 56077dc7..44541d5c 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -127,7 +127,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, extents_blks; + erofs_blk_t extent_end, chunkblks; unsigned int dst, src, unit; bool first_extent = true; @@ -136,6 +136,7 @@ int erofs_blob_write_chunk_indexes(struct erofs_inode *inode, else unit = EROFS_BLOCK_MAP_ENTRY_SIZE; + chunkblks = 1U << (inode->u.chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK); for (dst = src = 0; dst < inode->extent_isize; src += sizeof(void *), dst += unit) { struct erofs_blobchunk *chunk; @@ -152,20 +153,18 @@ int erofs_blob_write_chunk_indexes(struct erofs_inode *inode, idx.blkaddr = remapped_base + chunk->blkaddr; } - if (extent_start != EROFS_NULL_ADDR && - idx.blkaddr == extent_end + 1) { - extent_end = idx.blkaddr; - } else { + if (extent_start == EROFS_NULL_ADDR || + idx.blkaddr != extent_end) { if (extent_start != EROFS_NULL_ADDR) { erofs_droid_blocklist_write_extent(inode, extent_start, - (extent_end - extent_start) + 1, + extent_end - extent_start, first_extent, false); first_extent = false; } extent_start = idx.blkaddr; - extent_end = idx.blkaddr; } + extent_end = idx.blkaddr + chunkblks; idx.device_id = cpu_to_le16(chunk->device_id); idx.blkaddr = cpu_to_le32(idx.blkaddr); @@ -175,12 +174,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) - extents_blks = 0; - else - extents_blks = (extent_end - extent_start) + 1; - erofs_droid_blocklist_write_extent(inode, extent_start, extents_blks, + erofs_droid_blocklist_write_extent(inode, extent_start, + extent_start == EROFS_NULL_ADDR ? + 0 : extent_end - extent_start, first_extent, true); return dev_write(inode->sbi, inode->chunkindexes, off, inode->extent_isize); From 8c94c64498efd3dadfad33de785efa82c7127212 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 25 Jul 2023 01:06:44 +0800 Subject: [PATCH 03/17] erofs-utils: lib: fix improper alignment for chunked sparse files File position should be fixed to aligned with the chunk boundary. Otherwise, incorrect data could be read. Fixes: 7c49e8b195ad ("erofs-utils: support chunk-based sparse files") Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20230724170646.22281-1-hsiangkao@linux.alibaba.com --- lib/blobchunk.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/blobchunk.c b/lib/blobchunk.c index 44541d5c..c0df2f74 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -228,8 +228,12 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) offset = pos; else offset = ((pos >> chunkbits) + 1) << chunkbits; - } else { + } else if (offset != (offset & ~(chunksize - 1))) { offset &= ~(chunksize - 1); + if (lseek(fd, offset, SEEK_SET) != offset) { + ret = -EIO; + goto err; + } } if (offset > pos) { From ec35fca1da33becb14f6611289acdef687e72db6 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 25 Jul 2023 01:06:45 +0800 Subject: [PATCH 04/17] erofs-utils: lib: tidy up erofs_blob_getchunk() Mainly get rid of memory allocation on each chunk. Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20230724170646.22281-2-hsiangkao@linux.alibaba.com --- lib/blobchunk.c | 92 +++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/lib/blobchunk.c b/lib/blobchunk.c index c0df2f74..4619057e 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -51,60 +51,57 @@ struct erofs_blobchunk *erofs_get_unhashed_chunk(erofs_off_t chunksize, } static struct erofs_blobchunk *erofs_blob_getchunk(struct erofs_sb_info *sbi, - int fd, erofs_off_t chunksize) + u8 *buf, erofs_off_t chunksize) { static u8 zeroed[EROFS_MAX_BLOCK_SIZE]; - u8 *chunkdata, sha256[32]; - int ret; - unsigned int hash; - erofs_off_t blkpos; struct erofs_blobchunk *chunk; + unsigned int hash, padding; + u8 sha256[32]; + erofs_off_t blkpos; + int ret; - chunkdata = malloc(chunksize); - if (!chunkdata) - return ERR_PTR(-ENOMEM); - - ret = read(fd, chunkdata, chunksize); - if (ret < chunksize) { - chunk = ERR_PTR(-EIO); - goto out; - } - erofs_sha256(chunkdata, chunksize, sha256); + erofs_sha256(buf, chunksize, sha256); hash = memhash(sha256, sizeof(sha256)); chunk = hashmap_get_from_hash(&blob_hashmap, hash, sha256); if (chunk) { DBG_BUGON(chunksize != chunk->chunksize); - goto out; + erofs_dbg("Found duplicated chunk at %u", chunk->blkaddr); + return chunk; } + chunk = malloc(sizeof(struct erofs_blobchunk)); - if (!chunk) { - chunk = ERR_PTR(-ENOMEM); - goto out; - } + if (!chunk) + return ERR_PTR(-ENOMEM); chunk->chunksize = chunksize; + memcpy(chunk->sha256, sha256, sizeof(sha256)); blkpos = ftell(blobfile); DBG_BUGON(erofs_blkoff(sbi, blkpos)); - chunk->device_id = 0; + + if (multidev) + chunk->device_id = 1; + else + chunk->device_id = 0; chunk->blkaddr = erofs_blknr(sbi, blkpos); - memcpy(chunk->sha256, sha256, sizeof(sha256)); - hashmap_entry_init(&chunk->ent, hash); - hashmap_add(&blob_hashmap, chunk); erofs_dbg("Writing chunk (%u bytes) to %u", chunksize, chunk->blkaddr); - ret = fwrite(chunkdata, chunksize, 1, blobfile); - if (ret == 1 && erofs_blkoff(sbi, chunksize)) - ret = fwrite(zeroed, - erofs_blksiz(sbi) - erofs_blkoff(sbi, chunksize), - 1, blobfile); + ret = fwrite(buf, chunksize, 1, blobfile); + padding = erofs_blkoff(sbi, chunksize); + if (ret == 1) { + padding = erofs_blkoff(sbi, chunksize); + if (padding) { + padding = erofs_blksiz(sbi) - padding; + ret = fwrite(zeroed, padding, 1, blobfile); + } + } + if (ret < 1) { - hashmap_remove(&blob_hashmap, &chunk->ent); free(chunk); - chunk = ERR_PTR(-ENOSPC); - goto out; + return ERR_PTR(-ENOSPC); } -out: - free(chunkdata); + + hashmap_entry_init(&chunk->ent, hash); + hashmap_add(&blob_hashmap, chunk); return chunk; } @@ -189,6 +186,7 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) unsigned int count, unit; struct erofs_inode_chunk_index *idx; erofs_off_t pos, len, chunksize; + u8 *chunkdata; int ret; #ifdef SEEK_DATA @@ -212,11 +210,17 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) else unit = EROFS_BLOCK_MAP_ENTRY_SIZE; - inode->extent_isize = count * unit; - idx = malloc(count * max(sizeof(*idx), sizeof(void *))); - if (!idx) + chunkdata = malloc(chunksize); + if (!chunkdata) return -ENOMEM; - inode->chunkindexes = idx; + + inode->extent_isize = count * unit; + inode->chunkindexes = malloc(count * max(sizeof(*idx), sizeof(void *))); + if (!inode->chunkindexes) { + ret = -ENOMEM; + goto err; + } + idx = inode->chunkindexes; for (pos = 0; pos < inode->i_size; pos += len) { struct erofs_blobchunk *chunk; @@ -248,20 +252,26 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) #endif len = min_t(u64, inode->i_size - pos, chunksize); - chunk = erofs_blob_getchunk(sbi, fd, len); + ret = read(fd, chunkdata, len); + if (ret < len) { + ret = -EIO; + goto err; + } + + chunk = erofs_blob_getchunk(sbi, chunkdata, len); if (IS_ERR(chunk)) { ret = PTR_ERR(chunk); goto err; } - if (multidev) - chunk->device_id = 1; *(void **)idx++ = chunk; } inode->datalayout = EROFS_INODE_CHUNK_BASED; + free(chunkdata); return 0; err: free(inode->chunkindexes); inode->chunkindexes = NULL; + free(chunkdata); return ret; } From 7b46f7a0160ad1f4e66c9299a06b2d26e2a88e9f Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 25 Jul 2023 01:06:46 +0800 Subject: [PATCH 05/17] erofs-utils: lib: merge consecutive chunks if possible Since EROFS chunk size can be configured on a per-file basis, let's generate indexes with the best chunk size. Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20230724170646.22281-3-hsiangkao@linux.alibaba.com --- include/erofs/defs.h | 5 +++++ lib/blobchunk.c | 53 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/include/erofs/defs.h b/include/erofs/defs.h index 44af557b..20f97413 100644 --- a/include/erofs/defs.h +++ b/include/erofs/defs.h @@ -286,6 +286,11 @@ static inline unsigned int fls_long(unsigned long x) return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; } +static inline unsigned long lowbit(unsigned long n) +{ + return n & -n; +} + /** * __roundup_pow_of_two() - round up to nearest power of two * @n: value to round up diff --git a/lib/blobchunk.c b/lib/blobchunk.c index 4619057e..4e4295eb 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -179,13 +179,47 @@ int erofs_blob_write_chunk_indexes(struct erofs_inode *inode, return dev_write(inode->sbi, inode->chunkindexes, off, inode->extent_isize); } +int erofs_blob_mergechunks(struct erofs_inode *inode, unsigned int chunkbits, + unsigned int new_chunkbits) +{ + struct erofs_sb_info *sbi = inode->sbi; + unsigned int dst, src, unit, count; + + if (new_chunkbits - sbi->blkszbits > EROFS_CHUNK_FORMAT_BLKBITS_MASK) + new_chunkbits = EROFS_CHUNK_FORMAT_BLKBITS_MASK + sbi->blkszbits; + if (chunkbits >= new_chunkbits) /* no need to merge */ + goto out; + + if (inode->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES) + unit = sizeof(struct erofs_inode_chunk_index); + else + unit = EROFS_BLOCK_MAP_ENTRY_SIZE; + + count = round_up(inode->i_size, 1ULL << new_chunkbits) >> new_chunkbits; + for (dst = src = 0; dst < count; ++dst) { + *((void **)inode->chunkindexes + dst) = + *((void **)inode->chunkindexes + src); + src += 1U << (new_chunkbits - chunkbits); + } + + DBG_BUGON(count * unit >= inode->extent_isize); + inode->extent_isize = count * unit; + chunkbits = new_chunkbits; +out: + inode->u.chunkformat = (chunkbits - sbi->blkszbits) | + (inode->u.chunkformat & ~EROFS_CHUNK_FORMAT_BLKBITS_MASK); + return 0; +} + int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) { struct erofs_sb_info *sbi = inode->sbi; unsigned int chunkbits = cfg.c_chunkbits; unsigned int count, unit; + struct erofs_blobchunk *chunk, *lastch; struct erofs_inode_chunk_index *idx; erofs_off_t pos, len, chunksize; + erofs_blk_t lb, minextblks; u8 *chunkdata; int ret; @@ -201,10 +235,9 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) chunkbits = EROFS_CHUNK_FORMAT_BLKBITS_MASK + sbi->blkszbits; chunksize = 1ULL << chunkbits; count = DIV_ROUND_UP(inode->i_size, chunksize); - inode->u.chunkformat |= chunkbits - sbi->blkszbits; + if (multidev) inode->u.chunkformat |= EROFS_CHUNK_FORMAT_INDEXES; - if (inode->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES) unit = sizeof(struct erofs_inode_chunk_index); else @@ -222,8 +255,9 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) } idx = inode->chunkindexes; + lastch = NULL; + minextblks = BLK_ROUND_UP(sbi, inode->i_size); for (pos = 0; pos < inode->i_size; pos += len) { - struct erofs_blobchunk *chunk; #ifdef SEEK_DATA off_t offset = lseek(fd, pos, SEEK_DATA); @@ -247,6 +281,7 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) pos += chunksize; } while (pos < offset); DBG_BUGON(pos != offset); + lastch = NULL; continue; } #endif @@ -263,11 +298,21 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) ret = PTR_ERR(chunk); goto err; } + + if (lastch && (lastch->device_id != chunk->device_id || + erofs_pos(sbi, lastch->blkaddr) + lastch->chunksize != + erofs_pos(sbi, chunk->blkaddr))) { + lb = lowbit(pos >> sbi->blkszbits); + if (lb && lb < minextblks) + minextblks = lb; + } *(void **)idx++ = chunk; + lastch = chunk; } inode->datalayout = EROFS_INODE_CHUNK_BASED; free(chunkdata); - return 0; + return erofs_blob_mergechunks(inode, chunkbits, + ilog2(minextblks) + sbi->blkszbits); err: free(inode->chunkindexes); inode->chunkindexes = NULL; From b39289e8d66d7747abbee7d5940c65a54876a100 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Thu, 27 Jul 2023 12:57:05 +0800 Subject: [PATCH 06/17] erofs-utils: lib: initialize i_nlink to 2 in erofs_init_empty_dir() Set dir->i_nlink to 2 since "." and ".." are allocated. Also, tarerofs_init_empty_dir() is removed then. Signed-off-by: Jingbo Xu Reviewed-by: Gao Xiang Link: https://lore.kernel.org/r/20230727045712.45226-2-jefflexu@linux.alibaba.com Signed-off-by: Gao Xiang --- lib/inode.c | 2 ++ lib/tar.c | 14 ++------------ mkfs/main.c | 2 +- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/lib/inode.c b/lib/inode.c index c4d14767..d54f84f0 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -235,6 +235,8 @@ int erofs_init_empty_dir(struct erofs_inode *dir) return PTR_ERR(d); d->inode = erofs_igrab(dir->i_parent); d->type = EROFS_FT_DIR; + + dir->i_nlink = 2; return 0; } diff --git a/lib/tar.c b/lib/tar.c index 76ba69d5..3c145e57 100644 --- a/lib/tar.c +++ b/lib/tar.c @@ -138,16 +138,6 @@ static long long tarerofs_parsenum(const char *ptr, int len) return tarerofs_otoi(ptr, len); } -int tarerofs_init_empty_dir(struct erofs_inode *inode) -{ - int ret = erofs_init_empty_dir(inode); - - if (ret) - return ret; - inode->i_nlink = 2; - return 0; -} - static struct erofs_dentry *tarerofs_mkdir(struct erofs_inode *dir, const char *s) { struct erofs_inode *inode; @@ -163,7 +153,7 @@ static struct erofs_dentry *tarerofs_mkdir(struct erofs_inode *dir, const char * inode->i_gid = getgid(); inode->i_mtime = inode->sbi->build_time; inode->i_mtime_nsec = inode->sbi->build_time_nsec; - tarerofs_init_empty_dir(inode); + erofs_init_empty_dir(inode); d = erofs_d_alloc(dir, s); if (!IS_ERR(d)) { @@ -759,7 +749,7 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar) inode->i_nlink++; ret = 0; } else if (!inode->i_nlink) - ret = tarerofs_init_empty_dir(inode); + ret = erofs_init_empty_dir(inode); else ret = 0; out: diff --git a/mkfs/main.c b/mkfs/main.c index 92a07fda..bc5ed877 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -928,7 +928,7 @@ int main(int argc, char **argv) root_inode->i_parent = root_inode; root_inode->i_mtime = sbi.build_time; root_inode->i_mtime_nsec = sbi.build_time_nsec; - tarerofs_init_empty_dir(root_inode); + erofs_init_empty_dir(root_inode); while (!(err = tarerofs_parse_tar(root_inode, &erofstar))); From b6749839e710078187f2347dc29b7317cbb59d19 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 1 Aug 2023 21:27:55 +0800 Subject: [PATCH 07/17] erofs-utils: generate preallocated extents for tarerofs 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 Reviewed-by: Jingbo Xu Link: https://lore.kernel.org/r/20230801132755.23997-1-hsiangkao@linux.alibaba.com --- include/erofs/blobchunk.h | 7 +- include/erofs/block_list.h | 7 +- include/erofs/tar.h | 1 + lib/Makefile.am | 3 +- lib/blobchunk.c | 162 +++++++++++++++++++++++++++++-------- lib/block_list.c | 23 ++++-- lib/tar.c | 88 +------------------- mkfs/main.c | 41 ++++++---- 8 files changed, 185 insertions(+), 147 deletions(-) diff --git a/include/erofs/blobchunk.h b/include/erofs/blobchunk.h index 7c5645eb..010aee1e 100644 --- a/include/erofs/blobchunk.h +++ b/include/erofs/blobchunk.h @@ -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 } diff --git a/include/erofs/block_list.h b/include/erofs/block_list.h index 78fab44f..9f9975eb 100644 --- a/include/erofs/block_list.h +++ b/include/erofs/block_list.h @@ -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, diff --git a/include/erofs/tar.h b/include/erofs/tar.h index a14f8ac5..8d3f8dec 100644 --- a/include/erofs/tar.h +++ b/include/erofs/tar.h @@ -15,6 +15,7 @@ struct erofs_pax_header { struct erofs_tarfile { struct erofs_pax_header global; + char *mapfile; int fd; u64 offset; diff --git a/lib/Makefile.am b/lib/Makefile.am index ebe466b8..7a5dc03a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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 diff --git a/lib/blobchunk.c b/lib/blobchunk.c index 4e4295eb..cada5bb1 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -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 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd) 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; } diff --git a/lib/block_list.c b/lib/block_list.c index 896fb018..b45b553a 100644 --- a/lib/block_list.c +++ b/lib/block_list.c @@ -3,7 +3,6 @@ * Copyright (C), 2021, Coolpad Group Limited. * Created by Yue Hu */ -#ifdef WITH_ANDROID #include #include #include "erofs/block_list.h" @@ -12,17 +11,19 @@ #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) diff --git a/lib/tar.c b/lib/tar.c index 3c145e57..54ee33fd 100644 --- a/lib/tar.c +++ b/lib/tar.c @@ -341,44 +341,6 @@ int tarerofs_parse_pax_header(int fd, struct erofs_pax_header *eh, u32 size) 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 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar) 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 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar) 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 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *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; -} diff --git a/mkfs/main.c b/mkfs/main.c index bc5ed877..3809c713 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -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(); From 45b43e5d3c912210e82fe41ab37cd7bee7adfd39 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Thu, 3 Aug 2023 13:00:31 +0800 Subject: [PATCH 08/17] erofs-utils: dump: use a new subdir context for erofs_get_pathname() It's absolutely unsafe to reuse struct erofs_dir_context. Also, we'd like to refactor erofs_get_pathname() in the future. Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20230803050031.130026-1-hsiangkao@linux.alibaba.com --- lib/dir.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/dir.c b/lib/dir.c index e8df9f70..fff0bc07 100644 --- a/lib/dir.c +++ b/lib/dir.c @@ -217,10 +217,16 @@ static int erofs_get_pathname_iter(struct erofs_dir_context *ctx) } if (S_ISDIR(dir.i_mode)) { - ctx->dir = &dir; - pathctx->pos = pos + len + 1; - ret = erofs_iterate_dir(ctx, false); - pathctx->pos = pos; + struct erofs_get_pathname_context nctx = { + .ctx.flags = 0, + .ctx.dir = &dir, + .ctx.cb = erofs_get_pathname_iter, + .target_nid = pathctx->target_nid, + .buf = pathctx->buf, + .size = pathctx->size, + .pos = pos + len + 1, + }; + ret = erofs_iterate_dir(&nctx.ctx, false); if (ret == EROFS_PATHNAME_FOUND) { pathctx->buf[pos++] = '/'; strncpy(pathctx->buf + pos, dname, len); From 80e972439b5ba68c05711de95a9b57d7be058ebc Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 8 Aug 2023 17:23:34 +0800 Subject: [PATCH 09/17] erofs-utils: lib: add a way to request supported algorithms dump.erofs needs to print supported algorithms instead of available compressors. In addition, clean up erofs_get_compress_algorithm_id() too. Tested-by: Guo Xuenan Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20230808092335.111834-1-hsiangkao@linux.alibaba.com --- fsck/main.c | 8 ++-- include/erofs/compress.h | 3 +- lib/compress.c | 33 ++++---------- lib/compressor.c | 89 ++++++++++++++++++++++++++++--------- lib/compressor.h | 7 +-- lib/compressor_deflate.c | 2 - lib/compressor_libdeflate.c | 2 - lib/compressor_liblzma.c | 2 - lib/compressor_lz4.c | 2 - lib/compressor_lz4hc.c | 3 -- mkfs/main.c | 8 ++-- 11 files changed, 93 insertions(+), 66 deletions(-) diff --git a/fsck/main.c b/fsck/main.c index 39a55341..7f78513c 100644 --- a/fsck/main.c +++ b/fsck/main.c @@ -61,13 +61,15 @@ static struct list_head erofsfsck_link_hashtable[NR_HARDLINK_HASHTABLE]; static void print_available_decompressors(FILE *f, const char *delim) { - unsigned int i = 0; + int i = 0; + bool comma = false; const char *s; - while ((s = z_erofs_list_available_compressors(i)) != NULL) { - if (i++) + while ((s = z_erofs_list_available_compressors(&i)) != NULL) { + if (comma) fputs(delim, f); fputs(s, f); + comma = true; } fputc('\n', f); } diff --git a/include/erofs/compress.h b/include/erofs/compress.h index f1ad84aa..46cff032 100644 --- a/include/erofs/compress.h +++ b/include/erofs/compress.h @@ -23,7 +23,8 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *bh); int z_erofs_compress_exit(void); -const char *z_erofs_list_available_compressors(unsigned int i); +const char *z_erofs_list_supported_algorithms(int i, unsigned int *mask); +const char *z_erofs_list_available_compressors(int *i); static inline bool erofs_is_packed_inode(struct erofs_inode *inode) { diff --git a/lib/compress.c b/lib/compress.c index b43b077c..e5d310fb 100644 --- a/lib/compress.c +++ b/lib/compress.c @@ -1030,17 +1030,6 @@ int erofs_write_compressed_file(struct erofs_inode *inode, int fd) return ret; } -static int erofs_get_compress_algorithm_id(const char *name) -{ - if (!strcmp(name, "lz4") || !strcmp(name, "lz4hc")) - return Z_EROFS_COMPRESSION_LZ4; - if (!strcmp(name, "lzma")) - return Z_EROFS_COMPRESSION_LZMA; - if (!strcmp(name, "deflate") || !strcmp(name, "libdeflate")) - return Z_EROFS_COMPRESSION_DEFLATE; - return -ENOTSUP; -} - static int z_erofs_build_compr_cfgs(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh) { @@ -1123,23 +1112,21 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *s int i, ret; for (i = 0; cfg.c_compr_alg[i]; ++i) { - ret = erofs_compressor_init(sbi, &erofs_ccfg[i].handle, - cfg.c_compr_alg[i]); + struct erofs_compress *c = &erofs_ccfg[i].handle; + + ret = erofs_compressor_init(sbi, c, cfg.c_compr_alg[i]); if (ret) return ret; - ret = erofs_compressor_setlevel(&erofs_ccfg[i].handle, - cfg.c_compr_level[i]); + ret = erofs_compressor_setlevel(c, cfg.c_compr_level[i]); if (ret) return ret; - ret = erofs_get_compress_algorithm_id(cfg.c_compr_alg[i]); - if (ret < 0) - return ret; - erofs_ccfg[i].algorithmtype = ret; + erofs_ccfg[i].algorithmtype = + z_erofs_get_compress_algorithm_id(c); erofs_ccfg[i].enable = true; - sbi->available_compr_algs |= 1 << ret; - if (ret != Z_EROFS_COMPRESSION_LZ4) + sbi->available_compr_algs |= 1 << erofs_ccfg[i].algorithmtype; + if (erofs_ccfg[i].algorithmtype != Z_EROFS_COMPRESSION_LZ4) erofs_sb_set_compr_cfgs(sbi); } @@ -1172,10 +1159,8 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *s return -EINVAL; } - if (erofs_sb_has_compr_cfgs(sbi)) { - sbi->available_compr_algs |= 1 << ret; + if (erofs_sb_has_compr_cfgs(sbi)) return z_erofs_build_compr_cfgs(sbi, sb_bh); - } return 0; } diff --git a/lib/compressor.c b/lib/compressor.c index 4333f26f..93f56171 100644 --- a/lib/compressor.c +++ b/lib/compressor.c @@ -10,22 +10,71 @@ #define EROFS_CONFIG_COMPR_DEF_BOUNDARY (128) -static const struct erofs_compressor *compressors[] = { +static const struct erofs_algorithm { + char *name; + const struct erofs_compressor *c; + unsigned int id; + + /* its name won't be shown as a supported algorithm */ + bool optimisor; +} erofs_algs[] = { + { "lz4", #if LZ4_ENABLED -#if LZ4HC_ENABLED - &erofs_compressor_lz4hc, -#endif &erofs_compressor_lz4, +#else + NULL, #endif + Z_EROFS_COMPRESSION_LZ4, false }, + +#if LZ4HC_ENABLED + { "lz4hc", &erofs_compressor_lz4hc, + Z_EROFS_COMPRESSION_LZ4, true }, +#endif + + { "lzma", #if HAVE_LIBLZMA &erofs_compressor_lzma, +#else + NULL, #endif - &erofs_compressor_deflate, + Z_EROFS_COMPRESSION_LZMA, false }, + + { "deflate", &erofs_compressor_deflate, + Z_EROFS_COMPRESSION_DEFLATE, false }, + #if HAVE_LIBDEFLATE - &erofs_compressor_libdeflate, + { "libdeflate", &erofs_compressor_libdeflate, + Z_EROFS_COMPRESSION_DEFLATE, true }, #endif }; +int z_erofs_get_compress_algorithm_id(const struct erofs_compress *c) +{ + DBG_BUGON(!c->alg); + return c->alg->id; +} + +const char *z_erofs_list_supported_algorithms(int i, unsigned int *mask) +{ + if (i >= ARRAY_SIZE(erofs_algs)) + return NULL; + if (!erofs_algs[i].optimisor && (*mask & (1 << erofs_algs[i].id))) { + *mask ^= 1 << erofs_algs[i].id; + return erofs_algs[i].name; + } + return ""; +} + +const char *z_erofs_list_available_compressors(int *i) +{ + for (;*i < ARRAY_SIZE(erofs_algs); ++*i) { + if (!erofs_algs[*i].c) + continue; + return erofs_algs[(*i)++].name; + } + return NULL; +} + int erofs_compress_destsize(const struct erofs_compress *c, const void *src, unsigned int *srcsize, void *dst, unsigned int dstsize, bool inblocks) @@ -34,11 +83,11 @@ int erofs_compress_destsize(const struct erofs_compress *c, int ret; DBG_BUGON(!c->alg); - if (!c->alg->compress_destsize) + if (!c->alg->c->compress_destsize) return -ENOTSUP; uncompressed_capacity = *srcsize; - ret = c->alg->compress_destsize(c, src, srcsize, dst, dstsize); + ret = c->alg->c->compress_destsize(c, src, srcsize, dst, dstsize); if (ret < 0) return ret; @@ -55,16 +104,11 @@ int erofs_compress_destsize(const struct erofs_compress *c, return ret; } -const char *z_erofs_list_available_compressors(unsigned int i) -{ - return i >= ARRAY_SIZE(compressors) ? NULL : compressors[i]->name; -} - int erofs_compressor_setlevel(struct erofs_compress *c, int compression_level) { DBG_BUGON(!c->alg); - if (c->alg->setlevel) - return c->alg->setlevel(c, compression_level); + if (c->alg->c->setlevel) + return c->alg->c->setlevel(c, compression_level); if (compression_level >= 0) return -EINVAL; @@ -93,13 +137,16 @@ int erofs_compressor_init(struct erofs_sb_info *sbi, } ret = -EINVAL; - for (i = 0; i < ARRAY_SIZE(compressors); ++i) { - if (alg_name && strcmp(alg_name, compressors[i]->name)) + for (i = 0; i < ARRAY_SIZE(erofs_algs); ++i) { + if (alg_name && strcmp(alg_name, erofs_algs[i].name)) + continue; + + if (!erofs_algs[i].c) continue; - ret = compressors[i]->init(c); + ret = erofs_algs[i].c->init(c); if (!ret) { - DBG_BUGON(!c->alg); + c->alg = &erofs_algs[i]; return 0; } } @@ -109,7 +156,7 @@ int erofs_compressor_init(struct erofs_sb_info *sbi, int erofs_compressor_exit(struct erofs_compress *c) { - if (c->alg && c->alg->exit) - return c->alg->exit(c); + if (c->alg && c->alg->c->exit) + return c->alg->c->exit(c); return 0; } diff --git a/lib/compressor.h b/lib/compressor.h index 08a3988f..9fa01d12 100644 --- a/lib/compressor.h +++ b/lib/compressor.h @@ -12,8 +12,6 @@ struct erofs_compress; struct erofs_compressor { - const char *name; - int default_level; int best_level; @@ -26,9 +24,11 @@ struct erofs_compressor { void *dst, unsigned int dstsize); }; +struct erofs_algorithm; + struct erofs_compress { struct erofs_sb_info *sbi; - const struct erofs_compressor *alg; + const struct erofs_algorithm *alg; unsigned int compress_threshold; unsigned int compression_level; @@ -48,6 +48,7 @@ extern const struct erofs_compressor erofs_compressor_lzma; extern const struct erofs_compressor erofs_compressor_deflate; extern const struct erofs_compressor erofs_compressor_libdeflate; +int z_erofs_get_compress_algorithm_id(const struct erofs_compress *c); int erofs_compress_destsize(const struct erofs_compress *c, const void *src, unsigned int *srcsize, void *dst, unsigned int dstsize, bool inblocks); diff --git a/lib/compressor_deflate.c b/lib/compressor_deflate.c index 5a7a657b..4e5902e4 100644 --- a/lib/compressor_deflate.c +++ b/lib/compressor_deflate.c @@ -36,7 +36,6 @@ static int compressor_deflate_exit(struct erofs_compress *c) static int compressor_deflate_init(struct erofs_compress *c) { - c->alg = &erofs_compressor_deflate; c->private_data = NULL; erofs_warn("EXPERIMENTAL DEFLATE algorithm in use. Use at your own risk!"); @@ -68,7 +67,6 @@ static int erofs_compressor_deflate_setlevel(struct erofs_compress *c, } const struct erofs_compressor erofs_compressor_deflate = { - .name = "deflate", .default_level = 1, .best_level = 9, .init = compressor_deflate_init, diff --git a/lib/compressor_libdeflate.c b/lib/compressor_libdeflate.c index 2756dd86..c0b019a9 100644 --- a/lib/compressor_libdeflate.c +++ b/lib/compressor_libdeflate.c @@ -82,7 +82,6 @@ static int compressor_libdeflate_exit(struct erofs_compress *c) static int compressor_libdeflate_init(struct erofs_compress *c) { - c->alg = &erofs_compressor_libdeflate; c->private_data = NULL; erofs_warn("EXPERIMENTAL libdeflate compressor in use. Use at your own risk!"); @@ -104,7 +103,6 @@ static int erofs_compressor_libdeflate_setlevel(struct erofs_compress *c, } const struct erofs_compressor erofs_compressor_libdeflate = { - .name = "libdeflate", .default_level = 1, .best_level = 12, .init = compressor_libdeflate_init, diff --git a/lib/compressor_liblzma.c b/lib/compressor_liblzma.c index f274dce9..0ed6f238 100644 --- a/lib/compressor_liblzma.c +++ b/lib/compressor_liblzma.c @@ -88,7 +88,6 @@ static int erofs_compressor_liblzma_init(struct erofs_compress *c) { struct erofs_liblzma_context *ctx; - c->alg = &erofs_compressor_lzma; ctx = malloc(sizeof(*ctx)); if (!ctx) return -ENOMEM; @@ -100,7 +99,6 @@ static int erofs_compressor_liblzma_init(struct erofs_compress *c) } const struct erofs_compressor erofs_compressor_lzma = { - .name = "lzma", .default_level = LZMA_PRESET_DEFAULT, .best_level = 109, .init = erofs_compressor_liblzma_init, diff --git a/lib/compressor_lz4.c b/lib/compressor_lz4.c index e507b709..6677693d 100644 --- a/lib/compressor_lz4.c +++ b/lib/compressor_lz4.c @@ -32,13 +32,11 @@ static int compressor_lz4_exit(struct erofs_compress *c) static int compressor_lz4_init(struct erofs_compress *c) { - c->alg = &erofs_compressor_lz4; c->sbi->lz4_max_distance = LZ4_DISTANCE_MAX; return 0; } const struct erofs_compressor erofs_compressor_lz4 = { - .name = "lz4", .default_level = 0, .best_level = 0, .init = compressor_lz4_init, diff --git a/lib/compressor_lz4hc.c b/lib/compressor_lz4hc.c index f2120d88..b410e155 100644 --- a/lib/compressor_lz4hc.c +++ b/lib/compressor_lz4hc.c @@ -38,8 +38,6 @@ static int compressor_lz4hc_exit(struct erofs_compress *c) static int compressor_lz4hc_init(struct erofs_compress *c) { - c->alg = &erofs_compressor_lz4hc; - c->private_data = LZ4_createStreamHC(); if (!c->private_data) return -ENOMEM; @@ -60,7 +58,6 @@ static int compressor_lz4hc_setlevel(struct erofs_compress *c, } const struct erofs_compressor erofs_compressor_lz4hc = { - .name = "lz4hc", .default_level = LZ4HC_CLEVEL_DEFAULT, .best_level = LZ4HC_CLEVEL_MAX, .init = compressor_lz4hc_init, diff --git a/mkfs/main.c b/mkfs/main.c index 3809c713..9c2397cb 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -68,13 +68,15 @@ static struct option long_options[] = { static void print_available_compressors(FILE *f, const char *delim) { - unsigned int i = 0; + int i = 0; + bool comma = false; const char *s; - while ((s = z_erofs_list_available_compressors(i)) != NULL) { - if (i++) + while ((s = z_erofs_list_available_compressors(&i)) != NULL) { + if (comma) fputs(delim, f); fputs(s, f); + comma = true; } fputc('\n', f); } From afacff27d8b31090efbe25d6990edabb8c92f4bb Mon Sep 17 00:00:00 2001 From: Guo Xuenan Date: Tue, 8 Aug 2023 17:23:35 +0800 Subject: [PATCH 10/17] erofs-utils: dump: print more superblock fields Let's print compression algorithms and sb_extslots as well as update feature information for dump.erofs. The proposed superblock dump is shown as below: Filesystem magic number: 0xE0F5E1E2 Filesystem blocks: 4624 Filesystem inode metadata start block: 0 Filesystem shared xattr metadata start block: 0 Filesystem root nid: 37 Filesystem compr_algs: lz4, lzma Filesystem sb_extslots: 0 Filesystem inode count: 6131 Filesystem created: Wed Jun 7 17:15:44 2023 Filesystem features: sb_csum mtime 0padding compr_cfgs big_pcluster Filesystem UUID: not available Signed-off-by: Guo Xuenan Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20230808092335.111834-2-hsiangkao@linux.alibaba.com --- dump/main.c | 29 +++++++++++++++++++++++++++++ include/erofs/internal.h | 1 + lib/super.c | 6 ++++++ 3 files changed, 36 insertions(+) diff --git a/dump/main.c b/dump/main.c index 409c851d..7980f789 100644 --- a/dump/main.c +++ b/dump/main.c @@ -92,12 +92,14 @@ static struct erofsdump_feature feature_lists[] = { { true, EROFS_FEATURE_COMPAT_SB_CHKSUM, "sb_csum" }, { true, EROFS_FEATURE_COMPAT_MTIME, "mtime" }, { false, EROFS_FEATURE_INCOMPAT_ZERO_PADDING, "0padding" }, + { false, EROFS_FEATURE_INCOMPAT_COMPR_CFGS, "compr_cfgs" }, { false, EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER, "big_pcluster" }, { false, EROFS_FEATURE_INCOMPAT_CHUNKED_FILE, "chunked_file" }, { false, EROFS_FEATURE_INCOMPAT_DEVICE_TABLE, "device_table" }, { false, EROFS_FEATURE_INCOMPAT_ZTAILPACKING, "ztailpacking" }, { false, EROFS_FEATURE_INCOMPAT_FRAGMENTS, "fragments" }, { false, EROFS_FEATURE_INCOMPAT_DEDUPE, "dedupe" }, + { false, EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES, "xattr_prefixes" }, }; static int erofsdump_readdir(struct erofs_dir_context *ctx); @@ -588,6 +590,23 @@ static void erofsdump_print_statistic(void) erofsdump_filetype_distribution(file_types, OTHERFILETYPE); } +static void erofsdump_print_supported_compressors(FILE *f, unsigned int mask) +{ + unsigned int i = 0; + bool comma = false; + const char *s; + + while ((s = z_erofs_list_supported_algorithms(i++, &mask)) != NULL) { + if (*s == '\0') + continue; + if (comma) + fputs(", ", f); + fputs(s, f); + comma = true; + } + fputc('\n', f); +} + static void erofsdump_show_superblock(void) { time_t time = sbi.build_time; @@ -607,6 +626,16 @@ static void erofsdump_show_superblock(void) if (erofs_sb_has_fragments(&sbi) && sbi.packed_nid > 0) fprintf(stdout, "Filesystem packed nid: %llu\n", sbi.packed_nid | 0ULL); + if (erofs_sb_has_compr_cfgs(&sbi)) { + fprintf(stdout, "Filesystem compr_algs: "); + erofsdump_print_supported_compressors(stdout, + sbi.available_compr_algs); + } else { + fprintf(stdout, "Filesystem lz4_max_distance: %u\n", + sbi.lz4_max_distance | 0U); + } + fprintf(stdout, "Filesystem sb_extslots: %u\n", + sbi.extslots | 0U); fprintf(stdout, "Filesystem inode count: %llu\n", sbi.inos | 0ULL); fprintf(stdout, "Filesystem created: %s", diff --git a/include/erofs/internal.h b/include/erofs/internal.h index 04a9a695..a04e6a6e 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -74,6 +74,7 @@ struct erofs_sb_info { u64 build_time; u32 build_time_nsec; + u8 extslots; unsigned char islotbits; unsigned char blkszbits; diff --git a/lib/super.c b/lib/super.c index 16a1d62a..e8e84aa7 100644 --- a/lib/super.c +++ b/lib/super.c @@ -106,11 +106,17 @@ int erofs_read_superblock(struct erofs_sb_info *sbi) sbi->packed_nid = le64_to_cpu(dsb->packed_nid); sbi->inos = le64_to_cpu(dsb->inos); sbi->checksum = le32_to_cpu(dsb->checksum); + sbi->extslots = dsb->sb_extslots; sbi->build_time = le64_to_cpu(dsb->build_time); sbi->build_time_nsec = le32_to_cpu(dsb->build_time_nsec); memcpy(&sbi->uuid, dsb->uuid, sizeof(dsb->uuid)); + + if (erofs_sb_has_compr_cfgs(sbi)) + sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs); + else + sbi->lz4_max_distance = le16_to_cpu(dsb->u1.lz4_max_distance); return erofs_init_devices(sbi, dsb); } From 6d7a0f5646ada42c69702947491aeb4cae5f84b5 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Thu, 10 Aug 2023 14:46:32 +0800 Subject: [PATCH 11/17] erofs-utils: mkfs: fix double write of long xattr name prefixes Fix double write of long xattr name prefixes in non-tarerofs mode. Besides fix the compiling error of tar.h. Include "internal.h" to introduce prototypes of `struct erofs_inode` and `struct erofs_sb_info`. Fixes: 95d315fd7958 ("erofs-utils: introduce tarerofs") Signed-off-by: Jingbo Xu Reviewed-by: Gao Xiang Link: https://lore.kernel.org/r/20230810064633.56218-1-jefflexu@linux.alibaba.com Signed-off-by: Gao Xiang --- include/erofs/tar.h | 11 +++++++++++ mkfs/main.c | 3 --- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/erofs/tar.h b/include/erofs/tar.h index 8d3f8dec..b7c2ef89 100644 --- a/include/erofs/tar.h +++ b/include/erofs/tar.h @@ -2,8 +2,15 @@ #ifndef __EROFS_TAR_H #define __EROFS_TAR_H +#ifdef __cplusplus +extern "C" +{ +#endif + #include +#include "internal.h" + struct erofs_pax_header { struct stat st; bool use_mtime; @@ -27,4 +34,8 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar); int tarerofs_reserve_devtable(struct erofs_sb_info *sbi, unsigned int devices); int tarerofs_write_devtable(struct erofs_sb_info *sbi, struct erofs_tarfile *tar); +#ifdef __cplusplus +} +#endif + #endif diff --git a/mkfs/main.c b/mkfs/main.c index 9c2397cb..c03a7a8a 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -912,9 +912,6 @@ int main(int argc, char **argv) erofs_inode_manager_init(); - if (cfg.c_extra_ea_name_prefixes) - erofs_xattr_write_name_prefixes(&sbi, packedfile); - if (!tar_mode) { err = erofs_build_shared_xattrs_from_path(&sbi, cfg.c_src_path); if (err) { From 2dd318025111217a71713b962b7e92532d87ba1e Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Thu, 10 Aug 2023 14:46:33 +0800 Subject: [PATCH 12/17] erofs-utils: lib: remove prototypes of removed functions Remove prototypes of those that have been deleted. Signed-off-by: Jingbo Xu Reviewed-by: Gao Xiang Link: https://lore.kernel.org/r/20230810064633.56218-2-jefflexu@linux.alibaba.com Signed-off-by: Gao Xiang --- include/erofs/tar.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/erofs/tar.h b/include/erofs/tar.h index b7c2ef89..d5648f6b 100644 --- a/include/erofs/tar.h +++ b/include/erofs/tar.h @@ -29,10 +29,7 @@ struct erofs_tarfile { bool index_mode, aufs; }; -int tarerofs_init_empty_dir(struct erofs_inode *inode); int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar); -int tarerofs_reserve_devtable(struct erofs_sb_info *sbi, unsigned int devices); -int tarerofs_write_devtable(struct erofs_sb_info *sbi, struct erofs_tarfile *tar); #ifdef __cplusplus } From 60f71d6614ddaecc595fa14de3ac131226393a61 Mon Sep 17 00:00:00 2001 From: Yue Hu Date: Tue, 15 Aug 2023 18:24:05 +0800 Subject: [PATCH 13/17] AOSP: erofs-utils: add missing sbi argument to erofs_blknr in block list Commit fc30780ebf90 ("erofs-utils: lib: avoid global sbi dependencies (take 1)") updated the macro erofs_blknr by adding sbi argument. Fixes: fc30780ebf90 ("erofs-utils: lib: avoid global sbi dependencies (take 1)") Signed-off-by: Yue Hu Reviewed-by: Gao Xiang Link: https://lore.kernel.org/r/20230815102405.19486-1-zbestahu@gmail.com Signed-off-by: Gao Xiang --- lib/block_list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/block_list.c b/lib/block_list.c index b45b553a..f47a746f 100644 --- a/lib/block_list.c +++ b/lib/block_list.c @@ -108,7 +108,7 @@ void erofs_droid_blocklist_write_tail_end(struct erofs_inode *inode, return; /* XXX: another hack, which means it has been outputed before */ - if (erofs_blknr(inode->i_size)) { + if (erofs_blknr(inode->sbi, inode->i_size)) { if (blkaddr == NULL_ADDR) fprintf(block_list_fp, "\n"); else From 1e429b74bff825f61c5f99cbf3d41369df77a831 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Wed, 16 Aug 2023 11:49:38 +0800 Subject: [PATCH 14/17] erofs-utils: lib: fix potential out-of-bound in xattr_entrylist() Check the index before accessing array to avoid the potential out-of-bound access. Fixes: c47df5aa2d16 ("erofs-utils: fuse: introduce xattr support") Reviewed-by: Gao Xiang Signed-off-by: Jingbo Xu Link: https://lore.kernel.org/r/20230816034941.126866-2-jefflexu@linux.alibaba.com Signed-off-by: Gao Xiang --- lib/xattr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/xattr.c b/lib/xattr.c index 12f580e7..25487504 100644 --- a/lib/xattr.c +++ b/lib/xattr.c @@ -1229,11 +1229,14 @@ static int xattr_entrylist(struct xattr_iter *_it, { struct listxattr_iter *it = container_of(_it, struct listxattr_iter, it); + unsigned int base_index = entry->e_name_index; unsigned int prefix_len; const char *prefix; - prefix = xattr_types[entry->e_name_index].prefix; - prefix_len = xattr_types[entry->e_name_index].prefix_len; + if (base_index >= ARRAY_SIZE(xattr_types)) + return 1; + prefix = xattr_types[base_index].prefix; + prefix_len = xattr_types[base_index].prefix_len; if (!it->buffer) { it->buffer_ofs += prefix_len + entry->e_name_len + 1; From ac20be2c0d08d7e61d64e854ebbe23250e9ad0d2 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Thu, 17 Aug 2023 15:14:53 +0800 Subject: [PATCH 15/17] erofs-utils: lib: add match_base_prefix() helper Since the introduction of long xattr name prefix, match_prefix() will search among the long xattr name prefixes first and return the matched prefix, while erofs_getxattr() expects a base prefix even when the queried xattr name matches a long prefix. Thus introduce match_base_prefix() helper to do this. Signed-off-by: Jingbo Xu Link: https://lore.kernel.org/r/20230817071455.12040-2-jefflexu@linux.alibaba.com Signed-off-by: Gao Xiang --- lib/xattr.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/xattr.c b/lib/xattr.c index 25487504..4091fe6c 100644 --- a/lib/xattr.c +++ b/lib/xattr.c @@ -137,27 +137,34 @@ static struct xattr_item *get_xattritem(u8 prefix, char *kvbuf, return item; } -static bool match_prefix(const char *key, u8 *index, u16 *len) +static bool match_base_prefix(const char *key, u8 *index, u16 *len) { struct xattr_prefix *p; - struct ea_type_node *tnode; - list_for_each_entry(tnode, &ea_name_prefixes, list) { - p = &tnode->type; + for (p = xattr_types; p < xattr_types + ARRAY_SIZE(xattr_types); ++p) { if (p->prefix && !strncmp(p->prefix, key, p->prefix_len)) { *len = p->prefix_len; - *index = tnode->index; + *index = p - xattr_types; return true; } } - for (p = xattr_types; p < xattr_types + ARRAY_SIZE(xattr_types); ++p) { + return false; +} + +static bool match_prefix(const char *key, u8 *index, u16 *len) +{ + struct xattr_prefix *p; + struct ea_type_node *tnode; + + list_for_each_entry(tnode, &ea_name_prefixes, list) { + p = &tnode->type; if (p->prefix && !strncmp(p->prefix, key, p->prefix_len)) { *len = p->prefix_len; - *index = p - xattr_types; + *index = tnode->index; return true; } } - return false; + return match_base_prefix(key, index, len); } static struct xattr_item *parse_one_xattr(const char *path, const char *key, @@ -1198,7 +1205,7 @@ int erofs_getxattr(struct erofs_inode *vi, const char *name, char *buffer, if (ret) return ret; - if (!match_prefix(name, &prefix, &prefixlen)) + if (!match_base_prefix(name, &prefix, &prefixlen)) return -ENODATA; it.it.sbi = vi->sbi; From 43d3a69ef7118dd9c5bec8e2f8c186f684eaed13 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Thu, 17 Aug 2023 15:14:54 +0800 Subject: [PATCH 16/17] erofs-utils: add erofs_read_metadata() helper Add erofs_read_metadata() helper reading variable-sized metadata from inode specified by @nid. Read from meta inode if @nid is 0. Signed-off-by: Jingbo Xu Link: https://lore.kernel.org/r/20230817071455.12040-3-jefflexu@linux.alibaba.com Signed-off-by: Gao Xiang --- include/erofs/internal.h | 2 + lib/data.c | 84 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/include/erofs/internal.h b/include/erofs/internal.h index a04e6a6e..3e7319d8 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -364,6 +364,8 @@ int erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map, int z_erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map, char *raw, char *buffer, erofs_off_t skip, erofs_off_t length, bool trimmed); +void *erofs_read_metadata(struct erofs_sb_info *sbi, erofs_nid_t nid, + erofs_off_t *offset, int *lengthp); static inline int erofs_get_occupied_size(const struct erofs_inode *inode, erofs_off_t *size) diff --git a/lib/data.c b/lib/data.c index a172bb57..662e922e 100644 --- a/lib/data.c +++ b/lib/data.c @@ -372,3 +372,87 @@ int erofs_pread(struct erofs_inode *inode, char *buf, } return -EINVAL; } + +static void *erofs_read_metadata_nid(struct erofs_sb_info *sbi, erofs_nid_t nid, + erofs_off_t *offset, int *lengthp) +{ + struct erofs_inode vi = { .sbi = sbi, .nid = nid }; + __le16 __len; + int ret, len; + char *buffer; + + ret = erofs_read_inode_from_disk(&vi); + if (ret) + return ERR_PTR(ret); + + *offset = round_up(*offset, 4); + ret = erofs_pread(&vi, (void *)&__len, sizeof(__le16), *offset); + if (ret) + return ERR_PTR(ret); + + len = le16_to_cpu(__len); + if (!len) + return ERR_PTR(-EFSCORRUPTED); + + buffer = malloc(len); + if (!buffer) + return ERR_PTR(-ENOMEM); + *offset += sizeof(__le16); + *lengthp = len; + + ret = erofs_pread(&vi, buffer, len, *offset); + if (ret) { + free(buffer); + return ERR_PTR(ret); + } + *offset += len; + return buffer; +} + +static void *erofs_read_metadata_bdi(struct erofs_sb_info *sbi, + erofs_off_t *offset, int *lengthp) +{ + int ret, len, i, cnt; + void *buffer; + u8 data[EROFS_MAX_BLOCK_SIZE]; + + *offset = round_up(*offset, 4); + ret = blk_read(sbi, 0, data, erofs_blknr(sbi, *offset), 1); + if (ret) + return ERR_PTR(ret); + len = le16_to_cpu(*(__le16 *)&data[erofs_blkoff(sbi, *offset)]); + if (!len) + return ERR_PTR(-EFSCORRUPTED); + + buffer = malloc(len); + if (!buffer) + return ERR_PTR(-ENOMEM); + *offset += sizeof(__le16); + *lengthp = len; + + for (i = 0; i < len; i += cnt) { + cnt = min_t(int, erofs_blksiz(sbi) - erofs_blkoff(sbi, *offset), + len - i); + ret = blk_read(sbi, 0, data, erofs_blknr(sbi, *offset), 1); + if (ret) { + free(buffer); + return ERR_PTR(ret); + } + memcpy(buffer + i, data + erofs_blkoff(sbi, *offset), cnt); + *offset += cnt; + } + return buffer; +} + +/* + * read variable-sized metadata, offset will be aligned by 4-byte + * + * @nid is 0 if metadata is in meta inode + */ +void *erofs_read_metadata(struct erofs_sb_info *sbi, erofs_nid_t nid, + erofs_off_t *offset, int *lengthp) +{ + if (nid) + return erofs_read_metadata_nid(sbi, nid, offset, lengthp); + return erofs_read_metadata_bdi(sbi, offset, lengthp); +} From ac3b2b1f5d03416dbea20c39f76b40a035800bdb Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Thu, 17 Aug 2023 15:14:55 +0800 Subject: [PATCH 17/17] erofs-utils: support long xattr name prefixes for erofsfuse Make erofs_listxattr() and erofs_getxattr() routine support long xattr name prefixes. Although the on-disk format allows long xattr name prefixes to be placed in the meta inode or packed inode, currently mkfs.erofs will place them in packed inode by default. Thus let's also read long xattr name prefixes from packed inode by default. Since we need to read the content of the packed inode from disk when loading long xattr name prefixes, add dependency on zlib_LIBS for mkfs.erofs to resolve the compiling dependency. Signed-off-by: Jingbo Xu Link: https://lore.kernel.org/r/20230817071455.12040-4-jefflexu@linux.alibaba.com Signed-off-by: Gao Xiang --- include/erofs/internal.h | 6 ++ include/erofs/xattr.h | 2 + lib/super.c | 14 ++++- lib/xattr.c | 115 +++++++++++++++++++++++++++++++++++---- mkfs/Makefile.am | 3 +- 5 files changed, 128 insertions(+), 12 deletions(-) diff --git a/include/erofs/internal.h b/include/erofs/internal.h index 3e7319d8..db766cad 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -57,6 +57,11 @@ struct erofs_device_info { u32 mapped_blkaddr; }; +struct erofs_xattr_prefix_item { + struct erofs_xattr_long_prefix *prefix; + u8 infix_len; +}; + #define EROFS_PACKED_NID_UNALLOCATED -1 struct erofs_sb_info { @@ -99,6 +104,7 @@ struct erofs_sb_info { u32 xattr_prefix_start; u8 xattr_prefix_count; + struct erofs_xattr_prefix_item *xattr_prefixes; int devfd; u64 devsz; diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h index dc27cf6e..748442af 100644 --- a/include/erofs/xattr.h +++ b/include/erofs/xattr.h @@ -82,6 +82,8 @@ int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *p int erofs_xattr_insert_name_prefix(const char *prefix); void erofs_xattr_cleanup_name_prefixes(void); int erofs_xattr_write_name_prefixes(struct erofs_sb_info *sbi, FILE *f); +void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi); +int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi); int erofs_setxattr(struct erofs_inode *inode, char *key, const void *value, size_t size); diff --git a/lib/super.c b/lib/super.c index e8e84aa7..21dc51f7 100644 --- a/lib/super.c +++ b/lib/super.c @@ -6,6 +6,7 @@ #include #include "erofs/io.h" #include "erofs/print.h" +#include "erofs/xattr.h" static bool check_layout_compatibility(struct erofs_sb_info *sbi, struct erofs_super_block *dsb) @@ -101,6 +102,8 @@ int erofs_read_superblock(struct erofs_sb_info *sbi) sbi->primarydevice_blocks = le32_to_cpu(dsb->blocks); sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr); sbi->xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr); + sbi->xattr_prefix_start = le32_to_cpu(dsb->xattr_prefix_start); + sbi->xattr_prefix_count = dsb->xattr_prefix_count; sbi->islotbits = EROFS_ISLOTBITS; sbi->root_nid = le16_to_cpu(dsb->root_nid); sbi->packed_nid = le64_to_cpu(dsb->packed_nid); @@ -117,11 +120,20 @@ int erofs_read_superblock(struct erofs_sb_info *sbi) sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs); else sbi->lz4_max_distance = le16_to_cpu(dsb->u1.lz4_max_distance); - return erofs_init_devices(sbi, dsb); + + ret = erofs_init_devices(sbi, dsb); + if (ret) + return ret; + + ret = erofs_xattr_prefixes_init(sbi); + if (ret) + free(sbi->devs); + return ret; } void erofs_put_super(struct erofs_sb_info *sbi) { if (sbi->devs) free(sbi->devs); + erofs_xattr_prefixes_cleanup(sbi); } diff --git a/lib/xattr.c b/lib/xattr.c index 4091fe6c..46a301ad 100644 --- a/lib/xattr.c +++ b/lib/xattr.c @@ -1093,19 +1093,47 @@ static int xattr_foreach(struct xattr_iter *it, struct getxattr_iter { struct xattr_iter it; - int buffer_size, index; + int buffer_size, index, infix_len; char *buffer; const char *name; size_t len; }; +static int erofs_xattr_long_entrymatch(struct getxattr_iter *it, + struct erofs_xattr_entry *entry) +{ + struct erofs_sb_info *sbi = it->it.sbi; + struct erofs_xattr_prefix_item *pf = sbi->xattr_prefixes + + (entry->e_name_index & EROFS_XATTR_LONG_PREFIX_MASK); + + if (pf >= sbi->xattr_prefixes + sbi->xattr_prefix_count) + return -ENOATTR; + + if (it->index != pf->prefix->base_index || + it->len != entry->e_name_len + pf->infix_len) + return -ENOATTR; + + if (memcmp(it->name, pf->prefix->infix, pf->infix_len)) + return -ENOATTR; + + it->infix_len = pf->infix_len; + return 0; +} + static int xattr_entrymatch(struct xattr_iter *_it, struct erofs_xattr_entry *entry) { struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); - return (it->index != entry->e_name_index || - it->len != entry->e_name_len) ? -ENOATTR : 0; + /* should also match the infix for long name prefixes */ + if (entry->e_name_index & EROFS_XATTR_LONG_PREFIX) + return erofs_xattr_long_entrymatch(it, entry); + + if (it->index != entry->e_name_index || + it->len != entry->e_name_len) + return -ENOATTR; + it->infix_len = 0; + return 0; } static int xattr_namematch(struct xattr_iter *_it, @@ -1113,8 +1141,9 @@ static int xattr_namematch(struct xattr_iter *_it, { struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); - - return memcmp(buf, it->name + processed, len) ? -ENOATTR : 0; + if (memcmp(buf, it->name + it->infix_len + processed, len)) + return -ENOATTR; + return 0; } static int xattr_checkbuffer(struct xattr_iter *_it, @@ -1237,8 +1266,20 @@ static int xattr_entrylist(struct xattr_iter *_it, struct listxattr_iter *it = container_of(_it, struct listxattr_iter, it); unsigned int base_index = entry->e_name_index; - unsigned int prefix_len; - const char *prefix; + unsigned int prefix_len, infix_len = 0; + const char *prefix, *infix = NULL; + + if (entry->e_name_index & EROFS_XATTR_LONG_PREFIX) { + struct erofs_sb_info *sbi = _it->sbi; + struct erofs_xattr_prefix_item *pf = sbi->xattr_prefixes + + (entry->e_name_index & EROFS_XATTR_LONG_PREFIX_MASK); + + if (pf >= sbi->xattr_prefixes + sbi->xattr_prefix_count) + return 1; + infix = pf->prefix->infix; + infix_len = pf->infix_len; + base_index = pf->prefix->base_index; + } if (base_index >= ARRAY_SIZE(xattr_types)) return 1; @@ -1246,16 +1287,18 @@ static int xattr_entrylist(struct xattr_iter *_it, prefix_len = xattr_types[base_index].prefix_len; if (!it->buffer) { - it->buffer_ofs += prefix_len + entry->e_name_len + 1; + it->buffer_ofs += prefix_len + infix_len + + entry->e_name_len + 1; return 1; } - if (it->buffer_ofs + prefix_len + if (it->buffer_ofs + prefix_len + infix_len + entry->e_name_len + 1 > it->buffer_size) return -ERANGE; memcpy(it->buffer + it->buffer_ofs, prefix, prefix_len); - it->buffer_ofs += prefix_len; + memcpy(it->buffer + it->buffer_ofs + prefix_len, infix, infix_len); + it->buffer_ofs += prefix_len + infix_len; return 0; } @@ -1404,3 +1447,55 @@ void erofs_xattr_cleanup_name_prefixes(void) free(tnode); } } + +void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi) +{ + int i; + + if (sbi->xattr_prefixes) { + for (i = 0; i < sbi->xattr_prefix_count; i++) + free(sbi->xattr_prefixes[i].prefix); + free(sbi->xattr_prefixes); + sbi->xattr_prefixes = NULL; + } +} + +int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi) +{ + erofs_off_t pos = (erofs_off_t)sbi->xattr_prefix_start << 2; + struct erofs_xattr_prefix_item *pfs; + erofs_nid_t nid = 0; + int ret = 0, i, len; + void *buf; + + if (!sbi->xattr_prefix_count) + return 0; + + if (sbi->packed_nid) + nid = sbi->packed_nid; + + pfs = calloc(sbi->xattr_prefix_count, sizeof(*pfs)); + if (!pfs) + return -ENOMEM; + + for (i = 0; i < sbi->xattr_prefix_count; i++) { + buf = erofs_read_metadata(sbi, nid, &pos, &len); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + goto out; + } + if (len < sizeof(*pfs->prefix) || + len > EROFS_NAME_LEN + sizeof(*pfs->prefix)) { + free(buf); + ret = -EFSCORRUPTED; + goto out; + } + pfs[i].prefix = buf; + pfs[i].infix_len = len - sizeof(struct erofs_xattr_long_prefix); + } +out: + sbi->xattr_prefixes = pfs; + if (ret) + erofs_xattr_prefixes_cleanup(sbi); + return ret; +} diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 603c2f33..dd754859 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -6,4 +6,5 @@ AM_CPPFLAGS = ${libselinux_CFLAGS} mkfs_erofs_SOURCES = main.c mkfs_erofs_CFLAGS = -Wall -I$(top_srcdir)/include mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libselinux_LIBS} \ - ${libuuid_LIBS} ${liblz4_LIBS} ${liblzma_LIBS} ${libdeflate_LIBS} + ${libuuid_LIBS} ${liblz4_LIBS} ${liblzma_LIBS} ${zlib_LIBS} \ + ${libdeflate_LIBS}