summaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2020-02-26 17:55:02 +0100
committerAl Viro <viro@zeniv.linux.org.uk>2020-03-14 02:09:13 +0100
commitabc2c632e0cec6f76883d008c298e31cb3e2d242 (patch)
treeb80b01d4e9390f9cdf2f058cf7c04a0baa62c5eb /fs/namei.c
parentexpand path_parent_directory() in its callers (diff)
downloadlinux-abc2c632e0cec6f76883d008c298e31cb3e2d242.tar.xz
linux-abc2c632e0cec6f76883d008c298e31cb3e2d242.zip
follow_dotdot{,_rcu}(): lift switching nd->path to parent out of loop
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 88e5d7920540..772d82daf3b4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1365,7 +1365,9 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
static int follow_dotdot_rcu(struct nameidata *nd)
{
+ struct dentry *parent = NULL;
struct inode *inode = nd->inode;
+ unsigned seq;
while (1) {
if (path_equal(&nd->path, &nd->root)) {
@@ -1375,15 +1377,12 @@ static int follow_dotdot_rcu(struct nameidata *nd)
}
if (nd->path.dentry != nd->path.mnt->mnt_root) {
struct dentry *old = nd->path.dentry;
- struct dentry *parent = old->d_parent;
- unsigned seq;
+ parent = old->d_parent;
inode = parent->d_inode;
seq = read_seqcount_begin(&parent->d_seq);
if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
return -ECHILD;
- nd->path.dentry = parent;
- nd->seq = seq;
if (unlikely(!path_connected(nd->path.mnt, parent)))
return -ECHILD;
break;
@@ -1406,6 +1405,10 @@ static int follow_dotdot_rcu(struct nameidata *nd)
nd->seq = seq;
}
}
+ if (likely(parent)) {
+ nd->path.dentry = parent;
+ nd->seq = seq;
+ }
while (unlikely(d_mountpoint(nd->path.dentry))) {
struct mount *mounted;
mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
@@ -1442,7 +1445,7 @@ static void follow_mount(struct path *path)
static int follow_dotdot(struct nameidata *nd)
{
- struct dentry *parent;
+ struct dentry *parent = NULL;
while (1) {
if (path_equal(&nd->path, &nd->root)) {
if (unlikely(nd->flags & LOOKUP_BENEATH))
@@ -1452,13 +1455,10 @@ static int follow_dotdot(struct nameidata *nd)
if (nd->path.dentry != nd->path.mnt->mnt_root) {
/* rare case of legitimate dget_parent()... */
parent = dget_parent(nd->path.dentry);
-
if (unlikely(!path_connected(nd->path.mnt, parent))) {
dput(parent);
return -ENOENT;
}
- dput(nd->path.dentry);
- nd->path.dentry = parent;
break;
}
if (!follow_up(&nd->path))
@@ -1466,6 +1466,10 @@ static int follow_dotdot(struct nameidata *nd)
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
return -EXDEV;
}
+ if (likely(parent)) {
+ dput(nd->path.dentry);
+ nd->path.dentry = parent;
+ }
follow_mount(&nd->path);
nd->inode = nd->path.dentry->d_inode;
return 0;