]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
erofs: implement metadata compression
authorBo Liu (OpenAnolis) <liubo03@inspur.com>
Tue, 22 Jul 2025 00:32:29 +0000 (08:32 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Thu, 24 Jul 2025 11:43:31 +0000 (19:43 +0800)
Thanks to the meta buffer infrastructure, metadata-compressed inodes are
just read from the metabox inode instead of the blockdevice (or backing
file) inode.

The same is true for shared extended attributes.

When metadata compression is enabled, inode numbers are divided from
on-disk NIDs because of non-LTS 32-bit application compatibility.

Co-developed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: Bo Liu (OpenAnolis) <liubo03@inspur.com>
Acked-by: Chao Yu <chao@kernel.org>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20250722003229.2121752-1-hsiangkao@linux.alibaba.com
14 files changed:
Documentation/ABI/testing/sysfs-fs-erofs
fs/erofs/data.c
fs/erofs/decompressor.c
fs/erofs/dir.c
fs/erofs/erofs_fs.h
fs/erofs/fileio.c
fs/erofs/fscache.c
fs/erofs/inode.c
fs/erofs/internal.h
fs/erofs/super.c
fs/erofs/sysfs.c
fs/erofs/xattr.c
fs/erofs/zdata.c
fs/erofs/zmap.c

index bf3b6299c15e6e86fde36f836dd1c939763285e7..ad6d1a3ccd4e062c96fa74481521a9993842da69 100644 (file)
@@ -5,7 +5,7 @@ Description:    Shows all enabled kernel features.
                Supported features:
                zero_padding, compr_cfgs, big_pcluster, chunked_file,
                device_table, compr_head2, sb_chksum, ztailpacking,
-               dedupe, fragments.
+               dedupe, fragments, 48bit, metabox.
 
 What:          /sys/fs/erofs/<disk>/sync_decompress
 Date:          November 2021
index 383c1337e157d9689654f8f50a0609032d78f0b4..f46c47335b9cfb2d3a7c91a4f24e604ed6e5ebc2 100644 (file)
@@ -49,11 +49,18 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)
        return buf->base + (offset & ~PAGE_MASK);
 }
 
-void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb)
+int erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb,
+                      bool in_metabox)
 {
        struct erofs_sb_info *sbi = EROFS_SB(sb);
 
        buf->file = NULL;
+       if (in_metabox) {
+               if (unlikely(!sbi->metabox_inode))
+                       return -EFSCORRUPTED;
+               buf->mapping = sbi->metabox_inode->i_mapping;
+               return 0;
+       }
        buf->off = sbi->dif0.fsoff;
        if (erofs_is_fileio_mode(sbi)) {
                buf->file = sbi->dif0.file;     /* some fs like FUSE needs it */
@@ -62,12 +69,17 @@ void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb)
                buf->mapping = sbi->dif0.fscache->inode->i_mapping;
        else
                buf->mapping = sb->s_bdev->bd_mapping;
+       return 0;
 }
 
 void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb,
-                        erofs_off_t offset)
+                        erofs_off_t offset, bool in_metabox)
 {
-       erofs_init_metabuf(buf, sb);
+       int err;
+
+       err = erofs_init_metabuf(buf, sb, in_metabox);
+       if (err)
+               return ERR_PTR(err);
        return erofs_bread(buf, offset, true);
 }
 
@@ -118,7 +130,7 @@ int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map)
        pos = ALIGN(erofs_iloc(inode) + vi->inode_isize +
                    vi->xattr_isize, unit) + unit * chunknr;
 
-       idx = erofs_read_metabuf(&buf, sb, pos);
+       idx = erofs_read_metabuf(&buf, sb, pos, erofs_inode_in_metabox(inode));
        if (IS_ERR(idx)) {
                err = PTR_ERR(idx);
                goto out;
@@ -264,7 +276,6 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
 
        map.m_la = offset;
        map.m_llen = length;
-
        ret = erofs_map_blocks(inode, &map);
        if (ret < 0)
                return ret;
@@ -273,35 +284,37 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
        iomap->length = map.m_llen;
        iomap->flags = 0;
        iomap->private = NULL;
+       iomap->addr = IOMAP_NULL_ADDR;
        if (!(map.m_flags & EROFS_MAP_MAPPED)) {
                iomap->type = IOMAP_HOLE;
-               iomap->addr = IOMAP_NULL_ADDR;
                return 0;
        }
 
-       mdev = (struct erofs_map_dev) {
-               .m_deviceid = map.m_deviceid,
-               .m_pa = map.m_pa,
-       };
-       ret = erofs_map_dev(sb, &mdev);
-       if (ret)
-               return ret;
-
-       if (flags & IOMAP_DAX)
-               iomap->dax_dev = mdev.m_dif->dax_dev;
-       else
-               iomap->bdev = mdev.m_bdev;
-
-       iomap->addr = mdev.m_dif->fsoff + mdev.m_pa;
-       if (flags & IOMAP_DAX)
-               iomap->addr += mdev.m_dif->dax_part_off;
+       if (!(map.m_flags & EROFS_MAP_META) || !erofs_inode_in_metabox(inode)) {
+               mdev = (struct erofs_map_dev) {
+                       .m_deviceid = map.m_deviceid,
+                       .m_pa = map.m_pa,
+               };
+               ret = erofs_map_dev(sb, &mdev);
+               if (ret)
+                       return ret;
+
+               if (flags & IOMAP_DAX)
+                       iomap->dax_dev = mdev.m_dif->dax_dev;
+               else
+                       iomap->bdev = mdev.m_bdev;
+               iomap->addr = mdev.m_dif->fsoff + mdev.m_pa;
+               if (flags & IOMAP_DAX)
+                       iomap->addr += mdev.m_dif->dax_part_off;
+       }
 
        if (map.m_flags & EROFS_MAP_META) {
                void *ptr;
                struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
 
                iomap->type = IOMAP_INLINE;
-               ptr = erofs_read_metabuf(&buf, sb, mdev.m_pa);
+               ptr = erofs_read_metabuf(&buf, sb, map.m_pa,
+                                        erofs_inode_in_metabox(inode));
                if (IS_ERR(ptr))
                        return PTR_ERR(ptr);
                iomap->inline_data = ptr;
index 358061d7b660744c6d518a381fa36992618c175d..354762c9723f94b1a532d93ec83cd8e37ba7772b 100644 (file)
@@ -467,7 +467,7 @@ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb)
                return -EOPNOTSUPP;
        }
 
-       erofs_init_metabuf(&buf, sb);
+       (void)erofs_init_metabuf(&buf, sb, false);
        offset = EROFS_SUPER_OFFSET + sbi->sb_size;
        alg = 0;
        for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
index 3e4b38bec0aa49cf70cd952646a5ea8938dd4323..d1c6cd1a45e877b88e552faaa40061c76827007a 100644 (file)
@@ -34,7 +34,8 @@ static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx,
                }
 
                if (!dir_emit(ctx, de_name, de_namelen,
-                             le64_to_cpu(de->nid), d_type))
+                             erofs_nid_to_ino64(EROFS_SB(dir->i_sb),
+                                                le64_to_cpu(de->nid)), d_type))
                        return 1;
                ++de;
                ctx->pos += sizeof(struct erofs_dirent);
index 7b150ac64742f26b9281913626d6e308d5385638..377ee12b8b96677ea8b0a0bda3e3926302760096 100644 (file)
@@ -34,7 +34,7 @@
 #define EROFS_FEATURE_INCOMPAT_48BIT           0x00000080
 #define EROFS_FEATURE_INCOMPAT_METABOX         0x00000100
 #define EROFS_ALL_FEATURE_INCOMPAT             \
-       ((EROFS_FEATURE_INCOMPAT_48BIT << 1) - 1)
+       ((EROFS_FEATURE_INCOMPAT_METABOX << 1) - 1)
 
 #define EROFS_SB_EXTSLOT_SIZE  16
 
index 3ee082476c8c534aa8974b4e5c1697e5fc01ab73..b7b3432a9882e0e0e8912e6b126405eb12204547 100644 (file)
@@ -115,7 +115,7 @@ static int erofs_fileio_scan_folio(struct erofs_fileio *io, struct folio *folio)
                        void *src;
 
                        src = erofs_read_metabuf(&buf, inode->i_sb,
-                                                map->m_pa + ofs);
+                               map->m_pa + ofs, erofs_inode_in_metabox(inode));
                        if (IS_ERR(src)) {
                                err = PTR_ERR(src);
                                break;
index 9a8ee646e51d9d73e9cd6a08552d5c96673647f5..362acf828279fc829fb16b9ac17f1c734ada27e7 100644 (file)
@@ -274,7 +274,8 @@ static int erofs_fscache_data_read_slice(struct erofs_fscache_rq *req)
                size_t size = map.m_llen;
                void *src;
 
-               src = erofs_read_metabuf(&buf, sb, map.m_pa);
+               src = erofs_read_metabuf(&buf, sb, map.m_pa,
+                                        erofs_inode_in_metabox(inode));
                if (IS_ERR(src))
                        return PTR_ERR(src);
 
index 47215c5e33855bb48ee8b072f31fad1fe8badb37..9a2f59721522570d2bc46b474ec423a573dfb4fd 100644 (file)
@@ -29,6 +29,7 @@ static int erofs_read_inode(struct inode *inode)
        struct super_block *sb = inode->i_sb;
        erofs_blk_t blkaddr = erofs_blknr(sb, erofs_iloc(inode));
        unsigned int ofs = erofs_blkoff(sb, erofs_iloc(inode));
+       bool in_mbox = erofs_inode_in_metabox(inode);
        struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
        struct erofs_sb_info *sbi = EROFS_SB(sb);
        erofs_blk_t addrmask = BIT_ULL(48) - 1;
@@ -39,7 +40,7 @@ static int erofs_read_inode(struct inode *inode)
        void *ptr;
        int err = 0;
 
-       ptr = erofs_read_metabuf(&buf, sb, erofs_pos(sb, blkaddr));
+       ptr = erofs_read_metabuf(&buf, sb, erofs_pos(sb, blkaddr), in_mbox);
        if (IS_ERR(ptr)) {
                err = PTR_ERR(ptr);
                erofs_err(sb, "failed to read inode meta block (nid: %llu): %d",
@@ -78,7 +79,7 @@ static int erofs_read_inode(struct inode *inode)
 
                        memcpy(&copied, dic, gotten);
                        ptr = erofs_read_metabuf(&buf, sb,
-                                       erofs_pos(sb, blkaddr + 1));
+                                       erofs_pos(sb, blkaddr + 1), in_mbox);
                        if (IS_ERR(ptr)) {
                                err = PTR_ERR(ptr);
                                erofs_err(sb, "failed to read inode payload block (nid: %llu): %d",
@@ -264,13 +265,13 @@ static int erofs_fill_inode(struct inode *inode)
  * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
  * so that it will fit.
  */
-static ino_t erofs_squash_ino(erofs_nid_t nid)
+static ino_t erofs_squash_ino(struct super_block *sb, erofs_nid_t nid)
 {
-       ino_t ino = (ino_t)nid;
+       u64 ino64 = erofs_nid_to_ino64(EROFS_SB(sb), nid);
 
        if (sizeof(ino_t) < sizeof(erofs_nid_t))
-               ino ^= nid >> (sizeof(erofs_nid_t) - sizeof(ino_t)) * 8;
-       return ino;
+               ino64 ^= ino64 >> (sizeof(erofs_nid_t) - sizeof(ino_t)) * 8;
+       return (ino_t)ino64;
 }
 
 static int erofs_iget5_eq(struct inode *inode, void *opaque)
@@ -282,7 +283,7 @@ static int erofs_iget5_set(struct inode *inode, void *opaque)
 {
        const erofs_nid_t nid = *(erofs_nid_t *)opaque;
 
-       inode->i_ino = erofs_squash_ino(nid);
+       inode->i_ino = erofs_squash_ino(inode->i_sb, nid);
        EROFS_I(inode)->nid = nid;
        return 0;
 }
@@ -291,7 +292,7 @@ struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid)
 {
        struct inode *inode;
 
-       inode = iget5_locked(sb, erofs_squash_ino(nid), erofs_iget5_eq,
+       inode = iget5_locked(sb, erofs_squash_ino(sb, nid), erofs_iget5_eq,
                             erofs_iget5_set, &nid);
        if (!inode)
                return ERR_PTR(-ENOMEM);
index ad932f670bb645cbc614b08793d3241f7c1650ae..26f9aa57ff3cabefda9847406116f5e7cd294f6f 100644 (file)
@@ -125,6 +125,7 @@ struct erofs_sb_info {
        struct erofs_sb_lz4_info lz4;
 #endif /* CONFIG_EROFS_FS_ZIP */
        struct inode *packed_inode;
+       struct inode *metabox_inode;
        struct erofs_dev_context *devs;
        u64 total_blocks;
 
@@ -148,6 +149,7 @@ struct erofs_sb_info {
        /* what we really care is nid, rather than ino.. */
        erofs_nid_t root_nid;
        erofs_nid_t packed_nid;
+       erofs_nid_t metabox_nid;
        /* used for statfs, f_files - f_favail */
        u64 inos;
 
@@ -232,6 +234,23 @@ EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
 EROFS_FEATURE_FUNCS(xattr_filter, compat, COMPAT_XATTR_FILTER)
 EROFS_FEATURE_FUNCS(shared_ea_in_metabox, compat, COMPAT_SHARED_EA_IN_METABOX)
 
+static inline u64 erofs_nid_to_ino64(struct erofs_sb_info *sbi, erofs_nid_t nid)
+{
+       if (!erofs_sb_has_metabox(sbi))
+               return nid;
+
+       /*
+        * When metadata compression is enabled, avoid generating excessively
+        * large inode numbers for metadata-compressed inodes.  Shift NIDs in
+        * the 31-62 bit range left by one and move the metabox flag to bit 31.
+        *
+        * Note: on-disk NIDs remain unchanged as they are primarily used for
+        * compatibility with non-LFS 32-bit applications.
+        */
+       return ((nid << 1) & GENMASK_ULL(63, 32)) | (nid & GENMASK(30, 0)) |
+               ((nid >> EROFS_DIRENT_NID_METABOX_BIT) << 31);
+}
+
 /* atomic flag definitions */
 #define EROFS_I_EA_INITED_BIT  0
 #define EROFS_I_Z_INITED_BIT   1
@@ -281,12 +300,20 @@ struct erofs_inode {
 
 #define EROFS_I(ptr)   container_of(ptr, struct erofs_inode, vfs_inode)
 
+static inline bool erofs_inode_in_metabox(struct inode *inode)
+{
+       return EROFS_I(inode)->nid & BIT_ULL(EROFS_DIRENT_NID_METABOX_BIT);
+}
+
 static inline erofs_off_t erofs_iloc(struct inode *inode)
 {
        struct erofs_sb_info *sbi = EROFS_I_SB(inode);
+       erofs_nid_t nid_lo = EROFS_I(inode)->nid & EROFS_DIRENT_NID_MASK;
 
+       if (erofs_inode_in_metabox(inode))
+               return nid_lo << sbi->islotbits;
        return erofs_pos(inode->i_sb, sbi->meta_blkaddr) +
-               (EROFS_I(inode)->nid << sbi->islotbits);
+               (nid_lo << sbi->islotbits);
 }
 
 static inline unsigned int erofs_inode_version(unsigned int ifmt)
@@ -385,9 +412,10 @@ void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf,
 void erofs_unmap_metabuf(struct erofs_buf *buf);
 void erofs_put_metabuf(struct erofs_buf *buf);
 void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap);
-void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb);
+int erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb,
+                      bool in_metabox);
 void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb,
-                        erofs_off_t offset);
+                        erofs_off_t offset, bool in_metabox);
 int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *dev);
 int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                 u64 start, u64 len);
index bc27fa3bd678338de1f765fb92a3babd7890b0f6..c7b9b784dc3daf8ea67de3926e4a8297ee6c63b0 100644 (file)
@@ -141,7 +141,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
        struct erofs_deviceslot *dis;
        struct file *file;
 
-       dis = erofs_read_metabuf(buf, sb, *pos);
+       dis = erofs_read_metabuf(buf, sb, *pos, false);
        if (IS_ERR(dis))
                return PTR_ERR(dis);
 
@@ -258,7 +258,7 @@ static int erofs_read_superblock(struct super_block *sb)
        void *data;
        int ret;
 
-       data = erofs_read_metabuf(&buf, sb, 0);
+       data = erofs_read_metabuf(&buf, sb, 0, false);
        if (IS_ERR(data)) {
                erofs_err(sb, "cannot read erofs superblock");
                return PTR_ERR(data);
@@ -319,6 +319,14 @@ static int erofs_read_superblock(struct super_block *sb)
                sbi->root_nid = le16_to_cpu(dsb->rb.rootnid_2b);
        }
        sbi->packed_nid = le64_to_cpu(dsb->packed_nid);
+       if (erofs_sb_has_metabox(sbi)) {
+               if (sbi->sb_size <= offsetof(struct erofs_super_block,
+                                            metabox_nid))
+                       return -EFSCORRUPTED;
+               sbi->metabox_nid = le64_to_cpu(dsb->metabox_nid);
+               if (sbi->metabox_nid & BIT_ULL(EROFS_DIRENT_NID_METABOX_BIT))
+                       return -EFSCORRUPTED;   /* self-loop detection */
+       }
        sbi->inos = le64_to_cpu(dsb->inos);
 
        sbi->epoch = (s64)le64_to_cpu(dsb->epoch);
@@ -335,6 +343,8 @@ static int erofs_read_superblock(struct super_block *sb)
 
        if (erofs_sb_has_48bit(sbi))
                erofs_info(sb, "EXPERIMENTAL 48-bit layout support in use. Use at your own risk!");
+       if (erofs_sb_has_metabox(sbi))
+               erofs_info(sb, "EXPERIMENTAL metadata compression support in use. Use at your own risk!");
        if (erofs_is_fscache_mode(sb))
                erofs_info(sb, "[deprecated] fscache-based on-demand read feature in use. Use at your own risk!");
 out:
@@ -690,6 +700,12 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
                        return PTR_ERR(inode);
                sbi->packed_inode = inode;
        }
+       if (erofs_sb_has_metabox(sbi)) {
+               inode = erofs_iget(sb, sbi->metabox_nid);
+               if (IS_ERR(inode))
+                       return PTR_ERR(inode);
+               sbi->metabox_inode = inode;
+       }
 
        inode = erofs_iget(sb, sbi->root_nid);
        if (IS_ERR(inode))
@@ -845,6 +861,8 @@ static void erofs_drop_internal_inodes(struct erofs_sb_info *sbi)
 {
        iput(sbi->packed_inode);
        sbi->packed_inode = NULL;
+       iput(sbi->metabox_inode);
+       sbi->metabox_inode = NULL;
 #ifdef CONFIG_EROFS_FS_ZIP
        iput(sbi->managed_cache);
        sbi->managed_cache = NULL;
index eed8797a193f70a65c6b7df86f5251475600c7ec..a9fe35ba0906ffa8f2bff48cb18dc61a8ec0f76f 100644 (file)
@@ -95,6 +95,7 @@ EROFS_ATTR_FEATURE(ztailpacking);
 EROFS_ATTR_FEATURE(fragments);
 EROFS_ATTR_FEATURE(dedupe);
 EROFS_ATTR_FEATURE(48bit);
+EROFS_ATTR_FEATURE(metabox);
 
 static struct attribute *erofs_feat_attrs[] = {
        ATTR_LIST(zero_padding),
@@ -108,6 +109,7 @@ static struct attribute *erofs_feat_attrs[] = {
        ATTR_LIST(fragments),
        ATTR_LIST(dedupe),
        ATTR_LIST(48bit),
+       ATTR_LIST(metabox),
        NULL,
 };
 ATTRIBUTE_GROUPS(erofs_feat);
index d61110f511e0d13e18029fe517d7c6c6c22531a2..eaa9efd766eea718b9cb1164014ac62ae62c89e1 100644 (file)
@@ -77,7 +77,9 @@ static int erofs_init_inode_xattrs(struct inode *inode)
        }
 
        it.buf = __EROFS_BUF_INITIALIZER;
-       erofs_init_metabuf(&it.buf, sb);
+       ret = erofs_init_metabuf(&it.buf, sb, erofs_inode_in_metabox(inode));
+       if (ret)
+               goto out_unlock;
        it.pos = erofs_iloc(inode) + vi->inode_isize;
 
        /* read in shared xattr array (non-atomic, see kmalloc below) */
@@ -326,6 +328,9 @@ static int erofs_xattr_iter_inline(struct erofs_xattr_iter *it,
                return -ENODATA;
        }
 
+       ret = erofs_init_metabuf(&it->buf, it->sb, erofs_inode_in_metabox(inode));
+       if (ret)
+               return ret;
        remaining = vi->xattr_isize - xattr_header_sz;
        it->pos = erofs_iloc(inode) + vi->inode_isize + xattr_header_sz;
 
@@ -361,12 +366,17 @@ static int erofs_xattr_iter_shared(struct erofs_xattr_iter *it,
        struct erofs_inode *const vi = EROFS_I(inode);
        struct super_block *const sb = it->sb;
        struct erofs_sb_info *sbi = EROFS_SB(sb);
-       unsigned int i;
-       int ret = -ENODATA;
+       unsigned int i = 0;
+       int ret;
 
-       for (i = 0; i < vi->xattr_shared_count; ++i) {
+       ret = erofs_init_metabuf(&it->buf, sb,
+                                erofs_sb_has_shared_ea_in_metabox(sbi));
+       if (ret)
+               return ret;
+
+       while (i < vi->xattr_shared_count) {
                it->pos = erofs_pos(sb, sbi->xattr_blkaddr) +
-                               vi->xattr_shared_xattrs[i] * sizeof(__le32);
+                               vi->xattr_shared_xattrs[i++] * sizeof(__le32);
                it->kaddr = erofs_bread(&it->buf, it->pos, true);
                if (IS_ERR(it->kaddr))
                        return PTR_ERR(it->kaddr);
@@ -378,7 +388,7 @@ static int erofs_xattr_iter_shared(struct erofs_xattr_iter *it,
                if ((getxattr && ret != -ENODATA) || (!getxattr && ret))
                        break;
        }
-       return ret;
+       return i ? ret : -ENODATA;
 }
 
 int erofs_getxattr(struct inode *inode, int index, const char *name,
@@ -413,7 +423,6 @@ int erofs_getxattr(struct inode *inode, int index, const char *name,
 
        it.sb = inode->i_sb;
        it.buf = __EROFS_BUF_INITIALIZER;
-       erofs_init_metabuf(&it.buf, it.sb);
        it.buffer = buffer;
        it.buffer_size = buffer_size;
        it.buffer_ofs = 0;
@@ -439,7 +448,6 @@ ssize_t erofs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
 
        it.sb = dentry->d_sb;
        it.buf = __EROFS_BUF_INITIALIZER;
-       erofs_init_metabuf(&it.buf, it.sb);
        it.dentry = dentry;
        it.buffer = buffer;
        it.buffer_size = buffer_size;
@@ -485,7 +493,7 @@ int erofs_xattr_prefixes_init(struct super_block *sb)
        if (sbi->packed_inode)
                buf.mapping = sbi->packed_inode->i_mapping;
        else
-               erofs_init_metabuf(&buf, sb);
+               (void)erofs_init_metabuf(&buf, sb, false);
 
        for (i = 0; i < sbi->xattr_prefix_count; i++) {
                void *ptr = erofs_read_metadata(sb, &buf, &pos, &len);
index 0d1ddd9b15dedf74ada2af9f2986937bd7142e53..792f20888a8fc2f44192ace854a3fa637c6af690 100644 (file)
@@ -855,7 +855,10 @@ static int z_erofs_pcluster_begin(struct z_erofs_frontend *fe)
                /* bind cache first when cached decompression is preferred */
                z_erofs_bind_cache(fe);
        } else {
-               erofs_init_metabuf(&map->buf, sb);
+               ret = erofs_init_metabuf(&map->buf, sb,
+                                        erofs_inode_in_metabox(fe->inode));
+               if (ret)
+                       return ret;
                ptr = erofs_bread(&map->buf, map->m_pa, false);
                if (IS_ERR(ptr)) {
                        ret = PTR_ERR(ptr);
index b72a0e3f93622efdea3d6f4f287725b1a9182985..a93efd95c5556d802037439946f618290aa75f2a 100644 (file)
@@ -17,7 +17,7 @@ struct z_erofs_maprecorder {
        u16 delta[2];
        erofs_blk_t pblk, compressedblks;
        erofs_off_t nextpackoff;
-       bool partialref;
+       bool partialref, in_mbox;
 };
 
 static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
@@ -31,7 +31,7 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
        struct z_erofs_lcluster_index *di;
        unsigned int advise;
 
-       di = erofs_read_metabuf(&m->map->buf, inode->i_sb, pos);
+       di = erofs_read_metabuf(&m->map->buf, inode->i_sb, pos, m->in_mbox);
        if (IS_ERR(di))
                return PTR_ERR(di);
        m->lcn = lcn;
@@ -146,7 +146,7 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m,
        else
                return -EOPNOTSUPP;
 
-       in = erofs_read_metabuf(&m->map->buf, m->inode->i_sb, pos);
+       in = erofs_read_metabuf(&m->map->buf, inode->i_sb, pos, m->in_mbox);
        if (IS_ERR(in))
                return PTR_ERR(in);
 
@@ -392,6 +392,7 @@ static int z_erofs_map_blocks_fo(struct inode *inode,
        struct z_erofs_maprecorder m = {
                .inode = inode,
                .map = map,
+               .in_mbox = erofs_inode_in_metabox(inode),
        };
        int err = 0;
        unsigned int endoff, afmt;
@@ -521,6 +522,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
        unsigned int recsz = z_erofs_extent_recsize(vi->z_advise);
        erofs_off_t pos = round_up(Z_EROFS_MAP_HEADER_END(erofs_iloc(inode) +
                                   vi->inode_isize + vi->xattr_isize), recsz);
+       bool in_mbox = erofs_inode_in_metabox(inode);
        erofs_off_t lend = inode->i_size;
        erofs_off_t l, r, mid, pa, la, lstart;
        struct z_erofs_extent *ext;
@@ -530,7 +532,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
        map->m_flags = 0;
        if (recsz <= offsetof(struct z_erofs_extent, pstart_hi)) {
                if (recsz <= offsetof(struct z_erofs_extent, pstart_lo)) {
-                       ext = erofs_read_metabuf(&map->buf, sb, pos);
+                       ext = erofs_read_metabuf(&map->buf, sb, pos, in_mbox);
                        if (IS_ERR(ext))
                                return PTR_ERR(ext);
                        pa = le64_to_cpu(*(__le64 *)ext);
@@ -543,7 +545,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
                }
 
                for (; lstart <= map->m_la; lstart += 1 << vi->z_lclusterbits) {
-                       ext = erofs_read_metabuf(&map->buf, sb, pos);
+                       ext = erofs_read_metabuf(&map->buf, sb, pos, in_mbox);
                        if (IS_ERR(ext))
                                return PTR_ERR(ext);
                        map->m_plen = le32_to_cpu(ext->plen);
@@ -563,7 +565,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
                for (l = 0, r = vi->z_extents; l < r; ) {
                        mid = l + (r - l) / 2;
                        ext = erofs_read_metabuf(&map->buf, sb,
-                                                pos + mid * recsz);
+                                                pos + mid * recsz, in_mbox);
                        if (IS_ERR(ext))
                                return PTR_ERR(ext);
 
@@ -645,7 +647,7 @@ static int z_erofs_fill_inode(struct inode *inode, struct erofs_map_blocks *map)
                goto out_unlock;
 
        pos = ALIGN(erofs_iloc(inode) + vi->inode_isize + vi->xattr_isize, 8);
-       h = erofs_read_metabuf(&map->buf, sb, pos);
+       h = erofs_read_metabuf(&map->buf, sb, pos, erofs_inode_in_metabox(inode));
        if (IS_ERR(h)) {
                err = PTR_ERR(h);
                goto out_unlock;