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: stable/10/sys/kern/vfs_cache.c 324611 2017-10-13 21:58:44Z jhb $"); 37116182Sobrien 38190829Srwatson#include "opt_kdtrace.h" 39190141Skib#include "opt_ktrace.h" 40190141Skib 411541Srgrimes#include <sys/param.h> 42228433Savg#include <sys/systm.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); 65260817SavgSDT_PROBE_DEFINE3(vfs, namecache, enter, done, "struct vnode *", "char *", 66190829Srwatson "struct vnode *"); 67260817SavgSDT_PROBE_DEFINE2(vfs, namecache, enter_negative, done, "struct vnode *", 68190829Srwatson "char *"); 69260817SavgSDT_PROBE_DEFINE1(vfs, namecache, fullpath, entry, "struct vnode *"); 70260817SavgSDT_PROBE_DEFINE3(vfs, namecache, fullpath, hit, "struct vnode *", 71253075Savg "char *", "struct vnode *"); 72260817SavgSDT_PROBE_DEFINE1(vfs, namecache, fullpath, miss, "struct vnode *"); 73260817SavgSDT_PROBE_DEFINE3(vfs, namecache, fullpath, return, "int", 74253075Savg "struct vnode *", "char *"); 75260817SavgSDT_PROBE_DEFINE3(vfs, namecache, lookup, hit, "struct vnode *", "char *", 76190829Srwatson "struct vnode *"); 77260817SavgSDT_PROBE_DEFINE2(vfs, namecache, lookup, hit__negative, 78211616Srpaulo "struct vnode *", "char *"); 79260817SavgSDT_PROBE_DEFINE2(vfs, namecache, lookup, miss, "struct vnode *", 80190829Srwatson "char *"); 81260817SavgSDT_PROBE_DEFINE1(vfs, namecache, purge, done, "struct vnode *"); 82260817SavgSDT_PROBE_DEFINE1(vfs, namecache, purge_negative, done, "struct vnode *"); 83260817SavgSDT_PROBE_DEFINE1(vfs, namecache, purgevfs, done, "struct mount *"); 84260817SavgSDT_PROBE_DEFINE3(vfs, namecache, zap, done, "struct vnode *", "char *", 85190829Srwatson "struct vnode *"); 86260817SavgSDT_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/* 153302234Sbdrewery * 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"); 174213916Skibstatic u_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 */ 268273736ShselaskySYSCTL_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"); 276215281Sbrucec#define STATNODE(mode, name, var, descr) \ 277215281Sbrucec SYSCTL_ULONG(_vfs_cache, OID_AUTO, name, mode, var, 0, descr); 278215281SbrucecSTATNODE(CTLFLAG_RD, numneg, &numneg, "Number of negative cache entries"); 279215281SbrucecSTATNODE(CTLFLAG_RD, numcache, &numcache, "Number of cache entries"); 280215283Sbrucecstatic u_long numcalls; STATNODE(CTLFLAG_RD, numcalls, &numcalls, 281215304Sbrucec "Number of cache lookups"); 282215283Sbrucecstatic u_long dothits; STATNODE(CTLFLAG_RD, dothits, &dothits, 283215304Sbrucec "Number of '.' hits"); 284215283Sbrucecstatic u_long dotdothits; STATNODE(CTLFLAG_RD, dotdothits, &dotdothits, 285215304Sbrucec "Number of '..' hits"); 286215283Sbrucecstatic u_long numchecks; STATNODE(CTLFLAG_RD, numchecks, &numchecks, 287215304Sbrucec "Number of checks in lookup"); 288215283Sbrucecstatic u_long nummiss; STATNODE(CTLFLAG_RD, nummiss, &nummiss, 289215304Sbrucec "Number of cache misses"); 290215283Sbrucecstatic u_long nummisszap; STATNODE(CTLFLAG_RD, nummisszap, &nummisszap, 291215304Sbrucec "Number of cache misses we do not want to cache"); 292320756Smjgstatic u_long numposzaps; STATNODE(CTLFLAG_RD, numposzaps, &numposzaps, 293215304Sbrucec "Number of cache hits (positive) we do not want to cache"); 294215283Sbrucecstatic u_long numposhits; STATNODE(CTLFLAG_RD, numposhits, &numposhits, 295215304Sbrucec "Number of cache hits (positive)"); 296215283Sbrucecstatic u_long numnegzaps; STATNODE(CTLFLAG_RD, numnegzaps, &numnegzaps, 297215304Sbrucec "Number of cache hits (negative) we do not want to cache"); 298215283Sbrucecstatic u_long numneghits; STATNODE(CTLFLAG_RD, numneghits, &numneghits, 299215304Sbrucec "Number of cache hits (negative)"); 300215283Sbrucecstatic u_long numupgrades; STATNODE(CTLFLAG_RD, numupgrades, &numupgrades, 301215304Sbrucec "Number of updates of the cache after lookup (write lock + retry)"); 30229788Sphk 303187658SjhbSYSCTL_OPAQUE(_vfs_cache, OID_AUTO, nchstats, CTLFLAG_RD | CTLFLAG_MPSAFE, 304215304Sbrucec &nchstats, sizeof(nchstats), "LU", 305215304Sbrucec "VFS cache effectiveness statistics"); 30629788Sphk 307140712Sjeffstatic void cache_zap(struct namecache *ncp); 308194601Skibstatic int vn_vptocnp_locked(struct vnode **vp, struct ucred *cred, char *buf, 309194601Skib u_int *buflen); 310144318Sdasstatic int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir, 311144318Sdas char *buf, char **retbuf, u_int buflen); 3126968Sphk 31369774Sphkstatic MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries"); 31451906Sphk 315189593Sjhb#ifdef DIAGNOSTIC 31625453Sphk/* 31775402Speter * Grab an atomic snapshot of the name cache hash chain lengths 31875402Speter */ 319227309Sedstatic SYSCTL_NODE(_debug, OID_AUTO, hashstat, CTLFLAG_RW, NULL, 320227309Sed "hash table stats"); 32175402Speter 32275402Speterstatic int 32375402Spetersysctl_debug_hashstat_rawnchash(SYSCTL_HANDLER_ARGS) 32475402Speter{ 32575402Speter struct nchashhead *ncpp; 32675402Speter struct namecache *ncp; 327289418Spho int i, error, n_nchash, *cntbuf; 32875402Speter 329288079Smckusickretry: 33075402Speter n_nchash = nchash + 1; /* nchash is max index, not count */ 33175402Speter if (!req->oldptr) 33275402Speter return SYSCTL_OUT(req, 0, n_nchash * sizeof(int)); 333288079Smckusick cntbuf = malloc(n_nchash * sizeof(int), M_TEMP, M_ZERO | M_WAITOK); 334288079Smckusick CACHE_RLOCK(); 335288079Smckusick if (n_nchash != nchash + 1) { 336187839Sjhb CACHE_RUNLOCK(); 337288079Smckusick free(cntbuf, M_TEMP); 338288079Smckusick goto retry; 33975402Speter } 340288079Smckusick /* Scan hash tables counting entries */ 341288079Smckusick for (ncpp = nchashtbl, i = 0; i < n_nchash; ncpp++, i++) 342288079Smckusick LIST_FOREACH(ncp, ncpp, nc_hash) 343288079Smckusick cntbuf[i]++; 344288079Smckusick CACHE_RUNLOCK(); 345288079Smckusick for (error = 0, i = 0; i < n_nchash; i++) 346288079Smckusick if ((error = SYSCTL_OUT(req, &cntbuf[i], sizeof(int))) != 0) 347288079Smckusick break; 348288079Smckusick free(cntbuf, M_TEMP); 349288079Smckusick return (error); 35075402Speter} 351187658SjhbSYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnchash, CTLTYPE_INT|CTLFLAG_RD| 352215304Sbrucec CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_rawnchash, "S,int", 353215304Sbrucec "nchash chain lengths"); 35475402Speter 35575402Speterstatic int 35675402Spetersysctl_debug_hashstat_nchash(SYSCTL_HANDLER_ARGS) 35775402Speter{ 35875402Speter int error; 35975402Speter struct nchashhead *ncpp; 36075402Speter struct namecache *ncp; 36175402Speter int n_nchash; 36275402Speter int count, maxlength, used, pct; 36375402Speter 36475402Speter if (!req->oldptr) 36575402Speter return SYSCTL_OUT(req, 0, 4 * sizeof(int)); 36675402Speter 36775402Speter n_nchash = nchash + 1; /* nchash is max index, not count */ 36875402Speter used = 0; 36975402Speter maxlength = 0; 37075402Speter 37175402Speter /* Scan hash tables for applicable entries */ 37275402Speter for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) { 37375402Speter count = 0; 374187839Sjhb CACHE_RLOCK(); 37575402Speter LIST_FOREACH(ncp, ncpp, nc_hash) { 37675402Speter count++; 37775402Speter } 378187839Sjhb CACHE_RUNLOCK(); 37975402Speter if (count) 38075402Speter used++; 38175402Speter if (maxlength < count) 38275402Speter maxlength = count; 38375402Speter } 38475402Speter n_nchash = nchash + 1; 385232156Smaxim pct = (used * 100) / (n_nchash / 100); 38698994Salfred error = SYSCTL_OUT(req, &n_nchash, sizeof(n_nchash)); 38775402Speter if (error) 38875402Speter return (error); 38998994Salfred error = SYSCTL_OUT(req, &used, sizeof(used)); 39075402Speter if (error) 39175402Speter return (error); 39298994Salfred error = SYSCTL_OUT(req, &maxlength, sizeof(maxlength)); 39375402Speter if (error) 39475402Speter return (error); 39598994Salfred error = SYSCTL_OUT(req, &pct, sizeof(pct)); 39675402Speter if (error) 39775402Speter return (error); 39875402Speter return (0); 39975402Speter} 400187658SjhbSYSCTL_PROC(_debug_hashstat, OID_AUTO, nchash, CTLTYPE_INT|CTLFLAG_RD| 401215304Sbrucec CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_nchash, "I", 402232156Smaxim "nchash statistics (number of total/used buckets, maximum chain length, usage percentage)"); 403189593Sjhb#endif 40475402Speter 40575402Speter/* 406110952Sarr * cache_zap(): 407110952Sarr * 408110952Sarr * Removes a namecache entry from cache, whether it contains an actual 409110952Sarr * pointer to a vnode or if it is just a negative cache entry. 41022521Sdyson */ 41125453Sphkstatic void 412320756Smjgcache_zap(struct namecache *ncp) 41325453Sphk{ 414120792Sjeff struct vnode *vp; 415120792Sjeff 416187839Sjhb rw_assert(&cache_lock, RA_WLOCKED); 417147326Sjeff CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, ncp->nc_vp); 418190829Srwatson if (ncp->nc_vp != NULL) { 419289798Savg SDT_PROBE3(vfs, namecache, zap, done, ncp->nc_dvp, 420289798Savg nc_get_name(ncp), ncp->nc_vp); 421190829Srwatson } else { 422289798Savg SDT_PROBE2(vfs, namecache, zap_negative, done, ncp->nc_dvp, 423289798Savg nc_get_name(ncp)); 424190829Srwatson } 425120792Sjeff vp = NULL; 42625453Sphk LIST_REMOVE(ncp, nc_hash); 427190533Skan if (ncp->nc_flag & NCF_ISDOTDOT) { 428190533Skan if (ncp == ncp->nc_dvp->v_cache_dd) 429190533Skan ncp->nc_dvp->v_cache_dd = NULL; 430190533Skan } else { 431190533Skan LIST_REMOVE(ncp, nc_src); 432190533Skan if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src)) { 433190533Skan vp = ncp->nc_dvp; 434190533Skan numcachehv--; 435190533Skan } 43675654Stanimura } 43725453Sphk if (ncp->nc_vp) { 43825453Sphk TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst); 439190533Skan if (ncp == ncp->nc_vp->v_cache_dd) 440190533Skan ncp->nc_vp->v_cache_dd = NULL; 44125453Sphk } else { 44225453Sphk TAILQ_REMOVE(&ncneg, ncp, nc_dst); 44325453Sphk numneg--; 44425453Sphk } 44525453Sphk numcache--; 446116289Sdes cache_free(ncp); 447320756Smjg if (vp != NULL) 448120792Sjeff vdrop(vp); 44922521Sdyson} 4506968Sphk 45122521Sdyson/* 45223521Sbde * Lookup an entry in the cache 4536968Sphk * 4546968Sphk * Lookup is called with dvp pointing to the directory to search, 45522521Sdyson * cnp pointing to the name of the entry being sought. If the lookup 45622521Sdyson * succeeds, the vnode is returned in *vpp, and a status of -1 is 45722521Sdyson * returned. If the lookup determines that the name does not exist 458302234Sbdrewery * (negative caching), a status of ENOENT is returned. If the lookup 459183330Sjhb * fails, a status of zero is returned. If the directory vnode is 460183330Sjhb * recycled out from under us due to a forced unmount, a status of 461190387Sjhb * ENOENT is returned. 462144296Sjeff * 463144296Sjeff * vpp is locked and ref'd on return. If we're looking up DOTDOT, dvp is 464144296Sjeff * unlocked. If we're looking up . an extra ref is taken, but the lock is 465144296Sjeff * not recursively acquired. 4661541Srgrimes */ 4676968Sphk 4681541Srgrimesint 469320756Smjgcache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, 470320756Smjg struct timespec *tsp, int *ticksp) 4711541Srgrimes{ 47251906Sphk struct namecache *ncp; 473209390Sed uint32_t hash; 474187839Sjhb int error, ltype, wlocked; 4751541Srgrimes 4766928Sphk if (!doingcache) { 4776928Sphk cnp->cn_flags &= ~MAKEENTRY; 4781541Srgrimes return (0); 4796928Sphk } 480144296Sjeffretry: 481187839Sjhb CACHE_RLOCK(); 482187839Sjhb wlocked = 0; 48329788Sphk numcalls++; 484187839Sjhb error = 0; 48529788Sphk 486187839Sjhbretry_wlocked: 48725453Sphk if (cnp->cn_nameptr[0] == '.') { 48825453Sphk if (cnp->cn_namelen == 1) { 48925453Sphk *vpp = dvp; 490147326Sjeff CTR2(KTR_VFS, "cache_lookup(%p, %s) found via .", 491147326Sjeff dvp, cnp->cn_nameptr); 49229788Sphk dothits++; 493289798Savg SDT_PROBE3(vfs, namecache, lookup, hit, dvp, ".", *vpp); 494230394Sjhb if (tsp != NULL) 495230394Sjhb timespecclear(tsp); 496230394Sjhb if (ticksp != NULL) 497230394Sjhb *ticksp = ticks; 498144296Sjeff goto success; 49925453Sphk } 50025453Sphk if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') { 50129788Sphk dotdothits++; 502190829Srwatson if (dvp->v_cache_dd == NULL) { 503289798Savg SDT_PROBE3(vfs, namecache, lookup, miss, dvp, 504289798Savg "..", NULL); 505187839Sjhb goto unlock; 506190829Srwatson } 507190533Skan if ((cnp->cn_flags & MAKEENTRY) == 0) { 508190942Skib if (!wlocked && !CACHE_UPGRADE_LOCK()) 509190942Skib goto wlock; 510190533Skan if (dvp->v_cache_dd->nc_flag & NCF_ISDOTDOT) 511190533Skan cache_zap(dvp->v_cache_dd); 512190533Skan dvp->v_cache_dd = NULL; 513196203Skib CACHE_WUNLOCK(); 514196203Skib return (0); 51525453Sphk } 516230394Sjhb ncp = dvp->v_cache_dd; 517230394Sjhb if (ncp->nc_flag & NCF_ISDOTDOT) 518230394Sjhb *vpp = ncp->nc_vp; 519190533Skan else 520230394Sjhb *vpp = ncp->nc_dvp; 521191081Skan /* Return failure if negative entry was found. */ 522230394Sjhb if (*vpp == NULL) 523191082Skan goto negative_success; 524147326Sjeff CTR3(KTR_VFS, "cache_lookup(%p, %s) found %p via ..", 525147326Sjeff dvp, cnp->cn_nameptr, *vpp); 526289798Savg SDT_PROBE3(vfs, namecache, lookup, hit, dvp, "..", 527289798Savg *vpp); 528230489Skib cache_out_ts(ncp, tsp, ticksp); 529232420Srmacklem if ((ncp->nc_flag & (NCF_ISDOTDOT | NCF_DTS)) == 530232420Srmacklem NCF_DTS && tsp != NULL) 531232420Srmacklem *tsp = ((struct namecache_ts *)ncp)-> 532232420Srmacklem nc_dotdottime; 533144296Sjeff goto success; 53425453Sphk } 5351541Srgrimes } 5366968Sphk 53774501Speter hash = fnv_32_buf(cnp->cn_nameptr, cnp->cn_namelen, FNV1_32_INIT); 538144319Sdas hash = fnv_32_buf(&dvp, sizeof(dvp), hash); 53974501Speter LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { 54029788Sphk numchecks++; 54125453Sphk if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen && 542230441Skib !bcmp(nc_get_name(ncp), cnp->cn_nameptr, ncp->nc_nlen)) 54322521Sdyson break; 5441541Srgrimes } 5456968Sphk 54622521Sdyson /* We failed to find an entry */ 547187839Sjhb if (ncp == NULL) { 548289798Savg SDT_PROBE3(vfs, namecache, lookup, miss, dvp, cnp->cn_nameptr, 549289798Savg NULL); 55029804Sphk if ((cnp->cn_flags & MAKEENTRY) == 0) { 55129804Sphk nummisszap++; 55229804Sphk } else { 55329804Sphk nummiss++; 55429804Sphk } 55522521Sdyson nchstats.ncs_miss++; 556187839Sjhb goto unlock; 55722521Sdyson } 55822521Sdyson 5596968Sphk /* We don't want to have an entry, so dump it */ 5606928Sphk if ((cnp->cn_flags & MAKEENTRY) == 0) { 56129788Sphk numposzaps++; 5621541Srgrimes nchstats.ncs_badhits++; 563187839Sjhb if (!wlocked && !CACHE_UPGRADE_LOCK()) 564187839Sjhb goto wlock; 565140712Sjeff cache_zap(ncp); 566187839Sjhb CACHE_WUNLOCK(); 5676968Sphk return (0); 56823521Sbde } 5696968Sphk 5706968Sphk /* We found a "positive" match, return the vnode */ 571116201Sdes if (ncp->nc_vp) { 57229788Sphk numposhits++; 5731541Srgrimes nchstats.ncs_goodhits++; 5741541Srgrimes *vpp = ncp->nc_vp; 575147326Sjeff CTR4(KTR_VFS, "cache_lookup(%p, %s) found %p via ncp %p", 576147326Sjeff dvp, cnp->cn_nameptr, *vpp, ncp); 577289798Savg SDT_PROBE3(vfs, namecache, lookup, hit, dvp, nc_get_name(ncp), 578289798Savg *vpp); 579230489Skib cache_out_ts(ncp, tsp, ticksp); 580144296Sjeff goto success; 5811541Srgrimes } 5821541Srgrimes 583191082Skannegative_success: 5846968Sphk /* We found a negative match, and want to create it, so purge */ 5856968Sphk if (cnp->cn_nameiop == CREATE) { 58629788Sphk numnegzaps++; 5877013Sphk nchstats.ncs_badhits++; 588187839Sjhb if (!wlocked && !CACHE_UPGRADE_LOCK()) 589187839Sjhb goto wlock; 590140712Sjeff cache_zap(ncp); 591187839Sjhb CACHE_WUNLOCK(); 5926968Sphk return (0); 5936968Sphk } 5946968Sphk 595187839Sjhb if (!wlocked && !CACHE_UPGRADE_LOCK()) 596187839Sjhb goto wlock; 59729788Sphk numneghits++; 59822521Sdyson /* 599110967Sarr * We found a "negative" match, so we shift it to the end of 600110967Sarr * the "negative" cache entries queue to satisfy LRU. Also, 601110967Sarr * check to see if the entry is a whiteout; indicate this to 602110967Sarr * the componentname, if so. 60322521Sdyson */ 60425453Sphk TAILQ_REMOVE(&ncneg, ncp, nc_dst); 60525453Sphk TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst); 6066968Sphk nchstats.ncs_neghits++; 60725453Sphk if (ncp->nc_flag & NCF_WHITE) 60825453Sphk cnp->cn_flags |= ISWHITEOUT; 609289798Savg SDT_PROBE2(vfs, namecache, lookup, hit__negative, dvp, 610289798Savg nc_get_name(ncp)); 611230489Skib cache_out_ts(ncp, tsp, ticksp); 612187839Sjhb CACHE_WUNLOCK(); 6136968Sphk return (ENOENT); 614144296Sjeff 615187839Sjhbwlock: 616187839Sjhb /* 617187839Sjhb * We need to update the cache after our lookup, so upgrade to 618187839Sjhb * a write lock and retry the operation. 619187839Sjhb */ 620187839Sjhb CACHE_RUNLOCK(); 621187839Sjhb CACHE_WLOCK(); 622187839Sjhb numupgrades++; 623187839Sjhb wlocked = 1; 624187839Sjhb goto retry_wlocked; 625187839Sjhb 626144296Sjeffsuccess: 627144296Sjeff /* 628144296Sjeff * On success we return a locked and ref'd vnode as per the lookup 629144296Sjeff * protocol. 630144296Sjeff */ 631144296Sjeff if (dvp == *vpp) { /* lookup on "." */ 632144296Sjeff VREF(*vpp); 633187839Sjhb if (wlocked) 634187839Sjhb CACHE_WUNLOCK(); 635187839Sjhb else 636187839Sjhb CACHE_RUNLOCK(); 637172274Spjd /* 638172274Spjd * When we lookup "." we still can be asked to lock it 639172274Spjd * differently... 640172274Spjd */ 641178046Spjd ltype = cnp->cn_lkflags & LK_TYPE_MASK; 642183330Sjhb if (ltype != VOP_ISLOCKED(*vpp)) { 643183330Sjhb if (ltype == LK_EXCLUSIVE) { 644183330Sjhb vn_lock(*vpp, LK_UPGRADE | LK_RETRY); 645183330Sjhb if ((*vpp)->v_iflag & VI_DOOMED) { 646183330Sjhb /* forced unmount */ 647183330Sjhb vrele(*vpp); 648183330Sjhb *vpp = NULL; 649190387Sjhb return (ENOENT); 650183330Sjhb } 651183330Sjhb } else 652183330Sjhb vn_lock(*vpp, LK_DOWNGRADE | LK_RETRY); 653183330Sjhb } 654144296Sjeff return (-1); 655144296Sjeff } 656170000Spjd ltype = 0; /* silence gcc warning */ 657170000Spjd if (cnp->cn_flags & ISDOTDOT) { 658176559Sattilio ltype = VOP_ISLOCKED(dvp); 659175294Sattilio VOP_UNLOCK(dvp, 0); 660170000Spjd } 661144296Sjeff VI_LOCK(*vpp); 662187839Sjhb if (wlocked) 663187839Sjhb CACHE_WUNLOCK(); 664187839Sjhb else 665187839Sjhb CACHE_RUNLOCK(); 666176559Sattilio error = vget(*vpp, cnp->cn_lkflags | LK_INTERLOCK, cnp->cn_thread); 667190887Skib if (cnp->cn_flags & ISDOTDOT) { 668175202Sattilio vn_lock(dvp, ltype | LK_RETRY); 669190887Skib if (dvp->v_iflag & VI_DOOMED) { 670190887Skib if (error == 0) 671190887Skib vput(*vpp); 672190887Skib *vpp = NULL; 673190887Skib return (ENOENT); 674190887Skib } 675190887Skib } 676145006Sjeff if (error) { 677144296Sjeff *vpp = NULL; 678144296Sjeff goto retry; 679144296Sjeff } 680178046Spjd if ((cnp->cn_flags & ISLASTCN) && 681178046Spjd (cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE) { 682178046Spjd ASSERT_VOP_ELOCKED(*vpp, "cache_lookup"); 683178046Spjd } 684144296Sjeff return (-1); 685187839Sjhb 686187839Sjhbunlock: 687187839Sjhb if (wlocked) 688187839Sjhb CACHE_WUNLOCK(); 689187839Sjhb else 690187839Sjhb CACHE_RUNLOCK(); 691187839Sjhb return (0); 6921541Srgrimes} 6931541Srgrimes 6941541Srgrimes/* 6956968Sphk * Add an entry to the cache. 6961541Srgrimes */ 6971549Srgrimesvoid 698320756Smjgcache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, 699320756Smjg struct timespec *tsp, struct timespec *dtsp) 7001541Srgrimes{ 701185557Skib struct namecache *ncp, *n2; 702230441Skib struct namecache_ts *n3; 70351906Sphk struct nchashhead *ncpp; 704209390Sed uint32_t hash; 705190533Skan int flag; 706120792Sjeff int hold; 707120792Sjeff int zap; 70851906Sphk int len; 7091541Srgrimes 710147326Sjeff CTR3(KTR_VFS, "cache_enter(%p, %p, %s)", dvp, vp, cnp->cn_nameptr); 711147296Sjeff VNASSERT(vp == NULL || (vp->v_iflag & VI_DOOMED) == 0, vp, 712206671Skib ("cache_enter: Adding a doomed vnode")); 713206894Skib VNASSERT(dvp == NULL || (dvp->v_iflag & VI_DOOMED) == 0, dvp, 714206894Skib ("cache_enter: Doomed vnode used as src")); 715147296Sjeff 7161541Srgrimes if (!doingcache) 7171541Srgrimes return; 7186968Sphk 719187460Smckay /* 720187460Smckay * Avoid blowout in namecache entries. 721187460Smckay */ 722213916Skib if (numcache >= desiredvnodes * ncsizefactor) 723187460Smckay return; 724187460Smckay 725190533Skan flag = 0; 72625453Sphk if (cnp->cn_nameptr[0] == '.') { 727190533Skan if (cnp->cn_namelen == 1) 72825453Sphk return; 72925453Sphk if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') { 730187839Sjhb CACHE_WLOCK(); 731190533Skan /* 732190533Skan * If dotdot entry already exists, just retarget it 733190533Skan * to new parent vnode, otherwise continue with new 734190533Skan * namecache entry allocation. 735190533Skan */ 736191218Skan if ((ncp = dvp->v_cache_dd) != NULL && 737191218Skan ncp->nc_flag & NCF_ISDOTDOT) { 738191218Skan KASSERT(ncp->nc_dvp == dvp, 739191218Skan ("wrong isdotdot parent")); 740260240Skib if (ncp->nc_vp != NULL) { 741190533Skan TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, 742190533Skan ncp, nc_dst); 743260240Skib } else { 744191218Skan TAILQ_REMOVE(&ncneg, ncp, nc_dst); 745260240Skib numneg--; 746260240Skib } 747260240Skib if (vp != NULL) { 748190533Skan TAILQ_INSERT_HEAD(&vp->v_cache_dst, 749190533Skan ncp, nc_dst); 750260240Skib } else { 751191218Skan TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst); 752260240Skib numneg++; 753260240Skib } 754191218Skan ncp->nc_vp = vp; 755191218Skan CACHE_WUNLOCK(); 756191218Skan return; 757190533Skan } 758190533Skan dvp->v_cache_dd = NULL; 759289798Savg SDT_PROBE3(vfs, namecache, enter, done, dvp, "..", vp); 760187839Sjhb CACHE_WUNLOCK(); 761190533Skan flag = NCF_ISDOTDOT; 76225453Sphk } 7636968Sphk } 764116201Sdes 765120792Sjeff hold = 0; 766120792Sjeff zap = 0; 767182061Sjhb 768182061Sjhb /* 769182061Sjhb * Calculate the hash key and setup as much of the new 770182061Sjhb * namecache entry as possible before acquiring the lock. 771182061Sjhb */ 772230441Skib ncp = cache_alloc(cnp->cn_namelen, tsp != NULL); 773182061Sjhb ncp->nc_vp = vp; 774182061Sjhb ncp->nc_dvp = dvp; 775190533Skan ncp->nc_flag = flag; 776230441Skib if (tsp != NULL) { 777230441Skib n3 = (struct namecache_ts *)ncp; 778230441Skib n3->nc_time = *tsp; 779230441Skib n3->nc_ticks = ticks; 780230441Skib n3->nc_flag |= NCF_TS; 781232420Srmacklem if (dtsp != NULL) { 782232420Srmacklem n3->nc_dotdottime = *dtsp; 783232420Srmacklem n3->nc_flag |= NCF_DTS; 784232420Srmacklem } 785230441Skib } 786182061Sjhb len = ncp->nc_nlen = cnp->cn_namelen; 787182061Sjhb hash = fnv_32_buf(cnp->cn_nameptr, len, FNV1_32_INIT); 788230441Skib strlcpy(nc_get_name(ncp), cnp->cn_nameptr, len + 1); 789182061Sjhb hash = fnv_32_buf(&dvp, sizeof(dvp), hash); 790187839Sjhb CACHE_WLOCK(); 791182061Sjhb 792182061Sjhb /* 793186600Skib * See if this vnode or negative entry is already in the cache 794186600Skib * with this name. This can happen with concurrent lookups of 795186600Skib * the same path name. 796182061Sjhb */ 797186600Skib ncpp = NCHHASH(hash); 798186600Skib LIST_FOREACH(n2, ncpp, nc_hash) { 799186600Skib if (n2->nc_dvp == dvp && 800186600Skib n2->nc_nlen == cnp->cn_namelen && 801230441Skib !bcmp(nc_get_name(n2), cnp->cn_nameptr, n2->nc_nlen)) { 802230441Skib if (tsp != NULL) { 803230552Skib KASSERT((n2->nc_flag & NCF_TS) != 0, 804230552Skib ("no NCF_TS")); 805230441Skib n3 = (struct namecache_ts *)n2; 806230441Skib n3->nc_time = 807230441Skib ((struct namecache_ts *)ncp)->nc_time; 808230441Skib n3->nc_ticks = 809230441Skib ((struct namecache_ts *)ncp)->nc_ticks; 810232420Srmacklem if (dtsp != NULL) { 811232420Srmacklem n3->nc_dotdottime = 812232420Srmacklem ((struct namecache_ts *)ncp)-> 813232420Srmacklem nc_dotdottime; 814232420Srmacklem n3->nc_flag |= NCF_DTS; 815232420Srmacklem } 816230441Skib } 817187839Sjhb CACHE_WUNLOCK(); 818186600Skib cache_free(ncp); 819186600Skib return; 820182061Sjhb } 821185557Skib } 822182061Sjhb 823190945Skan if (flag == NCF_ISDOTDOT) { 824190945Skan /* 825190945Skan * See if we are trying to add .. entry, but some other lookup 826190945Skan * has populated v_cache_dd pointer already. 827190945Skan */ 828190945Skan if (dvp->v_cache_dd != NULL) { 829320756Smjg CACHE_WUNLOCK(); 830320756Smjg cache_free(ncp); 831320756Smjg return; 832190945Skan } 833190945Skan KASSERT(vp == NULL || vp->v_type == VDIR, 834190945Skan ("wrong vnode type %p", vp)); 835190945Skan dvp->v_cache_dd = ncp; 836190533Skan } 837190533Skan 83825453Sphk numcache++; 839320756Smjg if (vp == NULL) { 84025453Sphk numneg++; 841190533Skan if (cnp->cn_flags & ISWHITEOUT) 842190533Skan ncp->nc_flag |= NCF_WHITE; 84329071Sphk } else if (vp->v_type == VDIR) { 844190945Skan if (flag != NCF_ISDOTDOT) { 845232420Srmacklem /* 846232420Srmacklem * For this case, the cache entry maps both the 847232420Srmacklem * directory name in it and the name ".." for the 848232420Srmacklem * directory's parent. 849232420Srmacklem */ 850190533Skan if ((n2 = vp->v_cache_dd) != NULL && 851190533Skan (n2->nc_flag & NCF_ISDOTDOT) != 0) 852190533Skan cache_zap(n2); 853190533Skan vp->v_cache_dd = ncp; 854190533Skan } 855144319Sdas } else { 856190533Skan vp->v_cache_dd = NULL; 85728954Sphk } 85823521Sbde 85922521Sdyson /* 860182061Sjhb * Insert the new namecache entry into the appropriate chain 861182061Sjhb * within the cache entries table. 86222521Sdyson */ 8636928Sphk LIST_INSERT_HEAD(ncpp, ncp, nc_hash); 864190533Skan if (flag != NCF_ISDOTDOT) { 865190533Skan if (LIST_EMPTY(&dvp->v_cache_src)) { 866190533Skan hold = 1; 867190533Skan numcachehv++; 868190533Skan } 869190533Skan LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src); 87075654Stanimura } 871190533Skan 872110967Sarr /* 873110967Sarr * If the entry is "negative", we place it into the 874110967Sarr * "negative" cache queue, otherwise, we place it into the 875110967Sarr * destination vnode's cache entries queue. 876110967Sarr */ 877320756Smjg if (vp != NULL) { 87825453Sphk TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst); 879289798Savg SDT_PROBE3(vfs, namecache, enter, done, dvp, nc_get_name(ncp), 880289798Savg vp); 88125453Sphk } else { 88225453Sphk TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst); 883289798Savg SDT_PROBE2(vfs, namecache, enter_negative, done, dvp, 884289798Savg nc_get_name(ncp)); 88525453Sphk } 88651906Sphk if (numneg * ncnegfactor > numcache) { 88725453Sphk ncp = TAILQ_FIRST(&ncneg); 888260240Skib KASSERT(ncp->nc_vp == NULL, ("ncp %p vp %p on ncneg", 889260240Skib ncp, ncp->nc_vp)); 890120792Sjeff zap = 1; 89125453Sphk } 892120792Sjeff if (hold) 893120792Sjeff vhold(dvp); 894120792Sjeff if (zap) 895140712Sjeff cache_zap(ncp); 896187839Sjhb CACHE_WUNLOCK(); 8971541Srgrimes} 8981541Srgrimes 8991541Srgrimes/* 9001541Srgrimes * Name cache initialization, from vfs_init() when we are booting 9011541Srgrimes */ 90269664Speterstatic void 90369664Speternchinit(void *dummy __unused) 9041541Srgrimes{ 90523521Sbde 90625453Sphk TAILQ_INIT(&ncneg); 907116289Sdes 908230441Skib cache_zone_small = uma_zcreate("S VFS Cache", 909230441Skib sizeof(struct namecache) + CACHE_PATH_CUTOFF + 1, 910324611Sjhb NULL, NULL, NULL, NULL, UMA_ALIGNOF(struct namecache), 911324611Sjhb UMA_ZONE_ZINIT); 912230441Skib cache_zone_small_ts = uma_zcreate("STS VFS Cache", 913230441Skib sizeof(struct namecache_ts) + CACHE_PATH_CUTOFF + 1, 914324611Sjhb NULL, NULL, NULL, NULL, UMA_ALIGNOF(struct namecache_ts), 915324611Sjhb UMA_ZONE_ZINIT); 916230441Skib cache_zone_large = uma_zcreate("L VFS Cache", 917232420Srmacklem sizeof(struct namecache) + NAME_MAX + 1, 918324611Sjhb NULL, NULL, NULL, NULL, UMA_ALIGNOF(struct namecache), 919324611Sjhb UMA_ZONE_ZINIT); 920232420Srmacklem cache_zone_large_ts = uma_zcreate("LTS VFS Cache", 921230441Skib sizeof(struct namecache_ts) + NAME_MAX + 1, 922324611Sjhb NULL, NULL, NULL, NULL, UMA_ALIGNOF(struct namecache_ts), 923324611Sjhb UMA_ZONE_ZINIT); 924116289Sdes 92569664Speter nchashtbl = hashinit(desiredvnodes * 2, M_VFSCACHE, &nchash); 9261541Srgrimes} 927177253SrwatsonSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nchinit, NULL); 9281541Srgrimes 929288079Smckusickvoid 930288079Smckusickcache_changesize(int newmaxvnodes) 931288079Smckusick{ 932288079Smckusick struct nchashhead *new_nchashtbl, *old_nchashtbl; 933288079Smckusick u_long new_nchash, old_nchash; 934288079Smckusick struct namecache *ncp; 935288079Smckusick uint32_t hash; 936288079Smckusick int i; 93769664Speter 938288079Smckusick new_nchashtbl = hashinit(newmaxvnodes * 2, M_VFSCACHE, &new_nchash); 939288079Smckusick /* If same hash table size, nothing to do */ 940288079Smckusick if (nchash == new_nchash) { 941288079Smckusick free(new_nchashtbl, M_VFSCACHE); 942288079Smckusick return; 943288079Smckusick } 944288079Smckusick /* 945288079Smckusick * Move everything from the old hash table to the new table. 946288079Smckusick * None of the namecache entries in the table can be removed 947288079Smckusick * because to do so, they have to be removed from the hash table. 948288079Smckusick */ 949288079Smckusick CACHE_WLOCK(); 950288079Smckusick old_nchashtbl = nchashtbl; 951288079Smckusick old_nchash = nchash; 952288079Smckusick nchashtbl = new_nchashtbl; 953288079Smckusick nchash = new_nchash; 954288079Smckusick for (i = 0; i <= old_nchash; i++) { 955288079Smckusick while ((ncp = LIST_FIRST(&old_nchashtbl[i])) != NULL) { 956288079Smckusick hash = fnv_32_buf(nc_get_name(ncp), ncp->nc_nlen, 957288079Smckusick FNV1_32_INIT); 958288079Smckusick hash = fnv_32_buf(&ncp->nc_dvp, sizeof(ncp->nc_dvp), 959288079Smckusick hash); 960288079Smckusick LIST_REMOVE(ncp, nc_hash); 961288079Smckusick LIST_INSERT_HEAD(NCHHASH(hash), ncp, nc_hash); 962288079Smckusick } 963288079Smckusick } 964288079Smckusick CACHE_WUNLOCK(); 965288079Smckusick free(old_nchashtbl, M_VFSCACHE); 966288079Smckusick} 967288079Smckusick 9681541Srgrimes/* 96946011Sphk * Invalidate all entries to a particular vnode. 9701541Srgrimes */ 9711549Srgrimesvoid 972320756Smjgcache_purge(struct vnode *vp) 9731541Srgrimes{ 9741541Srgrimes 975147326Sjeff CTR1(KTR_VFS, "cache_purge(%p)", vp); 976289798Savg SDT_PROBE1(vfs, namecache, purge, done, vp); 977187839Sjhb CACHE_WLOCK(); 978147331Sjeff while (!LIST_EMPTY(&vp->v_cache_src)) 979147331Sjeff cache_zap(LIST_FIRST(&vp->v_cache_src)); 980116201Sdes while (!TAILQ_EMPTY(&vp->v_cache_dst)) 981140712Sjeff cache_zap(TAILQ_FIRST(&vp->v_cache_dst)); 982190533Skan if (vp->v_cache_dd != NULL) { 983190533Skan KASSERT(vp->v_cache_dd->nc_flag & NCF_ISDOTDOT, 984190533Skan ("lost dotdot link")); 985190533Skan cache_zap(vp->v_cache_dd); 986190533Skan } 987190533Skan KASSERT(vp->v_cache_dd == NULL, ("incomplete purge")); 988187839Sjhb CACHE_WUNLOCK(); 9891541Srgrimes} 9901541Srgrimes 9911541Srgrimes/* 992188833Sjhb * Invalidate all negative entries for a particular directory vnode. 993188833Sjhb */ 994188833Sjhbvoid 995320756Smjgcache_purge_negative(struct vnode *vp) 996188833Sjhb{ 997188833Sjhb struct namecache *cp, *ncp; 998188833Sjhb 999188833Sjhb CTR1(KTR_VFS, "cache_purge_negative(%p)", vp); 1000289798Savg SDT_PROBE1(vfs, namecache, purge_negative, done, vp); 1001188833Sjhb CACHE_WLOCK(); 1002188833Sjhb LIST_FOREACH_SAFE(cp, &vp->v_cache_src, nc_src, ncp) { 1003188833Sjhb if (cp->nc_vp == NULL) 1004188833Sjhb cache_zap(cp); 1005188833Sjhb } 1006188833Sjhb CACHE_WUNLOCK(); 1007188833Sjhb} 1008188833Sjhb 1009188833Sjhb/* 10106968Sphk * Flush all entries referencing a particular filesystem. 10111541Srgrimes */ 10121549Srgrimesvoid 1013320756Smjgcache_purgevfs(struct mount *mp) 10141541Srgrimes{ 10156968Sphk struct nchashhead *ncpp; 101622521Sdyson struct namecache *ncp, *nnp; 10171541Srgrimes 10186968Sphk /* Scan hash tables for applicable entries */ 1019289798Savg SDT_PROBE1(vfs, namecache, purgevfs, done, mp); 1020187839Sjhb CACHE_WLOCK(); 102129071Sphk for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) { 1022169999Spjd LIST_FOREACH_SAFE(ncp, ncpp, nc_hash, nnp) { 1023169999Spjd if (ncp->nc_dvp->v_mount == mp) 1024169999Spjd cache_zap(ncp); 10251541Srgrimes } 10261541Srgrimes } 1027187839Sjhb CACHE_WUNLOCK(); 10281541Srgrimes} 102928787Sphk 103028787Sphk/* 103128787Sphk * Perform canonical checks and cache lookup and pass on to filesystem 103228787Sphk * through the vop_cachedlookup only if needed. 103328787Sphk */ 103428787Sphk 103528787Sphkint 1036320756Smjgvfs_cache_lookup(struct vop_lookup_args *ap) 103728787Sphk{ 1038144296Sjeff struct vnode *dvp; 103928787Sphk int error; 104028787Sphk struct vnode **vpp = ap->a_vpp; 104128787Sphk struct componentname *cnp = ap->a_cnp; 104228787Sphk struct ucred *cred = cnp->cn_cred; 104328787Sphk int flags = cnp->cn_flags; 104483366Sjulian struct thread *td = cnp->cn_thread; 104528787Sphk 104628787Sphk *vpp = NULL; 104765665Sbp dvp = ap->a_dvp; 104828787Sphk 104965665Sbp if (dvp->v_type != VDIR) 1050116201Sdes return (ENOTDIR); 105128787Sphk 105265665Sbp if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && 105328787Sphk (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 105428787Sphk return (EROFS); 105528787Sphk 105683366Sjulian error = VOP_ACCESS(dvp, VEXEC, cred, td); 105728787Sphk if (error) 105828787Sphk return (error); 105928787Sphk 1060231088Sjhb error = cache_lookup(dvp, vpp, cnp, NULL, NULL); 1061144296Sjeff if (error == 0) 1062144287Sjeff return (VOP_CACHEDLOOKUP(dvp, vpp, cnp)); 1063183330Sjhb if (error == -1) 1064183330Sjhb return (0); 1065183330Sjhb return (error); 106628787Sphk} 106751906Sphk 106891690Seivind/* 106991690Seivind * XXX All of these sysctls would probably be more productive dead. 107091690Seivind */ 107151906Sphkstatic int disablecwd; 107291690SeivindSYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0, 107391690Seivind "Disable the getcwd syscall"); 107451906Sphk 1075167232Srwatson/* Implementation of the getcwd syscall. */ 107651906Sphkint 1077320756Smjgsys___getcwd(struct thread *td, struct __getcwd_args *uap) 107851906Sphk{ 1079112430Sphk 1080321009Sdchagin return (kern___getcwd(td, uap->buf, UIO_USERSPACE, uap->buflen, 1081321009Sdchagin MAXPATHLEN)); 1082102870Siedowse} 1083102870Siedowse 1084102870Siedowseint 1085321009Sdchaginkern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, u_int buflen, 1086321009Sdchagin u_int path_max) 1087102870Siedowse{ 1088102870Siedowse char *bp, *tmpbuf; 108951906Sphk struct filedesc *fdp; 1090185298Smarcus struct vnode *cdir, *rdir; 1091241896Skib int error; 109251906Sphk 1093112430Sphk if (disablecwd) 109451906Sphk return (ENODEV); 1095102870Siedowse if (buflen < 2) 109651906Sphk return (EINVAL); 1097321009Sdchagin if (buflen > path_max) 1098321009Sdchagin buflen = path_max; 1099144318Sdas 1100144318Sdas tmpbuf = malloc(buflen, M_TEMP, M_WAITOK); 1101144318Sdas fdp = td->td_proc->p_fd; 1102168355Srwatson FILEDESC_SLOCK(fdp); 1103185298Smarcus cdir = fdp->fd_cdir; 1104185298Smarcus VREF(cdir); 1105185298Smarcus rdir = fdp->fd_rdir; 1106185298Smarcus VREF(rdir); 1107168355Srwatson FILEDESC_SUNLOCK(fdp); 1108185298Smarcus error = vn_fullpath1(td, cdir, rdir, tmpbuf, &bp, buflen); 1109185298Smarcus vrele(rdir); 1110185298Smarcus vrele(cdir); 1111144318Sdas 1112144318Sdas if (!error) { 1113144318Sdas if (bufseg == UIO_SYSSPACE) 1114144318Sdas bcopy(bp, buf, strlen(bp) + 1); 1115144318Sdas else 1116144318Sdas error = copyout(bp, buf, strlen(bp) + 1); 1117190141Skib#ifdef KTRACE 1118190141Skib if (KTRPOINT(curthread, KTR_NAMEI)) 1119190141Skib ktrnamei(bp); 1120190141Skib#endif 1121144318Sdas } 1122102870Siedowse free(tmpbuf, M_TEMP); 112351906Sphk return (error); 112451906Sphk} 112551906Sphk 112659652Sgreen/* 112759652Sgreen * Thus begins the fullpath magic. 112859652Sgreen */ 112959652Sgreen 113059652Sgreen#undef STATNODE 1131215281Sbrucec#define STATNODE(name, descr) \ 113259652Sgreen static u_int name; \ 1133215281Sbrucec SYSCTL_UINT(_vfs_cache, OID_AUTO, name, CTLFLAG_RD, &name, 0, descr) 113459652Sgreen 113559652Sgreenstatic int disablefullpath; 113691690SeivindSYSCTL_INT(_debug, OID_AUTO, disablefullpath, CTLFLAG_RW, &disablefullpath, 0, 1137215304Sbrucec "Disable the vn_fullpath function"); 113859652Sgreen 1139144318Sdas/* These count for kern___getcwd(), too. */ 1140215281SbrucecSTATNODE(numfullpathcalls, "Number of fullpath search calls"); 1141215281SbrucecSTATNODE(numfullpathfail1, "Number of fullpath search errors (ENOTDIR)"); 1142215283SbrucecSTATNODE(numfullpathfail2, 1143215304Sbrucec "Number of fullpath search errors (VOP_VPTOCNP failures)"); 1144215281SbrucecSTATNODE(numfullpathfail4, "Number of fullpath search errors (ENOMEM)"); 1145215281SbrucecSTATNODE(numfullpathfound, "Number of successful fullpath calls"); 114659652Sgreen 114791690Seivind/* 114891690Seivind * Retrieve the full filesystem path that correspond to a vnode from the name 114991690Seivind * cache (if available) 115091690Seivind */ 115159652Sgreenint 115285287Sdesvn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf) 115385287Sdes{ 1154144318Sdas char *buf; 115559652Sgreen struct filedesc *fdp; 1156185298Smarcus struct vnode *rdir; 1157241896Skib int error; 115859652Sgreen 115959652Sgreen if (disablefullpath) 116059652Sgreen return (ENODEV); 116185287Sdes if (vn == NULL) 116259652Sgreen return (EINVAL); 1163144318Sdas 1164111119Simp buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1165144318Sdas fdp = td->td_proc->p_fd; 1166168355Srwatson FILEDESC_SLOCK(fdp); 1167185298Smarcus rdir = fdp->fd_rdir; 1168185298Smarcus VREF(rdir); 1169168355Srwatson FILEDESC_SUNLOCK(fdp); 1170185298Smarcus error = vn_fullpath1(td, vn, rdir, buf, retbuf, MAXPATHLEN); 1171185298Smarcus vrele(rdir); 1172144318Sdas 1173144318Sdas if (!error) 1174144318Sdas *freebuf = buf; 1175144318Sdas else 1176144318Sdas free(buf, M_TEMP); 1177144318Sdas return (error); 1178144318Sdas} 1179144318Sdas 1180144318Sdas/* 1181181060Scsjp * This function is similar to vn_fullpath, but it attempts to lookup the 1182181060Scsjp * pathname relative to the global root mount point. This is required for the 1183181060Scsjp * auditing sub-system, as audited pathnames must be absolute, relative to the 1184181060Scsjp * global root mount point. 1185181060Scsjp */ 1186181060Scsjpint 1187181060Scsjpvn_fullpath_global(struct thread *td, struct vnode *vn, 1188181060Scsjp char **retbuf, char **freebuf) 1189181060Scsjp{ 1190181060Scsjp char *buf; 1191181060Scsjp int error; 1192181060Scsjp 1193181060Scsjp if (disablefullpath) 1194181060Scsjp return (ENODEV); 1195181060Scsjp if (vn == NULL) 1196181060Scsjp return (EINVAL); 1197181060Scsjp buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1198181060Scsjp error = vn_fullpath1(td, vn, rootvnode, buf, retbuf, MAXPATHLEN); 1199181060Scsjp if (!error) 1200181060Scsjp *freebuf = buf; 1201181060Scsjp else 1202181060Scsjp free(buf, M_TEMP); 1203181060Scsjp return (error); 1204181060Scsjp} 1205181060Scsjp 1206193174Skibint 1207194601Skibvn_vptocnp(struct vnode **vp, struct ucred *cred, char *buf, u_int *buflen) 1208193174Skib{ 1209193174Skib int error; 1210193174Skib 1211193174Skib CACHE_RLOCK(); 1212194601Skib error = vn_vptocnp_locked(vp, cred, buf, buflen); 1213227697Skib if (error == 0) 1214193174Skib CACHE_RUNLOCK(); 1215193174Skib return (error); 1216193174Skib} 1217193174Skib 1218185956Smarcusstatic int 1219194601Skibvn_vptocnp_locked(struct vnode **vp, struct ucred *cred, char *buf, 1220194601Skib u_int *buflen) 1221185956Smarcus{ 1222185956Smarcus struct vnode *dvp; 1223193174Skib struct namecache *ncp; 1224241896Skib int error; 1225185956Smarcus 1226193174Skib TAILQ_FOREACH(ncp, &((*vp)->v_cache_dst), nc_dst) { 1227193174Skib if ((ncp->nc_flag & NCF_ISDOTDOT) == 0) 1228193174Skib break; 1229193174Skib } 1230193174Skib if (ncp != NULL) { 1231193174Skib if (*buflen < ncp->nc_nlen) { 1232193174Skib CACHE_RUNLOCK(); 1233227697Skib vrele(*vp); 1234193174Skib numfullpathfail4++; 1235193174Skib error = ENOMEM; 1236289798Savg SDT_PROBE3(vfs, namecache, fullpath, return, error, 1237289798Savg vp, NULL); 1238193174Skib return (error); 1239193174Skib } 1240193174Skib *buflen -= ncp->nc_nlen; 1241230441Skib memcpy(buf + *buflen, nc_get_name(ncp), ncp->nc_nlen); 1242289798Savg SDT_PROBE3(vfs, namecache, fullpath, hit, ncp->nc_dvp, 1243289798Savg nc_get_name(ncp), vp); 1244227697Skib dvp = *vp; 1245193174Skib *vp = ncp->nc_dvp; 1246227697Skib vref(*vp); 1247227697Skib CACHE_RUNLOCK(); 1248227697Skib vrele(dvp); 1249227697Skib CACHE_RLOCK(); 1250193174Skib return (0); 1251193174Skib } 1252289798Savg SDT_PROBE1(vfs, namecache, fullpath, miss, vp); 1253193174Skib 1254187839Sjhb CACHE_RUNLOCK(); 1255185956Smarcus vn_lock(*vp, LK_SHARED | LK_RETRY); 1256194601Skib error = VOP_VPTOCNP(*vp, &dvp, cred, buf, buflen); 1257227697Skib vput(*vp); 1258185956Smarcus if (error) { 1259185956Smarcus numfullpathfail2++; 1260289798Savg SDT_PROBE3(vfs, namecache, fullpath, return, error, vp, NULL); 1261185956Smarcus return (error); 1262185956Smarcus } 1263193174Skib 1264185956Smarcus *vp = dvp; 1265187839Sjhb CACHE_RLOCK(); 1266227697Skib if (dvp->v_iflag & VI_DOOMED) { 1267185956Smarcus /* forced unmount */ 1268190697Skan CACHE_RUNLOCK(); 1269227697Skib vrele(dvp); 1270193174Skib error = ENOENT; 1271289798Savg SDT_PROBE3(vfs, namecache, fullpath, return, error, vp, NULL); 1272193174Skib return (error); 1273185956Smarcus } 1274227697Skib /* 1275227697Skib * *vp has its use count incremented still. 1276227697Skib */ 1277185956Smarcus 1278185956Smarcus return (0); 1279185956Smarcus} 1280185956Smarcus 1281181060Scsjp/* 1282144318Sdas * The magic behind kern___getcwd() and vn_fullpath(). 1283144318Sdas */ 1284144318Sdasstatic int 1285144318Sdasvn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir, 1286144318Sdas char *buf, char **retbuf, u_int buflen) 1287144318Sdas{ 1288241896Skib int error, slash_prefixed; 1289190829Srwatson#ifdef KDTRACE_HOOKS 1290190829Srwatson struct vnode *startvp = vp; 1291190829Srwatson#endif 1292227697Skib struct vnode *vp1; 1293144318Sdas 1294185956Smarcus buflen--; 1295193174Skib buf[buflen] = '\0'; 1296144318Sdas error = 0; 129759652Sgreen slash_prefixed = 0; 1298144318Sdas 1299289798Savg SDT_PROBE1(vfs, namecache, fullpath, entry, vp); 1300193174Skib numfullpathcalls++; 1301227697Skib vref(vp); 1302187839Sjhb CACHE_RLOCK(); 1303144318Sdas if (vp->v_type != VDIR) { 1304194601Skib error = vn_vptocnp_locked(&vp, td->td_ucred, buf, &buflen); 1305193174Skib if (error) 1306190829Srwatson return (error); 1307193518Smarcus if (buflen == 0) { 1308193518Smarcus CACHE_RUNLOCK(); 1309227697Skib vrele(vp); 1310193174Skib return (ENOMEM); 1311193518Smarcus } 1312193174Skib buf[--buflen] = '/'; 1313144318Sdas slash_prefixed = 1; 1314144318Sdas } 1315144318Sdas while (vp != rdir && vp != rootvnode) { 1316101308Sjeff if (vp->v_vflag & VV_ROOT) { 1317155385Sjeff if (vp->v_iflag & VI_DOOMED) { /* forced unmount */ 1318187839Sjhb CACHE_RUNLOCK(); 1319227697Skib vrele(vp); 1320190387Sjhb error = ENOENT; 1321289798Savg SDT_PROBE3(vfs, namecache, fullpath, return, 1322289798Savg error, vp, NULL); 1323144318Sdas break; 132459652Sgreen } 1325227697Skib vp1 = vp->v_mount->mnt_vnodecovered; 1326227697Skib vref(vp1); 1327227697Skib CACHE_RUNLOCK(); 1328227697Skib vrele(vp); 1329227697Skib vp = vp1; 1330227697Skib CACHE_RLOCK(); 133159652Sgreen continue; 133259652Sgreen } 1333185956Smarcus if (vp->v_type != VDIR) { 1334193174Skib CACHE_RUNLOCK(); 1335227697Skib vrele(vp); 133659652Sgreen numfullpathfail1++; 1337144318Sdas error = ENOTDIR; 1338289798Savg SDT_PROBE3(vfs, namecache, fullpath, return, 1339289798Savg error, vp, NULL); 1340144318Sdas break; 134159652Sgreen } 1342194601Skib error = vn_vptocnp_locked(&vp, td->td_ucred, buf, &buflen); 1343193174Skib if (error) 1344193174Skib break; 1345193174Skib if (buflen == 0) { 1346193518Smarcus CACHE_RUNLOCK(); 1347227697Skib vrele(vp); 1348144318Sdas error = ENOMEM; 1349289798Savg SDT_PROBE3(vfs, namecache, fullpath, return, error, 1350289798Savg startvp, NULL); 1351144318Sdas break; 135259652Sgreen } 1353193174Skib buf[--buflen] = '/'; 135459652Sgreen slash_prefixed = 1; 1355144318Sdas } 1356193174Skib if (error) 1357144318Sdas return (error); 135859652Sgreen if (!slash_prefixed) { 1359193174Skib if (buflen == 0) { 1360193174Skib CACHE_RUNLOCK(); 1361227697Skib vrele(vp); 1362120792Sjeff numfullpathfail4++; 1363289798Savg SDT_PROBE3(vfs, namecache, fullpath, return, ENOMEM, 1364289798Savg startvp, NULL); 136559652Sgreen return (ENOMEM); 1366193174Skib } 1367193174Skib buf[--buflen] = '/'; 136859652Sgreen } 136959652Sgreen numfullpathfound++; 1370187839Sjhb CACHE_RUNLOCK(); 1371227697Skib vrele(vp); 1372144318Sdas 1373289798Savg SDT_PROBE3(vfs, namecache, fullpath, return, 0, startvp, buf + buflen); 1374193174Skib *retbuf = buf + buflen; 137559652Sgreen return (0); 137659652Sgreen} 1377177782Skib 1378248561Smckusickstruct vnode * 1379248561Smckusickvn_dir_dd_ino(struct vnode *vp) 1380248561Smckusick{ 1381248561Smckusick struct namecache *ncp; 1382248561Smckusick struct vnode *ddvp; 1383248561Smckusick 1384248561Smckusick ASSERT_VOP_LOCKED(vp, "vn_dir_dd_ino"); 1385248561Smckusick CACHE_RLOCK(); 1386248561Smckusick TAILQ_FOREACH(ncp, &(vp->v_cache_dst), nc_dst) { 1387248561Smckusick if ((ncp->nc_flag & NCF_ISDOTDOT) != 0) 1388248561Smckusick continue; 1389248561Smckusick ddvp = ncp->nc_dvp; 1390248561Smckusick VI_LOCK(ddvp); 1391248561Smckusick CACHE_RUNLOCK(); 1392248561Smckusick if (vget(ddvp, LK_INTERLOCK | LK_SHARED | LK_NOWAIT, curthread)) 1393248561Smckusick return (NULL); 1394248561Smckusick return (ddvp); 1395248561Smckusick } 1396248561Smckusick CACHE_RUNLOCK(); 1397248561Smckusick return (NULL); 1398248561Smckusick} 1399248561Smckusick 1400177782Skibint 1401177782Skibvn_commname(struct vnode *vp, char *buf, u_int buflen) 1402177782Skib{ 1403177782Skib struct namecache *ncp; 1404177782Skib int l; 1405177782Skib 1406187839Sjhb CACHE_RLOCK(); 1407190533Skan TAILQ_FOREACH(ncp, &vp->v_cache_dst, nc_dst) 1408190533Skan if ((ncp->nc_flag & NCF_ISDOTDOT) == 0) 1409190533Skan break; 1410190533Skan if (ncp == NULL) { 1411187839Sjhb CACHE_RUNLOCK(); 1412177782Skib return (ENOENT); 1413177782Skib } 1414177782Skib l = min(ncp->nc_nlen, buflen - 1); 1415230441Skib memcpy(buf, nc_get_name(ncp), l); 1416187839Sjhb CACHE_RUNLOCK(); 1417177782Skib buf[l] = '\0'; 1418177782Skib return (0); 1419177782Skib} 1420230129Smm 1421230394Sjhb/* ABI compat shims for old kernel modules. */ 1422230394Sjhb#undef cache_enter 1423230394Sjhb 1424230394Sjhbvoid cache_enter(struct vnode *dvp, struct vnode *vp, 1425230394Sjhb struct componentname *cnp); 1426230394Sjhb 1427230394Sjhbvoid 1428230394Sjhbcache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) 1429230394Sjhb{ 1430230394Sjhb 1431232420Srmacklem cache_enter_time(dvp, vp, cnp, NULL, NULL); 1432230394Sjhb} 1433230394Sjhb 1434230129Smm/* 1435230129Smm * This function updates path string to vnode's full global path 1436230129Smm * and checks the size of the new path string against the pathlen argument. 1437230129Smm * 1438230129Smm * Requires a locked, referenced vnode and GIANT lock held. 1439230129Smm * Vnode is re-locked on success or ENODEV, otherwise unlocked. 1440230129Smm * 1441230129Smm * If sysctl debug.disablefullpath is set, ENODEV is returned, 1442230129Smm * vnode is left locked and path remain untouched. 1443230129Smm * 1444230129Smm * If vp is a directory, the call to vn_fullpath_global() always succeeds 1445230143Smm * because it falls back to the ".." lookup if the namecache lookup fails. 1446230129Smm */ 1447230129Smmint 1448230129Smmvn_path_to_global_path(struct thread *td, struct vnode *vp, char *path, 1449230129Smm u_int pathlen) 1450230129Smm{ 1451230129Smm struct nameidata nd; 1452230129Smm struct vnode *vp1; 1453230129Smm char *rpath, *fbuf; 1454241896Skib int error; 1455230129Smm 1456230129Smm ASSERT_VOP_ELOCKED(vp, __func__); 1457230129Smm 1458230129Smm /* Return ENODEV if sysctl debug.disablefullpath==1 */ 1459230129Smm if (disablefullpath) 1460230129Smm return (ENODEV); 1461230129Smm 1462230129Smm /* Construct global filesystem path from vp. */ 1463230129Smm VOP_UNLOCK(vp, 0); 1464230129Smm error = vn_fullpath_global(td, vp, &rpath, &fbuf); 1465230129Smm 1466230129Smm if (error != 0) { 1467230129Smm vrele(vp); 1468230129Smm return (error); 1469230129Smm } 1470230129Smm 1471230129Smm if (strlen(rpath) >= pathlen) { 1472230129Smm vrele(vp); 1473230129Smm error = ENAMETOOLONG; 1474230129Smm goto out; 1475230129Smm } 1476230129Smm 1477230129Smm /* 1478230129Smm * Re-lookup the vnode by path to detect a possible rename. 1479230129Smm * As a side effect, the vnode is relocked. 1480230129Smm * If vnode was renamed, return ENOENT. 1481230129Smm */ 1482241896Skib NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, 1483230129Smm UIO_SYSSPACE, path, td); 1484230129Smm error = namei(&nd); 1485230129Smm if (error != 0) { 1486230129Smm vrele(vp); 1487230129Smm goto out; 1488230129Smm } 1489230129Smm NDFREE(&nd, NDF_ONLY_PNBUF); 1490230129Smm vp1 = nd.ni_vp; 1491230129Smm vrele(vp); 1492230129Smm if (vp1 == vp) 1493230129Smm strcpy(path, rpath); 1494230129Smm else { 1495230129Smm vput(vp1); 1496230129Smm error = ENOENT; 1497230129Smm } 1498230129Smm 1499230129Smmout: 1500230129Smm free(fbuf, M_TEMP); 1501230129Smm return (error); 1502230129Smm} 1503