From 90ad1a8ecb9bfd5ff4503ac42cd049a97643ee51 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 21 May 2012 17:30:15 +0200 Subject: vfs: split __dentry_open() Split __dentry_open() into two functions: do_dentry_open() - does most of the actual work, doesn't put file on failure open_check_o_direct() - after a successful open, checks direct_IO method This will allow i_op->atomic_open to do just the file initialization and leave the direct_IO checking to the VFS. Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro --- fs/open.c | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) (limited to 'fs/open.c') diff --git a/fs/open.c b/fs/open.c index d543012..9daa1ce 100644 --- a/fs/open.c +++ b/fs/open.c @@ -654,10 +654,23 @@ static inline int __get_file_write_access(struct inode *inode, return error; } -static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, - struct file *f, - int (*open)(struct inode *, struct file *), - const struct cred *cred) +int open_check_o_direct(struct file *f) +{ + /* NB: we're sure to have correct a_ops only after f_op->open */ + if (f->f_flags & O_DIRECT) { + if (!f->f_mapping->a_ops || + ((!f->f_mapping->a_ops->direct_IO) && + (!f->f_mapping->a_ops->get_xip_mem))) { + return -EINVAL; + } + } + return 0; +} + +static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt, + struct file *f, + int (*open)(struct inode *, struct file *), + const struct cred *cred) { static const struct file_operations empty_fops = {}; struct inode *inode; @@ -713,16 +726,6 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); - /* NB: we're sure to have correct a_ops only after f_op->open */ - if (f->f_flags & O_DIRECT) { - if (!f->f_mapping->a_ops || - ((!f->f_mapping->a_ops->direct_IO) && - (!f->f_mapping->a_ops->get_xip_mem))) { - fput(f); - f = ERR_PTR(-EINVAL); - } - } - return f; cleanup_all: @@ -750,6 +753,22 @@ cleanup_file: return ERR_PTR(error); } +static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, + struct file *f, + int (*open)(struct inode *, struct file *), + const struct cred *cred) +{ + struct file *res = do_dentry_open(dentry, mnt, f, open, cred); + if (!IS_ERR(res)) { + int error = open_check_o_direct(f); + if (error) { + fput(res); + res = ERR_PTR(error); + } + } + return res; +} + /** * lookup_instantiate_filp - instantiates the open intent filp * @nd: pointer to nameidata -- cgit v1.1 From 78f71eff3c274f3907f4aa1bbe3267281ba1c603 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 21 May 2012 17:30:16 +0200 Subject: vfs: do_dentry_open(): don't put filp Move put_filp() out to __dentry_open(), the only caller now. Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro --- fs/open.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/open.c') diff --git a/fs/open.c b/fs/open.c index 9daa1ce..511c548 100644 --- a/fs/open.c +++ b/fs/open.c @@ -747,7 +747,6 @@ cleanup_all: f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: - put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); @@ -765,6 +764,8 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, fput(res); res = ERR_PTR(error); } + } else { + put_filp(f); } return res; } -- cgit v1.1 From 91daee988db38b0207eec719a3160b163c077007 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 21 May 2012 17:30:17 +0200 Subject: vfs: nameidata_to_filp(): inline __dentry_open() Copy __dentry_open() into nameidata_to_filp(). Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro --- fs/open.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'fs/open.c') diff --git a/fs/open.c b/fs/open.c index 511c548..9fd34b7 100644 --- a/fs/open.c +++ b/fs/open.c @@ -828,9 +828,25 @@ struct file *nameidata_to_filp(struct nameidata *nd) /* Has the filesystem initialised the file for us? */ if (filp->f_path.dentry == NULL) { + struct file *res; + path_get(&nd->path); - filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp, - NULL, cred); + res = do_dentry_open(nd->path.dentry, nd->path.mnt, + filp, NULL, cred); + if (!IS_ERR(res)) { + int error; + + BUG_ON(res != filp); + + error = open_check_o_direct(filp); + if (error) { + fput(filp); + filp = ERR_PTR(error); + } + } else { + put_filp(filp); + filp = res; + } } return filp; } -- cgit v1.1 From 50ee93afcaa970620d1fb5a9894109a2ab152868 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 21 May 2012 17:30:18 +0200 Subject: vfs: nameidata_to_filp(): don't throw away file on error If open fails, don't put the file. This allows it to be reused if open needs to be retried. Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro --- fs/open.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'fs/open.c') diff --git a/fs/open.c b/fs/open.c index 9fd34b7..d6c79a0 100644 --- a/fs/open.c +++ b/fs/open.c @@ -824,10 +824,11 @@ struct file *nameidata_to_filp(struct nameidata *nd) /* Pick up the filp from the open intent */ filp = nd->intent.open.file; - nd->intent.open.file = NULL; /* Has the filesystem initialised the file for us? */ - if (filp->f_path.dentry == NULL) { + if (filp->f_path.dentry != NULL) { + nd->intent.open.file = NULL; + } else { struct file *res; path_get(&nd->path); @@ -836,6 +837,7 @@ struct file *nameidata_to_filp(struct nameidata *nd) if (!IS_ERR(res)) { int error; + nd->intent.open.file = NULL; BUG_ON(res != filp); error = open_check_o_direct(filp); @@ -844,7 +846,7 @@ struct file *nameidata_to_filp(struct nameidata *nd) filp = ERR_PTR(error); } } else { - put_filp(filp); + /* Allow nd->intent.open.file to be recycled */ filp = res; } } -- cgit v1.1