Commit 41409132 authored by Bo Liu (OpenAnolis)'s avatar Bo Liu (OpenAnolis) Committed by Gao Xiang
Browse files

erofs: implement metadata compression



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: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: default avatarBo Liu (OpenAnolis) <liubo03@inspur.com>
Acked-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20250722003229.2121752-1-hsiangkao@linux.alibaba.com
parent 681acbda
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+36 −23
Original line number Diff line number Diff line
@@ -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,12 +284,13 @@ 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;
	}

	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,
@@ -291,17 +303,18 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
			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;
+1 −1
Original line number Diff line number Diff line
@@ -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) {
+2 −1
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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

Loading