Commit 3acea5fc authored by Jingbo Xu's avatar Jingbo Xu Committed by Gao Xiang
Browse files

erofs: avoid hardcoded blocksize for subpage block support



As the first step of converting hardcoded blocksize to that specified in
on-disk superblock, convert all call sites of hardcoded blocksize to
sb->s_blocksize except for:

1) use sbi->blkszbits instead of sb->s_blocksize in
erofs_superblock_csum_verify() since sb->s_blocksize has not been
updated with the on-disk blocksize yet when the function is called.

2) use inode->i_blkbits instead of sb->s_blocksize in erofs_bread(),
since the inode operated on may be an anonymous inode in fscache mode.
Currently the anonymous inode is allocated from an anonymous mount
maintained in erofs, while in the near future we may allocate anonymous
inodes from a generic API directly and thus have no access to the
anonymous inode's i_sb.  Thus we keep the block size in i_blkbits for
anonymous inodes in fscache mode.

Be noted that this patch only gets rid of the hardcoded blocksize, in
preparation for actually setting the on-disk block size in the following
patch.  The hard limit of constraining the block size to PAGE_SIZE still
exists until the next patch.

Signed-off-by: default avatarJingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
Reviewed-by: default avatarYue Hu <huyue2@coolpad.com>
Reviewed-by: default avatarChao Yu <chao@kernel.org>
Link: https://lore.kernel.org/r/20230313135309.75269-2-jefflexu@linux.alibaba.com
[ Gao Xiang: fold a patch to fix incorrect truncated offsets. ]
Link: https://lore.kernel.org/r/20230413035734.15457-1-zhujia.zj@bytedance.com


Signed-off-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
parent 09a9639e
Loading
Loading
Loading
Loading
+27 −23
Original line number Diff line number Diff line
@@ -27,11 +27,15 @@ void erofs_put_metabuf(struct erofs_buf *buf)
	buf->page = NULL;
}

/*
 * Derive the block size from inode->i_blkbits to make compatible with
 * anonymous inode in fscache mode.
 */
void *erofs_bread(struct erofs_buf *buf, struct inode *inode,
		  erofs_blk_t blkaddr, enum erofs_kmap_type type)
{
	erofs_off_t offset = (erofs_off_t)blkaddr << inode->i_blkbits;
	struct address_space *const mapping = inode->i_mapping;
	erofs_off_t offset = blknr_to_addr(blkaddr);
	pgoff_t index = offset >> PAGE_SHIFT;
	struct page *page = buf->page;
	struct folio *folio;
@@ -79,33 +83,32 @@ static int erofs_map_blocks_flatmode(struct inode *inode,
	erofs_blk_t nblocks, lastblk;
	u64 offset = map->m_la;
	struct erofs_inode *vi = EROFS_I(inode);
	struct super_block *sb = inode->i_sb;
	bool tailendpacking = (vi->datalayout == EROFS_INODE_FLAT_INLINE);

	nblocks = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
	nblocks = erofs_iblks(inode);
	lastblk = nblocks - tailendpacking;

	/* there is no hole in flatmode */
	map->m_flags = EROFS_MAP_MAPPED;
	if (offset < blknr_to_addr(lastblk)) {
		map->m_pa = blknr_to_addr(vi->raw_blkaddr) + map->m_la;
		map->m_plen = blknr_to_addr(lastblk) - offset;
	if (offset < erofs_pos(sb, lastblk)) {
		map->m_pa = erofs_pos(sb, vi->raw_blkaddr) + map->m_la;
		map->m_plen = erofs_pos(sb, lastblk) - offset;
	} else if (tailendpacking) {
		map->m_pa = erofs_iloc(inode) + vi->inode_isize +
			vi->xattr_isize + erofs_blkoff(offset);
			vi->xattr_isize + erofs_blkoff(sb, offset);
		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) {
			erofs_err(inode->i_sb,
				  "inline data cross block boundary @ nid %llu",
		if (erofs_blkoff(sb, map->m_pa) + map->m_plen > sb->s_blocksize) {
			erofs_err(sb, "inline data cross block boundary @ nid %llu",
				  vi->nid);
			DBG_BUGON(1);
			return -EFSCORRUPTED;
		}
		map->m_flags |= EROFS_MAP_META;
	} else {
		erofs_err(inode->i_sb,
			  "internal error @ nid: %llu (size %llu), m_la 0x%llx",
		erofs_err(sb, "internal error @ nid: %llu (size %llu), m_la 0x%llx",
			  vi->nid, inode->i_size, map->m_la);
		DBG_BUGON(1);
		return -EIO;
@@ -148,29 +151,29 @@ 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;

	kaddr = erofs_read_metabuf(&buf, sb, erofs_blknr(pos), EROFS_KMAP);
	kaddr = erofs_read_metabuf(&buf, sb, erofs_blknr(sb, pos), EROFS_KMAP);
	if (IS_ERR(kaddr)) {
		err = PTR_ERR(kaddr);
		goto out;
	}
	map->m_la = chunknr << vi->chunkbits;
	map->m_plen = min_t(erofs_off_t, 1UL << vi->chunkbits,
			    roundup(inode->i_size - map->m_la, EROFS_BLKSIZ));
			round_up(inode->i_size - map->m_la, sb->s_blocksize));

	/* handle block map */
	if (!(vi->chunkformat & EROFS_CHUNK_FORMAT_INDEXES)) {
		__le32 *blkaddr = kaddr + erofs_blkoff(pos);
		__le32 *blkaddr = kaddr + erofs_blkoff(sb, pos);

		if (le32_to_cpu(*blkaddr) == EROFS_NULL_ADDR) {
			map->m_flags = 0;
		} else {
			map->m_pa = blknr_to_addr(le32_to_cpu(*blkaddr));
			map->m_pa = erofs_pos(sb, le32_to_cpu(*blkaddr));
			map->m_flags = EROFS_MAP_MAPPED;
		}
		goto out_unlock;
	}
	/* parse chunk indexes */
	idx = kaddr + erofs_blkoff(pos);
	idx = kaddr + erofs_blkoff(sb, pos);
	switch (le32_to_cpu(idx->blkaddr)) {
	case EROFS_NULL_ADDR:
		map->m_flags = 0;
@@ -178,7 +181,7 @@ int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map)
	default:
		map->m_deviceid = le16_to_cpu(idx->device_id) &
			EROFS_SB(sb)->device_id_mask;
		map->m_pa = blknr_to_addr(le32_to_cpu(idx->blkaddr));
		map->m_pa = erofs_pos(sb, le32_to_cpu(idx->blkaddr));
		map->m_flags = EROFS_MAP_MAPPED;
		break;
	}
@@ -222,8 +225,8 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)

			if (!dif->mapped_blkaddr)
				continue;
			startoff = blknr_to_addr(dif->mapped_blkaddr);
			length = blknr_to_addr(dif->blocks);
			startoff = erofs_pos(sb, dif->mapped_blkaddr);
			length = erofs_pos(sb, dif->blocks);

			if (map->m_pa >= startoff &&
			    map->m_pa < startoff + length) {
@@ -244,6 +247,7 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
		unsigned int flags, struct iomap *iomap, struct iomap *srcmap)
{
	int ret;
	struct super_block *sb = inode->i_sb;
	struct erofs_map_blocks map;
	struct erofs_map_dev mdev;

@@ -258,7 +262,7 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
		.m_deviceid = map.m_deviceid,
		.m_pa = map.m_pa,
	};
	ret = erofs_map_dev(inode->i_sb, &mdev);
	ret = erofs_map_dev(sb, &mdev);
	if (ret)
		return ret;

@@ -284,11 +288,11 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
		struct erofs_buf buf = __EROFS_BUF_INITIALIZER;

		iomap->type = IOMAP_INLINE;
		ptr = erofs_read_metabuf(&buf, inode->i_sb,
					 erofs_blknr(mdev.m_pa), EROFS_KMAP);
		ptr = erofs_read_metabuf(&buf, sb,
				erofs_blknr(sb, mdev.m_pa), EROFS_KMAP);
		if (IS_ERR(ptr))
			return PTR_ERR(ptr);
		iomap->inline_data = ptr + erofs_blkoff(mdev.m_pa);
		iomap->inline_data = ptr + erofs_blkoff(sb, mdev.m_pa);
		iomap->private = buf.base;
	} else {
		iomap->type = IOMAP_MAPPED;
+3 −3
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ int z_erofs_load_lz4_config(struct super_block *sb,
		if (!sbi->lz4.max_pclusterblks) {
			sbi->lz4.max_pclusterblks = 1;	/* reserved case */
		} else if (sbi->lz4.max_pclusterblks >
			   Z_EROFS_PCLUSTER_MAX_SIZE / EROFS_BLKSIZ) {
			   erofs_blknr(sb, Z_EROFS_PCLUSTER_MAX_SIZE)) {
			erofs_err(sb, "too large lz4 pclusterblks %u",
				  sbi->lz4.max_pclusterblks);
			return -EINVAL;
@@ -221,13 +221,13 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_lz4_decompress_ctx *ctx,
		support_0padding = true;
		ret = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in,
				min_t(unsigned int, rq->inputsize,
				      EROFS_BLKSIZ - rq->pageofs_in));
				      rq->sb->s_blocksize - rq->pageofs_in));
		if (ret) {
			kunmap_atomic(headpage);
			return ret;
		}
		may_inplace = !((rq->pageofs_in + rq->inputsize) &
				(EROFS_BLKSIZ - 1));
				(rq->sb->s_blocksize - 1));
	}

	inputmargin = rq->pageofs_in;
+2 −2
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
	kin = kmap(*rq->in);
	err = z_erofs_fixup_insize(rq, kin + rq->pageofs_in,
			min_t(unsigned int, rq->inputsize,
					 EROFS_BLKSIZ - rq->pageofs_in));
			      rq->sb->s_blocksize - rq->pageofs_in));
	if (err) {
		kunmap(*rq->in);
		return err;
+10 −12
Original line number Diff line number Diff line
@@ -50,9 +50,11 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
{
	struct inode *dir = file_inode(f);
	struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
	struct super_block *sb = dir->i_sb;
	unsigned long bsz = sb->s_blocksize;
	const size_t dirsize = i_size_read(dir);
	unsigned int i = ctx->pos / EROFS_BLKSIZ;
	unsigned int ofs = ctx->pos % EROFS_BLKSIZ;
	unsigned int i = erofs_blknr(sb, ctx->pos);
	unsigned int ofs = erofs_blkoff(sb, ctx->pos);
	int err = 0;
	bool initial = true;

@@ -62,32 +64,28 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)

		de = erofs_bread(&buf, dir, i, EROFS_KMAP);
		if (IS_ERR(de)) {
			erofs_err(dir->i_sb,
				  "fail to readdir of logical block %u of nid %llu",
			erofs_err(sb, "fail to readdir of logical block %u of nid %llu",
				  i, EROFS_I(dir)->nid);
			err = PTR_ERR(de);
			break;
		}

		nameoff = le16_to_cpu(de->nameoff);
		if (nameoff < sizeof(struct erofs_dirent) ||
		    nameoff >= EROFS_BLKSIZ) {
			erofs_err(dir->i_sb,
				  "invalid de[0].nameoff %u @ nid %llu",
		if (nameoff < sizeof(struct erofs_dirent) || nameoff >= bsz) {
			erofs_err(sb, "invalid de[0].nameoff %u @ nid %llu",
				  nameoff, EROFS_I(dir)->nid);
			err = -EFSCORRUPTED;
			break;
		}

		maxsize = min_t(unsigned int,
				dirsize - ctx->pos + ofs, EROFS_BLKSIZ);
		maxsize = min_t(unsigned int, dirsize - ctx->pos + ofs, bsz);

		/* search dirents at the arbitrary position */
		if (initial) {
			initial = false;

			ofs = roundup(ofs, sizeof(struct erofs_dirent));
			ctx->pos = blknr_to_addr(i) + ofs;
			ctx->pos = erofs_pos(sb, i) + ofs;
			if (ofs >= nameoff)
				goto skip_this;
		}
@@ -97,7 +95,7 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
		if (err)
			break;
skip_this:
		ctx->pos = blknr_to_addr(i) + maxsize;
		ctx->pos = erofs_pos(sb, i) + maxsize;
		++i;
		ofs = 0;
	}
+3 −2
Original line number Diff line number Diff line
@@ -209,8 +209,8 @@ static int erofs_fscache_data_read_slice(struct erofs_fscache_request *primary)
		void *src;

		/* For tail packing layout, the offset may be non-zero. */
		offset = erofs_blkoff(map.m_pa);
		blknr = erofs_blknr(map.m_pa);
		offset = erofs_blkoff(sb, map.m_pa);
		blknr = erofs_blknr(sb, map.m_pa);
		size = map.m_llen;

		src = erofs_read_metabuf(&buf, sb, blknr, EROFS_KMAP);
@@ -460,6 +460,7 @@ static struct erofs_fscache *erofs_fscache_acquire_cookie(struct super_block *sb
	inode->i_size = OFFSET_MAX;
	inode->i_mapping->a_ops = &erofs_fscache_meta_aops;
	mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
	inode->i_blkbits = EROFS_SB(sb)->blkszbits;
	inode->i_private = ctx;

	ctx->cookie = cookie;
Loading