Skip to content

Commit 12487f3

Browse files
author
Al Viro
committed
follow_dotdot{,_rcu}(): massage loops
The logics in both of them is the same: while true if in process' root // uncommon break if *not* in mount root // normal case find the parent return if at absolute root // very uncommon break move to underlying mountpoint report that we are in root Pull the common path out of the loop: if in process' root // uncommon goto in_root if unlikely(in mount root) while true if at absolute root goto in_root move to underlying mountpoint if in process' root goto in_root if in mount root break; find the parent // we are not in mount root return in_root: report that we are in root The reason for that transformation is that we get to keep the common path straight *and* get a separate block for "move through underlying mountpoints", which will allow to sanitize NO_XDEV handling there. What's more, the pared-down loops will be easier to deal with - in particular, non-RCU case has no need to grab mount_lock and rewriting it to the form that wouldn't do that is a non-trivial change. Better do that with less stuff getting in the way... Signed-off-by: Al Viro <[email protected]>
1 parent c2df196 commit 12487f3

File tree

1 file changed

+45
-32
lines changed

1 file changed

+45
-32
lines changed

fs/namei.c

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,21 +1691,12 @@ static struct dentry *follow_dotdot_rcu(struct nameidata *nd,
16911691
struct inode **inodep,
16921692
unsigned *seqp)
16931693
{
1694-
while (1) {
1695-
if (path_equal(&nd->path, &nd->root))
1696-
break;
1697-
if (nd->path.dentry != nd->path.mnt->mnt_root) {
1698-
struct dentry *old = nd->path.dentry;
1699-
struct dentry *parent = old->d_parent;
1694+
struct dentry *parent, *old;
17001695

1701-
*inodep = parent->d_inode;
1702-
*seqp = read_seqcount_begin(&parent->d_seq);
1703-
if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
1704-
return ERR_PTR(-ECHILD);
1705-
if (unlikely(!path_connected(nd->path.mnt, parent)))
1706-
return ERR_PTR(-ECHILD);
1707-
return parent;
1708-
} else {
1696+
if (path_equal(&nd->path, &nd->root))
1697+
goto in_root;
1698+
if (unlikely(nd->path.dentry == nd->path.mnt->mnt_root)) {
1699+
while (1) {
17091700
struct mount *mnt = real_mount(nd->path.mnt);
17101701
struct mount *mparent = mnt->mnt_parent;
17111702
struct dentry *mountpoint = mnt->mnt_mountpoint;
@@ -1714,16 +1705,30 @@ static struct dentry *follow_dotdot_rcu(struct nameidata *nd,
17141705
if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
17151706
return ERR_PTR(-ECHILD);
17161707
if (&mparent->mnt == nd->path.mnt)
1717-
break;
1708+
goto in_root;
17181709
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
17191710
return ERR_PTR(-ECHILD);
17201711
/* we know that mountpoint was pinned */
17211712
nd->path.dentry = mountpoint;
17221713
nd->path.mnt = &mparent->mnt;
17231714
nd->inode = inode;
17241715
nd->seq = seq;
1716+
if (path_equal(&nd->path, &nd->root))
1717+
goto in_root;
1718+
if (nd->path.dentry != nd->path.mnt->mnt_root)
1719+
break;
17251720
}
17261721
}
1722+
old = nd->path.dentry;
1723+
parent = old->d_parent;
1724+
*inodep = parent->d_inode;
1725+
*seqp = read_seqcount_begin(&parent->d_seq);
1726+
if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
1727+
return ERR_PTR(-ECHILD);
1728+
if (unlikely(!path_connected(nd->path.mnt, parent)))
1729+
return ERR_PTR(-ECHILD);
1730+
return parent;
1731+
in_root:
17271732
if (unlikely(nd->flags & LOOKUP_BENEATH))
17281733
return ERR_PTR(-ECHILD);
17291734
return NULL;
@@ -1733,25 +1738,33 @@ static struct dentry *follow_dotdot(struct nameidata *nd,
17331738
struct inode **inodep,
17341739
unsigned *seqp)
17351740
{
1736-
while (1) {
1737-
if (path_equal(&nd->path, &nd->root))
1738-
break;
1739-
if (nd->path.dentry != nd->path.mnt->mnt_root) {
1740-
/* rare case of legitimate dget_parent()... */
1741-
struct dentry *parent = dget_parent(nd->path.dentry);
1742-
if (unlikely(!path_connected(nd->path.mnt, parent))) {
1743-
dput(parent);
1744-
return ERR_PTR(-ENOENT);
1745-
}
1746-
*seqp = 0;
1747-
*inodep = parent->d_inode;
1748-
return parent;
1741+
struct dentry *parent;
1742+
1743+
if (path_equal(&nd->path, &nd->root))
1744+
goto in_root;
1745+
if (unlikely(nd->path.dentry == nd->path.mnt->mnt_root)) {
1746+
while (1) {
1747+
if (!follow_up(&nd->path))
1748+
goto in_root;
1749+
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
1750+
return ERR_PTR(-EXDEV);
1751+
if (path_equal(&nd->path, &nd->root))
1752+
goto in_root;
1753+
if (nd->path.dentry != nd->path.mnt->mnt_root)
1754+
break;
17491755
}
1750-
if (!follow_up(&nd->path))
1751-
break;
1752-
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
1753-
return ERR_PTR(-EXDEV);
17541756
}
1757+
/* rare case of legitimate dget_parent()... */
1758+
parent = dget_parent(nd->path.dentry);
1759+
if (unlikely(!path_connected(nd->path.mnt, parent))) {
1760+
dput(parent);
1761+
return ERR_PTR(-ENOENT);
1762+
}
1763+
*seqp = 0;
1764+
*inodep = parent->d_inode;
1765+
return parent;
1766+
1767+
in_root:
17551768
if (unlikely(nd->flags & LOOKUP_BENEATH))
17561769
return ERR_PTR(-EXDEV);
17571770
dget(nd->path.dentry);

0 commit comments

Comments
 (0)