[PATCH RFC 2/9] cachefiles: add content map file helpers

From: Jingbo Xu
Date: Mon Aug 01 2022 - 23:04:00 EST


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