summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-06-27 01:56:38 -0400
committerIan Moffett <ian@osmora.org>2025-06-27 02:01:06 -0400
commit8877f9b8a8992388b4f64d425a48b02a3229cf61 (patch)
tree14d161e9d6471821f02429bc9465fd75caf4524f
parentb9ecd48242fd2e08242704d2d0d1b919f88401c2 (diff)
kernel: namei: Add NAMEI_WANTPARENT flagexpt
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 <ian@osmora.org>
-rw-r--r--sys/include/sys/namei.h3
-rw-r--r--sys/kern/vfs_lookup.c47
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 <sys/types.h>
#include <sys/vnode.h>
+#include <sys/param.h>
+
+#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 <sys/namei.h>
#include <sys/vnode.h>
+#include <sys/param.h>
#include <sys/mount.h>
#include <sys/errno.h>
#include <vm/dynalloc.h>
@@ -118,20 +119,60 @@ vfs_get_fname_at(const char *path, size_t idx)
}
/*
+ * 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) {