Introduce new struct ovl_file_entry to store real file and real vm_ops handler. Signed-off-by: Chengguang Xu <cgxu519@xxxxxxxxxxxx> --- fs/overlayfs/file.c | 64 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 0d940e29d62b..14ab5344a918 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -21,6 +21,39 @@ struct ovl_aio_req { struct fd fd; }; +struct ovl_file_entry { + struct file *realfile; + void *vm_ops; +}; + +struct file *ovl_get_realfile(struct file *file) +{ + struct ovl_file_entry *ofe = file->private_data; + + return ofe->realfile; +} + +void ovl_set_realfile(struct file *file, struct file *realfile) +{ + struct ovl_file_entry *ofe = file->private_data; + + ofe->realfile = realfile; +} + +void *ovl_get_real_vmops(struct file *file) +{ + struct ovl_file_entry *ofe = file->private_data; + + return ofe->vm_ops; +} + +void ovl_set_real_vmops(struct file *file, void *vm_ops) +{ + struct ovl_file_entry *ofe = file->private_data; + + ofe->vm_ops = vm_ops; +} + static struct kmem_cache *ovl_aio_request_cachep; static char ovl_whatisit(struct inode *inode, struct inode *realinode) @@ -105,14 +138,14 @@ static int ovl_change_flags(struct file *file, unsigned int flags) return 0; } -static int ovl_real_fdget_meta(const struct file *file, struct fd *real, +static int ovl_real_fdget_meta(struct file *file, struct fd *real, bool allow_meta) { struct inode *inode = file_inode(file); struct inode *realinode; real->flags = 0; - real->file = file->private_data; + real->file = ovl_get_realfile(file); if (allow_meta) realinode = ovl_inode_real(inode); @@ -134,7 +167,7 @@ static int ovl_real_fdget_meta(const struct file *file, struct fd *real, return 0; } -static int ovl_real_fdget(const struct file *file, struct fd *real) +static int ovl_real_fdget(struct file *file, struct fd *real) { return ovl_real_fdget_meta(file, real, false); } @@ -144,25 +177,36 @@ static int ovl_open(struct inode *inode, struct file *file) struct file *realfile; int err; + file->private_data = kzalloc(sizeof(struct ovl_file_entry), GFP_KERNEL); + if (!file->private_data) + return -ENOMEM; + err = ovl_maybe_copy_up(file_dentry(file), file->f_flags); if (err) - return err; + goto out; /* No longer need these flags, so don't pass them on to underlying fs */ file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); realfile = ovl_open_realfile(file, ovl_inode_realdata(inode)); - if (IS_ERR(realfile)) - return PTR_ERR(realfile); - - file->private_data = realfile; + if (IS_ERR(realfile)) { + err = PTR_ERR(realfile); + goto out; + } + ovl_set_realfile(file, realfile); return 0; +out: + kfree(file->private_data); + file->private_data = NULL; + return err; } static int ovl_release(struct inode *inode, struct file *file) { - fput(file->private_data); + fput(ovl_get_realfile(file)); + kfree(file->private_data); + file->private_data = NULL; return 0; } @@ -451,7 +495,7 @@ 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 file *realfile = ovl_get_realfile(file); const struct cred *old_cred; int ret; -- 2.20.1