[PATCH 02/25] vfs: reorganize do_last()

From: Miklos Szeredi
Date: Wed Mar 07 2012 - 16:23:03 EST


From: Miklos Szeredi <mszeredi@xxxxxxx>

Make the slow lookup part of O_CREAT and non-O_CREAT opens common.

This allows atomic_open to be hooked into the slow lookup part.

The audit_inode() from after mutex_unlock() was moved down just before the "ok:"
label. Is this correct?

Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxx>
---
fs/namei.c | 93 +++++++++++++++++++++++++++++++++++------------------------
1 files changed, 55 insertions(+), 38 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index f9639bf..ff8bc94 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2113,6 +2113,8 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
int want_write = 0;
int acc_mode = op->acc_mode;
struct file *filp;
+ struct inode *inode;
+ int symlink_ok = 0;
int error;

nd->flags &= ~LOOKUP_PARENT;
@@ -2144,47 +2146,38 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
}

if (!(open_flag & O_CREAT)) {
- int symlink_ok = 0;
if (nd->last.name[nd->last.len])
nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
symlink_ok = 1;
/* we _can_ be in RCU mode here */
- error = walk_component(nd, path, &nd->last, LAST_NORM,
- !symlink_ok);
- if (error < 0)
- return ERR_PTR(error);
- if (error) /* symlink */
- return NULL;
- /* sayonara */
+ error = lookup_fast(nd, &nd->last, path, &inode);
+ if (error <= 0) {
+ if (error)
+ goto terminate;
+
+ goto finish_lookup;
+ }
+ /* cached lookup failed, no longer in RCU mode */
+ } else {
+ /* create side of things */
+
+ /*
+ * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED
+ * has been cleared when we got to the last component we are
+ * about to look up
+ */
error = complete_walk(nd);
if (error)
return ERR_PTR(error);

- error = -ENOTDIR;
- if (nd->flags & LOOKUP_DIRECTORY) {
- if (!nd->inode->i_op->lookup)
- goto exit;
- }
- audit_inode(pathname, nd->path.dentry);
- goto ok;
+ audit_inode(pathname, dir);
+ error = -EISDIR;
+ /* trailing slashes? */
+ if (nd->last.name[nd->last.len])
+ goto exit;
}

- /* create side of things */
- /*
- * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED has been
- * cleared when we got to the last component we are about to look up
- */
- error = complete_walk(nd);
- if (error)
- return ERR_PTR(error);
-
- audit_inode(pathname, dir);
- error = -EISDIR;
- /* trailing slashes? */
- if (nd->last.name[nd->last.len])
- goto exit;
-
mutex_lock(&dir->d_inode->i_mutex);

dentry = lookup_hash(nd);
@@ -2197,9 +2190,14 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
path->dentry = dentry;
path->mnt = nd->path.mnt;

- /* Negative dentry, just create the file */
+ /* Negative dentry, create the file if O_CREAT */
if (!dentry->d_inode) {
umode_t mode = op->mode;
+
+ error = -ENOENT;
+ if (!(open_flag & O_CREAT))
+ goto exit_mutex_unlock;
+
if (!IS_POSIXACL(dir->d_inode))
mode &= ~current_umask();
/*
@@ -2233,7 +2231,6 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
* It already exists.
*/
mutex_unlock(&dir->d_inode->i_mutex);
- audit_inode(pathname, path->dentry);

error = -EEXIST;
if (open_flag & O_EXCL)
@@ -2243,22 +2240,38 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
if (error)
goto exit_dput;

+ inode = path->dentry->d_inode;
+finish_lookup:
error = -ENOENT;
- if (!path->dentry->d_inode)
- goto exit_dput;
+ if (!inode) {
+ path_to_nameidata(path, nd);
+ goto terminate;
+ }

- if (path->dentry->d_inode->i_op->follow_link)
+ if (should_follow_link(inode, !symlink_ok)) {
+ if (nd->flags & LOOKUP_RCU) {
+ if (unlikely(unlazy_walk(nd, path->dentry))) {
+ error = -ECHILD;
+ goto terminate;
+ }
+ }
return NULL;
+ }

path_to_nameidata(path, nd);
- nd->inode = path->dentry->d_inode;
- /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */
+ nd->inode = inode;
+
error = complete_walk(nd);
if (error)
return ERR_PTR(error);
error = -EISDIR;
- if (S_ISDIR(nd->inode->i_mode))
+ if ((open_flag & O_CREAT) && S_ISDIR(inode->i_mode))
+ goto exit;
+ error = -ENOTDIR;
+ if (nd->flags & LOOKUP_DIRECTORY && !inode->i_op->lookup)
goto exit;
+
+ audit_inode(pathname, nd->path.dentry);
ok:
if (!S_ISREG(nd->inode->i_mode))
will_truncate = 0;
@@ -2303,6 +2316,10 @@ exit_dput:
exit:
filp = ERR_PTR(error);
goto out;
+
+terminate:
+ terminate_walk(nd);
+ return ERR_PTR(error);
}

static struct file *path_openat(int dfd, const char *pathname,
--
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/