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