Commit c665b394 authored by Jeffle Xu's avatar Jeffle Xu Committed by Gao Xiang
Browse files

erofs: implement fscache-based data readahead



Implement fscache-based data readahead. Also registers an individual
bdi for each erofs instance to enable readahead.

Signed-off-by: default avatarJeffle Xu <jefflexu@linux.alibaba.com>
Reviewed-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20220425122143.56815-21-jefflexu@linux.alibaba.com


Acked-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
parent bd735bda
Loading
Loading
Loading
Loading
+90 −0
Original line number Diff line number Diff line
@@ -162,12 +162,102 @@ static int erofs_fscache_readpage(struct file *file, struct page *page)
	return ret;
}

static void erofs_fscache_unlock_folios(struct readahead_control *rac,
					size_t len)
{
	while (len) {
		struct folio *folio = readahead_folio(rac);

		len -= folio_size(folio);
		folio_mark_uptodate(folio);
		folio_unlock(folio);
	}
}

static void erofs_fscache_readahead(struct readahead_control *rac)
{
	struct inode *inode = rac->mapping->host;
	struct super_block *sb = inode->i_sb;
	size_t len, count, done = 0;
	erofs_off_t pos;
	loff_t start, offset;
	int ret;

	if (!readahead_count(rac))
		return;

	start = readahead_pos(rac);
	len = readahead_length(rac);

	do {
		struct erofs_map_blocks map;
		struct erofs_map_dev mdev;

		pos = start + done;
		map.m_la = pos;

		ret = erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_RAW);
		if (ret)
			return;

		offset = start + done;
		count = min_t(size_t, map.m_llen - (pos - map.m_la),
			      len - done);

		if (!(map.m_flags & EROFS_MAP_MAPPED)) {
			struct iov_iter iter;

			iov_iter_xarray(&iter, READ, &rac->mapping->i_pages,
					offset, count);
			iov_iter_zero(count, &iter);

			erofs_fscache_unlock_folios(rac, count);
			ret = count;
			continue;
		}

		if (map.m_flags & EROFS_MAP_META) {
			struct folio *folio = readahead_folio(rac);

			ret = erofs_fscache_readpage_inline(folio, &map);
			if (!ret) {
				folio_mark_uptodate(folio);
				ret = folio_size(folio);
			}

			folio_unlock(folio);
			continue;
		}

		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 = erofs_fscache_read_folios(mdev.m_fscache->cookie,
				rac->mapping, offset, count,
				mdev.m_pa + (pos - map.m_la));
		/*
		 * For the error cases, the folios will be unlocked when
		 * .readahead() returns.
		 */
		if (!ret) {
			erofs_fscache_unlock_folios(rac, count);
			ret = count;
		}
	} while (ret > 0 && ((done += ret) < len));
}

static const struct address_space_operations erofs_fscache_meta_aops = {
	.readpage = erofs_fscache_meta_readpage,
};

const struct address_space_operations erofs_fscache_access_aops = {
	.readpage = erofs_fscache_readpage,
	.readahead = erofs_fscache_readahead,
};

int erofs_fscache_register_cookie(struct super_block *sb,
+4 −0
Original line number Diff line number Diff line
@@ -658,6 +658,10 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
						    sbi->opt.fsid, true);
		if (err)
			return err;

		err = super_setup_bdi(sb);
		if (err)
			return err;
	} else {
		if (!sb_set_blocksize(sb, EROFS_BLKSIZ)) {
			erofs_err(sb, "failed to set erofs blksize");