Besides the mapping mechanism provided by the backing fs, a self maintained bitmap can be used to track if the corresponding file range is cached by the backing file or not. In this case, a content map file is used to permanentize the bitmap. As the first step, add the helper functions for looking up and freeing these content map files. Signed-off-by: Jingbo Xu <jefflexu@xxxxxxxxxxxxxxxxx> --- fs/cachefiles/internal.h | 4 ++ fs/cachefiles/namei.c | 88 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index 6cba2c6de2f9..4c3ee6935811 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h @@ -270,6 +270,10 @@ extern struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, bool *_is_new); extern void cachefiles_put_directory(struct dentry *dir); +int cachefiles_look_up_map(struct cachefiles_cache *cache, + struct dentry *dir, struct file **pfile); +void cachefiles_put_map(struct file *file); + extern int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, char *filename); diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index facf2ebe464b..2948eea18ca2 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -231,6 +231,94 @@ void cachefiles_put_directory(struct dentry *dir) } } +/* + * Look up a content map file. + */ +int cachefiles_look_up_map(struct cachefiles_cache *cache, + struct dentry *dir, struct file **pfile) +{ + struct dentry *dentry; + struct file *file; + struct path path; + char *name = "Map"; + int ret; + + inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); +retry: + ret = cachefiles_inject_read_error(); + if (ret) + goto err_unlock_dir; + + dentry = lookup_one_len(name, dir, strlen(name)); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto err_unlock_dir; + } + + if (d_is_negative(dentry)) { + ret = cachefiles_has_space(cache, 1, 0, + cachefiles_has_space_for_create); + if (ret) + goto err_dput; + + ret = vfs_create(&init_user_ns, d_inode(dir), dentry, S_IFREG, true); + if (ret) + goto err_dput; + + if (unlikely(d_unhashed(dentry))) { + cachefiles_put_directory(dentry); + goto retry; + } + ASSERT(d_backing_inode(dentry)); + } + + inode_lock(d_inode(dentry)); + inode_unlock(d_inode(dir)); + + if (!__cachefiles_mark_inode_in_use(NULL, dentry)) { + inode_unlock(d_inode(dentry)); + dput(dentry); + return -EBUSY; + } + + inode_unlock(d_inode(dentry)); + ASSERT(d_backing_inode(dentry)); + + if (!d_is_reg(dentry)) { + pr_err("%pd is not a file\n", dentry); + cachefiles_put_directory(dentry); + return -EIO; + } + + path.mnt = cache->mnt; + path.dentry = dentry; + file = open_with_fake_path(&path, O_RDWR | O_LARGEFILE, + d_backing_inode(dentry), cache->cache_cred); + if (IS_ERR(file)) + cachefiles_put_directory(dentry); + + *pfile = file; + dput(dentry); + return 0; + +err_dput: + dput(dentry); +err_unlock_dir: + inode_unlock(d_inode(dir)); + return ret; +} + +/* + * Put a content map file. + */ +void cachefiles_put_map(struct file *file) +{ + if (file) { + cachefiles_do_unmark_inode_in_use(NULL, file->f_path.dentry); + fput(file); + } +} + /* * Remove a regular file from the cache. */ -- 2.27.0 -- Linux-cachefs mailing list Linux-cachefs@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/linux-cachefs