summaryrefslogtreecommitdiff
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-04-26 00:02:50 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2016-05-02 19:49:33 -0400
commit6ac087099edf09ca357e2f765e3e24677543897c (patch)
tree56dc485b6e28fba20710486a17b8025a690c876c /fs/namei.c
parent3b0a3c1ac1598722fc289da19219d14f2a37b31f (diff)
downloadlwn-6ac087099edf09ca357e2f765e3e24677543897c.tar.gz
lwn-6ac087099edf09ca357e2f765e3e24677543897c.zip
path_openat(): take O_PATH handling out of do_last()
do_last() and lookup_open() simpler that way and so does O_PATH itself. As it bloody well should: we find what the pathname resolves to, same way as in stat() et.al. and associate it with FMODE_PATH struct file. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c31
1 files changed, 24 insertions, 7 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 8249852b5fc6..8145b415e257 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3019,7 +3019,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
goto out_no_open;
}
- if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
+ if (dir_inode->i_op->atomic_open) {
return atomic_open(nd, dentry, path, file, op, got_write,
need_lookup, opened);
}
@@ -3219,7 +3219,7 @@ finish_open:
return error;
}
audit_inode(nd->name, nd->path.dentry, 0);
- if (unlikely(d_is_symlink(nd->path.dentry)) && !(open_flag & O_PATH)) {
+ if (unlikely(d_is_symlink(nd->path.dentry))) {
error = -ELOOP;
goto out;
}
@@ -3239,11 +3239,9 @@ finish_open:
got_write = true;
}
finish_open_created:
- if (likely(!(open_flag & O_PATH))) {
- error = may_open(&nd->path, acc_mode, open_flag);
- if (error)
- goto out;
- }
+ error = may_open(&nd->path, acc_mode, open_flag);
+ if (error)
+ goto out;
BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
error = vfs_open(&nd->path, file, current_cred());
if (!error) {
@@ -3357,6 +3355,18 @@ out:
return error;
}
+static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file)
+{
+ struct path path;
+ int error = path_lookupat(nd, flags, &path);
+ if (!error) {
+ audit_inode(nd->name, path.dentry, 0);
+ error = vfs_open(&path, file, current_cred());
+ path_put(&path);
+ }
+ return error;
+}
+
static struct file *path_openat(struct nameidata *nd,
const struct open_flags *op, unsigned flags)
{
@@ -3376,6 +3386,13 @@ static struct file *path_openat(struct nameidata *nd,
goto out2;
}
+ if (unlikely(file->f_flags & O_PATH)) {
+ error = do_o_path(nd, flags, file);
+ if (!error)
+ opened |= FILE_OPENED;
+ goto out2;
+ }
+
s = path_init(nd, flags);
if (IS_ERR(s)) {
put_filp(file);