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

Signed-off-by: Jeffle Xu <jeffl...@linux.alibaba.com>
---
 fs/erofs/fscache.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/erofs/super.c   |  4 ++
 2 files changed, 98 insertions(+)

diff --git a/fs/erofs/fscache.c b/fs/erofs/fscache.c
index d32cb5840c6d..620d44210809 100644
--- a/fs/erofs/fscache.c
+++ b/fs/erofs/fscache.c
@@ -148,12 +148,106 @@ static int erofs_fscache_readpage(struct file *file, 
struct page *page)
        return ret;
 }
 
+static inline 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;
+
+               /*
+                * 1) For CHUNK_BASED layout, the output m_la is rounded down to
+                * the nearest chunk boundary, and the output m_llen actually
+                * starts from the start of the containing chunk.
+                * 2) For other cases, the output m_la is equal to o_la.
+                */
+               offset = start + done;
+               count = min_t(size_t, map.m_llen - (pos - map.m_la), len - 
done);
+
+               /* Read-ahead Hole */
+               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;
+               }
+
+               /* Read-ahead Inline */
+               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;
+               }
+
+               /* Read-ahead No-inline */
+               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));
+               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,
 };
 
 /*
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 8c7181cd37e6..a5e4de60a0d8 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -621,6 +621,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;
        }
 
        err = erofs_read_superblock(sb);
-- 
2.27.0

--
Linux-cachefs mailing list
Linux-cachefs@redhat.com
https://listman.redhat.com/mailman/listinfo/linux-cachefs

Reply via email to