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