From d6c61fb034fb2eb103b290cc97a77d19b3d7ed33 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 14 May 2012 13:06:13 +0200 Subject: UBUNTU: ubuntu: overlayfs -- vfs: add i_op->open() Add a new inode operation i_op->open(). This is for stacked filesystems that want to return a struct file from a different filesystem. Signed-off-by: Miklos Szeredi --- Documentation/filesystems/Locking | 2 ++ Documentation/filesystems/vfs.txt | 8 ++++++++ fs/open.c | 25 +++++++++++++++++++++++-- include/linux/fs.h | 3 +++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 4fca82e5276..42b0539cffa 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -62,6 +62,7 @@ ata *); int (*removexattr) (struct dentry *, const char *); void (*truncate_range)(struct inode *, loff_t, loff_t); int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); + struct file *(*open)(struct dentry *,struct file *,const struct cred *); locking rules: all may block @@ -89,6 +90,7 @@ listxattr: no removexattr: yes truncate_range: yes fiemap: no +open: no Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on victim. cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 0d049202808..f06c91f7a86 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -364,6 +364,8 @@ struct inode_operations { ssize_t (*listxattr) (struct dentry *, char *, size_t); int (*removexattr) (struct dentry *, const char *); void (*truncate_range)(struct inode *, loff_t, loff_t); + struct file *(*open) (struct dentry *, struct file *, + const struct cred *); }; Again, all methods are called without any locks being held, unless @@ -475,6 +477,12 @@ otherwise noted. truncate_range: a method provided by the underlying filesystem to truncate a range of blocks , i.e. punch a hole somewhere in a file. + open: this is an alternative to f_op->open(), the difference is that this + method may return any open file, not necessarily originating from the + same filesystem as the one i_op->open() was called on. It may be useful + for stacking filesystems which want to allow native I/O directly on + underlying files. + The Address Space Object ======================== diff --git a/fs/open.c b/fs/open.c index 98fe2e4db87..0ca1ec017cb 100644 --- a/fs/open.c +++ b/fs/open.c @@ -800,7 +800,7 @@ struct file *nameidata_to_filp(struct nameidata *nd) /* Has the filesystem initialised the file for us? */ if (filp->f_path.dentry == NULL) - filp = __dentry_open(&nd->path, filp, NULL, cred); + filp = vfs_open(&nd->path, filp, cred); return filp; } @@ -825,7 +825,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, f = get_empty_filp(); if (f != NULL) { f->f_flags = flags; - ret = __dentry_open(&path, f, NULL, cred); + ret = vfs_open(&path, f, cred); } path_put(&path); @@ -833,6 +833,27 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, } EXPORT_SYMBOL(dentry_open); +/** + * vfs_open - open the file at the given path + * @path: path to open + * @filp: newly allocated file with f_flag initialized + * @cred: credentials to use + * + * Open the file. If successful, the returned file will have acquired + * an additional reference for path. + */ +struct file *vfs_open(struct path *path, struct file *filp, + const struct cred *cred) +{ + struct inode *inode = path->dentry->d_inode; + + if (inode->i_op->open) + return inode->i_op->open(path->dentry, filp, cred); + else + return __dentry_open(path, filp, NULL, cred); +} +EXPORT_SYMBOL(vfs_open); + static void __put_unused_fd(struct files_struct *files, unsigned int fd) { struct fdtable *fdt = files_fdtable(files); diff --git a/include/linux/fs.h b/include/linux/fs.h index 25c40b9f848..44b3aefc884 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1664,6 +1664,8 @@ struct inode_operations { void (*truncate_range)(struct inode *, loff_t, loff_t); int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); + struct file *(*open) (struct dentry *, struct file *, + const struct cred *); } ____cacheline_aligned; struct seq_file; @@ -2021,6 +2023,7 @@ extern long do_sys_open(int dfd, const char __user *filename, int flags, extern struct file *filp_open(const char *, int, umode_t); extern struct file *file_open_root(struct dentry *, struct vfsmount *, const char *, int); +extern struct file *vfs_open(struct path *, struct file *, const struct cred *); extern struct file * dentry_open(struct dentry *, struct vfsmount *, int, const struct cred *); extern int filp_close(struct file *, fl_owner_t id); -- cgit v1.2.3