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: Jeffle Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20220425122143.56815-21-jefflexu@linux.alibaba.com
Acked-by: Chao Yu <chao@kernel.org>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
This commit is contained in:
Jeffle Xu 2022-04-25 20:21:42 +08:00 committed by Gao Xiang
parent bd735bdaa6
commit c665b394b9
2 changed files with 94 additions and 0 deletions

View file

@ -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,

View file

@ -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");