diff options
Diffstat (limited to 'fs/erofs')
-rw-r--r-- | fs/erofs/fscache.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/fs/erofs/fscache.c b/fs/erofs/fscache.c index 26f038d9c4e1..ac02af8cce3e 100644 --- a/fs/erofs/fscache.c +++ b/fs/erofs/fscache.c @@ -5,6 +5,60 @@ #include <linux/fscache.h> #include "internal.h" +/* + * Read data from fscache and fill the read data into page cache described by + * @start/len, which shall be both aligned with PAGE_SIZE. @pstart describes + * the start physical address in the cache file. + */ +static int erofs_fscache_read_folios(struct fscache_cookie *cookie, + struct address_space *mapping, + loff_t start, size_t len, + loff_t pstart) +{ + enum netfs_io_source source; + struct netfs_io_request rreq = {}; + struct netfs_io_subrequest subreq = { .rreq = &rreq, }; + struct netfs_cache_resources *cres = &rreq.cache_resources; + struct super_block *sb = mapping->host->i_sb; + struct iov_iter iter; + size_t done = 0; + int ret; + + ret = fscache_begin_read_operation(cres, cookie); + if (ret) + return ret; + + while (done < len) { + subreq.start = pstart + done; + subreq.len = len - done; + subreq.flags = 1 << NETFS_SREQ_ONDEMAND; + + source = cres->ops->prepare_read(&subreq, LLONG_MAX); + if (WARN_ON(subreq.len == 0)) + source = NETFS_INVALID_READ; + if (source != NETFS_READ_FROM_CACHE) { + erofs_err(sb, "failed to fscache prepare_read (source %d)", + source); + ret = -EIO; + goto out; + } + + iov_iter_xarray(&iter, READ, &mapping->i_pages, + start + done, subreq.len); + ret = fscache_read(cres, subreq.start, &iter, + NETFS_READ_HOLE_FAIL, NULL, NULL); + if (ret) { + erofs_err(sb, "failed to fscache_read (ret %d)", ret); + goto out; + } + + done += subreq.len; + } +out: + fscache_end_operation(cres); + return ret; +} + static const struct address_space_operations erofs_fscache_meta_aops = { }; |