Browse Source

vfs: add i_op->dentry_open()

Add a new inode operation i_op->dentry_open().  This is for stacked filesystems
that want to return a struct file from a different filesystem.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Miklos Szeredi 10 years ago
parent
commit
4aa7c6346b
5 changed files with 40 additions and 5 deletions
  1. 2 0
      Documentation/filesystems/Locking
  2. 7 0
      Documentation/filesystems/vfs.txt
  3. 6 3
      fs/namei.c
  4. 21 2
      fs/open.c
  5. 4 0
      include/linux/fs.h

+ 2 - 0
Documentation/filesystems/Locking

@@ -67,6 +67,7 @@ prototypes:
 				struct file *, unsigned open_flag,
 				struct file *, unsigned open_flag,
 				umode_t create_mode, int *opened);
 				umode_t create_mode, int *opened);
 	int (*tmpfile) (struct inode *, struct dentry *, umode_t);
 	int (*tmpfile) (struct inode *, struct dentry *, umode_t);
+	int (*dentry_open)(struct dentry *, struct file *, const struct cred *);
 
 
 locking rules:
 locking rules:
 	all may block
 	all may block
@@ -96,6 +97,7 @@ fiemap:		no
 update_time:	no
 update_time:	no
 atomic_open:	yes
 atomic_open:	yes
 tmpfile:	no
 tmpfile:	no
+dentry_open:	no
 
 
 	Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 	Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
 victim.

+ 7 - 0
Documentation/filesystems/vfs.txt

@@ -364,6 +364,7 @@ struct inode_operations {
 	int (*atomic_open)(struct inode *, struct dentry *, struct file *,
 	int (*atomic_open)(struct inode *, struct dentry *, struct file *,
 			unsigned open_flag, umode_t create_mode, int *opened);
 			unsigned open_flag, umode_t create_mode, int *opened);
 	int (*tmpfile) (struct inode *, struct dentry *, umode_t);
 	int (*tmpfile) (struct inode *, struct dentry *, umode_t);
+	int (*dentry_open)(struct dentry *, struct file *, const struct cred *);
 };
 };
 
 
 Again, all methods are called without any locks being held, unless
 Again, all methods are called without any locks being held, unless
@@ -696,6 +697,12 @@ struct address_space_operations {
   	but instead uses bmap to find out where the blocks in the file
   	but instead uses bmap to find out where the blocks in the file
   	are and uses those addresses directly.
   	are and uses those addresses directly.
 
 
+  dentry_open: *WARNING: probably going away soon, do not use!* This is an
+	alternative to f_op->open(), the difference is that this method may open
+	a 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.
+
 
 
   invalidatepage: If a page has PagePrivate set, then invalidatepage
   invalidatepage: If a page has PagePrivate set, then invalidatepage
         will be called when part or all of the page is to be removed
         will be called when part or all of the page is to be removed

+ 6 - 3
fs/namei.c

@@ -3064,9 +3064,12 @@ finish_open_created:
 	error = may_open(&nd->path, acc_mode, open_flag);
 	error = may_open(&nd->path, acc_mode, open_flag);
 	if (error)
 	if (error)
 		goto out;
 		goto out;
-	file->f_path.mnt = nd->path.mnt;
-	error = finish_open(file, nd->path.dentry, NULL, opened);
-	if (error) {
+
+	BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
+	error = vfs_open(&nd->path, file, current_cred());
+	if (!error) {
+		*opened |= FILE_OPENED;
+	} else {
 		if (error == -EOPENSTALE)
 		if (error == -EOPENSTALE)
 			goto stale_open;
 			goto stale_open;
 		goto out;
 		goto out;

+ 21 - 2
fs/open.c

@@ -823,8 +823,7 @@ struct file *dentry_open(const struct path *path, int flags,
 	f = get_empty_filp();
 	f = get_empty_filp();
 	if (!IS_ERR(f)) {
 	if (!IS_ERR(f)) {
 		f->f_flags = flags;
 		f->f_flags = flags;
-		f->f_path = *path;
-		error = do_dentry_open(f, NULL, cred);
+		error = vfs_open(path, f, cred);
 		if (!error) {
 		if (!error) {
 			/* from now on we need fput() to dispose of f */
 			/* from now on we need fput() to dispose of f */
 			error = open_check_o_direct(f);
 			error = open_check_o_direct(f);
@@ -841,6 +840,26 @@ struct file *dentry_open(const struct path *path, int flags,
 }
 }
 EXPORT_SYMBOL(dentry_open);
 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
+ */
+int vfs_open(const struct path *path, struct file *filp,
+	     const struct cred *cred)
+{
+	struct inode *inode = path->dentry->d_inode;
+
+	if (inode->i_op->dentry_open)
+		return inode->i_op->dentry_open(path->dentry, filp, cred);
+	else {
+		filp->f_path = *path;
+		return do_dentry_open(filp, NULL, cred);
+	}
+}
+EXPORT_SYMBOL(vfs_open);
+
 static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op)
 static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op)
 {
 {
 	int lookup_flags = 0;
 	int lookup_flags = 0;

+ 4 - 0
include/linux/fs.h

@@ -1528,6 +1528,9 @@ struct inode_operations {
 			   umode_t create_mode, int *opened);
 			   umode_t create_mode, int *opened);
 	int (*tmpfile) (struct inode *, struct dentry *, umode_t);
 	int (*tmpfile) (struct inode *, struct dentry *, umode_t);
 	int (*set_acl)(struct inode *, struct posix_acl *, int);
 	int (*set_acl)(struct inode *, struct posix_acl *, int);
+
+	/* WARNING: probably going away soon, do not use! */
+	int (*dentry_open)(struct dentry *, struct file *, const struct cred *);
 } ____cacheline_aligned;
 } ____cacheline_aligned;
 
 
 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
@@ -2040,6 +2043,7 @@ extern struct file *file_open_name(struct filename *, int, umode_t);
 extern struct file *filp_open(const char *, int, umode_t);
 extern struct file *filp_open(const char *, int, umode_t);
 extern struct file *file_open_root(struct dentry *, struct vfsmount *,
 extern struct file *file_open_root(struct dentry *, struct vfsmount *,
 				   const char *, int);
 				   const char *, int);
+extern int vfs_open(const struct path *, struct file *, const struct cred *);
 extern struct file * dentry_open(const struct path *, int, const struct cred *);
 extern struct file * dentry_open(const struct path *, int, const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
 extern int filp_close(struct file *, fl_owner_t id);