[PATCH v2 bpf-next 1/4] namei: Introduce new helper function path_walk_parent()
From: Song Liu <song@kernel.org>
Date: 2025-06-03 06:59:37
Also in:
bpf, linux-fsdevel, lkml
Subsystem:
filesystems (vfs and infrastructure), the rest · Maintainers:
Alexander Viro, Christian Brauner, Linus Torvalds
This helper walks an input path to its parent. Logic are added to handle walking across mount tree. This will be used by landlock, and BPF LSM. Signed-off-by: Song Liu <song@kernel.org> --- fs/namei.c | 52 +++++++++++++++++++++++++++++++++++++++++++ include/linux/namei.h | 2 ++ 2 files changed, 54 insertions(+)
diff --git a/fs/namei.c b/fs/namei.c
index 4bb889fc980b..7d5bf2bb604f 100644
--- a/fs/namei.c
+++ b/fs/namei.c@@ -1424,6 +1424,58 @@ static bool choose_mountpoint(struct mount *m, const struct path *root, return found; } +/** + * path_walk_parent - Walk to the parent of path + * @path: input and output path. + * @root: root of the path walk, do not go beyond this root. If @root is + * zero'ed, walk all the way to real root. + * + * Given a path, find the parent path. Replace @path with the parent path. + * If we were already at the real root or a disconnected root, @path is + * not changed. + * + * The logic of path_walk_parent() is similar to follow_dotdot(), except + * that path_walk_parent() will continue walking for !path_connected case. + * This effectively means we are walking from disconnectedbind mount to the + * original mount point. If this behavior is not desired, the caller can + * add a check like: + * + * if (path_walk_parent(&path) && !path_connected(path.mnt, path.dentry) + * // continue walking + * else + * // stop walking + * + * Returns: + * true - if @path is updated to its parent. + * false - if @path is already the root (real root or @root). + */ +bool path_walk_parent(struct path *path, const struct path *root) +{ + struct dentry *parent; + + if (path_equal(path, root)) + return false; + + if (unlikely(path->dentry == path->mnt->mnt_root)) { + struct path p; + + if (!choose_mountpoint(real_mount(path->mnt), root, &p)) + return false; + path_put(path); + *path = p; + return true; + } + + if (unlikely(IS_ROOT(path->dentry))) + return false; + + parent = dget_parent(path->dentry); + dput(path->dentry); + path->dentry = parent; + return true; +} +EXPORT_SYMBOL_GPL(path_walk_parent); + /* * Perform an automount * - return -EISDIR to tell follow_managed() to stop and return the path we
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 5d085428e471..cba5373ecf86 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h@@ -85,6 +85,8 @@ extern int follow_down_one(struct path *); extern int follow_down(struct path *path, unsigned int flags); extern int follow_up(struct path *); +bool path_walk_parent(struct path *path, const struct path *root); + extern struct dentry *lock_rename(struct dentry *, struct dentry *); extern struct dentry *lock_rename_child(struct dentry *, struct dentry *); extern void unlock_rename(struct dentry *, struct dentry *);
--
2.47.1