diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2018-07-18 16:44:41 +0300 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2018-07-18 16:44:41 +0300 |
commit | d1d04ef8572bc8c22265057bd3d5a79f223f8f52 (patch) | |
tree | 1271b2ebd9542e0070b0b3830b0bad17c76ca4ea /fs/overlayfs | |
parent | e8c985bace1351c5f2d7a6f0d8ff3e677b58abb5 (diff) | |
download | linux-d1d04ef8572bc8c22265057bd3d5a79f223f8f52.tar.xz |
ovl: stack file ops
Implement file operations on a regular overlay file. The underlying file
is opened separately and cached in ->private_data.
It might be worth making an exception for such files when accounting in
nr_file to confirm to userspace expectations. We are only adding a small
overhead (248bytes for the struct file) since the real inode and dentry are
pinned by overlayfs anyway.
This patch doesn't have any effect, since the vfs will use d_real() to find
the real underlying file to open. The patch at the end of the series will
actually enable this functionality.
AV: make it use open_with_fake_path(), don't mess with override_creds
SzM: still need to mess with override_creds() until no fs uses
current_cred() in their open method.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/overlayfs')
-rw-r--r-- | fs/overlayfs/Makefile | 4 | ||||
-rw-r--r-- | fs/overlayfs/file.c | 76 | ||||
-rw-r--r-- | fs/overlayfs/inode.c | 1 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 3 |
4 files changed, 82 insertions, 2 deletions
diff --git a/fs/overlayfs/Makefile b/fs/overlayfs/Makefile index 30802347a020..46e1ff8ac056 100644 --- a/fs/overlayfs/Makefile +++ b/fs/overlayfs/Makefile @@ -4,5 +4,5 @@ obj-$(CONFIG_OVERLAY_FS) += overlay.o -overlay-objs := super.o namei.o util.o inode.o dir.o readdir.o copy_up.o \ - export.o +overlay-objs := super.o namei.o util.o inode.o file.o dir.o readdir.o \ + copy_up.o export.o diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c new file mode 100644 index 000000000000..ce7d002173a6 --- /dev/null +++ b/fs/overlayfs/file.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include <linux/cred.h> +#include <linux/file.h> +#include <linux/xattr.h> +#include "overlayfs.h" + +static struct file *ovl_open_realfile(const struct file *file) +{ + struct inode *inode = file_inode(file); + struct inode *upperinode = ovl_inode_upper(inode); + struct inode *realinode = upperinode ?: ovl_inode_lower(inode); + struct file *realfile; + const struct cred *old_cred; + + old_cred = ovl_override_creds(inode->i_sb); + realfile = open_with_fake_path(&file->f_path, file->f_flags | O_NOATIME, + realinode, current_cred()); + revert_creds(old_cred); + + pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n", + file, file, upperinode ? 'u' : 'l', file->f_flags, + realfile, IS_ERR(realfile) ? 0 : realfile->f_flags); + + return realfile; +} + +static int ovl_open(struct inode *inode, struct file *file) +{ + struct dentry *dentry = file_dentry(file); + struct file *realfile; + int err; + + err = ovl_open_maybe_copy_up(dentry, file->f_flags); + if (err) + return err; + + /* 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); + if (IS_ERR(realfile)) + return PTR_ERR(realfile); + + file->private_data = realfile; + + return 0; +} + +static int ovl_release(struct inode *inode, struct file *file) +{ + fput(file->private_data); + + return 0; +} + +static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) +{ + struct inode *realinode = ovl_inode_real(file_inode(file)); + + return generic_file_llseek_size(file, offset, whence, + realinode->i_sb->s_maxbytes, + i_size_read(realinode)); +} + +const struct file_operations ovl_file_operations = { + .open = ovl_open, + .release = ovl_release, + .llseek = ovl_llseek, +}; diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 5b6c86703d34..391e3a3b8ba1 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -535,6 +535,7 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev, switch (mode & S_IFMT) { case S_IFREG: inode->i_op = &ovl_file_inode_operations; + inode->i_fop = &ovl_file_operations; break; case S_IFDIR: diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index f28f1e37d457..16d439ebfe02 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -377,6 +377,9 @@ struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry, int ovl_cleanup(struct inode *dir, struct dentry *dentry); struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr); +/* file.c */ +extern const struct file_operations ovl_file_operations; + /* copy_up.c */ int ovl_copy_up(struct dentry *dentry); int ovl_copy_up_flags(struct dentry *dentry, int flags); |