Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Jul 2015 15:06:58 +0000 (UTC)
From:      Mateusz Guzik <mjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r285320 - head/sys/kern
Message-ID:  <201507091506.t69F6xLX098157@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mjg
Date: Thu Jul  9 15:06:58 2015
New Revision: 285320
URL: https://svnweb.freebsd.org/changeset/base/285320

Log:
  vfs: avoid spurious vref/vrele for absolute lookups
  
  namei used to vref fd_cdir, which was immediatley vrele'd on entry to
  the loop.
  
  Check for absolute lookup and vref the right vnode the first time.
  
  Reviewed by:	kib

Modified:
  head/sys/kern/vfs_lookup.c

Modified: head/sys/kern/vfs_lookup.c
==============================================================================
--- head/sys/kern/vfs_lookup.c	Thu Jul  9 15:06:24 2015	(r285319)
+++ head/sys/kern/vfs_lookup.c	Thu Jul  9 15:06:58 2015	(r285320)
@@ -109,6 +109,27 @@ namei_cleanup_cnp(struct componentname *
 #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);
+}
+
 /*
  * Convert a pathname into a pointer to a locked vnode.
  *
@@ -222,7 +243,18 @@ namei(struct nameidata *ndp)
 		AUDIT_ARG_UPATH2(td, ndp->ni_dirfd, cnp->cn_pnbuf);
 
 	dp = NULL;
-	if (cnp->cn_pnbuf[0] != '/') {
+	cnp->cn_nameptr = cnp->cn_pnbuf;
+	if (cnp->cn_pnbuf[0] == '/') {
+		error = namei_handle_root(ndp, &dp);
+		FILEDESC_SUNLOCK(fdp);
+		if (error != 0) {
+			vrele(ndp->ni_rootdir);
+			if (ndp->ni_startdir != NULL)
+				vrele(ndp->ni_startdir);
+			namei_cleanup_cnp(cnp);
+			return (error);
+		}
+	} else {
 		if (ndp->ni_startdir != NULL) {
 			dp = ndp->ni_startdir;
 			error = 0;
@@ -276,29 +308,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
-				vrele(ndp->ni_rootdir);
-				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) {
@@ -375,6 +384,19 @@ namei(struct nameidata *ndp)
 		ndp->ni_pathlen += linklen;
 		vput(ndp->ni_vp);
 		dp = ndp->ni_dvp;
+		/*
+		 * Check if root directory should replace current directory.
+		 */
+		cnp->cn_nameptr = cnp->cn_pnbuf;
+		if (*(cnp->cn_nameptr) == '/') {
+			vrele(dp);
+			error = namei_handle_root(ndp, &dp);
+			if (error != 0) {
+				vrele(ndp->ni_rootdir);
+				namei_cleanup_cnp(cnp);
+				return (error);
+			}
+		}
 	}
 	vrele(ndp->ni_rootdir);
 	namei_cleanup_cnp(cnp);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507091506.t69F6xLX098157>