summaryrefslogtreecommitdiff
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-02-23 17:54:08 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-14 09:15:25 -0400
commit13aab428a73d3200b9283b61b7fdf5713181ac66 (patch)
treeb7350283378b60366609dca7b02c412b4632879e /fs/namei.c
parent47c805dc2d2dff686962f5f0baa6bac2d703ba19 (diff)
downloadlwn-13aab428a73d3200b9283b61b7fdf5713181ac66.tar.gz
lwn-13aab428a73d3200b9283b61b7fdf5713181ac66.zip
separate -ESTALE/-ECHILD retries in do_filp_open() from real work
new helper: path_openat(). Does what do_filp_open() does, except that it tries only the walk mode (RCU/normal/force revalidation) it had been told to. Both create and non-create branches are using path_lookupat() now. Fixed the double audit_inode() in non-create branch. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c49
1 files changed, 20 insertions, 29 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 9c7fa946abe1..01a17dd2f151 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2292,19 +2292,14 @@ exit:
return ERR_PTR(error);
}
-/*
- * Note that the low bits of the passed in "open_flag"
- * are not the same as in the local variable "flag". See
- * open_to_namei_flags() for more details.
- */
-struct file *do_filp_open(int dfd, const char *pathname,
+static struct file *path_openat(int dfd, const char *pathname,
const struct open_flags *op, int flags)
{
struct file *filp;
struct nameidata nd;
- int error;
struct path path;
int count = 0;
+ int error;
filp = get_empty_filp();
if (!filp)
@@ -2319,42 +2314,27 @@ struct file *do_filp_open(int dfd, const char *pathname,
goto creat;
/* !O_CREAT, simple open */
- error = do_path_lookup(dfd, pathname, flags | op->intent, &nd);
+ error = path_lookupat(dfd, pathname, flags | op->intent, &nd);
if (unlikely(error))
- goto out_filp2;
+ goto out_filp;
error = -ELOOP;
if (!(nd.flags & LOOKUP_FOLLOW)) {
if (nd.inode->i_op->follow_link)
- goto out_path2;
+ goto out_path;
}
error = -ENOTDIR;
if (nd.flags & LOOKUP_DIRECTORY) {
if (!nd.inode->i_op->lookup)
- goto out_path2;
+ goto out_path;
}
audit_inode(pathname, nd.path.dentry);
filp = finish_open(&nd, op->open_flag, op->acc_mode);
-out2:
release_open_intent(&nd);
return filp;
-out_path2:
- path_put(&nd.path);
-out_filp2:
- filp = ERR_PTR(error);
- goto out2;
-
creat:
/* OK, have to create the file. Find the parent. */
- error = path_lookupat(dfd, pathname,
- LOOKUP_PARENT | LOOKUP_RCU | flags, &nd);
- if (unlikely(error == -ECHILD))
- error = path_lookupat(dfd, pathname, LOOKUP_PARENT | flags, &nd);
- if (unlikely(error == -ESTALE)) {
-reval:
- flags |= LOOKUP_REVAL;
- error = path_lookupat(dfd, pathname, LOOKUP_PARENT | flags, &nd);
- }
+ error = path_lookupat(dfd, pathname, LOOKUP_PARENT | flags, &nd);
if (unlikely(error))
goto out_filp;
if (unlikely(!audit_dummy_context()))
@@ -2398,8 +2378,6 @@ reval:
out:
if (nd.root.mnt)
path_put(&nd.root);
- if (filp == ERR_PTR(-ESTALE) && !(flags & LOOKUP_REVAL))
- goto reval;
release_open_intent(&nd);
return filp;
@@ -2412,6 +2390,19 @@ out_filp:
goto out;
}
+struct file *do_filp_open(int dfd, const char *pathname,
+ const struct open_flags *op, int flags)
+{
+ struct file *filp;
+
+ filp = path_openat(dfd, pathname, op, flags | LOOKUP_RCU);
+ if (unlikely(filp == ERR_PTR(-ECHILD)))
+ filp = path_openat(dfd, pathname, op, flags);
+ if (unlikely(filp == ERR_PTR(-ESTALE)))
+ filp = path_openat(dfd, pathname, op, flags | LOOKUP_REVAL);
+ return filp;
+}
+
/**
* lookup_create - lookup a dentry, creating it if it doesn't exist
* @nd: nameidata info