summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-02-24 01:44:09 +0300
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-14 16:15:25 +0300
commit47c805dc2d2dff686962f5f0baa6bac2d703ba19 (patch)
treeb596e0a1aadb1550ef2099df95832196cd0eeda1
parentc3e380b0b3cfa613189fb91513efd88a65e1d9d8 (diff)
downloadlinux-47c805dc2d2dff686962f5f0baa6bac2d703ba19.tar.xz
switch do_filp_open() to struct open_flags
take calculation of open_flags by open(2) arguments into new helper in fs/open.c, move filp_open() over there, have it and do_sys_open() use that helper, switch exec.c callers of do_filp_open() to explicit (and constant) struct open_flags. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/exec.c18
-rw-r--r--fs/internal.h8
-rw-r--r--fs/namei.c88
-rw-r--r--fs/open.c73
-rw-r--r--include/linux/fs.h2
5 files changed, 101 insertions, 88 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 52a447d9b6ab..ba99e1abb1aa 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -115,13 +115,16 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
struct file *file;
char *tmp = getname(library);
int error = PTR_ERR(tmp);
+ static const struct open_flags uselib_flags = {
+ .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
+ .acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN,
+ .intent = LOOKUP_OPEN
+ };
if (IS_ERR(tmp))
goto out;
- file = do_filp_open(AT_FDCWD, tmp,
- O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
- MAY_READ | MAY_EXEC | MAY_OPEN);
+ file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
putname(tmp);
error = PTR_ERR(file);
if (IS_ERR(file))
@@ -721,10 +724,13 @@ struct file *open_exec(const char *name)
{
struct file *file;
int err;
+ 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,
- O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
- MAY_EXEC | MAY_OPEN);
+ file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW);
if (IS_ERR(file))
goto out;
diff --git a/fs/internal.h b/fs/internal.h
index 9b976b57d7fe..6fdbdf2c6047 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -106,6 +106,14 @@ extern void put_super(struct super_block *sb);
struct nameidata;
extern struct file *nameidata_to_filp(struct nameidata *);
extern void release_open_intent(struct nameidata *);
+struct open_flags {
+ int open_flag;
+ int mode;
+ int acc_mode;
+ int intent;
+};
+extern struct file *do_filp_open(int dfd, const char *pathname,
+ const struct open_flags *op, int lookup_flags);
/*
* inode.c
diff --git a/fs/namei.c b/fs/namei.c
index 5e4206f45371..9c7fa946abe1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2169,13 +2169,6 @@ exit:
return ERR_PTR(error);
}
-struct open_flags {
- int open_flag;
- int mode;
- int acc_mode;
- int intent;
-};
-
/*
* Handle O_CREAT case for do_filp_open
*/
@@ -2305,74 +2298,28 @@ exit:
* open_to_namei_flags() for more details.
*/
struct file *do_filp_open(int dfd, const char *pathname,
- int open_flag, int mode, int acc_mode)
+ const struct open_flags *op, int flags)
{
struct file *filp;
struct nameidata nd;
int error;
struct path path;
int count = 0;
- int flag = open_to_namei_flags(open_flag);
- int flags = 0;
- struct open_flags op;
-
- if (!(open_flag & O_CREAT))
- mode = 0;
-
- /* Must never be set by userspace */
- open_flag &= ~FMODE_NONOTIFY;
-
- /*
- * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only
- * check for O_DSYNC if the need any syncing at all we enforce it's
- * always set instead of having to deal with possibly weird behaviour
- * for malicious applications setting only __O_SYNC.
- */
- if (open_flag & __O_SYNC)
- open_flag |= O_DSYNC;
-
- op.open_flag = open_flag;
-
- if (!acc_mode)
- acc_mode = MAY_OPEN | ACC_MODE(open_flag);
-
- /* O_TRUNC implies we need access checks for write permissions */
- if (open_flag & O_TRUNC)
- acc_mode |= MAY_WRITE;
-
- /* Allow the LSM permission hook to distinguish append
- access from general write access. */
- if (open_flag & O_APPEND)
- acc_mode |= MAY_APPEND;
-
- op.acc_mode = acc_mode;
-
- op.intent = LOOKUP_OPEN;
- if (open_flag & O_CREAT) {
- op.intent |= LOOKUP_CREATE;
- if (open_flag & O_EXCL)
- op.intent |= LOOKUP_EXCL;
- }
-
- if (open_flag & O_DIRECTORY)
- flags |= LOOKUP_DIRECTORY;
- if (!(open_flag & O_NOFOLLOW))
- flags |= LOOKUP_FOLLOW;
filp = get_empty_filp();
if (!filp)
return ERR_PTR(-ENFILE);
- filp->f_flags = open_flag;
+ filp->f_flags = op->open_flag;
nd.intent.open.file = filp;
- nd.intent.open.flags = flag;
- nd.intent.open.create_mode = mode;
+ nd.intent.open.flags = open_to_namei_flags(op->open_flag);
+ nd.intent.open.create_mode = op->mode;
- if (open_flag & O_CREAT)
+ if (op->open_flag & O_CREAT)
goto creat;
/* !O_CREAT, simple open */
- error = do_path_lookup(dfd, pathname, flags | op.intent, &nd);
+ error = do_path_lookup(dfd, pathname, flags | op->intent, &nd);
if (unlikely(error))
goto out_filp2;
error = -ELOOP;
@@ -2386,7 +2333,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
goto out_path2;
}
audit_inode(pathname, nd.path.dentry);
- filp = finish_open(&nd, open_flag, acc_mode);
+ filp = finish_open(&nd, op->open_flag, op->acc_mode);
out2:
release_open_intent(&nd);
return filp;
@@ -2416,7 +2363,7 @@ reval:
/*
* We have the parent and last component.
*/
- filp = do_last(&nd, &path, &op, pathname);
+ filp = do_last(&nd, &path, op, pathname);
while (unlikely(!filp)) { /* trailing symlink */
struct path link = path;
struct inode *linki = link.dentry->d_inode;
@@ -2443,7 +2390,7 @@ reval:
if (unlikely(error))
filp = ERR_PTR(error);
else
- filp = do_last(&nd, &path, &op, pathname);
+ filp = do_last(&nd, &path, op, pathname);
if (!IS_ERR(cookie) && linki->i_op->put_link)
linki->i_op->put_link(link.dentry, &nd, cookie);
path_put(&link);
@@ -2466,23 +2413,6 @@ out_filp:
}
/**
- * filp_open - open file and return file pointer
- *
- * @filename: 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(const char *filename, int flags, int mode)
-{
- return do_filp_open(AT_FDCWD, filename, flags, mode, 0);
-}
-EXPORT_SYMBOL(filp_open);
-
-/**
* lookup_create - lookup a dentry, creating it if it doesn't exist
* @nd: nameidata info
* @is_dir: directory flag
diff --git a/fs/open.c b/fs/open.c
index b47aab39c057..d05e18c60bae 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -890,15 +890,86 @@ void fd_install(unsigned int fd, struct file *file)
EXPORT_SYMBOL(fd_install);
+static inline int build_open_flags(int flags, int mode, struct open_flags *op)
+{
+ int lookup_flags = 0;
+ int acc_mode;
+
+ if (!(flags & O_CREAT))
+ mode = 0;
+ op->mode = mode;
+
+ /* Must never be set by userspace */
+ flags &= ~FMODE_NONOTIFY;
+
+ /*
+ * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only
+ * check for O_DSYNC if the need any syncing at all we enforce it's
+ * always set instead of having to deal with possibly weird behaviour
+ * for malicious applications setting only __O_SYNC.
+ */
+ if (flags & __O_SYNC)
+ flags |= O_DSYNC;
+
+ op->open_flag = flags;
+
+ acc_mode = MAY_OPEN | ACC_MODE(flags);
+
+ /* O_TRUNC implies we need access checks for write permissions */
+ if (flags & O_TRUNC)
+ acc_mode |= MAY_WRITE;
+
+ /* Allow the LSM permission hook to distinguish append
+ access from general write access. */
+ if (flags & O_APPEND)
+ acc_mode |= MAY_APPEND;
+
+ op->acc_mode = acc_mode;
+
+ op->intent = LOOKUP_OPEN;
+ if (flags & O_CREAT) {
+ op->intent |= LOOKUP_CREATE;
+ if (flags & O_EXCL)
+ op->intent |= LOOKUP_EXCL;
+ }
+
+ if (flags & O_DIRECTORY)
+ lookup_flags |= LOOKUP_DIRECTORY;
+ if (!(flags & O_NOFOLLOW))
+ lookup_flags |= LOOKUP_FOLLOW;
+ return lookup_flags;
+}
+
+/**
+ * filp_open - open file and return file pointer
+ *
+ * @filename: 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(const char *filename, int flags, int mode)
+{
+ struct open_flags op;
+ int lookup = build_open_flags(flags, mode, &op);
+ return do_filp_open(AT_FDCWD, filename, &op, lookup);
+}
+EXPORT_SYMBOL(filp_open);
+
long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
{
+ struct open_flags op;
+ int lookup = build_open_flags(flags, mode, &op);
char *tmp = getname(filename);
int fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
- struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);
+ 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 e38b50a4b9d2..9c75714f92c1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2205,8 +2205,6 @@ extern struct file *create_read_pipe(struct file *f, int flags);
extern struct file *create_write_pipe(int flags);
extern void free_write_pipe(struct file *);
-extern struct file *do_filp_open(int dfd, const char *pathname,
- int open_flag, int mode, int acc_mode);
extern int may_open(struct path *, int, int);
extern int kernel_read(struct file *, loff_t, char *, unsigned long);