...and fix up the callers. For do_file_open_root, just declare a getname_info on the stack and fill out the .name field. For do_filp_open, make it also take a getname_info pointer, and fix up its callers to call it appropriately. For filp_open, add a variant that takes a getname_info pointer and turn filp_open into a wrapper around it. Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> --- fs/exec.c | 5 +++-- fs/internal.h | 4 ++-- fs/namei.c | 28 +++++++++++++++------------- fs/open.c | 33 +++++++++++++++++++++++++++++---- include/linux/fs.h | 1 + kernel/acct.c | 6 +++--- mm/swapfile.c | 4 ++-- 7 files changed, 55 insertions(+), 26 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index b1c71ce..d62bff5 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -126,7 +126,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) if (IS_ERR(tmp)) goto out; - file = do_filp_open(AT_FDCWD, tmp->name, &uselib_flags, LOOKUP_FOLLOW); + file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW); putname(tmp); error = PTR_ERR(file); if (IS_ERR(file)) @@ -761,13 +761,14 @@ struct file *open_exec(const char *name) { struct file *file; int err; + struct getname_info tmp = { .name = name }; static const struct open_flags open_exec_flags = { .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, .acc_mode = MAY_EXEC | MAY_OPEN, .intent = LOOKUP_OPEN }; - file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW); + file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags, LOOKUP_FOLLOW); if (IS_ERR(file)) goto out; diff --git a/fs/internal.h b/fs/internal.h index 371bcc4..ddc0d2c 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -97,8 +97,8 @@ struct open_flags { int acc_mode; int intent; }; -extern struct file *do_filp_open(int dfd, const char *pathname, - const struct open_flags *op, int lookup_flags); +extern struct file *do_filp_open(int dfd, struct getname_info *ginfo, + const struct open_flags *op, int flags); extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, const char *, const struct open_flags *, int lookup_flags); diff --git a/fs/namei.c b/fs/namei.c index 8fe643e..599ac28 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2667,7 +2667,7 @@ out_dput: */ static int do_last(struct nameidata *nd, struct path *path, struct file *file, const struct open_flags *op, - int *opened, const char *pathname) + int *opened, struct getname_info *ginfo) { struct dentry *dir = nd->path.dentry; int open_flag = op->open_flag; @@ -2679,6 +2679,7 @@ static int do_last(struct nameidata *nd, struct path *path, struct path save_parent = { .dentry = NULL, .mnt = NULL }; bool retried = false; int error; + const char *pathname = ginfo->name; nd->flags &= ~LOOKUP_PARENT; nd->flags |= op->intent; @@ -2913,7 +2914,7 @@ stale_open: goto retry_lookup; } -static struct file *path_openat(int dfd, const char *pathname, +static struct file *path_openat(int dfd, struct getname_info *ginfo, struct nameidata *nd, const struct open_flags *op, int flags) { struct file *base = NULL; @@ -2928,16 +2929,16 @@ static struct file *path_openat(int dfd, const char *pathname, file->f_flags = op->open_flag; - error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base); + error = path_init(dfd, ginfo->name, flags | LOOKUP_PARENT, nd, &base); if (unlikely(error)) goto out; current->total_link_count = 0; - error = link_path_walk(pathname, nd); + error = link_path_walk(ginfo->name, nd); if (unlikely(error)) goto out; - error = do_last(nd, &path, file, op, &opened, pathname); + error = do_last(nd, &path, file, op, &opened, ginfo); while (unlikely(error > 0)) { /* trailing symlink */ struct path link = path; void *cookie; @@ -2955,7 +2956,7 @@ static struct file *path_openat(int dfd, const char *pathname, error = follow_link(&link, nd, &cookie); if (unlikely(error)) break; - error = do_last(nd, &path, file, op, &opened, pathname); + error = do_last(nd, &path, file, op, &opened, ginfo); put_link(nd, &link, cookie); } out: @@ -2979,17 +2980,17 @@ out: return file; } -struct file *do_filp_open(int dfd, const char *pathname, +struct file *do_filp_open(int dfd, struct getname_info *ginfo, const struct open_flags *op, int flags) { struct nameidata nd; struct file *filp; - filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU); + filp = path_openat(dfd, ginfo, &nd, op, flags | LOOKUP_RCU); if (unlikely(filp == ERR_PTR(-ECHILD))) - filp = path_openat(dfd, pathname, &nd, op, flags); + filp = path_openat(dfd, ginfo, &nd, op, flags); if (unlikely(filp == ERR_PTR(-ESTALE))) - filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL); + filp = path_openat(dfd, ginfo, &nd, op, flags | LOOKUP_REVAL); return filp; } @@ -2998,6 +2999,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, { struct nameidata nd; struct file *file; + struct getname_info ginfo = { .name = name }; nd.root.mnt = mnt; nd.root.dentry = dentry; @@ -3007,11 +3009,11 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN) return ERR_PTR(-ELOOP); - file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU); + file = path_openat(-1, &ginfo, &nd, op, flags | LOOKUP_RCU); if (unlikely(file == ERR_PTR(-ECHILD))) - file = path_openat(-1, name, &nd, op, flags); + file = path_openat(-1, &ginfo, &nd, op, flags); if (unlikely(file == ERR_PTR(-ESTALE))) - file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL); + file = path_openat(-1, &ginfo, &nd, op, flags | LOOKUP_REVAL); return file; } diff --git a/fs/open.c b/fs/open.c index 3796d0c..d0f225e 100644 --- a/fs/open.c +++ b/fs/open.c @@ -909,6 +909,24 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o } /** + * filp_open_ginfo - open file and return file pointer + * + * @ginfo: getname_info containing path to open + * @flags: open flags as per the open(2) second argument + * @mode: mode for the new file if O_CREAT is set, else ignored + * + * This is the helper to open a file from kernelspace if you really + * have to. But in generally you should not do this, so please move + * along, nothing to see here.. + */ +struct file *filp_open_ginfo(struct getname_info *ginfo, int flags, umode_t mode) +{ + struct open_flags op; + int lookup = build_open_flags(flags, mode, &op); + return do_filp_open(AT_FDCWD, ginfo, &op, lookup); +} + +/** * filp_open - open file and return file pointer * * @filename: path to open @@ -921,9 +939,16 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o */ struct file *filp_open(const char *filename, int flags, umode_t mode) { - struct open_flags op; - int lookup = build_open_flags(flags, mode, &op); - return do_filp_open(AT_FDCWD, filename, &op, lookup); + struct file *filp; + struct getname_info *ginfo = kzalloc(sizeof(*ginfo), GFP_KERNEL); + + if (!ginfo) + return ERR_PTR(-ENOMEM); + + ginfo->name = filename; + filp = filp_open_ginfo(ginfo, flags, mode); + putname(ginfo); + return filp; } EXPORT_SYMBOL(filp_open); @@ -951,7 +976,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) if (!IS_ERR(tmp)) { fd = get_unused_fd_flags(flags); if (fd >= 0) { - struct file *f = do_filp_open(dfd, tmp->name, &op, lookup); + struct file *f = do_filp_open(dfd, tmp, &op, lookup); if (IS_ERR(f)) { put_unused_fd(fd); fd = PTR_ERR(f); diff --git a/include/linux/fs.h b/include/linux/fs.h index 1b0d0fb..a37b0c1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2200,6 +2200,7 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len); extern long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode); +extern struct file *filp_open_ginfo(struct getname_info *, int, umode_t); extern struct file *filp_open(const char *, int, umode_t); extern struct file *file_open_root(struct dentry *, struct vfsmount *, const char *, int); diff --git a/kernel/acct.c b/kernel/acct.c index 3943608..a6b3e14 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -193,7 +193,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file, } } -static int acct_on(const char *name) +static int acct_on(struct getname_info *pathname) { struct file *file; struct vfsmount *mnt; @@ -201,7 +201,7 @@ static int acct_on(const char *name) struct bsd_acct_struct *acct = NULL; /* Difference from BSD - they don't do O_APPEND */ - file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); + file = filp_open_ginfo(pathname, O_WRONLY|O_APPEND|O_LARGEFILE, 0); if (IS_ERR(file)) return PTR_ERR(file); @@ -263,7 +263,7 @@ SYSCALL_DEFINE1(acct, const char __user *, name) struct getname_info *tmp = getname(name); if (IS_ERR(tmp)) return (PTR_ERR(tmp)); - error = acct_on(tmp->name); + error = acct_on(tmp); putname(tmp); } else { struct bsd_acct_struct *acct; diff --git a/mm/swapfile.c b/mm/swapfile.c index 8dbf46d..0f8b1a4 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1498,7 +1498,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (IS_ERR(pathname)) goto out; - victim = filp_open(pathname->name, O_RDWR|O_LARGEFILE, 0); + victim = filp_open_ginfo(pathname, O_RDWR|O_LARGEFILE, 0); err = PTR_ERR(victim); if (IS_ERR(victim)) goto out; @@ -1966,7 +1966,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) name = NULL; goto bad_swap; } - swap_file = filp_open(name->name, O_RDWR|O_LARGEFILE, 0); + swap_file = filp_open_ginfo(name, O_RDWR|O_LARGEFILE, 0); if (IS_ERR(swap_file)) { error = PTR_ERR(swap_file); swap_file = NULL; -- 1.7.11.4 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html