From: Al Viro Date: Fri, 28 Feb 2020 15:17:52 +0000 (-0500) Subject: follow_dotdot(): be lazy about changing nd->path X-Git-Tag: v5.15~4182^2~17 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=165200d6cb88a3cc1fdeb12e11e97fb96bf685d9;p=platform%2Fkernel%2Flinux-starfive.git follow_dotdot(): be lazy about changing nd->path Change nd->path only after the loop is done and only in case we hadn't ended up finding ourselves in root. Same for NO_XDEV check. That separates the "check how far back do we need to go through the mount stack" logics from the rest of .. traversal. NOTE: path_get/path_put introduced here are temporary. They will go away later in the series. Signed-off-by: Al Viro --- diff --git a/fs/namei.c b/fs/namei.c index af18ede..9cfb709 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1748,16 +1748,24 @@ static struct dentry *follow_dotdot(struct nameidata *nd, if (path_equal(&nd->path, &nd->root)) goto in_root; if (unlikely(nd->path.dentry == nd->path.mnt->mnt_root)) { + struct path path = nd->path; + path_get(&path); while (1) { - if (!follow_up(&nd->path)) + if (!follow_up(&path)) { + path_put(&path); goto in_root; - if (unlikely(nd->flags & LOOKUP_NO_XDEV)) - return ERR_PTR(-EXDEV); - if (path_equal(&nd->path, &nd->root)) + } + if (path_equal(&path, &nd->root)) { + path_put(&path); goto in_root; - if (nd->path.dentry != nd->path.mnt->mnt_root) + } + if (path.dentry != nd->path.mnt->mnt_root) break; } + path_put(&nd->path); + nd->path = path; + if (unlikely(nd->flags & LOOKUP_NO_XDEV)) + return ERR_PTR(-EXDEV); } /* rare case of legitimate dget_parent()... */ parent = dget_parent(nd->path.dentry);