summaryrefslogtreecommitdiff
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2024-10-07 15:22:29 +0200
committerAmir Goldstein <amir73il@gmail.com>2024-11-15 08:56:48 +0100
commit87a8a76c34a2ae6f667cc33249dc99705e363d1f (patch)
tree7b027644d0b4f252aa90e3b468eba00845de8e7b /fs/overlayfs
parentc2c54b5f34f6341f24d06689d4b986bd75b4b41c (diff)
ovl: allocate a container struct ovl_file for ovl private context
Instead of using ->private_data to point at realfile directly, so that we can add more context per ovl open file. Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/dir.c14
-rw-r--r--fs/overlayfs/file.c40
-rw-r--r--fs/overlayfs/overlayfs.h3
3 files changed, 48 insertions, 9 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 5cf529482a8a..08e683917d12 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -1323,6 +1323,7 @@ static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,
const struct cred *old_cred, *new_cred = NULL;
struct path realparentpath;
struct file *realfile;
+ struct ovl_file *of;
struct dentry *newdentry;
/* It's okay to set O_NOATIME, since the owner will be current fsuid */
int flags = file->f_flags | OVL_OPEN_FLAGS;
@@ -1344,14 +1345,21 @@ static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,
if (err)
goto out_revert_creds;
+ of = ovl_file_alloc(realfile);
+ if (!of) {
+ fput(realfile);
+ err = -ENOMEM;
+ goto out_revert_creds;
+ }
+
/* ovl_instantiate() consumes the newdentry reference on success */
newdentry = dget(realfile->f_path.dentry);
err = ovl_instantiate(dentry, inode, newdentry, false, file);
if (!err) {
- file->private_data = realfile;
+ file->private_data = of;
} else {
dput(newdentry);
- fput(realfile);
+ ovl_file_free(of);
}
out_revert_creds:
ovl_revert_creds(old_cred);
@@ -1407,7 +1415,7 @@ static int ovl_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
put_realfile:
/* Without FMODE_OPENED ->release() won't be called on @file */
if (!(file->f_mode & FMODE_OPENED))
- fput(file->private_data);
+ ovl_file_free(file->private_data);
put_inode:
iput(inode);
drop_write:
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index 4a1cf45e3fa1..0fa0795d335f 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -89,10 +89,32 @@ static int ovl_change_flags(struct file *file, unsigned int flags)
return 0;
}
+struct ovl_file {
+ struct file *realfile;
+};
+
+struct ovl_file *ovl_file_alloc(struct file *realfile)
+{
+ struct ovl_file *of = kzalloc(sizeof(struct ovl_file), GFP_KERNEL);
+
+ if (unlikely(!of))
+ return NULL;
+
+ of->realfile = realfile;
+ return of;
+}
+
+void ovl_file_free(struct ovl_file *of)
+{
+ fput(of->realfile);
+ kfree(of);
+}
+
static int ovl_real_fdget_path(const struct file *file, struct fd *real,
struct path *realpath)
{
- struct file *realfile = file->private_data;
+ struct ovl_file *of = file->private_data;
+ struct file *realfile = of->realfile;
real->word = (unsigned long)realfile;
@@ -144,6 +166,7 @@ static int ovl_open(struct inode *inode, struct file *file)
struct dentry *dentry = file_dentry(file);
struct file *realfile;
struct path realpath;
+ struct ovl_file *of;
int err;
/* lazy lookup and verify lowerdata */
@@ -166,15 +189,20 @@ static int ovl_open(struct inode *inode, struct file *file)
if (IS_ERR(realfile))
return PTR_ERR(realfile);
- file->private_data = realfile;
+ of = ovl_file_alloc(realfile);
+ if (!of) {
+ fput(realfile);
+ return -ENOMEM;
+ }
+
+ file->private_data = of;
return 0;
}
static int ovl_release(struct inode *inode, struct file *file)
{
- fput(file->private_data);
-
+ ovl_file_free(file->private_data);
return 0;
}
@@ -426,13 +454,13 @@ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
static int ovl_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct file *realfile = file->private_data;
+ struct ovl_file *of = file->private_data;
struct backing_file_ctx ctx = {
.cred = ovl_creds(file_inode(file)->i_sb),
.accessed = ovl_file_accessed,
};
- return backing_file_mmap(realfile, vma, &ctx);
+ return backing_file_mmap(of->realfile, vma, &ctx);
}
static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 7b7a6e3a43e2..6e32eb9cd1b6 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -863,6 +863,9 @@ int ovl_real_fileattr_set(const struct path *realpath, struct fileattr *fa);
int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa);
int ovl_fileattr_set(struct mnt_idmap *idmap,
struct dentry *dentry, struct fileattr *fa);
+struct ovl_file;
+struct ovl_file *ovl_file_alloc(struct file *realfile);
+void ovl_file_free(struct ovl_file *of);
/* copy_up.c */
int ovl_copy_up(struct dentry *dentry);