Commit fac7d191 authored by Al Viro's avatar Al Viro

fix EOPENSTALE bug in do_last()

EOPENSTALE occuring at the last component of a trailing symlink ends up
with do_last() retrying its lookup.  After the symlink body has been
discarded.  The thing is, all this retry_lookup logics in there is not
needed at all - the upper layers will do the right thing if we simply
return that -EOPENSTALE as we would with any other error.  Trying to
microoptimize in do_last() is a lot of headache for no good reason.

Cc: stable@vger.kernel.org # v4.2+
Tested-by: default avatarOleg Drokin <green@linuxhacker.ru>
Reviewed-and-Tested-by: default avatarJeff Layton <jlayton@poochiereds.net>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 1a695a90
...@@ -3166,9 +3166,7 @@ static int do_last(struct nameidata *nd, ...@@ -3166,9 +3166,7 @@ static int do_last(struct nameidata *nd,
int acc_mode = op->acc_mode; int acc_mode = op->acc_mode;
unsigned seq; unsigned seq;
struct inode *inode; struct inode *inode;
struct path save_parent = { .dentry = NULL, .mnt = NULL };
struct path path; struct path path;
bool retried = false;
int error; int error;
nd->flags &= ~LOOKUP_PARENT; nd->flags &= ~LOOKUP_PARENT;
...@@ -3211,7 +3209,6 @@ static int do_last(struct nameidata *nd, ...@@ -3211,7 +3209,6 @@ static int do_last(struct nameidata *nd,
return -EISDIR; return -EISDIR;
} }
retry_lookup:
if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) { if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
error = mnt_want_write(nd->path.mnt); error = mnt_want_write(nd->path.mnt);
if (!error) if (!error)
...@@ -3292,23 +3289,14 @@ static int do_last(struct nameidata *nd, ...@@ -3292,23 +3289,14 @@ static int do_last(struct nameidata *nd,
if (unlikely(error)) if (unlikely(error))
return error; return error;
if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) { path_to_nameidata(&path, nd);
path_to_nameidata(&path, nd);
} else {
save_parent.dentry = nd->path.dentry;
save_parent.mnt = mntget(path.mnt);
nd->path.dentry = path.dentry;
}
nd->inode = inode; nd->inode = inode;
nd->seq = seq; nd->seq = seq;
/* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */
finish_open: finish_open:
error = complete_walk(nd); error = complete_walk(nd);
if (error) { if (error)
path_put(&save_parent);
return error; return error;
}
audit_inode(nd->name, nd->path.dentry, 0); audit_inode(nd->name, nd->path.dentry, 0);
error = -EISDIR; error = -EISDIR;
if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry)) if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
...@@ -3331,13 +3319,9 @@ static int do_last(struct nameidata *nd, ...@@ -3331,13 +3319,9 @@ static int do_last(struct nameidata *nd,
goto out; goto out;
BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
error = vfs_open(&nd->path, file, current_cred()); error = vfs_open(&nd->path, file, current_cred());
if (!error) { if (error)
*opened |= FILE_OPENED;
} else {
if (error == -EOPENSTALE)
goto stale_open;
goto out; goto out;
} *opened |= FILE_OPENED;
opened: opened:
error = open_check_o_direct(file); error = open_check_o_direct(file);
if (!error) if (!error)
...@@ -3353,26 +3337,7 @@ static int do_last(struct nameidata *nd, ...@@ -3353,26 +3337,7 @@ static int do_last(struct nameidata *nd,
} }
if (got_write) if (got_write)
mnt_drop_write(nd->path.mnt); mnt_drop_write(nd->path.mnt);
path_put(&save_parent);
return error; return error;
stale_open:
/* If no saved parent or already retried then can't retry */
if (!save_parent.dentry || retried)
goto out;
BUG_ON(save_parent.dentry != dir);
path_put(&nd->path);
nd->path = save_parent;
nd->inode = dir->d_inode;
save_parent.mnt = NULL;
save_parent.dentry = NULL;
if (got_write) {
mnt_drop_write(nd->path.mnt);
got_write = false;
}
retried = true;
goto retry_lookup;
} }
static int do_tmpfile(struct nameidata *nd, unsigned flags, static int do_tmpfile(struct nameidata *nd, unsigned flags,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment