From 8877f9b8a8992388b4f64d425a48b02a3229cf61 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Fri, 27 Jun 2025 01:56:38 -0400 Subject: kernel: namei: Add NAMEI_WANTPARENT flag In some lookup cases, we may only be interested in the parent component. For example, the parent of "/foo/bar/mrow" is "/foo/bar/". The NAMEI_WANTPARENT asks namei to only look for the parent rather than the full path. Signed-off-by: Ian Moffett --- sys/include/sys/namei.h | 3 +++ sys/kern/vfs_lookup.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/sys/include/sys/namei.h b/sys/include/sys/namei.h index f81f905..ccd7f35 100644 --- a/sys/include/sys/namei.h +++ b/sys/include/sys/namei.h @@ -32,6 +32,9 @@ #include #include +#include + +#define NAMEI_WANTPARENT BIT(0) /* Request parent only */ struct nameidata { const char *path; /* Pathname */ diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index d04b812..d88c447 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -117,21 +118,61 @@ vfs_get_fname_at(const char *path, size_t idx) return ret; } +/* + * Count the number of components that exist within + * a path minus the delimiter as well as any redundant + * delimiters. + * + * @path: Path to count + */ +static uint8_t +namei_num_cnp(const char *path) +{ + const char *p = path; + uint8_t count = 0; + + while (*p != '\0') { + /* Skip redundant delimiters */ + if (p[0] == '/' && p[1] == '/') { + ++p; + continue; + } + + if (*p == '/') { + ++count; + } + ++p; + } + + /* Don't count leading slash */ + if (*(p - 1) == '/') { + --count; + } + + return count; +} + /* * Search for a path within a mountpoint. * * @mp: Mountpoint to search in. * @path: Path to search for. + * @ndp: Namei data pointer */ static struct vnode * -namei_mp_search(struct mount *mp, const char *path) +namei_mp_search(struct mount *mp, const char *path, struct nameidata *ndp) { struct vop_lookup_args lookup_args; struct vnode *vp = mp->vp; + uint8_t n_cnp = 0; char *name; int status; - for (size_t i = 1;; ++i) { + n_cnp = namei_num_cnp(path); + if (ISSET(ndp->flags, NAMEI_WANTPARENT)) { + --n_cnp; + } + for (size_t i = 1; i < n_cnp; ++i) { name = vfs_get_fname_at(path, i); if (name == NULL) break; @@ -212,7 +253,7 @@ namei(struct nameidata *ndp) /* If the name matches, search within */ if (strcmp(mp->name, name) == 0) - vp = namei_mp_search(mp, path); + vp = namei_mp_search(mp, path, ndp); /* Did we find it at this mountpoint? */ if (vp != NULL) { -- cgit v1.2.3