Loading fs/namei.c +130 −130 Original line number Diff line number Diff line Loading @@ -1363,70 +1363,6 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry, return ret; } 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)) break; if (nd->path.dentry != nd->path.mnt->mnt_root) { struct dentry *old = nd->path.dentry; 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; if (unlikely(!path_connected(nd->path.mnt, parent))) return -ECHILD; break; } else { struct mount *mnt = real_mount(nd->path.mnt); struct mount *mparent = mnt->mnt_parent; struct dentry *mountpoint = mnt->mnt_mountpoint; struct inode *inode2 = mountpoint->d_inode; unsigned seq = read_seqcount_begin(&mountpoint->d_seq); if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) return -ECHILD; if (&mparent->mnt == nd->path.mnt) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -ECHILD; /* we know that mountpoint was pinned */ nd->path.dentry = mountpoint; nd->path.mnt = &mparent->mnt; inode = inode2; nd->seq = seq; } } if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH)) return -ECHILD; } else { 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); if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) return -ECHILD; if (!mounted) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -ECHILD; nd->path.mnt = &mounted->mnt; nd->path.dentry = mounted->mnt.mnt_root; inode = nd->path.dentry->d_inode; nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); } nd->inode = inode; return 0; } /* * Skip to top of mountpoint pile in refwalk mode for follow_dotdot() */ Loading @@ -1443,38 +1379,6 @@ static void follow_mount(struct path *path) } } static int follow_dotdot(struct nameidata *nd) { struct dentry *parent = NULL; while (1) { if (path_equal(&nd->path, &nd->root)) break; 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; } break; } if (!follow_up(&nd->path)) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -EXDEV; } if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH)) return -EXDEV; } else { dput(nd->path.dentry); nd->path.dentry = parent; } follow_mount(&nd->path); nd->inode = nd->path.dentry->d_inode; return 0; } /* * This looks up the name in dcache and possibly revalidates the found dentry. * NULL is returned if the dentry does not exist in the cache. Loading Loading @@ -1654,40 +1558,6 @@ static inline int may_lookup(struct nameidata *nd) return inode_permission(nd->inode, MAY_EXEC); } static inline int handle_dots(struct nameidata *nd, int type) { if (type == LAST_DOTDOT) { int error = 0; if (!nd->root.mnt) { error = set_root(nd); if (error) return error; } if (nd->flags & LOOKUP_RCU) error = follow_dotdot_rcu(nd); else error = follow_dotdot(nd); if (error) return error; if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) { /* * If there was a racing rename or mount along our * path, then we can't be sure that ".." hasn't jumped * above nd->root (and so userspace should retry or use * some fallback). */ smp_rmb(); if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq))) return -EAGAIN; if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq))) return -EAGAIN; } } return 0; } enum {WALK_TRAILING = 1, WALK_MORE = 2, WALK_NOFOLLOW = 4}; static const char *pick_link(struct nameidata *nd, struct path *link, Loading Loading @@ -1817,6 +1687,136 @@ static const char *step_into(struct nameidata *nd, int flags, return pick_link(nd, &path, inode, seq, flags); } 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)) break; if (nd->path.dentry != nd->path.mnt->mnt_root) { struct dentry *old = nd->path.dentry; 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; if (unlikely(!path_connected(nd->path.mnt, parent))) return -ECHILD; break; } else { struct mount *mnt = real_mount(nd->path.mnt); struct mount *mparent = mnt->mnt_parent; struct dentry *mountpoint = mnt->mnt_mountpoint; struct inode *inode2 = mountpoint->d_inode; unsigned seq = read_seqcount_begin(&mountpoint->d_seq); if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) return -ECHILD; if (&mparent->mnt == nd->path.mnt) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -ECHILD; /* we know that mountpoint was pinned */ nd->path.dentry = mountpoint; nd->path.mnt = &mparent->mnt; inode = inode2; nd->seq = seq; } } if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH)) return -ECHILD; } else { 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); if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) return -ECHILD; if (!mounted) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -ECHILD; nd->path.mnt = &mounted->mnt; nd->path.dentry = mounted->mnt.mnt_root; inode = nd->path.dentry->d_inode; nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); } nd->inode = inode; return 0; } static int follow_dotdot(struct nameidata *nd) { struct dentry *parent = NULL; while (1) { if (path_equal(&nd->path, &nd->root)) break; 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; } break; } if (!follow_up(&nd->path)) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -EXDEV; } if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH)) return -EXDEV; } else { dput(nd->path.dentry); nd->path.dentry = parent; } follow_mount(&nd->path); nd->inode = nd->path.dentry->d_inode; return 0; } static inline int handle_dots(struct nameidata *nd, int type) { if (type == LAST_DOTDOT) { int error = 0; if (!nd->root.mnt) { error = set_root(nd); if (error) return error; } if (nd->flags & LOOKUP_RCU) error = follow_dotdot_rcu(nd); else error = follow_dotdot(nd); if (error) return error; if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) { /* * If there was a racing rename or mount along our * path, then we can't be sure that ".." hasn't jumped * above nd->root (and so userspace should retry or use * some fallback). */ smp_rmb(); if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq))) return -EAGAIN; if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq))) return -EAGAIN; } } return 0; } static const char *walk_component(struct nameidata *nd, int flags) { struct dentry *dentry; Loading Loading
fs/namei.c +130 −130 Original line number Diff line number Diff line Loading @@ -1363,70 +1363,6 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry, return ret; } 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)) break; if (nd->path.dentry != nd->path.mnt->mnt_root) { struct dentry *old = nd->path.dentry; 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; if (unlikely(!path_connected(nd->path.mnt, parent))) return -ECHILD; break; } else { struct mount *mnt = real_mount(nd->path.mnt); struct mount *mparent = mnt->mnt_parent; struct dentry *mountpoint = mnt->mnt_mountpoint; struct inode *inode2 = mountpoint->d_inode; unsigned seq = read_seqcount_begin(&mountpoint->d_seq); if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) return -ECHILD; if (&mparent->mnt == nd->path.mnt) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -ECHILD; /* we know that mountpoint was pinned */ nd->path.dentry = mountpoint; nd->path.mnt = &mparent->mnt; inode = inode2; nd->seq = seq; } } if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH)) return -ECHILD; } else { 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); if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) return -ECHILD; if (!mounted) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -ECHILD; nd->path.mnt = &mounted->mnt; nd->path.dentry = mounted->mnt.mnt_root; inode = nd->path.dentry->d_inode; nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); } nd->inode = inode; return 0; } /* * Skip to top of mountpoint pile in refwalk mode for follow_dotdot() */ Loading @@ -1443,38 +1379,6 @@ static void follow_mount(struct path *path) } } static int follow_dotdot(struct nameidata *nd) { struct dentry *parent = NULL; while (1) { if (path_equal(&nd->path, &nd->root)) break; 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; } break; } if (!follow_up(&nd->path)) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -EXDEV; } if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH)) return -EXDEV; } else { dput(nd->path.dentry); nd->path.dentry = parent; } follow_mount(&nd->path); nd->inode = nd->path.dentry->d_inode; return 0; } /* * This looks up the name in dcache and possibly revalidates the found dentry. * NULL is returned if the dentry does not exist in the cache. Loading Loading @@ -1654,40 +1558,6 @@ static inline int may_lookup(struct nameidata *nd) return inode_permission(nd->inode, MAY_EXEC); } static inline int handle_dots(struct nameidata *nd, int type) { if (type == LAST_DOTDOT) { int error = 0; if (!nd->root.mnt) { error = set_root(nd); if (error) return error; } if (nd->flags & LOOKUP_RCU) error = follow_dotdot_rcu(nd); else error = follow_dotdot(nd); if (error) return error; if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) { /* * If there was a racing rename or mount along our * path, then we can't be sure that ".." hasn't jumped * above nd->root (and so userspace should retry or use * some fallback). */ smp_rmb(); if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq))) return -EAGAIN; if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq))) return -EAGAIN; } } return 0; } enum {WALK_TRAILING = 1, WALK_MORE = 2, WALK_NOFOLLOW = 4}; static const char *pick_link(struct nameidata *nd, struct path *link, Loading Loading @@ -1817,6 +1687,136 @@ static const char *step_into(struct nameidata *nd, int flags, return pick_link(nd, &path, inode, seq, flags); } 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)) break; if (nd->path.dentry != nd->path.mnt->mnt_root) { struct dentry *old = nd->path.dentry; 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; if (unlikely(!path_connected(nd->path.mnt, parent))) return -ECHILD; break; } else { struct mount *mnt = real_mount(nd->path.mnt); struct mount *mparent = mnt->mnt_parent; struct dentry *mountpoint = mnt->mnt_mountpoint; struct inode *inode2 = mountpoint->d_inode; unsigned seq = read_seqcount_begin(&mountpoint->d_seq); if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) return -ECHILD; if (&mparent->mnt == nd->path.mnt) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -ECHILD; /* we know that mountpoint was pinned */ nd->path.dentry = mountpoint; nd->path.mnt = &mparent->mnt; inode = inode2; nd->seq = seq; } } if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH)) return -ECHILD; } else { 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); if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) return -ECHILD; if (!mounted) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -ECHILD; nd->path.mnt = &mounted->mnt; nd->path.dentry = mounted->mnt.mnt_root; inode = nd->path.dentry->d_inode; nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); } nd->inode = inode; return 0; } static int follow_dotdot(struct nameidata *nd) { struct dentry *parent = NULL; while (1) { if (path_equal(&nd->path, &nd->root)) break; 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; } break; } if (!follow_up(&nd->path)) break; if (unlikely(nd->flags & LOOKUP_NO_XDEV)) return -EXDEV; } if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH)) return -EXDEV; } else { dput(nd->path.dentry); nd->path.dentry = parent; } follow_mount(&nd->path); nd->inode = nd->path.dentry->d_inode; return 0; } static inline int handle_dots(struct nameidata *nd, int type) { if (type == LAST_DOTDOT) { int error = 0; if (!nd->root.mnt) { error = set_root(nd); if (error) return error; } if (nd->flags & LOOKUP_RCU) error = follow_dotdot_rcu(nd); else error = follow_dotdot(nd); if (error) return error; if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) { /* * If there was a racing rename or mount along our * path, then we can't be sure that ".." hasn't jumped * above nd->root (and so userspace should retry or use * some fallback). */ smp_rmb(); if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq))) return -EAGAIN; if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq))) return -EAGAIN; } } return 0; } static const char *walk_component(struct nameidata *nd, int flags) { struct dentry *dentry; Loading