In prep for the following support for page cache sharing based mmap, allocate an anonymous file of corresponding blob, so that we can link associated vma to the blob later. Signed-off-by: Jingbo Xu <jefflexu@xxxxxxxxxxxxxxxxx> --- fs/erofs/fscache.c | 75 +++++++++++++++++++++++++++++++++++++++++++++ fs/erofs/internal.h | 1 + 2 files changed, 76 insertions(+) diff --git a/fs/erofs/fscache.c b/fs/erofs/fscache.c index 7f2e2d17e8e0..bed02b21978a 100644 --- a/fs/erofs/fscache.c +++ b/fs/erofs/fscache.c @@ -4,6 +4,8 @@ * Copyright (C) 2022, Bytedance Inc. All rights reserved. */ #include <linux/fscache.h> +#include <linux/file.h> +#include <linux/anon_inodes.h> #include "internal.h" static DEFINE_MUTEX(erofs_domain_list_lock); @@ -22,6 +24,11 @@ struct erofs_fscache_request { refcount_t ref; }; +struct erofs_fscache_finfo { + erofs_off_t pa; + pgoff_t max_idx; +}; + static struct erofs_fscache_request *erofs_fscache_req_alloc(struct address_space *mapping, loff_t start, size_t len) { @@ -341,6 +348,74 @@ const struct address_space_operations erofs_fscache_access_aops = { .readahead = erofs_fscache_readahead, }; +static int erofs_fscache_share_meta_release(struct inode *inode, struct file *filp) +{ + kfree(filp->private_data); + filp->private_data = NULL; + return 0; +} + +static const struct file_operations erofs_fscache_share_meta_fops = { + .release = erofs_fscache_share_meta_release, +}; + +static int erofs_fscache_share_file_release(struct inode *inode, struct file *filp) +{ + fput(filp->private_data); + filp->private_data = NULL; + return 0; +} + +static int erofs_fscache_share_file_open(struct inode *inode, struct file *filp) +{ + /* since page cache sharing is enabled only when i_size <= chunk_size */ + struct erofs_map_blocks map = {}; /* .m_la = 0 */ + struct erofs_map_dev mdev; + struct erofs_fscache_finfo *finfo; + struct inode *realinode; + struct file *realfile; + int ret; + + ret = erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_RAW); + if (ret) + return ret; + + mdev = (struct erofs_map_dev) { + .m_deviceid = map.m_deviceid, + .m_pa = map.m_pa, + }; + ret = erofs_map_dev(inode->i_sb, &mdev); + if (ret) + return ret; + + finfo = kzalloc(sizeof(struct erofs_fscache_finfo), GFP_KERNEL); + if (!finfo) + return -ENOMEM; + finfo->pa = mdev.m_pa; + finfo->max_idx = DIV_ROUND_UP(mdev.m_pa + inode->i_size, PAGE_SIZE); + + realinode = mdev.m_fscache->inode; + ihold(realinode); + realfile = alloc_file_pseudo(realinode, filp->f_path.mnt, "[erofs]", + O_RDONLY, &erofs_fscache_share_meta_fops); + if (IS_ERR(realfile)) { + iput(realinode); + kfree(finfo); + return PTR_ERR(realfile); + } + + file_ra_state_init(&realfile->f_ra, filp->f_mapping); + realfile->private_data = finfo; + filp->private_data = realfile; + return 0; +} + +const struct file_operations erofs_fscache_share_file_fops = { + .llseek = generic_file_llseek, + .open = erofs_fscache_share_file_open, + .release = erofs_fscache_share_file_release, +}; + static void erofs_fscache_domain_put(struct erofs_domain *domain) { mutex_lock(&erofs_domain_list_lock); diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index b3d04bc2d279..7c6a7a2d9acf 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -616,6 +616,7 @@ struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb, void erofs_fscache_unregister_cookie(struct erofs_fscache *fscache); extern const struct address_space_operations erofs_fscache_access_aops; +extern const struct file_operations erofs_fscache_share_file_fops; #else static inline int erofs_fscache_register_fs(struct super_block *sb) { -- 2.19.1.6.gb485710b