namei: avoid needless relocking for absolute lookups
Mateusz Guzik
mjguzik at gmail.com
Mon Sep 1 19:55:26 UTC 2014
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>
More information about the freebsd-current
mailing list