vfs_cache.c revision 187658
1139804Simp/*-
222521Sdyson * Copyright (c) 1989, 1993, 1995
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
522521Sdyson * This code is derived from software contributed to Berkeley by
622521Sdyson * Poul-Henning Kamp of the FreeBSD Project.
722521Sdyson *
81541Srgrimes * Redistribution and use in source and binary forms, with or without
91541Srgrimes * modification, are permitted provided that the following conditions
101541Srgrimes * are met:
111541Srgrimes * 1. Redistributions of source code must retain the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer in the
151541Srgrimes *    documentation and/or other materials provided with the distribution.
161541Srgrimes * 4. Neither the name of the University nor the names of its contributors
171541Srgrimes *    may be used to endorse or promote products derived from this software
181541Srgrimes *    without specific prior written permission.
191541Srgrimes *
201541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301541Srgrimes * SUCH DAMAGE.
311541Srgrimes *
3223521Sbde *	@(#)vfs_cache.c	8.5 (Berkeley) 3/22/95
331541Srgrimes */
341541Srgrimes
35116182Sobrien#include <sys/cdefs.h>
36116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/vfs_cache.c 187658 2009-01-23 22:49:23Z jhb $");
37116182Sobrien
381541Srgrimes#include <sys/param.h>
39183155Sjhb#include <sys/filedesc.h>
40183155Sjhb#include <sys/fnv_hash.h>
4112820Sphk#include <sys/kernel.h>
4276166Smarkm#include <sys/lock.h>
43183155Sjhb#include <sys/malloc.h>
44183155Sjhb#include <sys/mount.h>
4589316Salfred#include <sys/mutex.h>
461541Srgrimes#include <sys/namei.h>
47183155Sjhb#include <sys/proc.h>
48102870Siedowse#include <sys/syscallsubr.h>
49183155Sjhb#include <sys/sysctl.h>
5051906Sphk#include <sys/sysproto.h>
51183155Sjhb#include <sys/systm.h>
52183155Sjhb#include <sys/vnode.h>
531541Srgrimes
54116289Sdes#include <vm/uma.h>
55116289Sdes
5651906Sphk/*
5759652Sgreen * This structure describes the elements in the cache of recent
5859652Sgreen * names looked up by namei.
5959652Sgreen */
6059652Sgreen
6159652Sgreenstruct	namecache {
6260938Sjake	LIST_ENTRY(namecache) nc_hash;	/* hash chain */
6360938Sjake	LIST_ENTRY(namecache) nc_src;	/* source vnode list */
6460938Sjake	TAILQ_ENTRY(namecache) nc_dst;	/* destination vnode list */
6559652Sgreen	struct	vnode *nc_dvp;		/* vnode of parent of name */
6659652Sgreen	struct	vnode *nc_vp;		/* vnode the name refers to */
6759652Sgreen	u_char	nc_flag;		/* flag bits */
6859652Sgreen	u_char	nc_nlen;		/* length of name */
6959652Sgreen	char	nc_name[0];		/* segment name */
7059652Sgreen};
7159652Sgreen
7259652Sgreen/*
731541Srgrimes * Name caching works as follows:
741541Srgrimes *
751541Srgrimes * Names found by directory scans are retained in a cache
761541Srgrimes * for future reference.  It is managed LRU, so frequently
771541Srgrimes * used names will hang around.  Cache is indexed by hash value
781541Srgrimes * obtained from (vp, name) where vp refers to the directory
791541Srgrimes * containing name.
801541Srgrimes *
8122521Sdyson * If it is a "negative" entry, (i.e. for a name that is known NOT to
8222521Sdyson * exist) the vnode pointer will be NULL.
836968Sphk *
841541Srgrimes * Upon reaching the last segment of a path, if the reference
851541Srgrimes * is for DELETE, or NOCACHE is set (rewrite), and the
861541Srgrimes * name is located in the cache, it will be dropped.
871541Srgrimes */
881541Srgrimes
891541Srgrimes/*
901541Srgrimes * Structures associated with name cacheing.
911541Srgrimes */
9274501Speter#define NCHHASH(hash) \
9374501Speter	(&nchashtbl[(hash) & nchash])
9460938Sjakestatic LIST_HEAD(nchashhead, namecache) *nchashtbl;	/* Hash Table */
9560938Sjakestatic TAILQ_HEAD(, namecache) ncneg;	/* Hash Table */
9623521Sbdestatic u_long	nchash;			/* size of hash table */
9762622SjhbSYSCTL_ULONG(_debug, OID_AUTO, nchash, CTLFLAG_RD, &nchash, 0, "");
9825453Sphkstatic u_long	ncnegfactor = 16;	/* ratio of negative entries */
9962622SjhbSYSCTL_ULONG(_debug, OID_AUTO, ncnegfactor, CTLFLAG_RW, &ncnegfactor, 0, "");
10091690Seivindstatic u_long	numneg;			/* number of cache entries allocated */
10162622SjhbSYSCTL_ULONG(_debug, OID_AUTO, numneg, CTLFLAG_RD, &numneg, 0, "");
10223521Sbdestatic u_long	numcache;		/* number of cache entries allocated */
10362622SjhbSYSCTL_ULONG(_debug, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0, "");
10475654Stanimurastatic u_long	numcachehv;		/* number of cache entries with vnodes held */
10575654StanimuraSYSCTL_ULONG(_debug, OID_AUTO, numcachehv, CTLFLAG_RD, &numcachehv, 0, "");
10684249Sdillon#if 0
10775654Stanimurastatic u_long	numcachepl;		/* number of cache purge for leaf entries */
10875654StanimuraSYSCTL_ULONG(_debug, OID_AUTO, numcachepl, CTLFLAG_RD, &numcachepl, 0, "");
10984249Sdillon#endif
11022521Sdysonstruct	nchstats nchstats;		/* cache effectiveness statistics */
1111541Srgrimes
112141627Sphkstatic struct mtx cache_lock;
113120792SjeffMTX_SYSINIT(vfscache, &cache_lock, "Name Cache", MTX_DEF);
114120792Sjeff
115120792Sjeff#define	CACHE_LOCK()	mtx_lock(&cache_lock)
116120792Sjeff#define	CACHE_UNLOCK()	mtx_unlock(&cache_lock)
117120792Sjeff
118116289Sdes/*
119116289Sdes * UMA zones for the VFS cache.
120116289Sdes *
121116289Sdes * The small cache is used for entries with short names, which are the
122116289Sdes * most common.  The large cache is used for entries which are too big to
123116289Sdes * fit in the small cache.
124116289Sdes */
125116289Sdesstatic uma_zone_t cache_zone_small;
126116289Sdesstatic uma_zone_t cache_zone_large;
127116289Sdes
128116289Sdes#define	CACHE_PATH_CUTOFF	32
129116289Sdes#define	CACHE_ZONE_SMALL	(sizeof(struct namecache) + CACHE_PATH_CUTOFF)
130116289Sdes#define	CACHE_ZONE_LARGE	(sizeof(struct namecache) + NAME_MAX)
131116289Sdes
132116289Sdes#define cache_alloc(len)	uma_zalloc(((len) <= CACHE_PATH_CUTOFF) ? \
133116289Sdes	cache_zone_small : cache_zone_large, M_WAITOK)
134116289Sdes#define cache_free(ncp)		do { \
135116289Sdes	if (ncp != NULL) \
136116289Sdes		uma_zfree(((ncp)->nc_nlen <= CACHE_PATH_CUTOFF) ? \
137116289Sdes		    cache_zone_small : cache_zone_large, (ncp)); \
138116289Sdes} while (0)
139116289Sdes
14023521Sbdestatic int	doingcache = 1;		/* 1 => enable the cache */
14123521SbdeSYSCTL_INT(_debug, OID_AUTO, vfscache, CTLFLAG_RW, &doingcache, 0, "");
14291690Seivind
14391690Seivind/* Export size information to userland */
144157799SjmgSYSCTL_INT(_debug_sizeof, OID_AUTO, namecache, CTLFLAG_RD, 0,
145157799Sjmg	sizeof(struct namecache), "");
14623521Sbde
14729788Sphk/*
14829788Sphk * The new name cache statistics
14929788Sphk */
150141627Sphkstatic SYSCTL_NODE(_vfs, OID_AUTO, cache, CTLFLAG_RW, 0, "Name cache statistics");
15129788Sphk#define STATNODE(mode, name, var) \
15262622Sjhb	SYSCTL_ULONG(_vfs_cache, OID_AUTO, name, mode, var, 0, "");
15329788SphkSTATNODE(CTLFLAG_RD, numneg, &numneg);
15429788SphkSTATNODE(CTLFLAG_RD, numcache, &numcache);
15529788Sphkstatic u_long numcalls; STATNODE(CTLFLAG_RD, numcalls, &numcalls);
15629788Sphkstatic u_long dothits; STATNODE(CTLFLAG_RD, dothits, &dothits);
15729788Sphkstatic u_long dotdothits; STATNODE(CTLFLAG_RD, dotdothits, &dotdothits);
15829788Sphkstatic u_long numchecks; STATNODE(CTLFLAG_RD, numchecks, &numchecks);
15929788Sphkstatic u_long nummiss; STATNODE(CTLFLAG_RD, nummiss, &nummiss);
16029804Sphkstatic u_long nummisszap; STATNODE(CTLFLAG_RD, nummisszap, &nummisszap);
16129788Sphkstatic u_long numposzaps; STATNODE(CTLFLAG_RD, numposzaps, &numposzaps);
16229788Sphkstatic u_long numposhits; STATNODE(CTLFLAG_RD, numposhits, &numposhits);
16329788Sphkstatic u_long numnegzaps; STATNODE(CTLFLAG_RD, numnegzaps, &numnegzaps);
16429788Sphkstatic u_long numneghits; STATNODE(CTLFLAG_RD, numneghits, &numneghits);
16529788Sphk
166187658SjhbSYSCTL_OPAQUE(_vfs_cache, OID_AUTO, nchstats, CTLFLAG_RD | CTLFLAG_MPSAFE,
167187658Sjhb	&nchstats, sizeof(nchstats), "LU", "VFS cache effectiveness statistics");
16829788Sphk
16968922Srwatson
17068922Srwatson
171140712Sjeffstatic void cache_zap(struct namecache *ncp);
172185956Smarcusstatic int vn_vptocnp(struct vnode **vp, char **bp, char *buf, u_int *buflen);
173144318Sdasstatic int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
174144318Sdas    char *buf, char **retbuf, u_int buflen);
1756968Sphk
17669774Sphkstatic MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
17751906Sphk
17822521Sdyson/*
17925453Sphk * Flags in namecache.nc_flag
18025453Sphk */
18125453Sphk#define NCF_WHITE	1
18275402Speter
18325453Sphk/*
18475402Speter * Grab an atomic snapshot of the name cache hash chain lengths
18575402Speter */
18675402SpeterSYSCTL_NODE(_debug, OID_AUTO, hashstat, CTLFLAG_RW, NULL, "hash table stats");
18775402Speter
18875402Speterstatic int
18975402Spetersysctl_debug_hashstat_rawnchash(SYSCTL_HANDLER_ARGS)
19075402Speter{
19175402Speter	int error;
19275402Speter	struct nchashhead *ncpp;
19375402Speter	struct namecache *ncp;
19475402Speter	int n_nchash;
19575402Speter	int count;
19675402Speter
19775402Speter	n_nchash = nchash + 1;	/* nchash is max index, not count */
19875402Speter	if (!req->oldptr)
19975402Speter		return SYSCTL_OUT(req, 0, n_nchash * sizeof(int));
20075402Speter
20175402Speter	/* Scan hash tables for applicable entries */
20275402Speter	for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) {
203181793Salfred		CACHE_LOCK();
20475402Speter		count = 0;
20575402Speter		LIST_FOREACH(ncp, ncpp, nc_hash) {
20675402Speter			count++;
20775402Speter		}
208181793Salfred		CACHE_UNLOCK();
20998994Salfred		error = SYSCTL_OUT(req, &count, sizeof(count));
21075402Speter		if (error)
21175402Speter			return (error);
21275402Speter	}
21375402Speter	return (0);
21475402Speter}
215187658SjhbSYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnchash, CTLTYPE_INT|CTLFLAG_RD|
216187658Sjhb	CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_rawnchash, "S,int",
217187658Sjhb	"nchash chain lengths");
21875402Speter
21975402Speterstatic int
22075402Spetersysctl_debug_hashstat_nchash(SYSCTL_HANDLER_ARGS)
22175402Speter{
22275402Speter	int error;
22375402Speter	struct nchashhead *ncpp;
22475402Speter	struct namecache *ncp;
22575402Speter	int n_nchash;
22675402Speter	int count, maxlength, used, pct;
22775402Speter
22875402Speter	if (!req->oldptr)
22975402Speter		return SYSCTL_OUT(req, 0, 4 * sizeof(int));
23075402Speter
23175402Speter	n_nchash = nchash + 1;	/* nchash is max index, not count */
23275402Speter	used = 0;
23375402Speter	maxlength = 0;
23475402Speter
23575402Speter	/* Scan hash tables for applicable entries */
23675402Speter	for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) {
23775402Speter		count = 0;
238181793Salfred		CACHE_LOCK();
23975402Speter		LIST_FOREACH(ncp, ncpp, nc_hash) {
24075402Speter			count++;
24175402Speter		}
242181793Salfred		CACHE_UNLOCK();
24375402Speter		if (count)
24475402Speter			used++;
24575402Speter		if (maxlength < count)
24675402Speter			maxlength = count;
24775402Speter	}
24875402Speter	n_nchash = nchash + 1;
24975402Speter	pct = (used * 100 * 100) / n_nchash;
25098994Salfred	error = SYSCTL_OUT(req, &n_nchash, sizeof(n_nchash));
25175402Speter	if (error)
25275402Speter		return (error);
25398994Salfred	error = SYSCTL_OUT(req, &used, sizeof(used));
25475402Speter	if (error)
25575402Speter		return (error);
25698994Salfred	error = SYSCTL_OUT(req, &maxlength, sizeof(maxlength));
25775402Speter	if (error)
25875402Speter		return (error);
25998994Salfred	error = SYSCTL_OUT(req, &pct, sizeof(pct));
26075402Speter	if (error)
26175402Speter		return (error);
26275402Speter	return (0);
26375402Speter}
264187658SjhbSYSCTL_PROC(_debug_hashstat, OID_AUTO, nchash, CTLTYPE_INT|CTLFLAG_RD|
265187658Sjhb	CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_nchash, "I",
266187658Sjhb	"nchash chain lengths");
26775402Speter
26875402Speter/*
269110952Sarr * cache_zap():
270110952Sarr *
271110952Sarr *   Removes a namecache entry from cache, whether it contains an actual
272110952Sarr *   pointer to a vnode or if it is just a negative cache entry.
27322521Sdyson */
27425453Sphkstatic void
275140712Sjeffcache_zap(ncp)
27625453Sphk	struct namecache *ncp;
27725453Sphk{
278120792Sjeff	struct vnode *vp;
279120792Sjeff
280140712Sjeff	mtx_assert(&cache_lock, MA_OWNED);
281147326Sjeff	CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, ncp->nc_vp);
282120792Sjeff	vp = NULL;
28325453Sphk	LIST_REMOVE(ncp, nc_hash);
28425453Sphk	LIST_REMOVE(ncp, nc_src);
28575654Stanimura	if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src)) {
286120792Sjeff		vp = ncp->nc_dvp;
28775654Stanimura		numcachehv--;
28875654Stanimura	}
28925453Sphk	if (ncp->nc_vp) {
29025453Sphk		TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst);
291147331Sjeff		ncp->nc_vp->v_dd = NULL;
29225453Sphk	} else {
29325453Sphk		TAILQ_REMOVE(&ncneg, ncp, nc_dst);
29425453Sphk		numneg--;
29525453Sphk	}
29625453Sphk	numcache--;
297116289Sdes	cache_free(ncp);
298120792Sjeff	if (vp)
299120792Sjeff		vdrop(vp);
30022521Sdyson}
3016968Sphk
30222521Sdyson/*
30323521Sbde * Lookup an entry in the cache
3046968Sphk *
3056968Sphk * Lookup is called with dvp pointing to the directory to search,
30622521Sdyson * cnp pointing to the name of the entry being sought. If the lookup
30722521Sdyson * succeeds, the vnode is returned in *vpp, and a status of -1 is
30822521Sdyson * returned. If the lookup determines that the name does not exist
30922521Sdyson * (negative cacheing), a status of ENOENT is returned. If the lookup
310183330Sjhb * fails, a status of zero is returned.  If the directory vnode is
311183330Sjhb * recycled out from under us due to a forced unmount, a status of
312183330Sjhb * EBADF is returned.
313144296Sjeff *
314144296Sjeff * vpp is locked and ref'd on return.  If we're looking up DOTDOT, dvp is
315144296Sjeff * unlocked.  If we're looking up . an extra ref is taken, but the lock is
316144296Sjeff * not recursively acquired.
3171541Srgrimes */
3186968Sphk
3191541Srgrimesint
3201541Srgrimescache_lookup(dvp, vpp, cnp)
3211541Srgrimes	struct vnode *dvp;
3221541Srgrimes	struct vnode **vpp;
3231541Srgrimes	struct componentname *cnp;
3241541Srgrimes{
32551906Sphk	struct namecache *ncp;
32674384Speter	u_int32_t hash;
327170000Spjd	int error, ltype;
3281541Srgrimes
3296928Sphk	if (!doingcache) {
3306928Sphk		cnp->cn_flags &= ~MAKEENTRY;
3311541Srgrimes		return (0);
3326928Sphk	}
333144296Sjeffretry:
334120792Sjeff	CACHE_LOCK();
33529788Sphk	numcalls++;
33629788Sphk
33725453Sphk	if (cnp->cn_nameptr[0] == '.') {
33825453Sphk		if (cnp->cn_namelen == 1) {
33925453Sphk			*vpp = dvp;
340147326Sjeff			CTR2(KTR_VFS, "cache_lookup(%p, %s) found via .",
341147326Sjeff			    dvp, cnp->cn_nameptr);
34229788Sphk			dothits++;
343144296Sjeff			goto success;
34425453Sphk		}
34525453Sphk		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
34629788Sphk			dotdothits++;
347144319Sdas			if (dvp->v_dd == NULL ||
34825453Sphk			    (cnp->cn_flags & MAKEENTRY) == 0) {
349120792Sjeff				CACHE_UNLOCK();
35025453Sphk				return (0);
35125453Sphk			}
35225453Sphk			*vpp = dvp->v_dd;
353147326Sjeff			CTR3(KTR_VFS, "cache_lookup(%p, %s) found %p via ..",
354147326Sjeff			    dvp, cnp->cn_nameptr, *vpp);
355144296Sjeff			goto success;
35625453Sphk		}
3571541Srgrimes	}
3586968Sphk
35974501Speter	hash = fnv_32_buf(cnp->cn_nameptr, cnp->cn_namelen, FNV1_32_INIT);
360144319Sdas	hash = fnv_32_buf(&dvp, sizeof(dvp), hash);
36174501Speter	LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) {
36229788Sphk		numchecks++;
36325453Sphk		if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen &&
36431879Sbde		    !bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen))
36522521Sdyson			break;
3661541Srgrimes	}
3676968Sphk
36822521Sdyson	/* We failed to find an entry */
36922521Sdyson	if (ncp == 0) {
37029804Sphk		if ((cnp->cn_flags & MAKEENTRY) == 0) {
37129804Sphk			nummisszap++;
37229804Sphk		} else {
37329804Sphk			nummiss++;
37429804Sphk		}
37522521Sdyson		nchstats.ncs_miss++;
376120792Sjeff		CACHE_UNLOCK();
37722521Sdyson		return (0);
37822521Sdyson	}
37922521Sdyson
3806968Sphk	/* We don't want to have an entry, so dump it */
3816928Sphk	if ((cnp->cn_flags & MAKEENTRY) == 0) {
38229788Sphk		numposzaps++;
3831541Srgrimes		nchstats.ncs_badhits++;
384140712Sjeff		cache_zap(ncp);
385120792Sjeff		CACHE_UNLOCK();
3866968Sphk		return (0);
38723521Sbde	}
3886968Sphk
3896968Sphk	/* We found a "positive" match, return the vnode */
390116201Sdes	if (ncp->nc_vp) {
39129788Sphk		numposhits++;
3921541Srgrimes		nchstats.ncs_goodhits++;
3931541Srgrimes		*vpp = ncp->nc_vp;
394147326Sjeff		CTR4(KTR_VFS, "cache_lookup(%p, %s) found %p via ncp %p",
395147326Sjeff		    dvp, cnp->cn_nameptr, *vpp, ncp);
396144296Sjeff		goto success;
3971541Srgrimes	}
3981541Srgrimes
3996968Sphk	/* We found a negative match, and want to create it, so purge */
4006968Sphk	if (cnp->cn_nameiop == CREATE) {
40129788Sphk		numnegzaps++;
4027013Sphk		nchstats.ncs_badhits++;
403140712Sjeff		cache_zap(ncp);
404120792Sjeff		CACHE_UNLOCK();
4056968Sphk		return (0);
4066968Sphk	}
4076968Sphk
40829788Sphk	numneghits++;
40922521Sdyson	/*
410110967Sarr	 * We found a "negative" match, so we shift it to the end of
411110967Sarr	 * the "negative" cache entries queue to satisfy LRU.  Also,
412110967Sarr	 * check to see if the entry is a whiteout; indicate this to
413110967Sarr	 * the componentname, if so.
41422521Sdyson	 */
41525453Sphk	TAILQ_REMOVE(&ncneg, ncp, nc_dst);
41625453Sphk	TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
4176968Sphk	nchstats.ncs_neghits++;
41825453Sphk	if (ncp->nc_flag & NCF_WHITE)
41925453Sphk		cnp->cn_flags |= ISWHITEOUT;
420120792Sjeff	CACHE_UNLOCK();
4216968Sphk	return (ENOENT);
422144296Sjeff
423144296Sjeffsuccess:
424144296Sjeff	/*
425144296Sjeff	 * On success we return a locked and ref'd vnode as per the lookup
426144296Sjeff	 * protocol.
427144296Sjeff	 */
428144296Sjeff	if (dvp == *vpp) {   /* lookup on "." */
429144296Sjeff		VREF(*vpp);
430144296Sjeff		CACHE_UNLOCK();
431172274Spjd		/*
432172274Spjd		 * When we lookup "." we still can be asked to lock it
433172274Spjd		 * differently...
434172274Spjd		 */
435178046Spjd		ltype = cnp->cn_lkflags & LK_TYPE_MASK;
436183330Sjhb		if (ltype != VOP_ISLOCKED(*vpp)) {
437183330Sjhb			if (ltype == LK_EXCLUSIVE) {
438183330Sjhb				vn_lock(*vpp, LK_UPGRADE | LK_RETRY);
439183330Sjhb				if ((*vpp)->v_iflag & VI_DOOMED) {
440183330Sjhb					/* forced unmount */
441183330Sjhb					vrele(*vpp);
442183330Sjhb					*vpp = NULL;
443183330Sjhb					return (EBADF);
444183330Sjhb				}
445183330Sjhb			} else
446183330Sjhb				vn_lock(*vpp, LK_DOWNGRADE | LK_RETRY);
447183330Sjhb		}
448144296Sjeff		return (-1);
449144296Sjeff	}
450170000Spjd	ltype = 0;	/* silence gcc warning */
451170000Spjd	if (cnp->cn_flags & ISDOTDOT) {
452176559Sattilio		ltype = VOP_ISLOCKED(dvp);
453175294Sattilio		VOP_UNLOCK(dvp, 0);
454170000Spjd	}
455144296Sjeff	VI_LOCK(*vpp);
456144296Sjeff	CACHE_UNLOCK();
457176559Sattilio	error = vget(*vpp, cnp->cn_lkflags | LK_INTERLOCK, cnp->cn_thread);
458145006Sjeff	if (cnp->cn_flags & ISDOTDOT)
459175202Sattilio		vn_lock(dvp, ltype | LK_RETRY);
460145006Sjeff	if (error) {
461144296Sjeff		*vpp = NULL;
462144296Sjeff		goto retry;
463144296Sjeff	}
464178046Spjd	if ((cnp->cn_flags & ISLASTCN) &&
465178046Spjd	    (cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE) {
466178046Spjd		ASSERT_VOP_ELOCKED(*vpp, "cache_lookup");
467178046Spjd	}
468144296Sjeff	return (-1);
4691541Srgrimes}
4701541Srgrimes
4711541Srgrimes/*
4726968Sphk * Add an entry to the cache.
4731541Srgrimes */
4741549Srgrimesvoid
4751541Srgrimescache_enter(dvp, vp, cnp)
4761541Srgrimes	struct vnode *dvp;
4771541Srgrimes	struct vnode *vp;
4781541Srgrimes	struct componentname *cnp;
4791541Srgrimes{
480185557Skib	struct namecache *ncp, *n2;
48151906Sphk	struct nchashhead *ncpp;
48274384Speter	u_int32_t hash;
483120792Sjeff	int hold;
484120792Sjeff	int zap;
48551906Sphk	int len;
4861541Srgrimes
487147326Sjeff	CTR3(KTR_VFS, "cache_enter(%p, %p, %s)", dvp, vp, cnp->cn_nameptr);
488147296Sjeff	VNASSERT(vp == NULL || (vp->v_iflag & VI_DOOMED) == 0, vp,
489147296Sjeff	    ("cahe_enter: Adding a doomed vnode"));
490147296Sjeff
4911541Srgrimes	if (!doingcache)
4921541Srgrimes		return;
4936968Sphk
494187460Smckay	/*
495187460Smckay	 * Avoid blowout in namecache entries.
496187460Smckay	 */
497187460Smckay	if (numcache >= desiredvnodes * 2)
498187460Smckay		return;
499187460Smckay
50025453Sphk	if (cnp->cn_nameptr[0] == '.') {
50125453Sphk		if (cnp->cn_namelen == 1) {
50225453Sphk			return;
5036928Sphk		}
504147450Sjeff		/*
505147450Sjeff		 * For dotdot lookups only cache the v_dd pointer if the
506147450Sjeff		 * directory has a link back to its parent via v_cache_dst.
507147450Sjeff		 * Without this an unlinked directory would keep a soft
508147450Sjeff		 * reference to its parent which could not be NULLd at
509147450Sjeff		 * cache_purge() time.
510147450Sjeff		 */
51125453Sphk		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
512147450Sjeff			CACHE_LOCK();
513147450Sjeff			if (!TAILQ_EMPTY(&dvp->v_cache_dst))
514147450Sjeff				dvp->v_dd = vp;
515147450Sjeff			CACHE_UNLOCK();
51625453Sphk			return;
51725453Sphk		}
5186968Sphk	}
519116201Sdes
520120792Sjeff	hold = 0;
521120792Sjeff	zap = 0;
522182061Sjhb
523182061Sjhb	/*
524182061Sjhb	 * Calculate the hash key and setup as much of the new
525182061Sjhb	 * namecache entry as possible before acquiring the lock.
526182061Sjhb	 */
527116289Sdes	ncp = cache_alloc(cnp->cn_namelen);
528182061Sjhb	ncp->nc_vp = vp;
529182061Sjhb	ncp->nc_dvp = dvp;
530182061Sjhb	len = ncp->nc_nlen = cnp->cn_namelen;
531182061Sjhb	hash = fnv_32_buf(cnp->cn_nameptr, len, FNV1_32_INIT);
532182061Sjhb	bcopy(cnp->cn_nameptr, ncp->nc_name, len);
533182061Sjhb	hash = fnv_32_buf(&dvp, sizeof(dvp), hash);
534120792Sjeff	CACHE_LOCK();
535182061Sjhb
536182061Sjhb	/*
537186600Skib	 * See if this vnode or negative entry is already in the cache
538186600Skib	 * with this name.  This can happen with concurrent lookups of
539186600Skib	 * the same path name.
540182061Sjhb	 */
541186600Skib	ncpp = NCHHASH(hash);
542186600Skib	LIST_FOREACH(n2, ncpp, nc_hash) {
543186600Skib		if (n2->nc_dvp == dvp &&
544186600Skib		    n2->nc_nlen == cnp->cn_namelen &&
545186600Skib		    !bcmp(n2->nc_name, cnp->cn_nameptr, n2->nc_nlen)) {
546186600Skib			CACHE_UNLOCK();
547186600Skib			cache_free(ncp);
548186600Skib			return;
549182061Sjhb		}
550185557Skib	}
551182061Sjhb
55225453Sphk	numcache++;
55328954Sphk	if (!vp) {
55425453Sphk		numneg++;
55528954Sphk		ncp->nc_flag = cnp->cn_flags & ISWHITEOUT ? NCF_WHITE : 0;
55629071Sphk	} else if (vp->v_type == VDIR) {
55729071Sphk		vp->v_dd = dvp;
558144319Sdas	} else {
559144319Sdas		vp->v_dd = NULL;
56028954Sphk	}
56123521Sbde
56222521Sdyson	/*
563182061Sjhb	 * Insert the new namecache entry into the appropriate chain
564182061Sjhb	 * within the cache entries table.
56522521Sdyson	 */
5666928Sphk	LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
56775654Stanimura	if (LIST_EMPTY(&dvp->v_cache_src)) {
568120792Sjeff		hold = 1;
56975654Stanimura		numcachehv++;
57075654Stanimura	}
57125453Sphk	LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src);
572110967Sarr	/*
573110967Sarr	 * If the entry is "negative", we place it into the
574110967Sarr	 * "negative" cache queue, otherwise, we place it into the
575110967Sarr	 * destination vnode's cache entries queue.
576110967Sarr	 */
57725453Sphk	if (vp) {
57825453Sphk		TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst);
57925453Sphk	} else {
58025453Sphk		TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
58125453Sphk	}
58251906Sphk	if (numneg * ncnegfactor > numcache) {
58325453Sphk		ncp = TAILQ_FIRST(&ncneg);
584120792Sjeff		zap = 1;
58525453Sphk	}
586120792Sjeff	if (hold)
587120792Sjeff		vhold(dvp);
588120792Sjeff	if (zap)
589140712Sjeff		cache_zap(ncp);
590140712Sjeff	CACHE_UNLOCK();
5911541Srgrimes}
5921541Srgrimes
5931541Srgrimes/*
5941541Srgrimes * Name cache initialization, from vfs_init() when we are booting
5951541Srgrimes */
59669664Speterstatic void
59769664Speternchinit(void *dummy __unused)
5981541Srgrimes{
59923521Sbde
60025453Sphk	TAILQ_INIT(&ncneg);
601116289Sdes
602116289Sdes	cache_zone_small = uma_zcreate("S VFS Cache", CACHE_ZONE_SMALL, NULL,
603116289Sdes	    NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
604116289Sdes	cache_zone_large = uma_zcreate("L VFS Cache", CACHE_ZONE_LARGE, NULL,
605116289Sdes	    NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
606116289Sdes
60769664Speter	nchashtbl = hashinit(desiredvnodes * 2, M_VFSCACHE, &nchash);
6081541Srgrimes}
609177253SrwatsonSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nchinit, NULL);
6101541Srgrimes
61169664Speter
6121541Srgrimes/*
61346011Sphk * Invalidate all entries to a particular vnode.
6141541Srgrimes */
6151549Srgrimesvoid
6161541Srgrimescache_purge(vp)
6171541Srgrimes	struct vnode *vp;
6181541Srgrimes{
6191541Srgrimes
620147326Sjeff	CTR1(KTR_VFS, "cache_purge(%p)", vp);
621120792Sjeff	CACHE_LOCK();
622147331Sjeff	while (!LIST_EMPTY(&vp->v_cache_src))
623147331Sjeff		cache_zap(LIST_FIRST(&vp->v_cache_src));
624116201Sdes	while (!TAILQ_EMPTY(&vp->v_cache_dst))
625140712Sjeff		cache_zap(TAILQ_FIRST(&vp->v_cache_dst));
626144319Sdas	vp->v_dd = NULL;
627120792Sjeff	CACHE_UNLOCK();
6281541Srgrimes}
6291541Srgrimes
6301541Srgrimes/*
6316968Sphk * Flush all entries referencing a particular filesystem.
6321541Srgrimes */
6331549Srgrimesvoid
6341541Srgrimescache_purgevfs(mp)
6351541Srgrimes	struct mount *mp;
6361541Srgrimes{
6376968Sphk	struct nchashhead *ncpp;
63822521Sdyson	struct namecache *ncp, *nnp;
6391541Srgrimes
6406968Sphk	/* Scan hash tables for applicable entries */
641120792Sjeff	CACHE_LOCK();
64229071Sphk	for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
643169999Spjd		LIST_FOREACH_SAFE(ncp, ncpp, nc_hash, nnp) {
644169999Spjd			if (ncp->nc_dvp->v_mount == mp)
645169999Spjd				cache_zap(ncp);
6461541Srgrimes		}
6471541Srgrimes	}
648120792Sjeff	CACHE_UNLOCK();
6491541Srgrimes}
65028787Sphk
65128787Sphk/*
65228787Sphk * Perform canonical checks and cache lookup and pass on to filesystem
65328787Sphk * through the vop_cachedlookup only if needed.
65428787Sphk */
65528787Sphk
65628787Sphkint
65728787Sphkvfs_cache_lookup(ap)
65828787Sphk	struct vop_lookup_args /* {
65928787Sphk		struct vnode *a_dvp;
66028787Sphk		struct vnode **a_vpp;
66128787Sphk		struct componentname *a_cnp;
66228787Sphk	} */ *ap;
66328787Sphk{
664144296Sjeff	struct vnode *dvp;
66528787Sphk	int error;
66628787Sphk	struct vnode **vpp = ap->a_vpp;
66728787Sphk	struct componentname *cnp = ap->a_cnp;
66828787Sphk	struct ucred *cred = cnp->cn_cred;
66928787Sphk	int flags = cnp->cn_flags;
67083366Sjulian	struct thread *td = cnp->cn_thread;
67128787Sphk
67228787Sphk	*vpp = NULL;
67365665Sbp	dvp = ap->a_dvp;
67428787Sphk
67565665Sbp	if (dvp->v_type != VDIR)
676116201Sdes		return (ENOTDIR);
67728787Sphk
67865665Sbp	if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
67928787Sphk	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
68028787Sphk		return (EROFS);
68128787Sphk
68283366Sjulian	error = VOP_ACCESS(dvp, VEXEC, cred, td);
68328787Sphk	if (error)
68428787Sphk		return (error);
68528787Sphk
68665665Sbp	error = cache_lookup(dvp, vpp, cnp);
687144296Sjeff	if (error == 0)
688144287Sjeff		return (VOP_CACHEDLOOKUP(dvp, vpp, cnp));
689183330Sjhb	if (error == -1)
690183330Sjhb		return (0);
691183330Sjhb	return (error);
69228787Sphk}
69351906Sphk
69451906Sphk
69551906Sphk#ifndef _SYS_SYSPROTO_H_
69651906Sphkstruct  __getcwd_args {
69751906Sphk	u_char	*buf;
69851906Sphk	u_int	buflen;
69951906Sphk};
70051906Sphk#endif
70151906Sphk
70291690Seivind/*
70391690Seivind * XXX All of these sysctls would probably be more productive dead.
70491690Seivind */
70551906Sphkstatic int disablecwd;
70691690SeivindSYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0,
70791690Seivind   "Disable the getcwd syscall");
70851906Sphk
709167232Srwatson/* Implementation of the getcwd syscall. */
71051906Sphkint
71183366Sjulian__getcwd(td, uap)
71283366Sjulian	struct thread *td;
71351906Sphk	struct __getcwd_args *uap;
71451906Sphk{
715112430Sphk
716102870Siedowse	return (kern___getcwd(td, uap->buf, UIO_USERSPACE, uap->buflen));
717102870Siedowse}
718102870Siedowse
719102870Siedowseint
720112430Sphkkern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, u_int buflen)
721102870Siedowse{
722102870Siedowse	char *bp, *tmpbuf;
72351906Sphk	struct filedesc *fdp;
724185298Smarcus	struct vnode *cdir, *rdir;
725185298Smarcus	int error, vfslocked;
72651906Sphk
727112430Sphk	if (disablecwd)
72851906Sphk		return (ENODEV);
729102870Siedowse	if (buflen < 2)
73051906Sphk		return (EINVAL);
731102870Siedowse	if (buflen > MAXPATHLEN)
732102870Siedowse		buflen = MAXPATHLEN;
733144318Sdas
734144318Sdas	tmpbuf = malloc(buflen, M_TEMP, M_WAITOK);
735144318Sdas	fdp = td->td_proc->p_fd;
736168355Srwatson	FILEDESC_SLOCK(fdp);
737185298Smarcus	cdir = fdp->fd_cdir;
738185298Smarcus	VREF(cdir);
739185298Smarcus	rdir = fdp->fd_rdir;
740185298Smarcus	VREF(rdir);
741168355Srwatson	FILEDESC_SUNLOCK(fdp);
742185298Smarcus	error = vn_fullpath1(td, cdir, rdir, tmpbuf, &bp, buflen);
743185298Smarcus	vfslocked = VFS_LOCK_GIANT(rdir->v_mount);
744185298Smarcus	vrele(rdir);
745185298Smarcus	VFS_UNLOCK_GIANT(vfslocked);
746185298Smarcus	vfslocked = VFS_LOCK_GIANT(cdir->v_mount);
747185298Smarcus	vrele(cdir);
748185298Smarcus	VFS_UNLOCK_GIANT(vfslocked);
749144318Sdas
750144318Sdas	if (!error) {
751144318Sdas		if (bufseg == UIO_SYSSPACE)
752144318Sdas			bcopy(bp, buf, strlen(bp) + 1);
753144318Sdas		else
754144318Sdas			error = copyout(bp, buf, strlen(bp) + 1);
755144318Sdas	}
756102870Siedowse	free(tmpbuf, M_TEMP);
75751906Sphk	return (error);
75851906Sphk}
75951906Sphk
76059652Sgreen/*
76159652Sgreen * Thus begins the fullpath magic.
76259652Sgreen */
76359652Sgreen
76459652Sgreen#undef STATNODE
76559652Sgreen#define STATNODE(name)							\
76659652Sgreen	static u_int name;						\
76762622Sjhb	SYSCTL_UINT(_vfs_cache, OID_AUTO, name, CTLFLAG_RD, &name, 0, "")
76859652Sgreen
76959652Sgreenstatic int disablefullpath;
77091690SeivindSYSCTL_INT(_debug, OID_AUTO, disablefullpath, CTLFLAG_RW, &disablefullpath, 0,
77191690Seivind	"Disable the vn_fullpath function");
77259652Sgreen
773144318Sdas/* These count for kern___getcwd(), too. */
77459652SgreenSTATNODE(numfullpathcalls);
77559652SgreenSTATNODE(numfullpathfail1);
77659652SgreenSTATNODE(numfullpathfail2);
77759652SgreenSTATNODE(numfullpathfail4);
77859652SgreenSTATNODE(numfullpathfound);
77959652Sgreen
78091690Seivind/*
78191690Seivind * Retrieve the full filesystem path that correspond to a vnode from the name
78291690Seivind * cache (if available)
78391690Seivind */
78459652Sgreenint
78585287Sdesvn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf)
78685287Sdes{
787144318Sdas	char *buf;
78859652Sgreen	struct filedesc *fdp;
789185298Smarcus	struct vnode *rdir;
790185298Smarcus	int error, vfslocked;
79159652Sgreen
79259652Sgreen	if (disablefullpath)
79359652Sgreen		return (ENODEV);
79485287Sdes	if (vn == NULL)
79559652Sgreen		return (EINVAL);
796144318Sdas
797111119Simp	buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
798144318Sdas	fdp = td->td_proc->p_fd;
799168355Srwatson	FILEDESC_SLOCK(fdp);
800185298Smarcus	rdir = fdp->fd_rdir;
801185298Smarcus	VREF(rdir);
802168355Srwatson	FILEDESC_SUNLOCK(fdp);
803185298Smarcus	error = vn_fullpath1(td, vn, rdir, buf, retbuf, MAXPATHLEN);
804185298Smarcus	vfslocked = VFS_LOCK_GIANT(rdir->v_mount);
805185298Smarcus	vrele(rdir);
806185298Smarcus	VFS_UNLOCK_GIANT(vfslocked);
807144318Sdas
808144318Sdas	if (!error)
809144318Sdas		*freebuf = buf;
810144318Sdas	else
811144318Sdas		free(buf, M_TEMP);
812144318Sdas	return (error);
813144318Sdas}
814144318Sdas
815144318Sdas/*
816181060Scsjp * This function is similar to vn_fullpath, but it attempts to lookup the
817181060Scsjp * pathname relative to the global root mount point.  This is required for the
818181060Scsjp * auditing sub-system, as audited pathnames must be absolute, relative to the
819181060Scsjp * global root mount point.
820181060Scsjp */
821181060Scsjpint
822181060Scsjpvn_fullpath_global(struct thread *td, struct vnode *vn,
823181060Scsjp    char **retbuf, char **freebuf)
824181060Scsjp{
825181060Scsjp	char *buf;
826181060Scsjp	int error;
827181060Scsjp
828181060Scsjp	if (disablefullpath)
829181060Scsjp		return (ENODEV);
830181060Scsjp	if (vn == NULL)
831181060Scsjp		return (EINVAL);
832181060Scsjp	buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
833181060Scsjp	error = vn_fullpath1(td, vn, rootvnode, buf, retbuf, MAXPATHLEN);
834181060Scsjp	if (!error)
835181060Scsjp		*freebuf = buf;
836181060Scsjp	else
837181060Scsjp		free(buf, M_TEMP);
838181060Scsjp	return (error);
839181060Scsjp}
840181060Scsjp
841185956Smarcusstatic int
842185956Smarcusvn_vptocnp(struct vnode **vp, char **bp, char *buf, u_int *buflen)
843185956Smarcus{
844185956Smarcus	struct vnode *dvp;
845185956Smarcus	int error, vfslocked;
846185956Smarcus
847185956Smarcus	vhold(*vp);
848185956Smarcus	CACHE_UNLOCK();
849185956Smarcus	vfslocked = VFS_LOCK_GIANT((*vp)->v_mount);
850185956Smarcus	vn_lock(*vp, LK_SHARED | LK_RETRY);
851185956Smarcus	error = VOP_VPTOCNP(*vp, &dvp, buf, buflen);
852185956Smarcus	VOP_UNLOCK(*vp, 0);
853186455Skib	vdrop(*vp);
854185956Smarcus	VFS_UNLOCK_GIANT(vfslocked);
855185956Smarcus	if (error) {
856185956Smarcus		numfullpathfail2++;
857185956Smarcus		return (error);
858185956Smarcus	}
859185956Smarcus	*bp = buf + *buflen;
860185956Smarcus	*vp = dvp;
861185956Smarcus	CACHE_LOCK();
862185956Smarcus	if ((*vp)->v_iflag & VI_DOOMED) {
863185956Smarcus		/* forced unmount */
864185956Smarcus		CACHE_UNLOCK();
865185956Smarcus		vdrop(*vp);
866185956Smarcus		return (ENOENT);
867185956Smarcus	}
868185956Smarcus	vdrop(*vp);
869185956Smarcus
870185956Smarcus	return (0);
871185956Smarcus}
872185956Smarcus
873181060Scsjp/*
874144318Sdas * The magic behind kern___getcwd() and vn_fullpath().
875144318Sdas */
876144318Sdasstatic int
877144318Sdasvn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
878144318Sdas    char *buf, char **retbuf, u_int buflen)
879144318Sdas{
880144318Sdas	char *bp;
881144318Sdas	int error, i, slash_prefixed;
882144318Sdas	struct namecache *ncp;
883144318Sdas
884185956Smarcus	buflen--;
885185956Smarcus	bp = buf + buflen;
88659652Sgreen	*bp = '\0';
887144318Sdas	error = 0;
88859652Sgreen	slash_prefixed = 0;
889144318Sdas
890144318Sdas	CACHE_LOCK();
891144318Sdas	numfullpathcalls++;
892144318Sdas	if (vp->v_type != VDIR) {
893144318Sdas		ncp = TAILQ_FIRST(&vp->v_cache_dst);
894185956Smarcus		if (ncp != NULL) {
895185956Smarcus			for (i = ncp->nc_nlen - 1; i >= 0 && bp > buf; i--)
896185956Smarcus				*--bp = ncp->nc_name[i];
897185956Smarcus			if (bp == buf) {
898185956Smarcus				numfullpathfail4++;
899185956Smarcus				CACHE_UNLOCK();
900185956Smarcus				return (ENOMEM);
901185956Smarcus			}
902185956Smarcus			vp = ncp->nc_dvp;
903185956Smarcus		} else {
904185956Smarcus			error = vn_vptocnp(&vp, &bp, buf, &buflen);
905185956Smarcus			if (error) {
906185956Smarcus				return (error);
907185956Smarcus			}
908144318Sdas		}
909185956Smarcus		*--bp = '/';
910185956Smarcus		buflen--;
911185956Smarcus		if (buflen < 0) {
912144318Sdas			numfullpathfail4++;
913144318Sdas			CACHE_UNLOCK();
914144318Sdas			return (ENOMEM);
915144318Sdas		}
916144318Sdas		slash_prefixed = 1;
917144318Sdas	}
918144318Sdas	while (vp != rdir && vp != rootvnode) {
919101308Sjeff		if (vp->v_vflag & VV_ROOT) {
920155385Sjeff			if (vp->v_iflag & VI_DOOMED) {	/* forced unmount */
921185956Smarcus				CACHE_UNLOCK();
922144318Sdas				error = EBADF;
923144318Sdas				break;
92459652Sgreen			}
92559652Sgreen			vp = vp->v_mount->mnt_vnodecovered;
92659652Sgreen			continue;
92759652Sgreen		}
928185956Smarcus		if (vp->v_type != VDIR) {
92959652Sgreen			numfullpathfail1++;
930185956Smarcus			CACHE_UNLOCK();
931144318Sdas			error = ENOTDIR;
932144318Sdas			break;
93359652Sgreen		}
93459652Sgreen		ncp = TAILQ_FIRST(&vp->v_cache_dst);
935185956Smarcus		if (ncp != NULL) {
936186458Smarcus			MPASS(vp->v_dd == NULL || ncp->nc_dvp == vp->v_dd);
937185956Smarcus			buflen -= ncp->nc_nlen - 1;
938185956Smarcus			for (i = ncp->nc_nlen - 1; i >= 0 && bp != buf; i--)
939185956Smarcus				*--bp = ncp->nc_name[i];
940185956Smarcus			if (bp == buf) {
941185956Smarcus				numfullpathfail4++;
942185956Smarcus				CACHE_UNLOCK();
943185956Smarcus				error = ENOMEM;
944185956Smarcus				break;
945185956Smarcus			}
946185956Smarcus			vp = ncp->nc_dvp;
947185956Smarcus		} else {
948185956Smarcus			error = vn_vptocnp(&vp, &bp, buf, &buflen);
949185956Smarcus			if (error) {
950185956Smarcus				break;
951185956Smarcus			}
95259652Sgreen		}
953185956Smarcus		*--bp = '/';
954185956Smarcus		buflen--;
955185956Smarcus		if (buflen < 0) {
956120792Sjeff			numfullpathfail4++;
957185956Smarcus			CACHE_UNLOCK();
958144318Sdas			error = ENOMEM;
959144318Sdas			break;
96059652Sgreen		}
96159652Sgreen		slash_prefixed = 1;
962144318Sdas	}
963185956Smarcus	if (error)
964144318Sdas		return (error);
96559652Sgreen	if (!slash_prefixed) {
96659652Sgreen		if (bp == buf) {
967120792Sjeff			numfullpathfail4++;
968144318Sdas			CACHE_UNLOCK();
96959652Sgreen			return (ENOMEM);
970144318Sdas		} else {
971144318Sdas			*--bp = '/';
97259652Sgreen		}
97359652Sgreen	}
97459652Sgreen	numfullpathfound++;
975144318Sdas	CACHE_UNLOCK();
976144318Sdas
977116201Sdes	*retbuf = bp;
97859652Sgreen	return (0);
97959652Sgreen}
980177782Skib
981177782Skibint
982177782Skibvn_commname(struct vnode *vp, char *buf, u_int buflen)
983177782Skib{
984177782Skib	struct namecache *ncp;
985177782Skib	int l;
986177782Skib
987177782Skib	CACHE_LOCK();
988177782Skib	ncp = TAILQ_FIRST(&vp->v_cache_dst);
989177782Skib	if (!ncp) {
990177782Skib		CACHE_UNLOCK();
991177782Skib		return (ENOENT);
992177782Skib	}
993177782Skib	l = min(ncp->nc_nlen, buflen - 1);
994177782Skib	memcpy(buf, ncp->nc_name, l);
995177782Skib	CACHE_UNLOCK();
996177782Skib	buf[l] = '\0';
997177782Skib	return (0);
998177782Skib}
999