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: releng/11.0/sys/kern/vfs_cache.c 298819 2016-04-29 22:15:33Z pfg $");
37116182Sobrien
38190141Skib#include "opt_ktrace.h"
39190141Skib
401541Srgrimes#include <sys/param.h>
41228433Savg#include <sys/systm.h>
42294475Smjg#include <sys/counter.h>
43183155Sjhb#include <sys/filedesc.h>
44183155Sjhb#include <sys/fnv_hash.h>
4512820Sphk#include <sys/kernel.h>
4676166Smarkm#include <sys/lock.h>
47183155Sjhb#include <sys/malloc.h>
48230129Smm#include <sys/fcntl.h>
49183155Sjhb#include <sys/mount.h>
501541Srgrimes#include <sys/namei.h>
51183155Sjhb#include <sys/proc.h>
52187839Sjhb#include <sys/rwlock.h>
53190829Srwatson#include <sys/sdt.h>
54102870Siedowse#include <sys/syscallsubr.h>
55183155Sjhb#include <sys/sysctl.h>
5651906Sphk#include <sys/sysproto.h>
57183155Sjhb#include <sys/vnode.h>
58190141Skib#ifdef KTRACE
59190141Skib#include <sys/ktrace.h>
60190141Skib#endif
611541Srgrimes
62116289Sdes#include <vm/uma.h>
63116289Sdes
64190829SrwatsonSDT_PROVIDER_DECLARE(vfs);
65258622SavgSDT_PROBE_DEFINE3(vfs, namecache, enter, done, "struct vnode *", "char *",
66190829Srwatson    "struct vnode *");
67258622SavgSDT_PROBE_DEFINE2(vfs, namecache, enter_negative, done, "struct vnode *",
68190829Srwatson    "char *");
69258622SavgSDT_PROBE_DEFINE1(vfs, namecache, fullpath, entry, "struct vnode *");
70258622SavgSDT_PROBE_DEFINE3(vfs, namecache, fullpath, hit, "struct vnode *",
71253075Savg    "char *", "struct vnode *");
72258622SavgSDT_PROBE_DEFINE1(vfs, namecache, fullpath, miss, "struct vnode *");
73258622SavgSDT_PROBE_DEFINE3(vfs, namecache, fullpath, return, "int",
74253075Savg    "struct vnode *", "char *");
75258622SavgSDT_PROBE_DEFINE3(vfs, namecache, lookup, hit, "struct vnode *", "char *",
76190829Srwatson    "struct vnode *");
77258622SavgSDT_PROBE_DEFINE2(vfs, namecache, lookup, hit__negative,
78211616Srpaulo    "struct vnode *", "char *");
79258622SavgSDT_PROBE_DEFINE2(vfs, namecache, lookup, miss, "struct vnode *",
80190829Srwatson    "char *");
81258622SavgSDT_PROBE_DEFINE1(vfs, namecache, purge, done, "struct vnode *");
82258622SavgSDT_PROBE_DEFINE1(vfs, namecache, purge_negative, done, "struct vnode *");
83258622SavgSDT_PROBE_DEFINE1(vfs, namecache, purgevfs, done, "struct mount *");
84258622SavgSDT_PROBE_DEFINE3(vfs, namecache, zap, done, "struct vnode *", "char *",
85190829Srwatson    "struct vnode *");
86258622SavgSDT_PROBE_DEFINE2(vfs, namecache, zap_negative, done, "struct vnode *",
87190829Srwatson    "char *");
88190829Srwatson
8951906Sphk/*
9059652Sgreen * This structure describes the elements in the cache of recent
9159652Sgreen * names looked up by namei.
9259652Sgreen */
9359652Sgreen
9459652Sgreenstruct	namecache {
9560938Sjake	LIST_ENTRY(namecache) nc_hash;	/* hash chain */
9660938Sjake	LIST_ENTRY(namecache) nc_src;	/* source vnode list */
9760938Sjake	TAILQ_ENTRY(namecache) nc_dst;	/* destination vnode list */
9859652Sgreen	struct	vnode *nc_dvp;		/* vnode of parent of name */
9959652Sgreen	struct	vnode *nc_vp;		/* vnode the name refers to */
10059652Sgreen	u_char	nc_flag;		/* flag bits */
10159652Sgreen	u_char	nc_nlen;		/* length of name */
102190829Srwatson	char	nc_name[0];		/* segment name + nul */
10359652Sgreen};
10459652Sgreen
10559652Sgreen/*
106230441Skib * struct namecache_ts repeats struct namecache layout up to the
107230441Skib * nc_nlen member.
108232420Srmacklem * struct namecache_ts is used in place of struct namecache when time(s) need
109232420Srmacklem * to be stored.  The nc_dotdottime field is used when a cache entry is mapping
110232420Srmacklem * both a non-dotdot directory name plus dotdot for the directory's
111232420Srmacklem * parent.
112230441Skib */
113230441Skibstruct	namecache_ts {
114230441Skib	LIST_ENTRY(namecache) nc_hash;	/* hash chain */
115230441Skib	LIST_ENTRY(namecache) nc_src;	/* source vnode list */
116230441Skib	TAILQ_ENTRY(namecache) nc_dst;	/* destination vnode list */
117230441Skib	struct	vnode *nc_dvp;		/* vnode of parent of name */
118230441Skib	struct	vnode *nc_vp;		/* vnode the name refers to */
119230441Skib	u_char	nc_flag;		/* flag bits */
120230441Skib	u_char	nc_nlen;		/* length of name */
121230441Skib	struct	timespec nc_time;	/* timespec provided by fs */
122232420Srmacklem	struct	timespec nc_dotdottime;	/* dotdot timespec provided by fs */
123230441Skib	int	nc_ticks;		/* ticks value when entry was added */
124230441Skib	char	nc_name[0];		/* segment name + nul */
125230441Skib};
126230441Skib
127230441Skib/*
128230441Skib * Flags in namecache.nc_flag
129230441Skib */
130230441Skib#define NCF_WHITE	0x01
131230441Skib#define NCF_ISDOTDOT	0x02
132230441Skib#define	NCF_TS		0x04
133232420Srmacklem#define	NCF_DTS		0x08
134230441Skib
135230441Skib/*
1361541Srgrimes * Name caching works as follows:
1371541Srgrimes *
1381541Srgrimes * Names found by directory scans are retained in a cache
1391541Srgrimes * for future reference.  It is managed LRU, so frequently
1401541Srgrimes * used names will hang around.  Cache is indexed by hash value
1411541Srgrimes * obtained from (vp, name) where vp refers to the directory
1421541Srgrimes * containing name.
1431541Srgrimes *
14422521Sdyson * If it is a "negative" entry, (i.e. for a name that is known NOT to
14522521Sdyson * exist) the vnode pointer will be NULL.
1466968Sphk *
1471541Srgrimes * Upon reaching the last segment of a path, if the reference
1481541Srgrimes * is for DELETE, or NOCACHE is set (rewrite), and the
1491541Srgrimes * name is located in the cache, it will be dropped.
1501541Srgrimes */
1511541Srgrimes
1521541Srgrimes/*
153298819Spfg * Structures associated with name caching.
1541541Srgrimes */
15574501Speter#define NCHHASH(hash) \
15674501Speter	(&nchashtbl[(hash) & nchash])
15760938Sjakestatic LIST_HEAD(nchashhead, namecache) *nchashtbl;	/* Hash Table */
15860938Sjakestatic TAILQ_HEAD(, namecache) ncneg;	/* Hash Table */
15923521Sbdestatic u_long	nchash;			/* size of hash table */
160213916SkibSYSCTL_ULONG(_debug, OID_AUTO, nchash, CTLFLAG_RD, &nchash, 0,
161213916Skib    "Size of namecache hash table");
16225453Sphkstatic u_long	ncnegfactor = 16;	/* ratio of negative entries */
163213916SkibSYSCTL_ULONG(_vfs, OID_AUTO, ncnegfactor, CTLFLAG_RW, &ncnegfactor, 0,
164213916Skib    "Ratio of negative namecache entries");
165213916Skibstatic u_long	numneg;			/* number of negative entries allocated */
166213916SkibSYSCTL_ULONG(_debug, OID_AUTO, numneg, CTLFLAG_RD, &numneg, 0,
167213916Skib    "Number of negative entries in namecache");
16823521Sbdestatic u_long	numcache;		/* number of cache entries allocated */
169213916SkibSYSCTL_ULONG(_debug, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0,
170213916Skib    "Number of namecache entries");
17175654Stanimurastatic u_long	numcachehv;		/* number of cache entries with vnodes held */
172213916SkibSYSCTL_ULONG(_debug, OID_AUTO, numcachehv, CTLFLAG_RD, &numcachehv, 0,
173213916Skib    "Number of namecache entries with vnodes held");
174295971Skibu_int	ncsizefactor = 2;
175213916SkibSYSCTL_UINT(_vfs, OID_AUTO, ncsizefactor, CTLFLAG_RW, &ncsizefactor, 0,
176213916Skib    "Size factor for namecache");
1771541Srgrimes
178213916Skibstruct nchstats	nchstats;		/* cache effectiveness statistics */
179213916Skib
180187839Sjhbstatic struct rwlock cache_lock;
181187839SjhbRW_SYSINIT(vfscache, &cache_lock, "Name Cache");
182120792Sjeff
183187839Sjhb#define	CACHE_UPGRADE_LOCK()	rw_try_upgrade(&cache_lock)
184187839Sjhb#define	CACHE_RLOCK()		rw_rlock(&cache_lock)
185187839Sjhb#define	CACHE_RUNLOCK()		rw_runlock(&cache_lock)
186187839Sjhb#define	CACHE_WLOCK()		rw_wlock(&cache_lock)
187187839Sjhb#define	CACHE_WUNLOCK()		rw_wunlock(&cache_lock)
188120792Sjeff
189116289Sdes/*
190116289Sdes * UMA zones for the VFS cache.
191116289Sdes *
192116289Sdes * The small cache is used for entries with short names, which are the
193116289Sdes * most common.  The large cache is used for entries which are too big to
194116289Sdes * fit in the small cache.
195116289Sdes */
196116289Sdesstatic uma_zone_t cache_zone_small;
197230441Skibstatic uma_zone_t cache_zone_small_ts;
198116289Sdesstatic uma_zone_t cache_zone_large;
199232420Srmacklemstatic uma_zone_t cache_zone_large_ts;
200116289Sdes
201190829Srwatson#define	CACHE_PATH_CUTOFF	35
202116289Sdes
203230441Skibstatic struct namecache *
204230441Skibcache_alloc(int len, int ts)
205230441Skib{
206116289Sdes
207232420Srmacklem	if (len > CACHE_PATH_CUTOFF) {
208232420Srmacklem		if (ts)
209232420Srmacklem			return (uma_zalloc(cache_zone_large_ts, M_WAITOK));
210232420Srmacklem		else
211232420Srmacklem			return (uma_zalloc(cache_zone_large, M_WAITOK));
212232420Srmacklem	}
213230441Skib	if (ts)
214230441Skib		return (uma_zalloc(cache_zone_small_ts, M_WAITOK));
215230441Skib	else
216230441Skib		return (uma_zalloc(cache_zone_small, M_WAITOK));
217230441Skib}
218230441Skib
219230441Skibstatic void
220230441Skibcache_free(struct namecache *ncp)
221230441Skib{
222230441Skib	int ts;
223230441Skib
224230441Skib	if (ncp == NULL)
225230441Skib		return;
226230441Skib	ts = ncp->nc_flag & NCF_TS;
227230441Skib	if (ncp->nc_nlen <= CACHE_PATH_CUTOFF) {
228230441Skib		if (ts)
229230441Skib			uma_zfree(cache_zone_small_ts, ncp);
230230441Skib		else
231230441Skib			uma_zfree(cache_zone_small, ncp);
232232420Srmacklem	} else if (ts)
233232420Srmacklem		uma_zfree(cache_zone_large_ts, ncp);
234232420Srmacklem	else
235230441Skib		uma_zfree(cache_zone_large, ncp);
236230441Skib}
237230441Skib
238230441Skibstatic char *
239230441Skibnc_get_name(struct namecache *ncp)
240230441Skib{
241230441Skib	struct namecache_ts *ncp_ts;
242230441Skib
243230441Skib	if ((ncp->nc_flag & NCF_TS) == 0)
244230441Skib		return (ncp->nc_name);
245230441Skib	ncp_ts = (struct namecache_ts *)ncp;
246230441Skib	return (ncp_ts->nc_name);
247230441Skib}
248230441Skib
249230489Skibstatic void
250230489Skibcache_out_ts(struct namecache *ncp, struct timespec *tsp, int *ticksp)
251230489Skib{
252230489Skib
253230552Skib	KASSERT((ncp->nc_flag & NCF_TS) != 0 ||
254230552Skib	    (tsp == NULL && ticksp == NULL),
255230552Skib	    ("No NCF_TS"));
256230489Skib
257230489Skib	if (tsp != NULL)
258230489Skib		*tsp = ((struct namecache_ts *)ncp)->nc_time;
259230489Skib	if (ticksp != NULL)
260230489Skib		*ticksp = ((struct namecache_ts *)ncp)->nc_ticks;
261230489Skib}
262230489Skib
26323521Sbdestatic int	doingcache = 1;		/* 1 => enable the cache */
264213916SkibSYSCTL_INT(_debug, OID_AUTO, vfscache, CTLFLAG_RW, &doingcache, 0,
265213916Skib    "VFS namecache enabled");
26691690Seivind
26791690Seivind/* Export size information to userland */
268273377ShselaskySYSCTL_INT(_debug_sizeof, OID_AUTO, namecache, CTLFLAG_RD, SYSCTL_NULL_INT_PTR,
269215304Sbrucec    sizeof(struct namecache), "sizeof(struct namecache)");
27023521Sbde
27129788Sphk/*
27229788Sphk * The new name cache statistics
27329788Sphk */
274215283Sbrucecstatic SYSCTL_NODE(_vfs, OID_AUTO, cache, CTLFLAG_RW, 0,
275215304Sbrucec    "Name cache statistics");
276294475Smjg#define STATNODE_ULONG(name, descr)	\
277294475Smjg	SYSCTL_ULONG(_vfs_cache, OID_AUTO, name, CTLFLAG_RD, &name, 0, descr);
278294475Smjg#define STATNODE_COUNTER(name, descr)	\
279294475Smjg	static counter_u64_t name;	\
280294475Smjg	SYSCTL_COUNTER_U64(_vfs_cache, OID_AUTO, name, CTLFLAG_RD, &name, descr);
281294475SmjgSTATNODE_ULONG(numneg, "Number of negative cache entries");
282294475SmjgSTATNODE_ULONG(numcache, "Number of cache entries");
283294475SmjgSTATNODE_COUNTER(numcalls, "Number of cache lookups");
284294475SmjgSTATNODE_COUNTER(dothits, "Number of '.' hits");
285294475SmjgSTATNODE_COUNTER(dotdothits, "Number of '..' hits");
286294475SmjgSTATNODE_COUNTER(numchecks, "Number of checks in lookup");
287294475SmjgSTATNODE_COUNTER(nummiss, "Number of cache misses");
288294475SmjgSTATNODE_COUNTER(nummisszap, "Number of cache misses we do not want to cache");
289294475SmjgSTATNODE_COUNTER(numposzaps,
290215304Sbrucec    "Number of cache hits (positive) we do not want to cache");
291294475SmjgSTATNODE_COUNTER(numposhits, "Number of cache hits (positive)");
292294475SmjgSTATNODE_COUNTER(numnegzaps,
293215304Sbrucec    "Number of cache hits (negative) we do not want to cache");
294294475SmjgSTATNODE_COUNTER(numneghits, "Number of cache hits (negative)");
295294475Smjg/* These count for kern___getcwd(), too. */
296294475SmjgSTATNODE_COUNTER(numfullpathcalls, "Number of fullpath search calls");
297294475SmjgSTATNODE_COUNTER(numfullpathfail1, "Number of fullpath search errors (ENOTDIR)");
298294475SmjgSTATNODE_COUNTER(numfullpathfail2,
299294475Smjg    "Number of fullpath search errors (VOP_VPTOCNP failures)");
300294475SmjgSTATNODE_COUNTER(numfullpathfail4, "Number of fullpath search errors (ENOMEM)");
301294475SmjgSTATNODE_COUNTER(numfullpathfound, "Number of successful fullpath calls");
302294475Smjgstatic long numupgrades; STATNODE_ULONG(numupgrades,
303215304Sbrucec    "Number of updates of the cache after lookup (write lock + retry)");
30429788Sphk
305140712Sjeffstatic void cache_zap(struct namecache *ncp);
306194601Skibstatic int vn_vptocnp_locked(struct vnode **vp, struct ucred *cred, char *buf,
307194601Skib    u_int *buflen);
308144318Sdasstatic int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
309144318Sdas    char *buf, char **retbuf, u_int buflen);
3106968Sphk
31169774Sphkstatic MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
31251906Sphk
313294476Smjgstatic uint32_t
314294476Smjgcache_get_hash(char *name, u_char len, struct vnode *dvp)
315294476Smjg{
316294476Smjg	uint32_t hash;
317294476Smjg
318294476Smjg	hash = fnv_32_buf(name, len, FNV1_32_INIT);
319294476Smjg	hash = fnv_32_buf(&dvp, sizeof(dvp), hash);
320294476Smjg	return (hash);
321294476Smjg}
322294476Smjg
323294475Smjgstatic int
324294475Smjgsysctl_nchstats(SYSCTL_HANDLER_ARGS)
325294475Smjg{
326294475Smjg	struct nchstats snap;
327294475Smjg
328294475Smjg	if (req->oldptr == NULL)
329294475Smjg		return (SYSCTL_OUT(req, 0, sizeof(snap)));
330294475Smjg
331294475Smjg	snap = nchstats;
332294475Smjg	snap.ncs_goodhits = counter_u64_fetch(numposhits);
333294475Smjg	snap.ncs_neghits = counter_u64_fetch(numneghits);
334294475Smjg	snap.ncs_badhits = counter_u64_fetch(numposzaps) +
335294475Smjg	    counter_u64_fetch(numnegzaps);
336294475Smjg	snap.ncs_miss = counter_u64_fetch(nummisszap) +
337294475Smjg	    counter_u64_fetch(nummiss);
338294475Smjg
339294475Smjg	return (SYSCTL_OUT(req, &snap, sizeof(snap)));
340294475Smjg}
341294475SmjgSYSCTL_PROC(_vfs_cache, OID_AUTO, nchstats, CTLTYPE_OPAQUE | CTLFLAG_RD |
342294475Smjg    CTLFLAG_MPSAFE, 0, 0, sysctl_nchstats, "LU",
343294475Smjg    "VFS cache effectiveness statistics");
344294475Smjg
345189593Sjhb#ifdef DIAGNOSTIC
34625453Sphk/*
34775402Speter * Grab an atomic snapshot of the name cache hash chain lengths
34875402Speter */
349227309Sedstatic SYSCTL_NODE(_debug, OID_AUTO, hashstat, CTLFLAG_RW, NULL,
350227309Sed    "hash table stats");
35175402Speter
35275402Speterstatic int
35375402Spetersysctl_debug_hashstat_rawnchash(SYSCTL_HANDLER_ARGS)
35475402Speter{
35575402Speter	struct nchashhead *ncpp;
35675402Speter	struct namecache *ncp;
357281677Smckusick	int i, error, n_nchash, *cntbuf;
35875402Speter
359287497Smckusickretry:
36075402Speter	n_nchash = nchash + 1;	/* nchash is max index, not count */
361281677Smckusick	if (req->oldptr == NULL)
36275402Speter		return SYSCTL_OUT(req, 0, n_nchash * sizeof(int));
363281677Smckusick	cntbuf = malloc(n_nchash * sizeof(int), M_TEMP, M_ZERO | M_WAITOK);
364281677Smckusick	CACHE_RLOCK();
365287497Smckusick	if (n_nchash != nchash + 1) {
366287497Smckusick		CACHE_RUNLOCK();
367287497Smckusick		free(cntbuf, M_TEMP);
368287497Smckusick		goto retry;
369287497Smckusick	}
370281677Smckusick	/* Scan hash tables counting entries */
371281677Smckusick	for (ncpp = nchashtbl, i = 0; i < n_nchash; ncpp++, i++)
372281677Smckusick		LIST_FOREACH(ncp, ncpp, nc_hash)
373281677Smckusick			cntbuf[i]++;
374281677Smckusick	CACHE_RUNLOCK();
375281677Smckusick	for (error = 0, i = 0; i < n_nchash; i++)
376281677Smckusick		if ((error = SYSCTL_OUT(req, &cntbuf[i], sizeof(int))) != 0)
377281677Smckusick			break;
378281677Smckusick	free(cntbuf, M_TEMP);
379281677Smckusick	return (error);
38075402Speter}
381187658SjhbSYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnchash, CTLTYPE_INT|CTLFLAG_RD|
382215304Sbrucec    CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_rawnchash, "S,int",
383215304Sbrucec    "nchash chain lengths");
38475402Speter
38575402Speterstatic int
38675402Spetersysctl_debug_hashstat_nchash(SYSCTL_HANDLER_ARGS)
38775402Speter{
38875402Speter	int error;
38975402Speter	struct nchashhead *ncpp;
39075402Speter	struct namecache *ncp;
39175402Speter	int n_nchash;
39275402Speter	int count, maxlength, used, pct;
39375402Speter
39475402Speter	if (!req->oldptr)
39575402Speter		return SYSCTL_OUT(req, 0, 4 * sizeof(int));
39675402Speter
397281677Smckusick	CACHE_RLOCK();
39875402Speter	n_nchash = nchash + 1;	/* nchash is max index, not count */
39975402Speter	used = 0;
40075402Speter	maxlength = 0;
40175402Speter
40275402Speter	/* Scan hash tables for applicable entries */
40375402Speter	for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) {
40475402Speter		count = 0;
40575402Speter		LIST_FOREACH(ncp, ncpp, nc_hash) {
40675402Speter			count++;
40775402Speter		}
40875402Speter		if (count)
40975402Speter			used++;
41075402Speter		if (maxlength < count)
41175402Speter			maxlength = count;
41275402Speter	}
41375402Speter	n_nchash = nchash + 1;
414281677Smckusick	CACHE_RUNLOCK();
415232156Smaxim	pct = (used * 100) / (n_nchash / 100);
41698994Salfred	error = SYSCTL_OUT(req, &n_nchash, sizeof(n_nchash));
41775402Speter	if (error)
41875402Speter		return (error);
41998994Salfred	error = SYSCTL_OUT(req, &used, sizeof(used));
42075402Speter	if (error)
42175402Speter		return (error);
42298994Salfred	error = SYSCTL_OUT(req, &maxlength, sizeof(maxlength));
42375402Speter	if (error)
42475402Speter		return (error);
42598994Salfred	error = SYSCTL_OUT(req, &pct, sizeof(pct));
42675402Speter	if (error)
42775402Speter		return (error);
42875402Speter	return (0);
42975402Speter}
430187658SjhbSYSCTL_PROC(_debug_hashstat, OID_AUTO, nchash, CTLTYPE_INT|CTLFLAG_RD|
431215304Sbrucec    CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_nchash, "I",
432232156Smaxim    "nchash statistics (number of total/used buckets, maximum chain length, usage percentage)");
433189593Sjhb#endif
43475402Speter
43575402Speter/*
436110952Sarr * cache_zap():
437110952Sarr *
438110952Sarr *   Removes a namecache entry from cache, whether it contains an actual
439110952Sarr *   pointer to a vnode or if it is just a negative cache entry.
44022521Sdyson */
44125453Sphkstatic void
442293295Smjgcache_zap(struct namecache *ncp)
44325453Sphk{
444120792Sjeff	struct vnode *vp;
445120792Sjeff
446187839Sjhb	rw_assert(&cache_lock, RA_WLOCKED);
447147326Sjeff	CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, ncp->nc_vp);
448190829Srwatson	if (ncp->nc_vp != NULL) {
449288336Savg		SDT_PROBE3(vfs, namecache, zap, done, ncp->nc_dvp,
450288336Savg		    nc_get_name(ncp), ncp->nc_vp);
451190829Srwatson	} else {
452288336Savg		SDT_PROBE2(vfs, namecache, zap_negative, done, ncp->nc_dvp,
453288336Savg		    nc_get_name(ncp));
454190829Srwatson	}
455120792Sjeff	vp = NULL;
45625453Sphk	LIST_REMOVE(ncp, nc_hash);
457190533Skan	if (ncp->nc_flag & NCF_ISDOTDOT) {
458190533Skan		if (ncp == ncp->nc_dvp->v_cache_dd)
459190533Skan			ncp->nc_dvp->v_cache_dd = NULL;
460190533Skan	} else {
461190533Skan		LIST_REMOVE(ncp, nc_src);
462190533Skan		if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src)) {
463190533Skan			vp = ncp->nc_dvp;
464190533Skan			numcachehv--;
465190533Skan		}
46675654Stanimura	}
46725453Sphk	if (ncp->nc_vp) {
46825453Sphk		TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst);
469190533Skan		if (ncp == ncp->nc_vp->v_cache_dd)
470190533Skan			ncp->nc_vp->v_cache_dd = NULL;
47125453Sphk	} else {
47225453Sphk		TAILQ_REMOVE(&ncneg, ncp, nc_dst);
47325453Sphk		numneg--;
47425453Sphk	}
47525453Sphk	numcache--;
476116289Sdes	cache_free(ncp);
477293295Smjg	if (vp != NULL)
478120792Sjeff		vdrop(vp);
47922521Sdyson}
4806968Sphk
48122521Sdyson/*
48223521Sbde * Lookup an entry in the cache
4836968Sphk *
4846968Sphk * Lookup is called with dvp pointing to the directory to search,
48522521Sdyson * cnp pointing to the name of the entry being sought. If the lookup
48622521Sdyson * succeeds, the vnode is returned in *vpp, and a status of -1 is
48722521Sdyson * returned. If the lookup determines that the name does not exist
488298819Spfg * (negative caching), a status of ENOENT is returned. If the lookup
489183330Sjhb * fails, a status of zero is returned.  If the directory vnode is
490183330Sjhb * recycled out from under us due to a forced unmount, a status of
491190387Sjhb * ENOENT is returned.
492144296Sjeff *
493144296Sjeff * vpp is locked and ref'd on return.  If we're looking up DOTDOT, dvp is
494144296Sjeff * unlocked.  If we're looking up . an extra ref is taken, but the lock is
495144296Sjeff * not recursively acquired.
4961541Srgrimes */
4976968Sphk
4981541Srgrimesint
499293295Smjgcache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
500293295Smjg    struct timespec *tsp, int *ticksp)
5011541Srgrimes{
50251906Sphk	struct namecache *ncp;
503209390Sed	uint32_t hash;
504187839Sjhb	int error, ltype, wlocked;
5051541Srgrimes
5066928Sphk	if (!doingcache) {
5076928Sphk		cnp->cn_flags &= ~MAKEENTRY;
5081541Srgrimes		return (0);
5096928Sphk	}
510144296Sjeffretry:
511187839Sjhb	wlocked = 0;
512294475Smjg	counter_u64_add(numcalls, 1);
513187839Sjhb	error = 0;
51429788Sphk
515187839Sjhbretry_wlocked:
51625453Sphk	if (cnp->cn_nameptr[0] == '.') {
51725453Sphk		if (cnp->cn_namelen == 1) {
51825453Sphk			*vpp = dvp;
519147326Sjeff			CTR2(KTR_VFS, "cache_lookup(%p, %s) found via .",
520147326Sjeff			    dvp, cnp->cn_nameptr);
521294475Smjg			counter_u64_add(dothits, 1);
522288336Savg			SDT_PROBE3(vfs, namecache, lookup, hit, dvp, ".", *vpp);
523230394Sjhb			if (tsp != NULL)
524230394Sjhb				timespecclear(tsp);
525230394Sjhb			if (ticksp != NULL)
526230394Sjhb				*ticksp = ticks;
527294477Smjg			VREF(*vpp);
528294477Smjg			/*
529294477Smjg			 * When we lookup "." we still can be asked to lock it
530294477Smjg			 * differently...
531294477Smjg			 */
532294477Smjg			ltype = cnp->cn_lkflags & LK_TYPE_MASK;
533294477Smjg			if (ltype != VOP_ISLOCKED(*vpp)) {
534294477Smjg				if (ltype == LK_EXCLUSIVE) {
535294477Smjg					vn_lock(*vpp, LK_UPGRADE | LK_RETRY);
536294477Smjg					if ((*vpp)->v_iflag & VI_DOOMED) {
537294477Smjg						/* forced unmount */
538294477Smjg						vrele(*vpp);
539294477Smjg						*vpp = NULL;
540294477Smjg						return (ENOENT);
541294477Smjg					}
542294477Smjg				} else
543294477Smjg					vn_lock(*vpp, LK_DOWNGRADE | LK_RETRY);
544294477Smjg			}
545294477Smjg			return (-1);
54625453Sphk		}
547294477Smjg		if (!wlocked)
548294477Smjg			CACHE_RLOCK();
54925453Sphk		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
550294475Smjg			counter_u64_add(dotdothits, 1);
551190829Srwatson			if (dvp->v_cache_dd == NULL) {
552288336Savg				SDT_PROBE3(vfs, namecache, lookup, miss, dvp,
553288336Savg				    "..", NULL);
554187839Sjhb				goto unlock;
555190829Srwatson			}
556190533Skan			if ((cnp->cn_flags & MAKEENTRY) == 0) {
557190942Skib				if (!wlocked && !CACHE_UPGRADE_LOCK())
558190942Skib					goto wlock;
559190533Skan				if (dvp->v_cache_dd->nc_flag & NCF_ISDOTDOT)
560190533Skan					cache_zap(dvp->v_cache_dd);
561190533Skan				dvp->v_cache_dd = NULL;
562196203Skib				CACHE_WUNLOCK();
563196203Skib				return (0);
56425453Sphk			}
565230394Sjhb			ncp = dvp->v_cache_dd;
566230394Sjhb			if (ncp->nc_flag & NCF_ISDOTDOT)
567230394Sjhb				*vpp = ncp->nc_vp;
568190533Skan			else
569230394Sjhb				*vpp = ncp->nc_dvp;
570191081Skan			/* Return failure if negative entry was found. */
571230394Sjhb			if (*vpp == NULL)
572191082Skan				goto negative_success;
573147326Sjeff			CTR3(KTR_VFS, "cache_lookup(%p, %s) found %p via ..",
574147326Sjeff			    dvp, cnp->cn_nameptr, *vpp);
575288336Savg			SDT_PROBE3(vfs, namecache, lookup, hit, dvp, "..",
576288336Savg			    *vpp);
577230489Skib			cache_out_ts(ncp, tsp, ticksp);
578232420Srmacklem			if ((ncp->nc_flag & (NCF_ISDOTDOT | NCF_DTS)) ==
579232420Srmacklem			    NCF_DTS && tsp != NULL)
580232420Srmacklem				*tsp = ((struct namecache_ts *)ncp)->
581232420Srmacklem				    nc_dotdottime;
582144296Sjeff			goto success;
58325453Sphk		}
584294477Smjg	} else if (!wlocked)
585294477Smjg		CACHE_RLOCK();
5866968Sphk
587294476Smjg	hash = cache_get_hash(cnp->cn_nameptr, cnp->cn_namelen, dvp);
58874501Speter	LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) {
589294475Smjg		counter_u64_add(numchecks, 1);
59025453Sphk		if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen &&
591230441Skib		    !bcmp(nc_get_name(ncp), cnp->cn_nameptr, ncp->nc_nlen))
59222521Sdyson			break;
5931541Srgrimes	}
5946968Sphk
59522521Sdyson	/* We failed to find an entry */
596187839Sjhb	if (ncp == NULL) {
597288336Savg		SDT_PROBE3(vfs, namecache, lookup, miss, dvp, cnp->cn_nameptr,
598288336Savg		    NULL);
59929804Sphk		if ((cnp->cn_flags & MAKEENTRY) == 0) {
600294475Smjg			counter_u64_add(nummisszap, 1);
60129804Sphk		} else {
602294475Smjg			counter_u64_add(nummiss, 1);
60329804Sphk		}
604187839Sjhb		goto unlock;
60522521Sdyson	}
60622521Sdyson
6076968Sphk	/* We don't want to have an entry, so dump it */
6086928Sphk	if ((cnp->cn_flags & MAKEENTRY) == 0) {
609294475Smjg		counter_u64_add(numposzaps, 1);
610187839Sjhb		if (!wlocked && !CACHE_UPGRADE_LOCK())
611187839Sjhb			goto wlock;
612140712Sjeff		cache_zap(ncp);
613187839Sjhb		CACHE_WUNLOCK();
6146968Sphk		return (0);
61523521Sbde	}
6166968Sphk
6176968Sphk	/* We found a "positive" match, return the vnode */
618116201Sdes	if (ncp->nc_vp) {
619294475Smjg		counter_u64_add(numposhits, 1);
6201541Srgrimes		*vpp = ncp->nc_vp;
621147326Sjeff		CTR4(KTR_VFS, "cache_lookup(%p, %s) found %p via ncp %p",
622147326Sjeff		    dvp, cnp->cn_nameptr, *vpp, ncp);
623288336Savg		SDT_PROBE3(vfs, namecache, lookup, hit, dvp, nc_get_name(ncp),
624288336Savg		    *vpp);
625230489Skib		cache_out_ts(ncp, tsp, ticksp);
626144296Sjeff		goto success;
6271541Srgrimes	}
6281541Srgrimes
629191082Skannegative_success:
6306968Sphk	/* We found a negative match, and want to create it, so purge */
6316968Sphk	if (cnp->cn_nameiop == CREATE) {
632294475Smjg		counter_u64_add(numnegzaps, 1);
633187839Sjhb		if (!wlocked && !CACHE_UPGRADE_LOCK())
634187839Sjhb			goto wlock;
635140712Sjeff		cache_zap(ncp);
636187839Sjhb		CACHE_WUNLOCK();
6376968Sphk		return (0);
6386968Sphk	}
6396968Sphk
640187839Sjhb	if (!wlocked && !CACHE_UPGRADE_LOCK())
641187839Sjhb		goto wlock;
642294475Smjg	counter_u64_add(numneghits, 1);
64322521Sdyson	/*
644110967Sarr	 * We found a "negative" match, so we shift it to the end of
645110967Sarr	 * the "negative" cache entries queue to satisfy LRU.  Also,
646110967Sarr	 * check to see if the entry is a whiteout; indicate this to
647110967Sarr	 * the componentname, if so.
64822521Sdyson	 */
64925453Sphk	TAILQ_REMOVE(&ncneg, ncp, nc_dst);
65025453Sphk	TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
65125453Sphk	if (ncp->nc_flag & NCF_WHITE)
65225453Sphk		cnp->cn_flags |= ISWHITEOUT;
653288336Savg	SDT_PROBE2(vfs, namecache, lookup, hit__negative, dvp,
654288336Savg	    nc_get_name(ncp));
655230489Skib	cache_out_ts(ncp, tsp, ticksp);
656187839Sjhb	CACHE_WUNLOCK();
6576968Sphk	return (ENOENT);
658144296Sjeff
659187839Sjhbwlock:
660187839Sjhb	/*
661187839Sjhb	 * We need to update the cache after our lookup, so upgrade to
662187839Sjhb	 * a write lock and retry the operation.
663187839Sjhb	 */
664187839Sjhb	CACHE_RUNLOCK();
665187839Sjhb	CACHE_WLOCK();
666187839Sjhb	numupgrades++;
667187839Sjhb	wlocked = 1;
668187839Sjhb	goto retry_wlocked;
669187839Sjhb
670144296Sjeffsuccess:
671144296Sjeff	/*
672144296Sjeff	 * On success we return a locked and ref'd vnode as per the lookup
673144296Sjeff	 * protocol.
674144296Sjeff	 */
675294477Smjg	MPASS(dvp != *vpp);
676170000Spjd	ltype = 0;	/* silence gcc warning */
677170000Spjd	if (cnp->cn_flags & ISDOTDOT) {
678176559Sattilio		ltype = VOP_ISLOCKED(dvp);
679175294Sattilio		VOP_UNLOCK(dvp, 0);
680170000Spjd	}
681285632Smjg	vhold(*vpp);
682187839Sjhb	if (wlocked)
683187839Sjhb		CACHE_WUNLOCK();
684187839Sjhb	else
685187839Sjhb		CACHE_RUNLOCK();
686285632Smjg	error = vget(*vpp, cnp->cn_lkflags | LK_VNHELD, cnp->cn_thread);
687190887Skib	if (cnp->cn_flags & ISDOTDOT) {
688175202Sattilio		vn_lock(dvp, ltype | LK_RETRY);
689190887Skib		if (dvp->v_iflag & VI_DOOMED) {
690190887Skib			if (error == 0)
691190887Skib				vput(*vpp);
692190887Skib			*vpp = NULL;
693190887Skib			return (ENOENT);
694190887Skib		}
695190887Skib	}
696145006Sjeff	if (error) {
697144296Sjeff		*vpp = NULL;
698144296Sjeff		goto retry;
699144296Sjeff	}
700178046Spjd	if ((cnp->cn_flags & ISLASTCN) &&
701178046Spjd	    (cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE) {
702178046Spjd		ASSERT_VOP_ELOCKED(*vpp, "cache_lookup");
703178046Spjd	}
704144296Sjeff	return (-1);
705187839Sjhb
706187839Sjhbunlock:
707187839Sjhb	if (wlocked)
708187839Sjhb		CACHE_WUNLOCK();
709187839Sjhb	else
710187839Sjhb		CACHE_RUNLOCK();
711187839Sjhb	return (0);
7121541Srgrimes}
7131541Srgrimes
7141541Srgrimes/*
7156968Sphk * Add an entry to the cache.
7161541Srgrimes */
7171549Srgrimesvoid
718293295Smjgcache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
719293295Smjg    struct timespec *tsp, struct timespec *dtsp)
7201541Srgrimes{
721185557Skib	struct namecache *ncp, *n2;
722230441Skib	struct namecache_ts *n3;
72351906Sphk	struct nchashhead *ncpp;
724209390Sed	uint32_t hash;
725190533Skan	int flag;
72651906Sphk	int len;
7271541Srgrimes
728147326Sjeff	CTR3(KTR_VFS, "cache_enter(%p, %p, %s)", dvp, vp, cnp->cn_nameptr);
729147296Sjeff	VNASSERT(vp == NULL || (vp->v_iflag & VI_DOOMED) == 0, vp,
730206671Skib	    ("cache_enter: Adding a doomed vnode"));
731206894Skib	VNASSERT(dvp == NULL || (dvp->v_iflag & VI_DOOMED) == 0, dvp,
732206894Skib	    ("cache_enter: Doomed vnode used as src"));
733147296Sjeff
7341541Srgrimes	if (!doingcache)
7351541Srgrimes		return;
7366968Sphk
737187460Smckay	/*
738187460Smckay	 * Avoid blowout in namecache entries.
739187460Smckay	 */
740213916Skib	if (numcache >= desiredvnodes * ncsizefactor)
741187460Smckay		return;
742187460Smckay
743190533Skan	flag = 0;
74425453Sphk	if (cnp->cn_nameptr[0] == '.') {
745190533Skan		if (cnp->cn_namelen == 1)
74625453Sphk			return;
74725453Sphk		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
748187839Sjhb			CACHE_WLOCK();
749190533Skan			/*
750190533Skan			 * If dotdot entry already exists, just retarget it
751190533Skan			 * to new parent vnode, otherwise continue with new
752190533Skan			 * namecache entry allocation.
753190533Skan			 */
754191218Skan			if ((ncp = dvp->v_cache_dd) != NULL &&
755191218Skan			    ncp->nc_flag & NCF_ISDOTDOT) {
756191218Skan				KASSERT(ncp->nc_dvp == dvp,
757191218Skan				    ("wrong isdotdot parent"));
758259953Skib				if (ncp->nc_vp != NULL) {
759190533Skan					TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst,
760190533Skan					    ncp, nc_dst);
761259953Skib				} else {
762191218Skan					TAILQ_REMOVE(&ncneg, ncp, nc_dst);
763259953Skib					numneg--;
764259953Skib				}
765259953Skib				if (vp != NULL) {
766190533Skan					TAILQ_INSERT_HEAD(&vp->v_cache_dst,
767190533Skan					    ncp, nc_dst);
768259953Skib				} else {
769191218Skan					TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
770259953Skib					numneg++;
771259953Skib				}
772191218Skan				ncp->nc_vp = vp;
773191218Skan				CACHE_WUNLOCK();
774191218Skan				return;
775190533Skan			}
776190533Skan			dvp->v_cache_dd = NULL;
777288336Savg			SDT_PROBE3(vfs, namecache, enter, done, dvp, "..", vp);
778187839Sjhb			CACHE_WUNLOCK();
779190533Skan			flag = NCF_ISDOTDOT;
78025453Sphk		}
7816968Sphk	}
782116201Sdes
783182061Sjhb	/*
784182061Sjhb	 * Calculate the hash key and setup as much of the new
785182061Sjhb	 * namecache entry as possible before acquiring the lock.
786182061Sjhb	 */
787230441Skib	ncp = cache_alloc(cnp->cn_namelen, tsp != NULL);
788182061Sjhb	ncp->nc_vp = vp;
789182061Sjhb	ncp->nc_dvp = dvp;
790190533Skan	ncp->nc_flag = flag;
791230441Skib	if (tsp != NULL) {
792230441Skib		n3 = (struct namecache_ts *)ncp;
793230441Skib		n3->nc_time = *tsp;
794230441Skib		n3->nc_ticks = ticks;
795230441Skib		n3->nc_flag |= NCF_TS;
796232420Srmacklem		if (dtsp != NULL) {
797232420Srmacklem			n3->nc_dotdottime = *dtsp;
798232420Srmacklem			n3->nc_flag |= NCF_DTS;
799232420Srmacklem		}
800230441Skib	}
801182061Sjhb	len = ncp->nc_nlen = cnp->cn_namelen;
802294476Smjg	hash = cache_get_hash(cnp->cn_nameptr, len, dvp);
803230441Skib	strlcpy(nc_get_name(ncp), cnp->cn_nameptr, len + 1);
804187839Sjhb	CACHE_WLOCK();
805182061Sjhb
806182061Sjhb	/*
807186600Skib	 * See if this vnode or negative entry is already in the cache
808186600Skib	 * with this name.  This can happen with concurrent lookups of
809186600Skib	 * the same path name.
810182061Sjhb	 */
811186600Skib	ncpp = NCHHASH(hash);
812186600Skib	LIST_FOREACH(n2, ncpp, nc_hash) {
813186600Skib		if (n2->nc_dvp == dvp &&
814186600Skib		    n2->nc_nlen == cnp->cn_namelen &&
815230441Skib		    !bcmp(nc_get_name(n2), cnp->cn_nameptr, n2->nc_nlen)) {
816230441Skib			if (tsp != NULL) {
817230552Skib				KASSERT((n2->nc_flag & NCF_TS) != 0,
818230552Skib				    ("no NCF_TS"));
819230441Skib				n3 = (struct namecache_ts *)n2;
820230441Skib				n3->nc_time =
821230441Skib				    ((struct namecache_ts *)ncp)->nc_time;
822230441Skib				n3->nc_ticks =
823230441Skib				    ((struct namecache_ts *)ncp)->nc_ticks;
824232420Srmacklem				if (dtsp != NULL) {
825232420Srmacklem					n3->nc_dotdottime =
826232420Srmacklem					    ((struct namecache_ts *)ncp)->
827232420Srmacklem					    nc_dotdottime;
828232420Srmacklem					n3->nc_flag |= NCF_DTS;
829232420Srmacklem				}
830230441Skib			}
831187839Sjhb			CACHE_WUNLOCK();
832186600Skib			cache_free(ncp);
833186600Skib			return;
834182061Sjhb		}
835185557Skib	}
836182061Sjhb
837190945Skan	if (flag == NCF_ISDOTDOT) {
838190945Skan		/*
839190945Skan		 * See if we are trying to add .. entry, but some other lookup
840190945Skan		 * has populated v_cache_dd pointer already.
841190945Skan		 */
842190945Skan		if (dvp->v_cache_dd != NULL) {
843293295Smjg			CACHE_WUNLOCK();
844293295Smjg			cache_free(ncp);
845293295Smjg			return;
846190945Skan		}
847190945Skan		KASSERT(vp == NULL || vp->v_type == VDIR,
848190945Skan		    ("wrong vnode type %p", vp));
849190945Skan		dvp->v_cache_dd = ncp;
850190533Skan	}
851190533Skan
85225453Sphk	numcache++;
853294478Smjg	if (vp != NULL) {
854294478Smjg		if (vp->v_type == VDIR) {
855294478Smjg			if (flag != NCF_ISDOTDOT) {
856294478Smjg				/*
857294478Smjg				 * For this case, the cache entry maps both the
858294478Smjg				 * directory name in it and the name ".." for the
859294478Smjg				 * directory's parent.
860294478Smjg				 */
861294478Smjg				if ((n2 = vp->v_cache_dd) != NULL &&
862294478Smjg				    (n2->nc_flag & NCF_ISDOTDOT) != 0)
863294478Smjg					cache_zap(n2);
864294478Smjg				vp->v_cache_dd = ncp;
865294478Smjg			}
866294478Smjg		} else {
867294478Smjg			vp->v_cache_dd = NULL;
868190533Skan		}
86928954Sphk	}
87023521Sbde
87122521Sdyson	/*
872182061Sjhb	 * Insert the new namecache entry into the appropriate chain
873182061Sjhb	 * within the cache entries table.
87422521Sdyson	 */
8756928Sphk	LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
876190533Skan	if (flag != NCF_ISDOTDOT) {
877190533Skan		if (LIST_EMPTY(&dvp->v_cache_src)) {
878294478Smjg			vhold(dvp);
879190533Skan			numcachehv++;
880190533Skan		}
881190533Skan		LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src);
88275654Stanimura	}
883190533Skan
884110967Sarr	/*
885110967Sarr	 * If the entry is "negative", we place it into the
886110967Sarr	 * "negative" cache queue, otherwise, we place it into the
887110967Sarr	 * destination vnode's cache entries queue.
888110967Sarr	 */
889293295Smjg	if (vp != NULL) {
89025453Sphk		TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst);
891288336Savg		SDT_PROBE3(vfs, namecache, enter, done, dvp, nc_get_name(ncp),
892288336Savg		    vp);
89325453Sphk	} else {
894294478Smjg		if (cnp->cn_flags & ISWHITEOUT)
895294478Smjg			ncp->nc_flag |= NCF_WHITE;
89625453Sphk		TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
897294478Smjg		numneg++;
898288336Savg		SDT_PROBE2(vfs, namecache, enter_negative, done, dvp,
899288336Savg		    nc_get_name(ncp));
90025453Sphk	}
90151906Sphk	if (numneg * ncnegfactor > numcache) {
90225453Sphk		ncp = TAILQ_FIRST(&ncneg);
903259953Skib		KASSERT(ncp->nc_vp == NULL, ("ncp %p vp %p on ncneg",
904259953Skib		    ncp, ncp->nc_vp));
905294478Smjg		cache_zap(ncp);
90625453Sphk	}
907187839Sjhb	CACHE_WUNLOCK();
9081541Srgrimes}
9091541Srgrimes
9101541Srgrimes/*
9111541Srgrimes * Name cache initialization, from vfs_init() when we are booting
9121541Srgrimes */
91369664Speterstatic void
91469664Speternchinit(void *dummy __unused)
9151541Srgrimes{
91623521Sbde
91725453Sphk	TAILQ_INIT(&ncneg);
918116289Sdes
919230441Skib	cache_zone_small = uma_zcreate("S VFS Cache",
920230441Skib	    sizeof(struct namecache) + CACHE_PATH_CUTOFF + 1,
921230441Skib	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
922230441Skib	cache_zone_small_ts = uma_zcreate("STS VFS Cache",
923230441Skib	    sizeof(struct namecache_ts) + CACHE_PATH_CUTOFF + 1,
924230441Skib	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
925230441Skib	cache_zone_large = uma_zcreate("L VFS Cache",
926232420Srmacklem	    sizeof(struct namecache) + NAME_MAX + 1,
927232420Srmacklem	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
928232420Srmacklem	cache_zone_large_ts = uma_zcreate("LTS VFS Cache",
929230441Skib	    sizeof(struct namecache_ts) + NAME_MAX + 1,
930230441Skib	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
931116289Sdes
93269664Speter	nchashtbl = hashinit(desiredvnodes * 2, M_VFSCACHE, &nchash);
933294475Smjg
934294475Smjg	numcalls = counter_u64_alloc(M_WAITOK);
935294475Smjg	dothits = counter_u64_alloc(M_WAITOK);
936294475Smjg	dotdothits = counter_u64_alloc(M_WAITOK);
937294475Smjg	numchecks = counter_u64_alloc(M_WAITOK);
938294475Smjg	nummiss = counter_u64_alloc(M_WAITOK);
939294475Smjg	nummisszap = counter_u64_alloc(M_WAITOK);
940294475Smjg	numposzaps = counter_u64_alloc(M_WAITOK);
941294475Smjg	numposhits = counter_u64_alloc(M_WAITOK);
942294475Smjg	numnegzaps = counter_u64_alloc(M_WAITOK);
943294475Smjg	numneghits = counter_u64_alloc(M_WAITOK);
944294475Smjg	numfullpathcalls = counter_u64_alloc(M_WAITOK);
945294475Smjg	numfullpathfail1 = counter_u64_alloc(M_WAITOK);
946294475Smjg	numfullpathfail2 = counter_u64_alloc(M_WAITOK);
947294475Smjg	numfullpathfail4 = counter_u64_alloc(M_WAITOK);
948294475Smjg	numfullpathfound = counter_u64_alloc(M_WAITOK);
9491541Srgrimes}
950177253SrwatsonSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nchinit, NULL);
9511541Srgrimes
952287497Smckusickvoid
953287497Smckusickcache_changesize(int newmaxvnodes)
954287497Smckusick{
955287497Smckusick	struct nchashhead *new_nchashtbl, *old_nchashtbl;
956287497Smckusick	u_long new_nchash, old_nchash;
957287497Smckusick	struct namecache *ncp;
958287497Smckusick	uint32_t hash;
959287497Smckusick	int i;
96069664Speter
961287497Smckusick	new_nchashtbl = hashinit(newmaxvnodes * 2, M_VFSCACHE, &new_nchash);
962287497Smckusick	/* If same hash table size, nothing to do */
963287497Smckusick	if (nchash == new_nchash) {
964287497Smckusick		free(new_nchashtbl, M_VFSCACHE);
965287497Smckusick		return;
966287497Smckusick	}
967287497Smckusick	/*
968287497Smckusick	 * Move everything from the old hash table to the new table.
969287497Smckusick	 * None of the namecache entries in the table can be removed
970287497Smckusick	 * because to do so, they have to be removed from the hash table.
971287497Smckusick	 */
972287497Smckusick	CACHE_WLOCK();
973287497Smckusick	old_nchashtbl = nchashtbl;
974287497Smckusick	old_nchash = nchash;
975287497Smckusick	nchashtbl = new_nchashtbl;
976287497Smckusick	nchash = new_nchash;
977287497Smckusick	for (i = 0; i <= old_nchash; i++) {
978287497Smckusick		while ((ncp = LIST_FIRST(&old_nchashtbl[i])) != NULL) {
979294476Smjg			hash = cache_get_hash(nc_get_name(ncp), ncp->nc_nlen,
980294476Smjg			    ncp->nc_dvp);
981287497Smckusick			LIST_REMOVE(ncp, nc_hash);
982287497Smckusick			LIST_INSERT_HEAD(NCHHASH(hash), ncp, nc_hash);
983287497Smckusick		}
984287497Smckusick	}
985287497Smckusick	CACHE_WUNLOCK();
986287497Smckusick	free(old_nchashtbl, M_VFSCACHE);
987287497Smckusick}
988287497Smckusick
9891541Srgrimes/*
99046011Sphk * Invalidate all entries to a particular vnode.
9911541Srgrimes */
9921549Srgrimesvoid
993293295Smjgcache_purge(struct vnode *vp)
9941541Srgrimes{
9951541Srgrimes
996147326Sjeff	CTR1(KTR_VFS, "cache_purge(%p)", vp);
997288336Savg	SDT_PROBE1(vfs, namecache, purge, done, vp);
998187839Sjhb	CACHE_WLOCK();
999147331Sjeff	while (!LIST_EMPTY(&vp->v_cache_src))
1000147331Sjeff		cache_zap(LIST_FIRST(&vp->v_cache_src));
1001116201Sdes	while (!TAILQ_EMPTY(&vp->v_cache_dst))
1002140712Sjeff		cache_zap(TAILQ_FIRST(&vp->v_cache_dst));
1003190533Skan	if (vp->v_cache_dd != NULL) {
1004190533Skan		KASSERT(vp->v_cache_dd->nc_flag & NCF_ISDOTDOT,
1005190533Skan		   ("lost dotdot link"));
1006190533Skan		cache_zap(vp->v_cache_dd);
1007190533Skan	}
1008190533Skan	KASSERT(vp->v_cache_dd == NULL, ("incomplete purge"));
1009187839Sjhb	CACHE_WUNLOCK();
10101541Srgrimes}
10111541Srgrimes
10121541Srgrimes/*
1013188833Sjhb * Invalidate all negative entries for a particular directory vnode.
1014188833Sjhb */
1015188833Sjhbvoid
1016293295Smjgcache_purge_negative(struct vnode *vp)
1017188833Sjhb{
1018188833Sjhb	struct namecache *cp, *ncp;
1019188833Sjhb
1020188833Sjhb	CTR1(KTR_VFS, "cache_purge_negative(%p)", vp);
1021288336Savg	SDT_PROBE1(vfs, namecache, purge_negative, done, vp);
1022188833Sjhb	CACHE_WLOCK();
1023188833Sjhb	LIST_FOREACH_SAFE(cp, &vp->v_cache_src, nc_src, ncp) {
1024188833Sjhb		if (cp->nc_vp == NULL)
1025188833Sjhb			cache_zap(cp);
1026188833Sjhb	}
1027188833Sjhb	CACHE_WUNLOCK();
1028188833Sjhb}
1029188833Sjhb
1030188833Sjhb/*
10316968Sphk * Flush all entries referencing a particular filesystem.
10321541Srgrimes */
10331549Srgrimesvoid
1034293295Smjgcache_purgevfs(struct mount *mp)
10351541Srgrimes{
10366968Sphk	struct nchashhead *ncpp;
103722521Sdyson	struct namecache *ncp, *nnp;
10381541Srgrimes
10396968Sphk	/* Scan hash tables for applicable entries */
1040288336Savg	SDT_PROBE1(vfs, namecache, purgevfs, done, mp);
1041187839Sjhb	CACHE_WLOCK();
104229071Sphk	for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
1043169999Spjd		LIST_FOREACH_SAFE(ncp, ncpp, nc_hash, nnp) {
1044169999Spjd			if (ncp->nc_dvp->v_mount == mp)
1045169999Spjd				cache_zap(ncp);
10461541Srgrimes		}
10471541Srgrimes	}
1048187839Sjhb	CACHE_WUNLOCK();
10491541Srgrimes}
105028787Sphk
105128787Sphk/*
105228787Sphk * Perform canonical checks and cache lookup and pass on to filesystem
105328787Sphk * through the vop_cachedlookup only if needed.
105428787Sphk */
105528787Sphk
105628787Sphkint
1057293295Smjgvfs_cache_lookup(struct vop_lookup_args *ap)
105828787Sphk{
1059144296Sjeff	struct vnode *dvp;
106028787Sphk	int error;
106128787Sphk	struct vnode **vpp = ap->a_vpp;
106228787Sphk	struct componentname *cnp = ap->a_cnp;
106328787Sphk	struct ucred *cred = cnp->cn_cred;
106428787Sphk	int flags = cnp->cn_flags;
106583366Sjulian	struct thread *td = cnp->cn_thread;
106628787Sphk
106728787Sphk	*vpp = NULL;
106865665Sbp	dvp = ap->a_dvp;
106928787Sphk
107065665Sbp	if (dvp->v_type != VDIR)
1071116201Sdes		return (ENOTDIR);
107228787Sphk
107365665Sbp	if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
107428787Sphk	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
107528787Sphk		return (EROFS);
107628787Sphk
107783366Sjulian	error = VOP_ACCESS(dvp, VEXEC, cred, td);
107828787Sphk	if (error)
107928787Sphk		return (error);
108028787Sphk
1081231088Sjhb	error = cache_lookup(dvp, vpp, cnp, NULL, NULL);
1082144296Sjeff	if (error == 0)
1083144287Sjeff		return (VOP_CACHEDLOOKUP(dvp, vpp, cnp));
1084183330Sjhb	if (error == -1)
1085183330Sjhb		return (0);
1086183330Sjhb	return (error);
108728787Sphk}
108851906Sphk
108991690Seivind/*
109091690Seivind * XXX All of these sysctls would probably be more productive dead.
109191690Seivind */
109251906Sphkstatic int disablecwd;
109391690SeivindSYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0,
109491690Seivind   "Disable the getcwd syscall");
109551906Sphk
1096167232Srwatson/* Implementation of the getcwd syscall. */
109751906Sphkint
1098293295Smjgsys___getcwd(struct thread *td, struct __getcwd_args *uap)
109951906Sphk{
1100112430Sphk
1101281829Strasz	return (kern___getcwd(td, uap->buf, UIO_USERSPACE, uap->buflen,
1102281829Strasz	    MAXPATHLEN));
1103102870Siedowse}
1104102870Siedowse
1105102870Siedowseint
1106281829Straszkern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, u_int buflen,
1107281829Strasz    u_int path_max)
1108102870Siedowse{
1109102870Siedowse	char *bp, *tmpbuf;
111051906Sphk	struct filedesc *fdp;
1111185298Smarcus	struct vnode *cdir, *rdir;
1112241896Skib	int error;
111351906Sphk
1114112430Sphk	if (disablecwd)
111551906Sphk		return (ENODEV);
1116102870Siedowse	if (buflen < 2)
111751906Sphk		return (EINVAL);
1118281829Strasz	if (buflen > path_max)
1119281829Strasz		buflen = path_max;
1120144318Sdas
1121144318Sdas	tmpbuf = malloc(buflen, M_TEMP, M_WAITOK);
1122144318Sdas	fdp = td->td_proc->p_fd;
1123168355Srwatson	FILEDESC_SLOCK(fdp);
1124185298Smarcus	cdir = fdp->fd_cdir;
1125185298Smarcus	VREF(cdir);
1126185298Smarcus	rdir = fdp->fd_rdir;
1127185298Smarcus	VREF(rdir);
1128168355Srwatson	FILEDESC_SUNLOCK(fdp);
1129185298Smarcus	error = vn_fullpath1(td, cdir, rdir, tmpbuf, &bp, buflen);
1130185298Smarcus	vrele(rdir);
1131185298Smarcus	vrele(cdir);
1132144318Sdas
1133144318Sdas	if (!error) {
1134144318Sdas		if (bufseg == UIO_SYSSPACE)
1135144318Sdas			bcopy(bp, buf, strlen(bp) + 1);
1136144318Sdas		else
1137144318Sdas			error = copyout(bp, buf, strlen(bp) + 1);
1138190141Skib#ifdef KTRACE
1139190141Skib	if (KTRPOINT(curthread, KTR_NAMEI))
1140190141Skib		ktrnamei(bp);
1141190141Skib#endif
1142144318Sdas	}
1143102870Siedowse	free(tmpbuf, M_TEMP);
114451906Sphk	return (error);
114551906Sphk}
114651906Sphk
114759652Sgreen/*
114859652Sgreen * Thus begins the fullpath magic.
114959652Sgreen */
115059652Sgreen
115159652Sgreenstatic int disablefullpath;
115291690SeivindSYSCTL_INT(_debug, OID_AUTO, disablefullpath, CTLFLAG_RW, &disablefullpath, 0,
1153215304Sbrucec    "Disable the vn_fullpath function");
115459652Sgreen
115591690Seivind/*
115691690Seivind * Retrieve the full filesystem path that correspond to a vnode from the name
115791690Seivind * cache (if available)
115891690Seivind */
115959652Sgreenint
116085287Sdesvn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf)
116185287Sdes{
1162144318Sdas	char *buf;
116359652Sgreen	struct filedesc *fdp;
1164185298Smarcus	struct vnode *rdir;
1165241896Skib	int error;
116659652Sgreen
116759652Sgreen	if (disablefullpath)
116859652Sgreen		return (ENODEV);
116985287Sdes	if (vn == NULL)
117059652Sgreen		return (EINVAL);
1171144318Sdas
1172111119Simp	buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
1173144318Sdas	fdp = td->td_proc->p_fd;
1174168355Srwatson	FILEDESC_SLOCK(fdp);
1175185298Smarcus	rdir = fdp->fd_rdir;
1176185298Smarcus	VREF(rdir);
1177168355Srwatson	FILEDESC_SUNLOCK(fdp);
1178185298Smarcus	error = vn_fullpath1(td, vn, rdir, buf, retbuf, MAXPATHLEN);
1179185298Smarcus	vrele(rdir);
1180144318Sdas
1181144318Sdas	if (!error)
1182144318Sdas		*freebuf = buf;
1183144318Sdas	else
1184144318Sdas		free(buf, M_TEMP);
1185144318Sdas	return (error);
1186144318Sdas}
1187144318Sdas
1188144318Sdas/*
1189181060Scsjp * This function is similar to vn_fullpath, but it attempts to lookup the
1190181060Scsjp * pathname relative to the global root mount point.  This is required for the
1191181060Scsjp * auditing sub-system, as audited pathnames must be absolute, relative to the
1192181060Scsjp * global root mount point.
1193181060Scsjp */
1194181060Scsjpint
1195181060Scsjpvn_fullpath_global(struct thread *td, struct vnode *vn,
1196181060Scsjp    char **retbuf, char **freebuf)
1197181060Scsjp{
1198181060Scsjp	char *buf;
1199181060Scsjp	int error;
1200181060Scsjp
1201181060Scsjp	if (disablefullpath)
1202181060Scsjp		return (ENODEV);
1203181060Scsjp	if (vn == NULL)
1204181060Scsjp		return (EINVAL);
1205181060Scsjp	buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
1206181060Scsjp	error = vn_fullpath1(td, vn, rootvnode, buf, retbuf, MAXPATHLEN);
1207181060Scsjp	if (!error)
1208181060Scsjp		*freebuf = buf;
1209181060Scsjp	else
1210181060Scsjp		free(buf, M_TEMP);
1211181060Scsjp	return (error);
1212181060Scsjp}
1213181060Scsjp
1214193174Skibint
1215194601Skibvn_vptocnp(struct vnode **vp, struct ucred *cred, char *buf, u_int *buflen)
1216193174Skib{
1217193174Skib	int error;
1218193174Skib
1219193174Skib	CACHE_RLOCK();
1220194601Skib	error = vn_vptocnp_locked(vp, cred, buf, buflen);
1221227697Skib	if (error == 0)
1222193174Skib		CACHE_RUNLOCK();
1223193174Skib	return (error);
1224193174Skib}
1225193174Skib
1226185956Smarcusstatic int
1227194601Skibvn_vptocnp_locked(struct vnode **vp, struct ucred *cred, char *buf,
1228194601Skib    u_int *buflen)
1229185956Smarcus{
1230185956Smarcus	struct vnode *dvp;
1231193174Skib	struct namecache *ncp;
1232241896Skib	int error;
1233185956Smarcus
1234193174Skib	TAILQ_FOREACH(ncp, &((*vp)->v_cache_dst), nc_dst) {
1235193174Skib		if ((ncp->nc_flag & NCF_ISDOTDOT) == 0)
1236193174Skib			break;
1237193174Skib	}
1238193174Skib	if (ncp != NULL) {
1239193174Skib		if (*buflen < ncp->nc_nlen) {
1240193174Skib			CACHE_RUNLOCK();
1241227697Skib			vrele(*vp);
1242294475Smjg			counter_u64_add(numfullpathfail4, 1);
1243193174Skib			error = ENOMEM;
1244288336Savg			SDT_PROBE3(vfs, namecache, fullpath, return, error,
1245288336Savg			    vp, NULL);
1246193174Skib			return (error);
1247193174Skib		}
1248193174Skib		*buflen -= ncp->nc_nlen;
1249230441Skib		memcpy(buf + *buflen, nc_get_name(ncp), ncp->nc_nlen);
1250288336Savg		SDT_PROBE3(vfs, namecache, fullpath, hit, ncp->nc_dvp,
1251288336Savg		    nc_get_name(ncp), vp);
1252227697Skib		dvp = *vp;
1253193174Skib		*vp = ncp->nc_dvp;
1254227697Skib		vref(*vp);
1255227697Skib		CACHE_RUNLOCK();
1256227697Skib		vrele(dvp);
1257227697Skib		CACHE_RLOCK();
1258193174Skib		return (0);
1259193174Skib	}
1260288336Savg	SDT_PROBE1(vfs, namecache, fullpath, miss, vp);
1261193174Skib
1262187839Sjhb	CACHE_RUNLOCK();
1263185956Smarcus	vn_lock(*vp, LK_SHARED | LK_RETRY);
1264194601Skib	error = VOP_VPTOCNP(*vp, &dvp, cred, buf, buflen);
1265227697Skib	vput(*vp);
1266185956Smarcus	if (error) {
1267294475Smjg		counter_u64_add(numfullpathfail2, 1);
1268288336Savg		SDT_PROBE3(vfs, namecache, fullpath, return,  error, vp, NULL);
1269185956Smarcus		return (error);
1270185956Smarcus	}
1271193174Skib
1272185956Smarcus	*vp = dvp;
1273187839Sjhb	CACHE_RLOCK();
1274227697Skib	if (dvp->v_iflag & VI_DOOMED) {
1275185956Smarcus		/* forced unmount */
1276190697Skan		CACHE_RUNLOCK();
1277227697Skib		vrele(dvp);
1278193174Skib		error = ENOENT;
1279288336Savg		SDT_PROBE3(vfs, namecache, fullpath, return, error, vp, NULL);
1280193174Skib		return (error);
1281185956Smarcus	}
1282227697Skib	/*
1283227697Skib	 * *vp has its use count incremented still.
1284227697Skib	 */
1285185956Smarcus
1286185956Smarcus	return (0);
1287185956Smarcus}
1288185956Smarcus
1289181060Scsjp/*
1290144318Sdas * The magic behind kern___getcwd() and vn_fullpath().
1291144318Sdas */
1292144318Sdasstatic int
1293144318Sdasvn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
1294144318Sdas    char *buf, char **retbuf, u_int buflen)
1295144318Sdas{
1296241896Skib	int error, slash_prefixed;
1297190829Srwatson#ifdef KDTRACE_HOOKS
1298190829Srwatson	struct vnode *startvp = vp;
1299190829Srwatson#endif
1300227697Skib	struct vnode *vp1;
1301144318Sdas
1302185956Smarcus	buflen--;
1303193174Skib	buf[buflen] = '\0';
1304144318Sdas	error = 0;
130559652Sgreen	slash_prefixed = 0;
1306144318Sdas
1307288336Savg	SDT_PROBE1(vfs, namecache, fullpath, entry, vp);
1308294475Smjg	counter_u64_add(numfullpathcalls, 1);
1309227697Skib	vref(vp);
1310187839Sjhb	CACHE_RLOCK();
1311144318Sdas	if (vp->v_type != VDIR) {
1312194601Skib		error = vn_vptocnp_locked(&vp, td->td_ucred, buf, &buflen);
1313193174Skib		if (error)
1314190829Srwatson			return (error);
1315193518Smarcus		if (buflen == 0) {
1316193518Smarcus			CACHE_RUNLOCK();
1317227697Skib			vrele(vp);
1318193174Skib			return (ENOMEM);
1319193518Smarcus		}
1320193174Skib		buf[--buflen] = '/';
1321144318Sdas		slash_prefixed = 1;
1322144318Sdas	}
1323144318Sdas	while (vp != rdir && vp != rootvnode) {
1324101308Sjeff		if (vp->v_vflag & VV_ROOT) {
1325155385Sjeff			if (vp->v_iflag & VI_DOOMED) {	/* forced unmount */
1326187839Sjhb				CACHE_RUNLOCK();
1327227697Skib				vrele(vp);
1328190387Sjhb				error = ENOENT;
1329288336Savg				SDT_PROBE3(vfs, namecache, fullpath, return,
1330288336Savg				    error, vp, NULL);
1331144318Sdas				break;
133259652Sgreen			}
1333227697Skib			vp1 = vp->v_mount->mnt_vnodecovered;
1334227697Skib			vref(vp1);
1335227697Skib			CACHE_RUNLOCK();
1336227697Skib			vrele(vp);
1337227697Skib			vp = vp1;
1338227697Skib			CACHE_RLOCK();
133959652Sgreen			continue;
134059652Sgreen		}
1341185956Smarcus		if (vp->v_type != VDIR) {
1342193174Skib			CACHE_RUNLOCK();
1343227697Skib			vrele(vp);
1344294475Smjg			counter_u64_add(numfullpathfail1, 1);
1345144318Sdas			error = ENOTDIR;
1346288336Savg			SDT_PROBE3(vfs, namecache, fullpath, return,
1347288336Savg			    error, vp, NULL);
1348144318Sdas			break;
134959652Sgreen		}
1350194601Skib		error = vn_vptocnp_locked(&vp, td->td_ucred, buf, &buflen);
1351193174Skib		if (error)
1352193174Skib			break;
1353193174Skib		if (buflen == 0) {
1354193518Smarcus			CACHE_RUNLOCK();
1355227697Skib			vrele(vp);
1356144318Sdas			error = ENOMEM;
1357288336Savg			SDT_PROBE3(vfs, namecache, fullpath, return, error,
1358288336Savg			    startvp, NULL);
1359144318Sdas			break;
136059652Sgreen		}
1361193174Skib		buf[--buflen] = '/';
136259652Sgreen		slash_prefixed = 1;
1363144318Sdas	}
1364193174Skib	if (error)
1365144318Sdas		return (error);
136659652Sgreen	if (!slash_prefixed) {
1367193174Skib		if (buflen == 0) {
1368193174Skib			CACHE_RUNLOCK();
1369227697Skib			vrele(vp);
1370294475Smjg			counter_u64_add(numfullpathfail4, 1);
1371288336Savg			SDT_PROBE3(vfs, namecache, fullpath, return, ENOMEM,
1372288336Savg			    startvp, NULL);
137359652Sgreen			return (ENOMEM);
1374193174Skib		}
1375193174Skib		buf[--buflen] = '/';
137659652Sgreen	}
1377294475Smjg	counter_u64_add(numfullpathfound, 1);
1378187839Sjhb	CACHE_RUNLOCK();
1379227697Skib	vrele(vp);
1380144318Sdas
1381288336Savg	SDT_PROBE3(vfs, namecache, fullpath, return, 0, startvp, buf + buflen);
1382193174Skib	*retbuf = buf + buflen;
138359652Sgreen	return (0);
138459652Sgreen}
1385177782Skib
1386248561Smckusickstruct vnode *
1387248561Smckusickvn_dir_dd_ino(struct vnode *vp)
1388248561Smckusick{
1389248561Smckusick	struct namecache *ncp;
1390248561Smckusick	struct vnode *ddvp;
1391248561Smckusick
1392248561Smckusick	ASSERT_VOP_LOCKED(vp, "vn_dir_dd_ino");
1393248561Smckusick	CACHE_RLOCK();
1394248561Smckusick	TAILQ_FOREACH(ncp, &(vp->v_cache_dst), nc_dst) {
1395248561Smckusick		if ((ncp->nc_flag & NCF_ISDOTDOT) != 0)
1396248561Smckusick			continue;
1397248561Smckusick		ddvp = ncp->nc_dvp;
1398285632Smjg		vhold(ddvp);
1399248561Smckusick		CACHE_RUNLOCK();
1400285632Smjg		if (vget(ddvp, LK_SHARED | LK_NOWAIT | LK_VNHELD, curthread))
1401248561Smckusick			return (NULL);
1402248561Smckusick		return (ddvp);
1403248561Smckusick	}
1404248561Smckusick	CACHE_RUNLOCK();
1405248561Smckusick	return (NULL);
1406248561Smckusick}
1407248561Smckusick
1408177782Skibint
1409177782Skibvn_commname(struct vnode *vp, char *buf, u_int buflen)
1410177782Skib{
1411177782Skib	struct namecache *ncp;
1412177782Skib	int l;
1413177782Skib
1414187839Sjhb	CACHE_RLOCK();
1415190533Skan	TAILQ_FOREACH(ncp, &vp->v_cache_dst, nc_dst)
1416190533Skan		if ((ncp->nc_flag & NCF_ISDOTDOT) == 0)
1417190533Skan			break;
1418190533Skan	if (ncp == NULL) {
1419187839Sjhb		CACHE_RUNLOCK();
1420177782Skib		return (ENOENT);
1421177782Skib	}
1422177782Skib	l = min(ncp->nc_nlen, buflen - 1);
1423230441Skib	memcpy(buf, nc_get_name(ncp), l);
1424187839Sjhb	CACHE_RUNLOCK();
1425177782Skib	buf[l] = '\0';
1426177782Skib	return (0);
1427177782Skib}
1428230129Smm
1429230394Sjhb/* ABI compat shims for old kernel modules. */
1430230394Sjhb#undef cache_enter
1431230394Sjhb
1432230394Sjhbvoid	cache_enter(struct vnode *dvp, struct vnode *vp,
1433230394Sjhb	    struct componentname *cnp);
1434230394Sjhb
1435230394Sjhbvoid
1436230394Sjhbcache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
1437230394Sjhb{
1438230394Sjhb
1439232420Srmacklem	cache_enter_time(dvp, vp, cnp, NULL, NULL);
1440230394Sjhb}
1441230394Sjhb
1442230129Smm/*
1443230129Smm * This function updates path string to vnode's full global path
1444230129Smm * and checks the size of the new path string against the pathlen argument.
1445230129Smm *
1446269462Spluknet * Requires a locked, referenced vnode.
1447230129Smm * Vnode is re-locked on success or ENODEV, otherwise unlocked.
1448230129Smm *
1449230129Smm * If sysctl debug.disablefullpath is set, ENODEV is returned,
1450230129Smm * vnode is left locked and path remain untouched.
1451230129Smm *
1452230129Smm * If vp is a directory, the call to vn_fullpath_global() always succeeds
1453230143Smm * because it falls back to the ".." lookup if the namecache lookup fails.
1454230129Smm */
1455230129Smmint
1456230129Smmvn_path_to_global_path(struct thread *td, struct vnode *vp, char *path,
1457230129Smm    u_int pathlen)
1458230129Smm{
1459230129Smm	struct nameidata nd;
1460230129Smm	struct vnode *vp1;
1461230129Smm	char *rpath, *fbuf;
1462241896Skib	int error;
1463230129Smm
1464230129Smm	ASSERT_VOP_ELOCKED(vp, __func__);
1465230129Smm
1466230129Smm	/* Return ENODEV if sysctl debug.disablefullpath==1 */
1467230129Smm	if (disablefullpath)
1468230129Smm		return (ENODEV);
1469230129Smm
1470230129Smm	/* Construct global filesystem path from vp. */
1471230129Smm	VOP_UNLOCK(vp, 0);
1472230129Smm	error = vn_fullpath_global(td, vp, &rpath, &fbuf);
1473230129Smm
1474230129Smm	if (error != 0) {
1475230129Smm		vrele(vp);
1476230129Smm		return (error);
1477230129Smm	}
1478230129Smm
1479230129Smm	if (strlen(rpath) >= pathlen) {
1480230129Smm		vrele(vp);
1481230129Smm		error = ENAMETOOLONG;
1482230129Smm		goto out;
1483230129Smm	}
1484230129Smm
1485230129Smm	/*
1486230129Smm	 * Re-lookup the vnode by path to detect a possible rename.
1487230129Smm	 * As a side effect, the vnode is relocked.
1488230129Smm	 * If vnode was renamed, return ENOENT.
1489230129Smm	 */
1490241896Skib	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
1491230129Smm	    UIO_SYSSPACE, path, td);
1492230129Smm	error = namei(&nd);
1493230129Smm	if (error != 0) {
1494230129Smm		vrele(vp);
1495230129Smm		goto out;
1496230129Smm	}
1497230129Smm	NDFREE(&nd, NDF_ONLY_PNBUF);
1498230129Smm	vp1 = nd.ni_vp;
1499230129Smm	vrele(vp);
1500230129Smm	if (vp1 == vp)
1501230129Smm		strcpy(path, rpath);
1502230129Smm	else {
1503230129Smm		vput(vp1);
1504230129Smm		error = ENOENT;
1505230129Smm	}
1506230129Smm
1507230129Smmout:
1508230129Smm	free(fbuf, M_TEMP);
1509230129Smm	return (error);
1510230129Smm}
1511