Currently for absolute lookups the kernel vrefs fd_cdir and
immediately unrefs it and vrefs root vnode.

Patch below changes the code to start with vrefing root vnode for
absolute lookups.

In a crap microbenchmark of 16 threads opening /foo file I got a ~6%
speedup.

The code may require further refactoring later.

diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index e4f9d64..421adb6 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -129,6 +129,27 @@ namei_cleanup_cnp(struct componentname *cnp)
 #endif
 }
 
+static int
+namei_handle_root(struct nameidata *ndp, struct vnode **dpp)
+{
+       struct componentname *cnp = &ndp->ni_cnd;
+
+       if (ndp->ni_strictrelative != 0) {
+#ifdef KTRACE
+               if (KTRPOINT(curthread, KTR_CAPFAIL))
+                       ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
+#endif
+               return (ENOTCAPABLE);
+       }
+       while (*(cnp->cn_nameptr) == '/') {
+               cnp->cn_nameptr++;
+               ndp->ni_pathlen--;
+       }
+       *dpp = ndp->ni_rootdir;
+       VREF(*dpp);
+       return (0);
+}
+
 int
 namei(struct nameidata *ndp)
 {
@@ -221,6 +242,7 @@ namei(struct nameidata *ndp)
                AUDIT_ARG_UPATH2(td, ndp->ni_dirfd, cnp->cn_pnbuf);
 
        dp = NULL;
+       cnp->cn_nameptr = cnp->cn_pnbuf;
        if (cnp->cn_pnbuf[0] != '/') {
                if (ndp->ni_startdir != NULL) {
                        dp = ndp->ni_startdir;
@@ -263,6 +285,15 @@ namei(struct nameidata *ndp)
                        namei_cleanup_cnp(cnp);
                        return (error);
                }
+       } else {
+               error = namei_handle_root(ndp, &dp);
+               FILEDESC_SUNLOCK(fdp);
+               if (ndp->ni_startdir != NULL)
+                       vrele(ndp->ni_startdir);
+               if (error != 0) {
+                       namei_cleanup_cnp(cnp);
+                       return (error);
+               }
        }
        if (dp == NULL) {
                dp = fdp->fd_cdir;
@@ -274,28 +305,6 @@ namei(struct nameidata *ndp)
        SDT_PROBE(vfs, namei, lookup, entry, dp, cnp->cn_pnbuf,
            cnp->cn_flags, 0, 0);
        for (;;) {
-               /*
-                * Check if root directory should replace current directory.
-                * Done at start of translation and after symbolic link.
-                */
-               cnp->cn_nameptr = cnp->cn_pnbuf;
-               if (*(cnp->cn_nameptr) == '/') {
-                       vrele(dp);
-                       if (ndp->ni_strictrelative != 0) {
-#ifdef KTRACE
-                               if (KTRPOINT(curthread, KTR_CAPFAIL))
-                                       ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
-#endif
-                               namei_cleanup_cnp(cnp);
-                               return (ENOTCAPABLE);
-                       }
-                       while (*(cnp->cn_nameptr) == '/') {
-                               cnp->cn_nameptr++;
-                               ndp->ni_pathlen--;
-                       }
-                       dp = ndp->ni_rootdir;
-                       VREF(dp);
-               }
                ndp->ni_startdir = dp;
                error = lookup(ndp);
                if (error) {
@@ -370,6 +379,18 @@ namei(struct nameidata *ndp)
                ndp->ni_pathlen += linklen;
                vput(ndp->ni_vp);
                dp = ndp->ni_dvp;
+               cnp->cn_nameptr = cnp->cn_pnbuf;
+               /*
+                * Check if root directory should replace current directory.
+                */
+               if (*(cnp->cn_nameptr) == '/') {
+                       vrele(dp);
+                       error = namei_handle_root(ndp, &dp);
+                       if (error != 0) {
+                               namei_cleanup_cnp(cnp);
+                               return (error);
+                       }
+               }
        }
        namei_cleanup_cnp(cnp);
        vput(ndp->ni_vp);
-- 
Mateusz Guzik <mjguzik gmail.com>
_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"

Reply via email to