1*a9643ea8Slogwang /*- 2*a9643ea8Slogwang * Copyright (c) 1989, 1993, 1995 3*a9643ea8Slogwang * The Regents of the University of California. All rights reserved. 4*a9643ea8Slogwang * 5*a9643ea8Slogwang * This code is derived from software contributed to Berkeley by 6*a9643ea8Slogwang * Poul-Henning Kamp of the FreeBSD Project. 7*a9643ea8Slogwang * 8*a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without 9*a9643ea8Slogwang * modification, are permitted provided that the following conditions 10*a9643ea8Slogwang * are met: 11*a9643ea8Slogwang * 1. Redistributions of source code must retain the above copyright 12*a9643ea8Slogwang * notice, this list of conditions and the following disclaimer. 13*a9643ea8Slogwang * 2. Redistributions in binary form must reproduce the above copyright 14*a9643ea8Slogwang * notice, this list of conditions and the following disclaimer in the 15*a9643ea8Slogwang * documentation and/or other materials provided with the distribution. 16*a9643ea8Slogwang * 4. Neither the name of the University nor the names of its contributors 17*a9643ea8Slogwang * may be used to endorse or promote products derived from this software 18*a9643ea8Slogwang * without specific prior written permission. 19*a9643ea8Slogwang * 20*a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21*a9643ea8Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22*a9643ea8Slogwang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23*a9643ea8Slogwang * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24*a9643ea8Slogwang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25*a9643ea8Slogwang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26*a9643ea8Slogwang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27*a9643ea8Slogwang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28*a9643ea8Slogwang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29*a9643ea8Slogwang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30*a9643ea8Slogwang * SUCH DAMAGE. 31*a9643ea8Slogwang * 32*a9643ea8Slogwang * @(#)vfs_cache.c 8.5 (Berkeley) 3/22/95 33*a9643ea8Slogwang */ 34*a9643ea8Slogwang 35*a9643ea8Slogwang #include <sys/cdefs.h> 36*a9643ea8Slogwang __FBSDID("$FreeBSD$"); 37*a9643ea8Slogwang 38*a9643ea8Slogwang #include "opt_ktrace.h" 39*a9643ea8Slogwang 40*a9643ea8Slogwang #include <sys/param.h> 41*a9643ea8Slogwang #include <sys/systm.h> 42*a9643ea8Slogwang #include <sys/counter.h> 43*a9643ea8Slogwang #include <sys/filedesc.h> 44*a9643ea8Slogwang #include <sys/fnv_hash.h> 45*a9643ea8Slogwang #include <sys/kernel.h> 46*a9643ea8Slogwang #include <sys/lock.h> 47*a9643ea8Slogwang #include <sys/malloc.h> 48*a9643ea8Slogwang #include <sys/fcntl.h> 49*a9643ea8Slogwang #include <sys/mount.h> 50*a9643ea8Slogwang #include <sys/namei.h> 51*a9643ea8Slogwang #include <sys/proc.h> 52*a9643ea8Slogwang #include <sys/rwlock.h> 53*a9643ea8Slogwang #include <sys/sdt.h> 54*a9643ea8Slogwang #include <sys/syscallsubr.h> 55*a9643ea8Slogwang #include <sys/sysctl.h> 56*a9643ea8Slogwang #include <sys/sysproto.h> 57*a9643ea8Slogwang #include <sys/vnode.h> 58*a9643ea8Slogwang #ifdef KTRACE 59*a9643ea8Slogwang #include <sys/ktrace.h> 60*a9643ea8Slogwang #endif 61*a9643ea8Slogwang 62*a9643ea8Slogwang #include <vm/uma.h> 63*a9643ea8Slogwang 64*a9643ea8Slogwang SDT_PROVIDER_DECLARE(vfs); 65*a9643ea8Slogwang SDT_PROBE_DEFINE3(vfs, namecache, enter, done, "struct vnode *", "char *", 66*a9643ea8Slogwang "struct vnode *"); 67*a9643ea8Slogwang SDT_PROBE_DEFINE2(vfs, namecache, enter_negative, done, "struct vnode *", 68*a9643ea8Slogwang "char *"); 69*a9643ea8Slogwang SDT_PROBE_DEFINE1(vfs, namecache, fullpath, entry, "struct vnode *"); 70*a9643ea8Slogwang SDT_PROBE_DEFINE3(vfs, namecache, fullpath, hit, "struct vnode *", 71*a9643ea8Slogwang "char *", "struct vnode *"); 72*a9643ea8Slogwang SDT_PROBE_DEFINE1(vfs, namecache, fullpath, miss, "struct vnode *"); 73*a9643ea8Slogwang SDT_PROBE_DEFINE3(vfs, namecache, fullpath, return, "int", 74*a9643ea8Slogwang "struct vnode *", "char *"); 75*a9643ea8Slogwang SDT_PROBE_DEFINE3(vfs, namecache, lookup, hit, "struct vnode *", "char *", 76*a9643ea8Slogwang "struct vnode *"); 77*a9643ea8Slogwang SDT_PROBE_DEFINE2(vfs, namecache, lookup, hit__negative, 78*a9643ea8Slogwang "struct vnode *", "char *"); 79*a9643ea8Slogwang SDT_PROBE_DEFINE2(vfs, namecache, lookup, miss, "struct vnode *", 80*a9643ea8Slogwang "char *"); 81*a9643ea8Slogwang SDT_PROBE_DEFINE1(vfs, namecache, purge, done, "struct vnode *"); 82*a9643ea8Slogwang SDT_PROBE_DEFINE1(vfs, namecache, purge_negative, done, "struct vnode *"); 83*a9643ea8Slogwang SDT_PROBE_DEFINE1(vfs, namecache, purgevfs, done, "struct mount *"); 84*a9643ea8Slogwang SDT_PROBE_DEFINE3(vfs, namecache, zap, done, "struct vnode *", "char *", 85*a9643ea8Slogwang "struct vnode *"); 86*a9643ea8Slogwang SDT_PROBE_DEFINE2(vfs, namecache, zap_negative, done, "struct vnode *", 87*a9643ea8Slogwang "char *"); 88*a9643ea8Slogwang 89*a9643ea8Slogwang /* 90*a9643ea8Slogwang * This structure describes the elements in the cache of recent 91*a9643ea8Slogwang * names looked up by namei. 92*a9643ea8Slogwang */ 93*a9643ea8Slogwang 94*a9643ea8Slogwang struct namecache { 95*a9643ea8Slogwang LIST_ENTRY(namecache) nc_hash; /* hash chain */ 96*a9643ea8Slogwang LIST_ENTRY(namecache) nc_src; /* source vnode list */ 97*a9643ea8Slogwang TAILQ_ENTRY(namecache) nc_dst; /* destination vnode list */ 98*a9643ea8Slogwang struct vnode *nc_dvp; /* vnode of parent of name */ 99*a9643ea8Slogwang struct vnode *nc_vp; /* vnode the name refers to */ 100*a9643ea8Slogwang u_char nc_flag; /* flag bits */ 101*a9643ea8Slogwang u_char nc_nlen; /* length of name */ 102*a9643ea8Slogwang char nc_name[0]; /* segment name + nul */ 103*a9643ea8Slogwang }; 104*a9643ea8Slogwang 105*a9643ea8Slogwang /* 106*a9643ea8Slogwang * struct namecache_ts repeats struct namecache layout up to the 107*a9643ea8Slogwang * nc_nlen member. 108*a9643ea8Slogwang * struct namecache_ts is used in place of struct namecache when time(s) need 109*a9643ea8Slogwang * to be stored. The nc_dotdottime field is used when a cache entry is mapping 110*a9643ea8Slogwang * both a non-dotdot directory name plus dotdot for the directory's 111*a9643ea8Slogwang * parent. 112*a9643ea8Slogwang */ 113*a9643ea8Slogwang struct namecache_ts { 114*a9643ea8Slogwang LIST_ENTRY(namecache) nc_hash; /* hash chain */ 115*a9643ea8Slogwang LIST_ENTRY(namecache) nc_src; /* source vnode list */ 116*a9643ea8Slogwang TAILQ_ENTRY(namecache) nc_dst; /* destination vnode list */ 117*a9643ea8Slogwang struct vnode *nc_dvp; /* vnode of parent of name */ 118*a9643ea8Slogwang struct vnode *nc_vp; /* vnode the name refers to */ 119*a9643ea8Slogwang u_char nc_flag; /* flag bits */ 120*a9643ea8Slogwang u_char nc_nlen; /* length of name */ 121*a9643ea8Slogwang struct timespec nc_time; /* timespec provided by fs */ 122*a9643ea8Slogwang struct timespec nc_dotdottime; /* dotdot timespec provided by fs */ 123*a9643ea8Slogwang int nc_ticks; /* ticks value when entry was added */ 124*a9643ea8Slogwang char nc_name[0]; /* segment name + nul */ 125*a9643ea8Slogwang }; 126*a9643ea8Slogwang 127*a9643ea8Slogwang /* 128*a9643ea8Slogwang * Flags in namecache.nc_flag 129*a9643ea8Slogwang */ 130*a9643ea8Slogwang #define NCF_WHITE 0x01 131*a9643ea8Slogwang #define NCF_ISDOTDOT 0x02 132*a9643ea8Slogwang #define NCF_TS 0x04 133*a9643ea8Slogwang #define NCF_DTS 0x08 134*a9643ea8Slogwang 135*a9643ea8Slogwang /* 136*a9643ea8Slogwang * Name caching works as follows: 137*a9643ea8Slogwang * 138*a9643ea8Slogwang * Names found by directory scans are retained in a cache 139*a9643ea8Slogwang * for future reference. It is managed LRU, so frequently 140*a9643ea8Slogwang * used names will hang around. Cache is indexed by hash value 141*a9643ea8Slogwang * obtained from (vp, name) where vp refers to the directory 142*a9643ea8Slogwang * containing name. 143*a9643ea8Slogwang * 144*a9643ea8Slogwang * If it is a "negative" entry, (i.e. for a name that is known NOT to 145*a9643ea8Slogwang * exist) the vnode pointer will be NULL. 146*a9643ea8Slogwang * 147*a9643ea8Slogwang * Upon reaching the last segment of a path, if the reference 148*a9643ea8Slogwang * is for DELETE, or NOCACHE is set (rewrite), and the 149*a9643ea8Slogwang * name is located in the cache, it will be dropped. 150*a9643ea8Slogwang */ 151*a9643ea8Slogwang 152*a9643ea8Slogwang /* 153*a9643ea8Slogwang * Structures associated with name caching. 154*a9643ea8Slogwang */ 155*a9643ea8Slogwang #define NCHHASH(hash) \ 156*a9643ea8Slogwang (&nchashtbl[(hash) & nchash]) 157*a9643ea8Slogwang static LIST_HEAD(nchashhead, namecache) *nchashtbl; /* Hash Table */ 158*a9643ea8Slogwang static TAILQ_HEAD(, namecache) ncneg; /* Hash Table */ 159*a9643ea8Slogwang static u_long nchash; /* size of hash table */ 160*a9643ea8Slogwang SYSCTL_ULONG(_debug, OID_AUTO, nchash, CTLFLAG_RD, &nchash, 0, 161*a9643ea8Slogwang "Size of namecache hash table"); 162*a9643ea8Slogwang static u_long ncnegfactor = 16; /* ratio of negative entries */ 163*a9643ea8Slogwang SYSCTL_ULONG(_vfs, OID_AUTO, ncnegfactor, CTLFLAG_RW, &ncnegfactor, 0, 164*a9643ea8Slogwang "Ratio of negative namecache entries"); 165*a9643ea8Slogwang static u_long numneg; /* number of negative entries allocated */ 166*a9643ea8Slogwang SYSCTL_ULONG(_debug, OID_AUTO, numneg, CTLFLAG_RD, &numneg, 0, 167*a9643ea8Slogwang "Number of negative entries in namecache"); 168*a9643ea8Slogwang static u_long numcache; /* number of cache entries allocated */ 169*a9643ea8Slogwang SYSCTL_ULONG(_debug, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0, 170*a9643ea8Slogwang "Number of namecache entries"); 171*a9643ea8Slogwang static u_long numcachehv; /* number of cache entries with vnodes held */ 172*a9643ea8Slogwang SYSCTL_ULONG(_debug, OID_AUTO, numcachehv, CTLFLAG_RD, &numcachehv, 0, 173*a9643ea8Slogwang "Number of namecache entries with vnodes held"); 174*a9643ea8Slogwang u_int ncsizefactor = 2; 175*a9643ea8Slogwang SYSCTL_UINT(_vfs, OID_AUTO, ncsizefactor, CTLFLAG_RW, &ncsizefactor, 0, 176*a9643ea8Slogwang "Size factor for namecache"); 177*a9643ea8Slogwang 178*a9643ea8Slogwang struct nchstats nchstats; /* cache effectiveness statistics */ 179*a9643ea8Slogwang 180*a9643ea8Slogwang static struct rwlock cache_lock; 181*a9643ea8Slogwang RW_SYSINIT(vfscache, &cache_lock, "Name Cache"); 182*a9643ea8Slogwang 183*a9643ea8Slogwang #define CACHE_UPGRADE_LOCK() rw_try_upgrade(&cache_lock) 184*a9643ea8Slogwang #define CACHE_RLOCK() rw_rlock(&cache_lock) 185*a9643ea8Slogwang #define CACHE_RUNLOCK() rw_runlock(&cache_lock) 186*a9643ea8Slogwang #define CACHE_WLOCK() rw_wlock(&cache_lock) 187*a9643ea8Slogwang #define CACHE_WUNLOCK() rw_wunlock(&cache_lock) 188*a9643ea8Slogwang 189*a9643ea8Slogwang /* 190*a9643ea8Slogwang * UMA zones for the VFS cache. 191*a9643ea8Slogwang * 192*a9643ea8Slogwang * The small cache is used for entries with short names, which are the 193*a9643ea8Slogwang * most common. The large cache is used for entries which are too big to 194*a9643ea8Slogwang * fit in the small cache. 195*a9643ea8Slogwang */ 196*a9643ea8Slogwang static uma_zone_t cache_zone_small; 197*a9643ea8Slogwang static uma_zone_t cache_zone_small_ts; 198*a9643ea8Slogwang static uma_zone_t cache_zone_large; 199*a9643ea8Slogwang static uma_zone_t cache_zone_large_ts; 200*a9643ea8Slogwang 201*a9643ea8Slogwang #define CACHE_PATH_CUTOFF 35 202*a9643ea8Slogwang 203*a9643ea8Slogwang static struct namecache * 204*a9643ea8Slogwang cache_alloc(int len, int ts) 205*a9643ea8Slogwang { 206*a9643ea8Slogwang 207*a9643ea8Slogwang if (len > CACHE_PATH_CUTOFF) { 208*a9643ea8Slogwang if (ts) 209*a9643ea8Slogwang return (uma_zalloc(cache_zone_large_ts, M_WAITOK)); 210*a9643ea8Slogwang else 211*a9643ea8Slogwang return (uma_zalloc(cache_zone_large, M_WAITOK)); 212*a9643ea8Slogwang } 213*a9643ea8Slogwang if (ts) 214*a9643ea8Slogwang return (uma_zalloc(cache_zone_small_ts, M_WAITOK)); 215*a9643ea8Slogwang else 216*a9643ea8Slogwang return (uma_zalloc(cache_zone_small, M_WAITOK)); 217*a9643ea8Slogwang } 218*a9643ea8Slogwang 219*a9643ea8Slogwang static void 220*a9643ea8Slogwang cache_free(struct namecache *ncp) 221*a9643ea8Slogwang { 222*a9643ea8Slogwang int ts; 223*a9643ea8Slogwang 224*a9643ea8Slogwang if (ncp == NULL) 225*a9643ea8Slogwang return; 226*a9643ea8Slogwang ts = ncp->nc_flag & NCF_TS; 227*a9643ea8Slogwang if (ncp->nc_nlen <= CACHE_PATH_CUTOFF) { 228*a9643ea8Slogwang if (ts) 229*a9643ea8Slogwang uma_zfree(cache_zone_small_ts, ncp); 230*a9643ea8Slogwang else 231*a9643ea8Slogwang uma_zfree(cache_zone_small, ncp); 232*a9643ea8Slogwang } else if (ts) 233*a9643ea8Slogwang uma_zfree(cache_zone_large_ts, ncp); 234*a9643ea8Slogwang else 235*a9643ea8Slogwang uma_zfree(cache_zone_large, ncp); 236*a9643ea8Slogwang } 237*a9643ea8Slogwang 238*a9643ea8Slogwang static char * 239*a9643ea8Slogwang nc_get_name(struct namecache *ncp) 240*a9643ea8Slogwang { 241*a9643ea8Slogwang struct namecache_ts *ncp_ts; 242*a9643ea8Slogwang 243*a9643ea8Slogwang if ((ncp->nc_flag & NCF_TS) == 0) 244*a9643ea8Slogwang return (ncp->nc_name); 245*a9643ea8Slogwang ncp_ts = (struct namecache_ts *)ncp; 246*a9643ea8Slogwang return (ncp_ts->nc_name); 247*a9643ea8Slogwang } 248*a9643ea8Slogwang 249*a9643ea8Slogwang static void 250*a9643ea8Slogwang cache_out_ts(struct namecache *ncp, struct timespec *tsp, int *ticksp) 251*a9643ea8Slogwang { 252*a9643ea8Slogwang 253*a9643ea8Slogwang KASSERT((ncp->nc_flag & NCF_TS) != 0 || 254*a9643ea8Slogwang (tsp == NULL && ticksp == NULL), 255*a9643ea8Slogwang ("No NCF_TS")); 256*a9643ea8Slogwang 257*a9643ea8Slogwang if (tsp != NULL) 258*a9643ea8Slogwang *tsp = ((struct namecache_ts *)ncp)->nc_time; 259*a9643ea8Slogwang if (ticksp != NULL) 260*a9643ea8Slogwang *ticksp = ((struct namecache_ts *)ncp)->nc_ticks; 261*a9643ea8Slogwang } 262*a9643ea8Slogwang 263*a9643ea8Slogwang static int doingcache = 1; /* 1 => enable the cache */ 264*a9643ea8Slogwang SYSCTL_INT(_debug, OID_AUTO, vfscache, CTLFLAG_RW, &doingcache, 0, 265*a9643ea8Slogwang "VFS namecache enabled"); 266*a9643ea8Slogwang 267*a9643ea8Slogwang /* Export size information to userland */ 268*a9643ea8Slogwang SYSCTL_INT(_debug_sizeof, OID_AUTO, namecache, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, 269*a9643ea8Slogwang sizeof(struct namecache), "sizeof(struct namecache)"); 270*a9643ea8Slogwang 271*a9643ea8Slogwang /* 272*a9643ea8Slogwang * The new name cache statistics 273*a9643ea8Slogwang */ 274*a9643ea8Slogwang static SYSCTL_NODE(_vfs, OID_AUTO, cache, CTLFLAG_RW, 0, 275*a9643ea8Slogwang "Name cache statistics"); 276*a9643ea8Slogwang #define STATNODE_ULONG(name, descr) \ 277*a9643ea8Slogwang SYSCTL_ULONG(_vfs_cache, OID_AUTO, name, CTLFLAG_RD, &name, 0, descr); 278*a9643ea8Slogwang #define STATNODE_COUNTER(name, descr) \ 279*a9643ea8Slogwang static counter_u64_t name; \ 280*a9643ea8Slogwang SYSCTL_COUNTER_U64(_vfs_cache, OID_AUTO, name, CTLFLAG_RD, &name, descr); 281*a9643ea8Slogwang STATNODE_ULONG(numneg, "Number of negative cache entries"); 282*a9643ea8Slogwang STATNODE_ULONG(numcache, "Number of cache entries"); 283*a9643ea8Slogwang STATNODE_COUNTER(numcalls, "Number of cache lookups"); 284*a9643ea8Slogwang STATNODE_COUNTER(dothits, "Number of '.' hits"); 285*a9643ea8Slogwang STATNODE_COUNTER(dotdothits, "Number of '..' hits"); 286*a9643ea8Slogwang STATNODE_COUNTER(numchecks, "Number of checks in lookup"); 287*a9643ea8Slogwang STATNODE_COUNTER(nummiss, "Number of cache misses"); 288*a9643ea8Slogwang STATNODE_COUNTER(nummisszap, "Number of cache misses we do not want to cache"); 289*a9643ea8Slogwang STATNODE_COUNTER(numposzaps, 290*a9643ea8Slogwang "Number of cache hits (positive) we do not want to cache"); 291*a9643ea8Slogwang STATNODE_COUNTER(numposhits, "Number of cache hits (positive)"); 292*a9643ea8Slogwang STATNODE_COUNTER(numnegzaps, 293*a9643ea8Slogwang "Number of cache hits (negative) we do not want to cache"); 294*a9643ea8Slogwang STATNODE_COUNTER(numneghits, "Number of cache hits (negative)"); 295*a9643ea8Slogwang /* These count for kern___getcwd(), too. */ 296*a9643ea8Slogwang STATNODE_COUNTER(numfullpathcalls, "Number of fullpath search calls"); 297*a9643ea8Slogwang STATNODE_COUNTER(numfullpathfail1, "Number of fullpath search errors (ENOTDIR)"); 298*a9643ea8Slogwang STATNODE_COUNTER(numfullpathfail2, 299*a9643ea8Slogwang "Number of fullpath search errors (VOP_VPTOCNP failures)"); 300*a9643ea8Slogwang STATNODE_COUNTER(numfullpathfail4, "Number of fullpath search errors (ENOMEM)"); 301*a9643ea8Slogwang STATNODE_COUNTER(numfullpathfound, "Number of successful fullpath calls"); 302*a9643ea8Slogwang static long numupgrades; STATNODE_ULONG(numupgrades, 303*a9643ea8Slogwang "Number of updates of the cache after lookup (write lock + retry)"); 304*a9643ea8Slogwang 305*a9643ea8Slogwang static void cache_zap(struct namecache *ncp); 306*a9643ea8Slogwang static int vn_vptocnp_locked(struct vnode **vp, struct ucred *cred, char *buf, 307*a9643ea8Slogwang u_int *buflen); 308*a9643ea8Slogwang static int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir, 309*a9643ea8Slogwang char *buf, char **retbuf, u_int buflen); 310*a9643ea8Slogwang 311*a9643ea8Slogwang static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries"); 312*a9643ea8Slogwang 313*a9643ea8Slogwang static uint32_t 314*a9643ea8Slogwang cache_get_hash(char *name, u_char len, struct vnode *dvp) 315*a9643ea8Slogwang { 316*a9643ea8Slogwang uint32_t hash; 317*a9643ea8Slogwang 318*a9643ea8Slogwang hash = fnv_32_buf(name, len, FNV1_32_INIT); 319*a9643ea8Slogwang hash = fnv_32_buf(&dvp, sizeof(dvp), hash); 320*a9643ea8Slogwang return (hash); 321*a9643ea8Slogwang } 322*a9643ea8Slogwang 323*a9643ea8Slogwang static int 324*a9643ea8Slogwang sysctl_nchstats(SYSCTL_HANDLER_ARGS) 325*a9643ea8Slogwang { 326*a9643ea8Slogwang struct nchstats snap; 327*a9643ea8Slogwang 328*a9643ea8Slogwang if (req->oldptr == NULL) 329*a9643ea8Slogwang return (SYSCTL_OUT(req, 0, sizeof(snap))); 330*a9643ea8Slogwang 331*a9643ea8Slogwang snap = nchstats; 332*a9643ea8Slogwang snap.ncs_goodhits = counter_u64_fetch(numposhits); 333*a9643ea8Slogwang snap.ncs_neghits = counter_u64_fetch(numneghits); 334*a9643ea8Slogwang snap.ncs_badhits = counter_u64_fetch(numposzaps) + 335*a9643ea8Slogwang counter_u64_fetch(numnegzaps); 336*a9643ea8Slogwang snap.ncs_miss = counter_u64_fetch(nummisszap) + 337*a9643ea8Slogwang counter_u64_fetch(nummiss); 338*a9643ea8Slogwang 339*a9643ea8Slogwang return (SYSCTL_OUT(req, &snap, sizeof(snap))); 340*a9643ea8Slogwang } 341*a9643ea8Slogwang SYSCTL_PROC(_vfs_cache, OID_AUTO, nchstats, CTLTYPE_OPAQUE | CTLFLAG_RD | 342*a9643ea8Slogwang CTLFLAG_MPSAFE, 0, 0, sysctl_nchstats, "LU", 343*a9643ea8Slogwang "VFS cache effectiveness statistics"); 344*a9643ea8Slogwang 345*a9643ea8Slogwang #ifdef DIAGNOSTIC 346*a9643ea8Slogwang /* 347*a9643ea8Slogwang * Grab an atomic snapshot of the name cache hash chain lengths 348*a9643ea8Slogwang */ 349*a9643ea8Slogwang static SYSCTL_NODE(_debug, OID_AUTO, hashstat, CTLFLAG_RW, NULL, 350*a9643ea8Slogwang "hash table stats"); 351*a9643ea8Slogwang 352*a9643ea8Slogwang static int 353*a9643ea8Slogwang sysctl_debug_hashstat_rawnchash(SYSCTL_HANDLER_ARGS) 354*a9643ea8Slogwang { 355*a9643ea8Slogwang struct nchashhead *ncpp; 356*a9643ea8Slogwang struct namecache *ncp; 357*a9643ea8Slogwang int i, error, n_nchash, *cntbuf; 358*a9643ea8Slogwang 359*a9643ea8Slogwang retry: 360*a9643ea8Slogwang n_nchash = nchash + 1; /* nchash is max index, not count */ 361*a9643ea8Slogwang if (req->oldptr == NULL) 362*a9643ea8Slogwang return SYSCTL_OUT(req, 0, n_nchash * sizeof(int)); 363*a9643ea8Slogwang cntbuf = malloc(n_nchash * sizeof(int), M_TEMP, M_ZERO | M_WAITOK); 364*a9643ea8Slogwang CACHE_RLOCK(); 365*a9643ea8Slogwang if (n_nchash != nchash + 1) { 366*a9643ea8Slogwang CACHE_RUNLOCK(); 367*a9643ea8Slogwang free(cntbuf, M_TEMP); 368*a9643ea8Slogwang goto retry; 369*a9643ea8Slogwang } 370*a9643ea8Slogwang /* Scan hash tables counting entries */ 371*a9643ea8Slogwang for (ncpp = nchashtbl, i = 0; i < n_nchash; ncpp++, i++) 372*a9643ea8Slogwang LIST_FOREACH(ncp, ncpp, nc_hash) 373*a9643ea8Slogwang cntbuf[i]++; 374*a9643ea8Slogwang CACHE_RUNLOCK(); 375*a9643ea8Slogwang for (error = 0, i = 0; i < n_nchash; i++) 376*a9643ea8Slogwang if ((error = SYSCTL_OUT(req, &cntbuf[i], sizeof(int))) != 0) 377*a9643ea8Slogwang break; 378*a9643ea8Slogwang free(cntbuf, M_TEMP); 379*a9643ea8Slogwang return (error); 380*a9643ea8Slogwang } 381*a9643ea8Slogwang SYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnchash, CTLTYPE_INT|CTLFLAG_RD| 382*a9643ea8Slogwang CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_rawnchash, "S,int", 383*a9643ea8Slogwang "nchash chain lengths"); 384*a9643ea8Slogwang 385*a9643ea8Slogwang static int 386*a9643ea8Slogwang sysctl_debug_hashstat_nchash(SYSCTL_HANDLER_ARGS) 387*a9643ea8Slogwang { 388*a9643ea8Slogwang int error; 389*a9643ea8Slogwang struct nchashhead *ncpp; 390*a9643ea8Slogwang struct namecache *ncp; 391*a9643ea8Slogwang int n_nchash; 392*a9643ea8Slogwang int count, maxlength, used, pct; 393*a9643ea8Slogwang 394*a9643ea8Slogwang if (!req->oldptr) 395*a9643ea8Slogwang return SYSCTL_OUT(req, 0, 4 * sizeof(int)); 396*a9643ea8Slogwang 397*a9643ea8Slogwang CACHE_RLOCK(); 398*a9643ea8Slogwang n_nchash = nchash + 1; /* nchash is max index, not count */ 399*a9643ea8Slogwang used = 0; 400*a9643ea8Slogwang maxlength = 0; 401*a9643ea8Slogwang 402*a9643ea8Slogwang /* Scan hash tables for applicable entries */ 403*a9643ea8Slogwang for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) { 404*a9643ea8Slogwang count = 0; 405*a9643ea8Slogwang LIST_FOREACH(ncp, ncpp, nc_hash) { 406*a9643ea8Slogwang count++; 407*a9643ea8Slogwang } 408*a9643ea8Slogwang if (count) 409*a9643ea8Slogwang used++; 410*a9643ea8Slogwang if (maxlength < count) 411*a9643ea8Slogwang maxlength = count; 412*a9643ea8Slogwang } 413*a9643ea8Slogwang n_nchash = nchash + 1; 414*a9643ea8Slogwang CACHE_RUNLOCK(); 415*a9643ea8Slogwang pct = (used * 100) / (n_nchash / 100); 416*a9643ea8Slogwang error = SYSCTL_OUT(req, &n_nchash, sizeof(n_nchash)); 417*a9643ea8Slogwang if (error) 418*a9643ea8Slogwang return (error); 419*a9643ea8Slogwang error = SYSCTL_OUT(req, &used, sizeof(used)); 420*a9643ea8Slogwang if (error) 421*a9643ea8Slogwang return (error); 422*a9643ea8Slogwang error = SYSCTL_OUT(req, &maxlength, sizeof(maxlength)); 423*a9643ea8Slogwang if (error) 424*a9643ea8Slogwang return (error); 425*a9643ea8Slogwang error = SYSCTL_OUT(req, &pct, sizeof(pct)); 426*a9643ea8Slogwang if (error) 427*a9643ea8Slogwang return (error); 428*a9643ea8Slogwang return (0); 429*a9643ea8Slogwang } 430*a9643ea8Slogwang SYSCTL_PROC(_debug_hashstat, OID_AUTO, nchash, CTLTYPE_INT|CTLFLAG_RD| 431*a9643ea8Slogwang CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_nchash, "I", 432*a9643ea8Slogwang "nchash statistics (number of total/used buckets, maximum chain length, usage percentage)"); 433*a9643ea8Slogwang #endif 434*a9643ea8Slogwang 435*a9643ea8Slogwang /* 436*a9643ea8Slogwang * cache_zap(): 437*a9643ea8Slogwang * 438*a9643ea8Slogwang * Removes a namecache entry from cache, whether it contains an actual 439*a9643ea8Slogwang * pointer to a vnode or if it is just a negative cache entry. 440*a9643ea8Slogwang */ 441*a9643ea8Slogwang static void 442*a9643ea8Slogwang cache_zap(struct namecache *ncp) 443*a9643ea8Slogwang { 444*a9643ea8Slogwang struct vnode *vp; 445*a9643ea8Slogwang 446*a9643ea8Slogwang rw_assert(&cache_lock, RA_WLOCKED); 447*a9643ea8Slogwang CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, ncp->nc_vp); 448*a9643ea8Slogwang if (ncp->nc_vp != NULL) { 449*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, zap, done, ncp->nc_dvp, 450*a9643ea8Slogwang nc_get_name(ncp), ncp->nc_vp); 451*a9643ea8Slogwang } else { 452*a9643ea8Slogwang SDT_PROBE2(vfs, namecache, zap_negative, done, ncp->nc_dvp, 453*a9643ea8Slogwang nc_get_name(ncp)); 454*a9643ea8Slogwang } 455*a9643ea8Slogwang vp = NULL; 456*a9643ea8Slogwang LIST_REMOVE(ncp, nc_hash); 457*a9643ea8Slogwang if (ncp->nc_flag & NCF_ISDOTDOT) { 458*a9643ea8Slogwang if (ncp == ncp->nc_dvp->v_cache_dd) 459*a9643ea8Slogwang ncp->nc_dvp->v_cache_dd = NULL; 460*a9643ea8Slogwang } else { 461*a9643ea8Slogwang LIST_REMOVE(ncp, nc_src); 462*a9643ea8Slogwang if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src)) { 463*a9643ea8Slogwang vp = ncp->nc_dvp; 464*a9643ea8Slogwang numcachehv--; 465*a9643ea8Slogwang } 466*a9643ea8Slogwang } 467*a9643ea8Slogwang if (ncp->nc_vp) { 468*a9643ea8Slogwang TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst); 469*a9643ea8Slogwang if (ncp == ncp->nc_vp->v_cache_dd) 470*a9643ea8Slogwang ncp->nc_vp->v_cache_dd = NULL; 471*a9643ea8Slogwang } else { 472*a9643ea8Slogwang TAILQ_REMOVE(&ncneg, ncp, nc_dst); 473*a9643ea8Slogwang numneg--; 474*a9643ea8Slogwang } 475*a9643ea8Slogwang numcache--; 476*a9643ea8Slogwang cache_free(ncp); 477*a9643ea8Slogwang if (vp != NULL) 478*a9643ea8Slogwang vdrop(vp); 479*a9643ea8Slogwang } 480*a9643ea8Slogwang 481*a9643ea8Slogwang /* 482*a9643ea8Slogwang * Lookup an entry in the cache 483*a9643ea8Slogwang * 484*a9643ea8Slogwang * Lookup is called with dvp pointing to the directory to search, 485*a9643ea8Slogwang * cnp pointing to the name of the entry being sought. If the lookup 486*a9643ea8Slogwang * succeeds, the vnode is returned in *vpp, and a status of -1 is 487*a9643ea8Slogwang * returned. If the lookup determines that the name does not exist 488*a9643ea8Slogwang * (negative caching), a status of ENOENT is returned. If the lookup 489*a9643ea8Slogwang * fails, a status of zero is returned. If the directory vnode is 490*a9643ea8Slogwang * recycled out from under us due to a forced unmount, a status of 491*a9643ea8Slogwang * ENOENT is returned. 492*a9643ea8Slogwang * 493*a9643ea8Slogwang * vpp is locked and ref'd on return. If we're looking up DOTDOT, dvp is 494*a9643ea8Slogwang * unlocked. If we're looking up . an extra ref is taken, but the lock is 495*a9643ea8Slogwang * not recursively acquired. 496*a9643ea8Slogwang */ 497*a9643ea8Slogwang 498*a9643ea8Slogwang int 499*a9643ea8Slogwang cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, 500*a9643ea8Slogwang struct timespec *tsp, int *ticksp) 501*a9643ea8Slogwang { 502*a9643ea8Slogwang struct namecache *ncp; 503*a9643ea8Slogwang uint32_t hash; 504*a9643ea8Slogwang int error, ltype, wlocked; 505*a9643ea8Slogwang 506*a9643ea8Slogwang if (!doingcache) { 507*a9643ea8Slogwang cnp->cn_flags &= ~MAKEENTRY; 508*a9643ea8Slogwang return (0); 509*a9643ea8Slogwang } 510*a9643ea8Slogwang retry: 511*a9643ea8Slogwang wlocked = 0; 512*a9643ea8Slogwang counter_u64_add(numcalls, 1); 513*a9643ea8Slogwang error = 0; 514*a9643ea8Slogwang 515*a9643ea8Slogwang retry_wlocked: 516*a9643ea8Slogwang if (cnp->cn_nameptr[0] == '.') { 517*a9643ea8Slogwang if (cnp->cn_namelen == 1) { 518*a9643ea8Slogwang *vpp = dvp; 519*a9643ea8Slogwang CTR2(KTR_VFS, "cache_lookup(%p, %s) found via .", 520*a9643ea8Slogwang dvp, cnp->cn_nameptr); 521*a9643ea8Slogwang counter_u64_add(dothits, 1); 522*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, lookup, hit, dvp, ".", *vpp); 523*a9643ea8Slogwang if (tsp != NULL) 524*a9643ea8Slogwang timespecclear(tsp); 525*a9643ea8Slogwang if (ticksp != NULL) 526*a9643ea8Slogwang *ticksp = ticks; 527*a9643ea8Slogwang VREF(*vpp); 528*a9643ea8Slogwang /* 529*a9643ea8Slogwang * When we lookup "." we still can be asked to lock it 530*a9643ea8Slogwang * differently... 531*a9643ea8Slogwang */ 532*a9643ea8Slogwang ltype = cnp->cn_lkflags & LK_TYPE_MASK; 533*a9643ea8Slogwang if (ltype != VOP_ISLOCKED(*vpp)) { 534*a9643ea8Slogwang if (ltype == LK_EXCLUSIVE) { 535*a9643ea8Slogwang vn_lock(*vpp, LK_UPGRADE | LK_RETRY); 536*a9643ea8Slogwang if ((*vpp)->v_iflag & VI_DOOMED) { 537*a9643ea8Slogwang /* forced unmount */ 538*a9643ea8Slogwang vrele(*vpp); 539*a9643ea8Slogwang *vpp = NULL; 540*a9643ea8Slogwang return (ENOENT); 541*a9643ea8Slogwang } 542*a9643ea8Slogwang } else 543*a9643ea8Slogwang vn_lock(*vpp, LK_DOWNGRADE | LK_RETRY); 544*a9643ea8Slogwang } 545*a9643ea8Slogwang return (-1); 546*a9643ea8Slogwang } 547*a9643ea8Slogwang if (!wlocked) 548*a9643ea8Slogwang CACHE_RLOCK(); 549*a9643ea8Slogwang if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') { 550*a9643ea8Slogwang counter_u64_add(dotdothits, 1); 551*a9643ea8Slogwang if (dvp->v_cache_dd == NULL) { 552*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, lookup, miss, dvp, 553*a9643ea8Slogwang "..", NULL); 554*a9643ea8Slogwang goto unlock; 555*a9643ea8Slogwang } 556*a9643ea8Slogwang if ((cnp->cn_flags & MAKEENTRY) == 0) { 557*a9643ea8Slogwang if (!wlocked && !CACHE_UPGRADE_LOCK()) 558*a9643ea8Slogwang goto wlock; 559*a9643ea8Slogwang if (dvp->v_cache_dd->nc_flag & NCF_ISDOTDOT) 560*a9643ea8Slogwang cache_zap(dvp->v_cache_dd); 561*a9643ea8Slogwang dvp->v_cache_dd = NULL; 562*a9643ea8Slogwang CACHE_WUNLOCK(); 563*a9643ea8Slogwang return (0); 564*a9643ea8Slogwang } 565*a9643ea8Slogwang ncp = dvp->v_cache_dd; 566*a9643ea8Slogwang if (ncp->nc_flag & NCF_ISDOTDOT) 567*a9643ea8Slogwang *vpp = ncp->nc_vp; 568*a9643ea8Slogwang else 569*a9643ea8Slogwang *vpp = ncp->nc_dvp; 570*a9643ea8Slogwang /* Return failure if negative entry was found. */ 571*a9643ea8Slogwang if (*vpp == NULL) 572*a9643ea8Slogwang goto negative_success; 573*a9643ea8Slogwang CTR3(KTR_VFS, "cache_lookup(%p, %s) found %p via ..", 574*a9643ea8Slogwang dvp, cnp->cn_nameptr, *vpp); 575*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, lookup, hit, dvp, "..", 576*a9643ea8Slogwang *vpp); 577*a9643ea8Slogwang cache_out_ts(ncp, tsp, ticksp); 578*a9643ea8Slogwang if ((ncp->nc_flag & (NCF_ISDOTDOT | NCF_DTS)) == 579*a9643ea8Slogwang NCF_DTS && tsp != NULL) 580*a9643ea8Slogwang *tsp = ((struct namecache_ts *)ncp)-> 581*a9643ea8Slogwang nc_dotdottime; 582*a9643ea8Slogwang goto success; 583*a9643ea8Slogwang } 584*a9643ea8Slogwang } else if (!wlocked) 585*a9643ea8Slogwang CACHE_RLOCK(); 586*a9643ea8Slogwang 587*a9643ea8Slogwang hash = cache_get_hash(cnp->cn_nameptr, cnp->cn_namelen, dvp); 588*a9643ea8Slogwang LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { 589*a9643ea8Slogwang counter_u64_add(numchecks, 1); 590*a9643ea8Slogwang if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen && 591*a9643ea8Slogwang !bcmp(nc_get_name(ncp), cnp->cn_nameptr, ncp->nc_nlen)) 592*a9643ea8Slogwang break; 593*a9643ea8Slogwang } 594*a9643ea8Slogwang 595*a9643ea8Slogwang /* We failed to find an entry */ 596*a9643ea8Slogwang if (ncp == NULL) { 597*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, lookup, miss, dvp, cnp->cn_nameptr, 598*a9643ea8Slogwang NULL); 599*a9643ea8Slogwang if ((cnp->cn_flags & MAKEENTRY) == 0) { 600*a9643ea8Slogwang counter_u64_add(nummisszap, 1); 601*a9643ea8Slogwang } else { 602*a9643ea8Slogwang counter_u64_add(nummiss, 1); 603*a9643ea8Slogwang } 604*a9643ea8Slogwang goto unlock; 605*a9643ea8Slogwang } 606*a9643ea8Slogwang 607*a9643ea8Slogwang /* We don't want to have an entry, so dump it */ 608*a9643ea8Slogwang if ((cnp->cn_flags & MAKEENTRY) == 0) { 609*a9643ea8Slogwang counter_u64_add(numposzaps, 1); 610*a9643ea8Slogwang if (!wlocked && !CACHE_UPGRADE_LOCK()) 611*a9643ea8Slogwang goto wlock; 612*a9643ea8Slogwang cache_zap(ncp); 613*a9643ea8Slogwang CACHE_WUNLOCK(); 614*a9643ea8Slogwang return (0); 615*a9643ea8Slogwang } 616*a9643ea8Slogwang 617*a9643ea8Slogwang /* We found a "positive" match, return the vnode */ 618*a9643ea8Slogwang if (ncp->nc_vp) { 619*a9643ea8Slogwang counter_u64_add(numposhits, 1); 620*a9643ea8Slogwang *vpp = ncp->nc_vp; 621*a9643ea8Slogwang CTR4(KTR_VFS, "cache_lookup(%p, %s) found %p via ncp %p", 622*a9643ea8Slogwang dvp, cnp->cn_nameptr, *vpp, ncp); 623*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, lookup, hit, dvp, nc_get_name(ncp), 624*a9643ea8Slogwang *vpp); 625*a9643ea8Slogwang cache_out_ts(ncp, tsp, ticksp); 626*a9643ea8Slogwang goto success; 627*a9643ea8Slogwang } 628*a9643ea8Slogwang 629*a9643ea8Slogwang negative_success: 630*a9643ea8Slogwang /* We found a negative match, and want to create it, so purge */ 631*a9643ea8Slogwang if (cnp->cn_nameiop == CREATE) { 632*a9643ea8Slogwang counter_u64_add(numnegzaps, 1); 633*a9643ea8Slogwang if (!wlocked && !CACHE_UPGRADE_LOCK()) 634*a9643ea8Slogwang goto wlock; 635*a9643ea8Slogwang cache_zap(ncp); 636*a9643ea8Slogwang CACHE_WUNLOCK(); 637*a9643ea8Slogwang return (0); 638*a9643ea8Slogwang } 639*a9643ea8Slogwang 640*a9643ea8Slogwang if (!wlocked && !CACHE_UPGRADE_LOCK()) 641*a9643ea8Slogwang goto wlock; 642*a9643ea8Slogwang counter_u64_add(numneghits, 1); 643*a9643ea8Slogwang /* 644*a9643ea8Slogwang * We found a "negative" match, so we shift it to the end of 645*a9643ea8Slogwang * the "negative" cache entries queue to satisfy LRU. Also, 646*a9643ea8Slogwang * check to see if the entry is a whiteout; indicate this to 647*a9643ea8Slogwang * the componentname, if so. 648*a9643ea8Slogwang */ 649*a9643ea8Slogwang TAILQ_REMOVE(&ncneg, ncp, nc_dst); 650*a9643ea8Slogwang TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst); 651*a9643ea8Slogwang if (ncp->nc_flag & NCF_WHITE) 652*a9643ea8Slogwang cnp->cn_flags |= ISWHITEOUT; 653*a9643ea8Slogwang SDT_PROBE2(vfs, namecache, lookup, hit__negative, dvp, 654*a9643ea8Slogwang nc_get_name(ncp)); 655*a9643ea8Slogwang cache_out_ts(ncp, tsp, ticksp); 656*a9643ea8Slogwang CACHE_WUNLOCK(); 657*a9643ea8Slogwang return (ENOENT); 658*a9643ea8Slogwang 659*a9643ea8Slogwang wlock: 660*a9643ea8Slogwang /* 661*a9643ea8Slogwang * We need to update the cache after our lookup, so upgrade to 662*a9643ea8Slogwang * a write lock and retry the operation. 663*a9643ea8Slogwang */ 664*a9643ea8Slogwang CACHE_RUNLOCK(); 665*a9643ea8Slogwang CACHE_WLOCK(); 666*a9643ea8Slogwang numupgrades++; 667*a9643ea8Slogwang wlocked = 1; 668*a9643ea8Slogwang goto retry_wlocked; 669*a9643ea8Slogwang 670*a9643ea8Slogwang success: 671*a9643ea8Slogwang /* 672*a9643ea8Slogwang * On success we return a locked and ref'd vnode as per the lookup 673*a9643ea8Slogwang * protocol. 674*a9643ea8Slogwang */ 675*a9643ea8Slogwang MPASS(dvp != *vpp); 676*a9643ea8Slogwang ltype = 0; /* silence gcc warning */ 677*a9643ea8Slogwang if (cnp->cn_flags & ISDOTDOT) { 678*a9643ea8Slogwang ltype = VOP_ISLOCKED(dvp); 679*a9643ea8Slogwang VOP_UNLOCK(dvp, 0); 680*a9643ea8Slogwang } 681*a9643ea8Slogwang vhold(*vpp); 682*a9643ea8Slogwang if (wlocked) 683*a9643ea8Slogwang CACHE_WUNLOCK(); 684*a9643ea8Slogwang else 685*a9643ea8Slogwang CACHE_RUNLOCK(); 686*a9643ea8Slogwang error = vget(*vpp, cnp->cn_lkflags | LK_VNHELD, cnp->cn_thread); 687*a9643ea8Slogwang if (cnp->cn_flags & ISDOTDOT) { 688*a9643ea8Slogwang vn_lock(dvp, ltype | LK_RETRY); 689*a9643ea8Slogwang if (dvp->v_iflag & VI_DOOMED) { 690*a9643ea8Slogwang if (error == 0) 691*a9643ea8Slogwang vput(*vpp); 692*a9643ea8Slogwang *vpp = NULL; 693*a9643ea8Slogwang return (ENOENT); 694*a9643ea8Slogwang } 695*a9643ea8Slogwang } 696*a9643ea8Slogwang if (error) { 697*a9643ea8Slogwang *vpp = NULL; 698*a9643ea8Slogwang goto retry; 699*a9643ea8Slogwang } 700*a9643ea8Slogwang if ((cnp->cn_flags & ISLASTCN) && 701*a9643ea8Slogwang (cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE) { 702*a9643ea8Slogwang ASSERT_VOP_ELOCKED(*vpp, "cache_lookup"); 703*a9643ea8Slogwang } 704*a9643ea8Slogwang return (-1); 705*a9643ea8Slogwang 706*a9643ea8Slogwang unlock: 707*a9643ea8Slogwang if (wlocked) 708*a9643ea8Slogwang CACHE_WUNLOCK(); 709*a9643ea8Slogwang else 710*a9643ea8Slogwang CACHE_RUNLOCK(); 711*a9643ea8Slogwang return (0); 712*a9643ea8Slogwang } 713*a9643ea8Slogwang 714*a9643ea8Slogwang /* 715*a9643ea8Slogwang * Add an entry to the cache. 716*a9643ea8Slogwang */ 717*a9643ea8Slogwang void 718*a9643ea8Slogwang cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, 719*a9643ea8Slogwang struct timespec *tsp, struct timespec *dtsp) 720*a9643ea8Slogwang { 721*a9643ea8Slogwang struct namecache *ncp, *n2; 722*a9643ea8Slogwang struct namecache_ts *n3; 723*a9643ea8Slogwang struct nchashhead *ncpp; 724*a9643ea8Slogwang uint32_t hash; 725*a9643ea8Slogwang int flag; 726*a9643ea8Slogwang int len; 727*a9643ea8Slogwang 728*a9643ea8Slogwang CTR3(KTR_VFS, "cache_enter(%p, %p, %s)", dvp, vp, cnp->cn_nameptr); 729*a9643ea8Slogwang VNASSERT(vp == NULL || (vp->v_iflag & VI_DOOMED) == 0, vp, 730*a9643ea8Slogwang ("cache_enter: Adding a doomed vnode")); 731*a9643ea8Slogwang VNASSERT(dvp == NULL || (dvp->v_iflag & VI_DOOMED) == 0, dvp, 732*a9643ea8Slogwang ("cache_enter: Doomed vnode used as src")); 733*a9643ea8Slogwang 734*a9643ea8Slogwang if (!doingcache) 735*a9643ea8Slogwang return; 736*a9643ea8Slogwang 737*a9643ea8Slogwang /* 738*a9643ea8Slogwang * Avoid blowout in namecache entries. 739*a9643ea8Slogwang */ 740*a9643ea8Slogwang if (numcache >= desiredvnodes * ncsizefactor) 741*a9643ea8Slogwang return; 742*a9643ea8Slogwang 743*a9643ea8Slogwang flag = 0; 744*a9643ea8Slogwang if (cnp->cn_nameptr[0] == '.') { 745*a9643ea8Slogwang if (cnp->cn_namelen == 1) 746*a9643ea8Slogwang return; 747*a9643ea8Slogwang if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') { 748*a9643ea8Slogwang CACHE_WLOCK(); 749*a9643ea8Slogwang /* 750*a9643ea8Slogwang * If dotdot entry already exists, just retarget it 751*a9643ea8Slogwang * to new parent vnode, otherwise continue with new 752*a9643ea8Slogwang * namecache entry allocation. 753*a9643ea8Slogwang */ 754*a9643ea8Slogwang if ((ncp = dvp->v_cache_dd) != NULL && 755*a9643ea8Slogwang ncp->nc_flag & NCF_ISDOTDOT) { 756*a9643ea8Slogwang KASSERT(ncp->nc_dvp == dvp, 757*a9643ea8Slogwang ("wrong isdotdot parent")); 758*a9643ea8Slogwang if (ncp->nc_vp != NULL) { 759*a9643ea8Slogwang TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, 760*a9643ea8Slogwang ncp, nc_dst); 761*a9643ea8Slogwang } else { 762*a9643ea8Slogwang TAILQ_REMOVE(&ncneg, ncp, nc_dst); 763*a9643ea8Slogwang numneg--; 764*a9643ea8Slogwang } 765*a9643ea8Slogwang if (vp != NULL) { 766*a9643ea8Slogwang TAILQ_INSERT_HEAD(&vp->v_cache_dst, 767*a9643ea8Slogwang ncp, nc_dst); 768*a9643ea8Slogwang } else { 769*a9643ea8Slogwang TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst); 770*a9643ea8Slogwang numneg++; 771*a9643ea8Slogwang } 772*a9643ea8Slogwang ncp->nc_vp = vp; 773*a9643ea8Slogwang CACHE_WUNLOCK(); 774*a9643ea8Slogwang return; 775*a9643ea8Slogwang } 776*a9643ea8Slogwang dvp->v_cache_dd = NULL; 777*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, enter, done, dvp, "..", vp); 778*a9643ea8Slogwang CACHE_WUNLOCK(); 779*a9643ea8Slogwang flag = NCF_ISDOTDOT; 780*a9643ea8Slogwang } 781*a9643ea8Slogwang } 782*a9643ea8Slogwang 783*a9643ea8Slogwang /* 784*a9643ea8Slogwang * Calculate the hash key and setup as much of the new 785*a9643ea8Slogwang * namecache entry as possible before acquiring the lock. 786*a9643ea8Slogwang */ 787*a9643ea8Slogwang ncp = cache_alloc(cnp->cn_namelen, tsp != NULL); 788*a9643ea8Slogwang ncp->nc_vp = vp; 789*a9643ea8Slogwang ncp->nc_dvp = dvp; 790*a9643ea8Slogwang ncp->nc_flag = flag; 791*a9643ea8Slogwang if (tsp != NULL) { 792*a9643ea8Slogwang n3 = (struct namecache_ts *)ncp; 793*a9643ea8Slogwang n3->nc_time = *tsp; 794*a9643ea8Slogwang n3->nc_ticks = ticks; 795*a9643ea8Slogwang n3->nc_flag |= NCF_TS; 796*a9643ea8Slogwang if (dtsp != NULL) { 797*a9643ea8Slogwang n3->nc_dotdottime = *dtsp; 798*a9643ea8Slogwang n3->nc_flag |= NCF_DTS; 799*a9643ea8Slogwang } 800*a9643ea8Slogwang } 801*a9643ea8Slogwang len = ncp->nc_nlen = cnp->cn_namelen; 802*a9643ea8Slogwang hash = cache_get_hash(cnp->cn_nameptr, len, dvp); 803*a9643ea8Slogwang strlcpy(nc_get_name(ncp), cnp->cn_nameptr, len + 1); 804*a9643ea8Slogwang CACHE_WLOCK(); 805*a9643ea8Slogwang 806*a9643ea8Slogwang /* 807*a9643ea8Slogwang * See if this vnode or negative entry is already in the cache 808*a9643ea8Slogwang * with this name. This can happen with concurrent lookups of 809*a9643ea8Slogwang * the same path name. 810*a9643ea8Slogwang */ 811*a9643ea8Slogwang ncpp = NCHHASH(hash); 812*a9643ea8Slogwang LIST_FOREACH(n2, ncpp, nc_hash) { 813*a9643ea8Slogwang if (n2->nc_dvp == dvp && 814*a9643ea8Slogwang n2->nc_nlen == cnp->cn_namelen && 815*a9643ea8Slogwang !bcmp(nc_get_name(n2), cnp->cn_nameptr, n2->nc_nlen)) { 816*a9643ea8Slogwang if (tsp != NULL) { 817*a9643ea8Slogwang KASSERT((n2->nc_flag & NCF_TS) != 0, 818*a9643ea8Slogwang ("no NCF_TS")); 819*a9643ea8Slogwang n3 = (struct namecache_ts *)n2; 820*a9643ea8Slogwang n3->nc_time = 821*a9643ea8Slogwang ((struct namecache_ts *)ncp)->nc_time; 822*a9643ea8Slogwang n3->nc_ticks = 823*a9643ea8Slogwang ((struct namecache_ts *)ncp)->nc_ticks; 824*a9643ea8Slogwang if (dtsp != NULL) { 825*a9643ea8Slogwang n3->nc_dotdottime = 826*a9643ea8Slogwang ((struct namecache_ts *)ncp)-> 827*a9643ea8Slogwang nc_dotdottime; 828*a9643ea8Slogwang n3->nc_flag |= NCF_DTS; 829*a9643ea8Slogwang } 830*a9643ea8Slogwang } 831*a9643ea8Slogwang CACHE_WUNLOCK(); 832*a9643ea8Slogwang cache_free(ncp); 833*a9643ea8Slogwang return; 834*a9643ea8Slogwang } 835*a9643ea8Slogwang } 836*a9643ea8Slogwang 837*a9643ea8Slogwang if (flag == NCF_ISDOTDOT) { 838*a9643ea8Slogwang /* 839*a9643ea8Slogwang * See if we are trying to add .. entry, but some other lookup 840*a9643ea8Slogwang * has populated v_cache_dd pointer already. 841*a9643ea8Slogwang */ 842*a9643ea8Slogwang if (dvp->v_cache_dd != NULL) { 843*a9643ea8Slogwang CACHE_WUNLOCK(); 844*a9643ea8Slogwang cache_free(ncp); 845*a9643ea8Slogwang return; 846*a9643ea8Slogwang } 847*a9643ea8Slogwang KASSERT(vp == NULL || vp->v_type == VDIR, 848*a9643ea8Slogwang ("wrong vnode type %p", vp)); 849*a9643ea8Slogwang dvp->v_cache_dd = ncp; 850*a9643ea8Slogwang } 851*a9643ea8Slogwang 852*a9643ea8Slogwang numcache++; 853*a9643ea8Slogwang if (vp != NULL) { 854*a9643ea8Slogwang if (vp->v_type == VDIR) { 855*a9643ea8Slogwang if (flag != NCF_ISDOTDOT) { 856*a9643ea8Slogwang /* 857*a9643ea8Slogwang * For this case, the cache entry maps both the 858*a9643ea8Slogwang * directory name in it and the name ".." for the 859*a9643ea8Slogwang * directory's parent. 860*a9643ea8Slogwang */ 861*a9643ea8Slogwang if ((n2 = vp->v_cache_dd) != NULL && 862*a9643ea8Slogwang (n2->nc_flag & NCF_ISDOTDOT) != 0) 863*a9643ea8Slogwang cache_zap(n2); 864*a9643ea8Slogwang vp->v_cache_dd = ncp; 865*a9643ea8Slogwang } 866*a9643ea8Slogwang } else { 867*a9643ea8Slogwang vp->v_cache_dd = NULL; 868*a9643ea8Slogwang } 869*a9643ea8Slogwang } 870*a9643ea8Slogwang 871*a9643ea8Slogwang /* 872*a9643ea8Slogwang * Insert the new namecache entry into the appropriate chain 873*a9643ea8Slogwang * within the cache entries table. 874*a9643ea8Slogwang */ 875*a9643ea8Slogwang LIST_INSERT_HEAD(ncpp, ncp, nc_hash); 876*a9643ea8Slogwang if (flag != NCF_ISDOTDOT) { 877*a9643ea8Slogwang if (LIST_EMPTY(&dvp->v_cache_src)) { 878*a9643ea8Slogwang vhold(dvp); 879*a9643ea8Slogwang numcachehv++; 880*a9643ea8Slogwang } 881*a9643ea8Slogwang LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src); 882*a9643ea8Slogwang } 883*a9643ea8Slogwang 884*a9643ea8Slogwang /* 885*a9643ea8Slogwang * If the entry is "negative", we place it into the 886*a9643ea8Slogwang * "negative" cache queue, otherwise, we place it into the 887*a9643ea8Slogwang * destination vnode's cache entries queue. 888*a9643ea8Slogwang */ 889*a9643ea8Slogwang if (vp != NULL) { 890*a9643ea8Slogwang TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst); 891*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, enter, done, dvp, nc_get_name(ncp), 892*a9643ea8Slogwang vp); 893*a9643ea8Slogwang } else { 894*a9643ea8Slogwang if (cnp->cn_flags & ISWHITEOUT) 895*a9643ea8Slogwang ncp->nc_flag |= NCF_WHITE; 896*a9643ea8Slogwang TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst); 897*a9643ea8Slogwang numneg++; 898*a9643ea8Slogwang SDT_PROBE2(vfs, namecache, enter_negative, done, dvp, 899*a9643ea8Slogwang nc_get_name(ncp)); 900*a9643ea8Slogwang } 901*a9643ea8Slogwang if (numneg * ncnegfactor > numcache) { 902*a9643ea8Slogwang ncp = TAILQ_FIRST(&ncneg); 903*a9643ea8Slogwang KASSERT(ncp->nc_vp == NULL, ("ncp %p vp %p on ncneg", 904*a9643ea8Slogwang ncp, ncp->nc_vp)); 905*a9643ea8Slogwang cache_zap(ncp); 906*a9643ea8Slogwang } 907*a9643ea8Slogwang CACHE_WUNLOCK(); 908*a9643ea8Slogwang } 909*a9643ea8Slogwang 910*a9643ea8Slogwang /* 911*a9643ea8Slogwang * Name cache initialization, from vfs_init() when we are booting 912*a9643ea8Slogwang */ 913*a9643ea8Slogwang static void 914*a9643ea8Slogwang nchinit(void *dummy __unused) 915*a9643ea8Slogwang { 916*a9643ea8Slogwang 917*a9643ea8Slogwang TAILQ_INIT(&ncneg); 918*a9643ea8Slogwang 919*a9643ea8Slogwang cache_zone_small = uma_zcreate("S VFS Cache", 920*a9643ea8Slogwang sizeof(struct namecache) + CACHE_PATH_CUTOFF + 1, 921*a9643ea8Slogwang NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT); 922*a9643ea8Slogwang cache_zone_small_ts = uma_zcreate("STS VFS Cache", 923*a9643ea8Slogwang sizeof(struct namecache_ts) + CACHE_PATH_CUTOFF + 1, 924*a9643ea8Slogwang NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT); 925*a9643ea8Slogwang cache_zone_large = uma_zcreate("L VFS Cache", 926*a9643ea8Slogwang sizeof(struct namecache) + NAME_MAX + 1, 927*a9643ea8Slogwang NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT); 928*a9643ea8Slogwang cache_zone_large_ts = uma_zcreate("LTS VFS Cache", 929*a9643ea8Slogwang sizeof(struct namecache_ts) + NAME_MAX + 1, 930*a9643ea8Slogwang NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT); 931*a9643ea8Slogwang 932*a9643ea8Slogwang nchashtbl = hashinit(desiredvnodes * 2, M_VFSCACHE, &nchash); 933*a9643ea8Slogwang 934*a9643ea8Slogwang numcalls = counter_u64_alloc(M_WAITOK); 935*a9643ea8Slogwang dothits = counter_u64_alloc(M_WAITOK); 936*a9643ea8Slogwang dotdothits = counter_u64_alloc(M_WAITOK); 937*a9643ea8Slogwang numchecks = counter_u64_alloc(M_WAITOK); 938*a9643ea8Slogwang nummiss = counter_u64_alloc(M_WAITOK); 939*a9643ea8Slogwang nummisszap = counter_u64_alloc(M_WAITOK); 940*a9643ea8Slogwang numposzaps = counter_u64_alloc(M_WAITOK); 941*a9643ea8Slogwang numposhits = counter_u64_alloc(M_WAITOK); 942*a9643ea8Slogwang numnegzaps = counter_u64_alloc(M_WAITOK); 943*a9643ea8Slogwang numneghits = counter_u64_alloc(M_WAITOK); 944*a9643ea8Slogwang numfullpathcalls = counter_u64_alloc(M_WAITOK); 945*a9643ea8Slogwang numfullpathfail1 = counter_u64_alloc(M_WAITOK); 946*a9643ea8Slogwang numfullpathfail2 = counter_u64_alloc(M_WAITOK); 947*a9643ea8Slogwang numfullpathfail4 = counter_u64_alloc(M_WAITOK); 948*a9643ea8Slogwang numfullpathfound = counter_u64_alloc(M_WAITOK); 949*a9643ea8Slogwang } 950*a9643ea8Slogwang SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nchinit, NULL); 951*a9643ea8Slogwang 952*a9643ea8Slogwang void 953*a9643ea8Slogwang cache_changesize(int newmaxvnodes) 954*a9643ea8Slogwang { 955*a9643ea8Slogwang struct nchashhead *new_nchashtbl, *old_nchashtbl; 956*a9643ea8Slogwang u_long new_nchash, old_nchash; 957*a9643ea8Slogwang struct namecache *ncp; 958*a9643ea8Slogwang uint32_t hash; 959*a9643ea8Slogwang int i; 960*a9643ea8Slogwang 961*a9643ea8Slogwang new_nchashtbl = hashinit(newmaxvnodes * 2, M_VFSCACHE, &new_nchash); 962*a9643ea8Slogwang /* If same hash table size, nothing to do */ 963*a9643ea8Slogwang if (nchash == new_nchash) { 964*a9643ea8Slogwang free(new_nchashtbl, M_VFSCACHE); 965*a9643ea8Slogwang return; 966*a9643ea8Slogwang } 967*a9643ea8Slogwang /* 968*a9643ea8Slogwang * Move everything from the old hash table to the new table. 969*a9643ea8Slogwang * None of the namecache entries in the table can be removed 970*a9643ea8Slogwang * because to do so, they have to be removed from the hash table. 971*a9643ea8Slogwang */ 972*a9643ea8Slogwang CACHE_WLOCK(); 973*a9643ea8Slogwang old_nchashtbl = nchashtbl; 974*a9643ea8Slogwang old_nchash = nchash; 975*a9643ea8Slogwang nchashtbl = new_nchashtbl; 976*a9643ea8Slogwang nchash = new_nchash; 977*a9643ea8Slogwang for (i = 0; i <= old_nchash; i++) { 978*a9643ea8Slogwang while ((ncp = LIST_FIRST(&old_nchashtbl[i])) != NULL) { 979*a9643ea8Slogwang hash = cache_get_hash(nc_get_name(ncp), ncp->nc_nlen, 980*a9643ea8Slogwang ncp->nc_dvp); 981*a9643ea8Slogwang LIST_REMOVE(ncp, nc_hash); 982*a9643ea8Slogwang LIST_INSERT_HEAD(NCHHASH(hash), ncp, nc_hash); 983*a9643ea8Slogwang } 984*a9643ea8Slogwang } 985*a9643ea8Slogwang CACHE_WUNLOCK(); 986*a9643ea8Slogwang free(old_nchashtbl, M_VFSCACHE); 987*a9643ea8Slogwang } 988*a9643ea8Slogwang 989*a9643ea8Slogwang /* 990*a9643ea8Slogwang * Invalidate all entries to a particular vnode. 991*a9643ea8Slogwang */ 992*a9643ea8Slogwang void 993*a9643ea8Slogwang cache_purge(struct vnode *vp) 994*a9643ea8Slogwang { 995*a9643ea8Slogwang 996*a9643ea8Slogwang CTR1(KTR_VFS, "cache_purge(%p)", vp); 997*a9643ea8Slogwang SDT_PROBE1(vfs, namecache, purge, done, vp); 998*a9643ea8Slogwang CACHE_WLOCK(); 999*a9643ea8Slogwang while (!LIST_EMPTY(&vp->v_cache_src)) 1000*a9643ea8Slogwang cache_zap(LIST_FIRST(&vp->v_cache_src)); 1001*a9643ea8Slogwang while (!TAILQ_EMPTY(&vp->v_cache_dst)) 1002*a9643ea8Slogwang cache_zap(TAILQ_FIRST(&vp->v_cache_dst)); 1003*a9643ea8Slogwang if (vp->v_cache_dd != NULL) { 1004*a9643ea8Slogwang KASSERT(vp->v_cache_dd->nc_flag & NCF_ISDOTDOT, 1005*a9643ea8Slogwang ("lost dotdot link")); 1006*a9643ea8Slogwang cache_zap(vp->v_cache_dd); 1007*a9643ea8Slogwang } 1008*a9643ea8Slogwang KASSERT(vp->v_cache_dd == NULL, ("incomplete purge")); 1009*a9643ea8Slogwang CACHE_WUNLOCK(); 1010*a9643ea8Slogwang } 1011*a9643ea8Slogwang 1012*a9643ea8Slogwang /* 1013*a9643ea8Slogwang * Invalidate all negative entries for a particular directory vnode. 1014*a9643ea8Slogwang */ 1015*a9643ea8Slogwang void 1016*a9643ea8Slogwang cache_purge_negative(struct vnode *vp) 1017*a9643ea8Slogwang { 1018*a9643ea8Slogwang struct namecache *cp, *ncp; 1019*a9643ea8Slogwang 1020*a9643ea8Slogwang CTR1(KTR_VFS, "cache_purge_negative(%p)", vp); 1021*a9643ea8Slogwang SDT_PROBE1(vfs, namecache, purge_negative, done, vp); 1022*a9643ea8Slogwang CACHE_WLOCK(); 1023*a9643ea8Slogwang LIST_FOREACH_SAFE(cp, &vp->v_cache_src, nc_src, ncp) { 1024*a9643ea8Slogwang if (cp->nc_vp == NULL) 1025*a9643ea8Slogwang cache_zap(cp); 1026*a9643ea8Slogwang } 1027*a9643ea8Slogwang CACHE_WUNLOCK(); 1028*a9643ea8Slogwang } 1029*a9643ea8Slogwang 1030*a9643ea8Slogwang /* 1031*a9643ea8Slogwang * Flush all entries referencing a particular filesystem. 1032*a9643ea8Slogwang */ 1033*a9643ea8Slogwang void 1034*a9643ea8Slogwang cache_purgevfs(struct mount *mp) 1035*a9643ea8Slogwang { 1036*a9643ea8Slogwang struct nchashhead *ncpp; 1037*a9643ea8Slogwang struct namecache *ncp, *nnp; 1038*a9643ea8Slogwang 1039*a9643ea8Slogwang /* Scan hash tables for applicable entries */ 1040*a9643ea8Slogwang SDT_PROBE1(vfs, namecache, purgevfs, done, mp); 1041*a9643ea8Slogwang CACHE_WLOCK(); 1042*a9643ea8Slogwang for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) { 1043*a9643ea8Slogwang LIST_FOREACH_SAFE(ncp, ncpp, nc_hash, nnp) { 1044*a9643ea8Slogwang if (ncp->nc_dvp->v_mount == mp) 1045*a9643ea8Slogwang cache_zap(ncp); 1046*a9643ea8Slogwang } 1047*a9643ea8Slogwang } 1048*a9643ea8Slogwang CACHE_WUNLOCK(); 1049*a9643ea8Slogwang } 1050*a9643ea8Slogwang 1051*a9643ea8Slogwang /* 1052*a9643ea8Slogwang * Perform canonical checks and cache lookup and pass on to filesystem 1053*a9643ea8Slogwang * through the vop_cachedlookup only if needed. 1054*a9643ea8Slogwang */ 1055*a9643ea8Slogwang 1056*a9643ea8Slogwang int 1057*a9643ea8Slogwang vfs_cache_lookup(struct vop_lookup_args *ap) 1058*a9643ea8Slogwang { 1059*a9643ea8Slogwang struct vnode *dvp; 1060*a9643ea8Slogwang int error; 1061*a9643ea8Slogwang struct vnode **vpp = ap->a_vpp; 1062*a9643ea8Slogwang struct componentname *cnp = ap->a_cnp; 1063*a9643ea8Slogwang struct ucred *cred = cnp->cn_cred; 1064*a9643ea8Slogwang int flags = cnp->cn_flags; 1065*a9643ea8Slogwang struct thread *td = cnp->cn_thread; 1066*a9643ea8Slogwang 1067*a9643ea8Slogwang *vpp = NULL; 1068*a9643ea8Slogwang dvp = ap->a_dvp; 1069*a9643ea8Slogwang 1070*a9643ea8Slogwang if (dvp->v_type != VDIR) 1071*a9643ea8Slogwang return (ENOTDIR); 1072*a9643ea8Slogwang 1073*a9643ea8Slogwang if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && 1074*a9643ea8Slogwang (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 1075*a9643ea8Slogwang return (EROFS); 1076*a9643ea8Slogwang 1077*a9643ea8Slogwang error = VOP_ACCESS(dvp, VEXEC, cred, td); 1078*a9643ea8Slogwang if (error) 1079*a9643ea8Slogwang return (error); 1080*a9643ea8Slogwang 1081*a9643ea8Slogwang error = cache_lookup(dvp, vpp, cnp, NULL, NULL); 1082*a9643ea8Slogwang if (error == 0) 1083*a9643ea8Slogwang return (VOP_CACHEDLOOKUP(dvp, vpp, cnp)); 1084*a9643ea8Slogwang if (error == -1) 1085*a9643ea8Slogwang return (0); 1086*a9643ea8Slogwang return (error); 1087*a9643ea8Slogwang } 1088*a9643ea8Slogwang 1089*a9643ea8Slogwang /* 1090*a9643ea8Slogwang * XXX All of these sysctls would probably be more productive dead. 1091*a9643ea8Slogwang */ 1092*a9643ea8Slogwang static int disablecwd; 1093*a9643ea8Slogwang SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0, 1094*a9643ea8Slogwang "Disable the getcwd syscall"); 1095*a9643ea8Slogwang 1096*a9643ea8Slogwang /* Implementation of the getcwd syscall. */ 1097*a9643ea8Slogwang int 1098*a9643ea8Slogwang sys___getcwd(struct thread *td, struct __getcwd_args *uap) 1099*a9643ea8Slogwang { 1100*a9643ea8Slogwang 1101*a9643ea8Slogwang return (kern___getcwd(td, uap->buf, UIO_USERSPACE, uap->buflen, 1102*a9643ea8Slogwang MAXPATHLEN)); 1103*a9643ea8Slogwang } 1104*a9643ea8Slogwang 1105*a9643ea8Slogwang int 1106*a9643ea8Slogwang kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, u_int buflen, 1107*a9643ea8Slogwang u_int path_max) 1108*a9643ea8Slogwang { 1109*a9643ea8Slogwang char *bp, *tmpbuf; 1110*a9643ea8Slogwang struct filedesc *fdp; 1111*a9643ea8Slogwang struct vnode *cdir, *rdir; 1112*a9643ea8Slogwang int error; 1113*a9643ea8Slogwang 1114*a9643ea8Slogwang if (disablecwd) 1115*a9643ea8Slogwang return (ENODEV); 1116*a9643ea8Slogwang if (buflen < 2) 1117*a9643ea8Slogwang return (EINVAL); 1118*a9643ea8Slogwang if (buflen > path_max) 1119*a9643ea8Slogwang buflen = path_max; 1120*a9643ea8Slogwang 1121*a9643ea8Slogwang tmpbuf = malloc(buflen, M_TEMP, M_WAITOK); 1122*a9643ea8Slogwang fdp = td->td_proc->p_fd; 1123*a9643ea8Slogwang FILEDESC_SLOCK(fdp); 1124*a9643ea8Slogwang cdir = fdp->fd_cdir; 1125*a9643ea8Slogwang VREF(cdir); 1126*a9643ea8Slogwang rdir = fdp->fd_rdir; 1127*a9643ea8Slogwang VREF(rdir); 1128*a9643ea8Slogwang FILEDESC_SUNLOCK(fdp); 1129*a9643ea8Slogwang error = vn_fullpath1(td, cdir, rdir, tmpbuf, &bp, buflen); 1130*a9643ea8Slogwang vrele(rdir); 1131*a9643ea8Slogwang vrele(cdir); 1132*a9643ea8Slogwang 1133*a9643ea8Slogwang if (!error) { 1134*a9643ea8Slogwang if (bufseg == UIO_SYSSPACE) 1135*a9643ea8Slogwang bcopy(bp, buf, strlen(bp) + 1); 1136*a9643ea8Slogwang else 1137*a9643ea8Slogwang error = copyout(bp, buf, strlen(bp) + 1); 1138*a9643ea8Slogwang #ifdef KTRACE 1139*a9643ea8Slogwang if (KTRPOINT(curthread, KTR_NAMEI)) 1140*a9643ea8Slogwang ktrnamei(bp); 1141*a9643ea8Slogwang #endif 1142*a9643ea8Slogwang } 1143*a9643ea8Slogwang free(tmpbuf, M_TEMP); 1144*a9643ea8Slogwang return (error); 1145*a9643ea8Slogwang } 1146*a9643ea8Slogwang 1147*a9643ea8Slogwang /* 1148*a9643ea8Slogwang * Thus begins the fullpath magic. 1149*a9643ea8Slogwang */ 1150*a9643ea8Slogwang 1151*a9643ea8Slogwang static int disablefullpath; 1152*a9643ea8Slogwang SYSCTL_INT(_debug, OID_AUTO, disablefullpath, CTLFLAG_RW, &disablefullpath, 0, 1153*a9643ea8Slogwang "Disable the vn_fullpath function"); 1154*a9643ea8Slogwang 1155*a9643ea8Slogwang /* 1156*a9643ea8Slogwang * Retrieve the full filesystem path that correspond to a vnode from the name 1157*a9643ea8Slogwang * cache (if available) 1158*a9643ea8Slogwang */ 1159*a9643ea8Slogwang int 1160*a9643ea8Slogwang vn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf) 1161*a9643ea8Slogwang { 1162*a9643ea8Slogwang char *buf; 1163*a9643ea8Slogwang struct filedesc *fdp; 1164*a9643ea8Slogwang struct vnode *rdir; 1165*a9643ea8Slogwang int error; 1166*a9643ea8Slogwang 1167*a9643ea8Slogwang if (disablefullpath) 1168*a9643ea8Slogwang return (ENODEV); 1169*a9643ea8Slogwang if (vn == NULL) 1170*a9643ea8Slogwang return (EINVAL); 1171*a9643ea8Slogwang 1172*a9643ea8Slogwang buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1173*a9643ea8Slogwang fdp = td->td_proc->p_fd; 1174*a9643ea8Slogwang FILEDESC_SLOCK(fdp); 1175*a9643ea8Slogwang rdir = fdp->fd_rdir; 1176*a9643ea8Slogwang VREF(rdir); 1177*a9643ea8Slogwang FILEDESC_SUNLOCK(fdp); 1178*a9643ea8Slogwang error = vn_fullpath1(td, vn, rdir, buf, retbuf, MAXPATHLEN); 1179*a9643ea8Slogwang vrele(rdir); 1180*a9643ea8Slogwang 1181*a9643ea8Slogwang if (!error) 1182*a9643ea8Slogwang *freebuf = buf; 1183*a9643ea8Slogwang else 1184*a9643ea8Slogwang free(buf, M_TEMP); 1185*a9643ea8Slogwang return (error); 1186*a9643ea8Slogwang } 1187*a9643ea8Slogwang 1188*a9643ea8Slogwang /* 1189*a9643ea8Slogwang * This function is similar to vn_fullpath, but it attempts to lookup the 1190*a9643ea8Slogwang * pathname relative to the global root mount point. This is required for the 1191*a9643ea8Slogwang * auditing sub-system, as audited pathnames must be absolute, relative to the 1192*a9643ea8Slogwang * global root mount point. 1193*a9643ea8Slogwang */ 1194*a9643ea8Slogwang int 1195*a9643ea8Slogwang vn_fullpath_global(struct thread *td, struct vnode *vn, 1196*a9643ea8Slogwang char **retbuf, char **freebuf) 1197*a9643ea8Slogwang { 1198*a9643ea8Slogwang char *buf; 1199*a9643ea8Slogwang int error; 1200*a9643ea8Slogwang 1201*a9643ea8Slogwang if (disablefullpath) 1202*a9643ea8Slogwang return (ENODEV); 1203*a9643ea8Slogwang if (vn == NULL) 1204*a9643ea8Slogwang return (EINVAL); 1205*a9643ea8Slogwang buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1206*a9643ea8Slogwang error = vn_fullpath1(td, vn, rootvnode, buf, retbuf, MAXPATHLEN); 1207*a9643ea8Slogwang if (!error) 1208*a9643ea8Slogwang *freebuf = buf; 1209*a9643ea8Slogwang else 1210*a9643ea8Slogwang free(buf, M_TEMP); 1211*a9643ea8Slogwang return (error); 1212*a9643ea8Slogwang } 1213*a9643ea8Slogwang 1214*a9643ea8Slogwang int 1215*a9643ea8Slogwang vn_vptocnp(struct vnode **vp, struct ucred *cred, char *buf, u_int *buflen) 1216*a9643ea8Slogwang { 1217*a9643ea8Slogwang int error; 1218*a9643ea8Slogwang 1219*a9643ea8Slogwang CACHE_RLOCK(); 1220*a9643ea8Slogwang error = vn_vptocnp_locked(vp, cred, buf, buflen); 1221*a9643ea8Slogwang if (error == 0) 1222*a9643ea8Slogwang CACHE_RUNLOCK(); 1223*a9643ea8Slogwang return (error); 1224*a9643ea8Slogwang } 1225*a9643ea8Slogwang 1226*a9643ea8Slogwang static int 1227*a9643ea8Slogwang vn_vptocnp_locked(struct vnode **vp, struct ucred *cred, char *buf, 1228*a9643ea8Slogwang u_int *buflen) 1229*a9643ea8Slogwang { 1230*a9643ea8Slogwang struct vnode *dvp; 1231*a9643ea8Slogwang struct namecache *ncp; 1232*a9643ea8Slogwang int error; 1233*a9643ea8Slogwang 1234*a9643ea8Slogwang TAILQ_FOREACH(ncp, &((*vp)->v_cache_dst), nc_dst) { 1235*a9643ea8Slogwang if ((ncp->nc_flag & NCF_ISDOTDOT) == 0) 1236*a9643ea8Slogwang break; 1237*a9643ea8Slogwang } 1238*a9643ea8Slogwang if (ncp != NULL) { 1239*a9643ea8Slogwang if (*buflen < ncp->nc_nlen) { 1240*a9643ea8Slogwang CACHE_RUNLOCK(); 1241*a9643ea8Slogwang vrele(*vp); 1242*a9643ea8Slogwang counter_u64_add(numfullpathfail4, 1); 1243*a9643ea8Slogwang error = ENOMEM; 1244*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, fullpath, return, error, 1245*a9643ea8Slogwang vp, NULL); 1246*a9643ea8Slogwang return (error); 1247*a9643ea8Slogwang } 1248*a9643ea8Slogwang *buflen -= ncp->nc_nlen; 1249*a9643ea8Slogwang memcpy(buf + *buflen, nc_get_name(ncp), ncp->nc_nlen); 1250*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, fullpath, hit, ncp->nc_dvp, 1251*a9643ea8Slogwang nc_get_name(ncp), vp); 1252*a9643ea8Slogwang dvp = *vp; 1253*a9643ea8Slogwang *vp = ncp->nc_dvp; 1254*a9643ea8Slogwang vref(*vp); 1255*a9643ea8Slogwang CACHE_RUNLOCK(); 1256*a9643ea8Slogwang vrele(dvp); 1257*a9643ea8Slogwang CACHE_RLOCK(); 1258*a9643ea8Slogwang return (0); 1259*a9643ea8Slogwang } 1260*a9643ea8Slogwang SDT_PROBE1(vfs, namecache, fullpath, miss, vp); 1261*a9643ea8Slogwang 1262*a9643ea8Slogwang CACHE_RUNLOCK(); 1263*a9643ea8Slogwang vn_lock(*vp, LK_SHARED | LK_RETRY); 1264*a9643ea8Slogwang error = VOP_VPTOCNP(*vp, &dvp, cred, buf, buflen); 1265*a9643ea8Slogwang vput(*vp); 1266*a9643ea8Slogwang if (error) { 1267*a9643ea8Slogwang counter_u64_add(numfullpathfail2, 1); 1268*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, fullpath, return, error, vp, NULL); 1269*a9643ea8Slogwang return (error); 1270*a9643ea8Slogwang } 1271*a9643ea8Slogwang 1272*a9643ea8Slogwang *vp = dvp; 1273*a9643ea8Slogwang CACHE_RLOCK(); 1274*a9643ea8Slogwang if (dvp->v_iflag & VI_DOOMED) { 1275*a9643ea8Slogwang /* forced unmount */ 1276*a9643ea8Slogwang CACHE_RUNLOCK(); 1277*a9643ea8Slogwang vrele(dvp); 1278*a9643ea8Slogwang error = ENOENT; 1279*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, fullpath, return, error, vp, NULL); 1280*a9643ea8Slogwang return (error); 1281*a9643ea8Slogwang } 1282*a9643ea8Slogwang /* 1283*a9643ea8Slogwang * *vp has its use count incremented still. 1284*a9643ea8Slogwang */ 1285*a9643ea8Slogwang 1286*a9643ea8Slogwang return (0); 1287*a9643ea8Slogwang } 1288*a9643ea8Slogwang 1289*a9643ea8Slogwang /* 1290*a9643ea8Slogwang * The magic behind kern___getcwd() and vn_fullpath(). 1291*a9643ea8Slogwang */ 1292*a9643ea8Slogwang static int 1293*a9643ea8Slogwang vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir, 1294*a9643ea8Slogwang char *buf, char **retbuf, u_int buflen) 1295*a9643ea8Slogwang { 1296*a9643ea8Slogwang int error, slash_prefixed; 1297*a9643ea8Slogwang #ifdef KDTRACE_HOOKS 1298*a9643ea8Slogwang struct vnode *startvp = vp; 1299*a9643ea8Slogwang #endif 1300*a9643ea8Slogwang struct vnode *vp1; 1301*a9643ea8Slogwang 1302*a9643ea8Slogwang buflen--; 1303*a9643ea8Slogwang buf[buflen] = '\0'; 1304*a9643ea8Slogwang error = 0; 1305*a9643ea8Slogwang slash_prefixed = 0; 1306*a9643ea8Slogwang 1307*a9643ea8Slogwang SDT_PROBE1(vfs, namecache, fullpath, entry, vp); 1308*a9643ea8Slogwang counter_u64_add(numfullpathcalls, 1); 1309*a9643ea8Slogwang vref(vp); 1310*a9643ea8Slogwang CACHE_RLOCK(); 1311*a9643ea8Slogwang if (vp->v_type != VDIR) { 1312*a9643ea8Slogwang error = vn_vptocnp_locked(&vp, td->td_ucred, buf, &buflen); 1313*a9643ea8Slogwang if (error) 1314*a9643ea8Slogwang return (error); 1315*a9643ea8Slogwang if (buflen == 0) { 1316*a9643ea8Slogwang CACHE_RUNLOCK(); 1317*a9643ea8Slogwang vrele(vp); 1318*a9643ea8Slogwang return (ENOMEM); 1319*a9643ea8Slogwang } 1320*a9643ea8Slogwang buf[--buflen] = '/'; 1321*a9643ea8Slogwang slash_prefixed = 1; 1322*a9643ea8Slogwang } 1323*a9643ea8Slogwang while (vp != rdir && vp != rootvnode) { 1324*a9643ea8Slogwang if (vp->v_vflag & VV_ROOT) { 1325*a9643ea8Slogwang if (vp->v_iflag & VI_DOOMED) { /* forced unmount */ 1326*a9643ea8Slogwang CACHE_RUNLOCK(); 1327*a9643ea8Slogwang vrele(vp); 1328*a9643ea8Slogwang error = ENOENT; 1329*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, fullpath, return, 1330*a9643ea8Slogwang error, vp, NULL); 1331*a9643ea8Slogwang break; 1332*a9643ea8Slogwang } 1333*a9643ea8Slogwang vp1 = vp->v_mount->mnt_vnodecovered; 1334*a9643ea8Slogwang vref(vp1); 1335*a9643ea8Slogwang CACHE_RUNLOCK(); 1336*a9643ea8Slogwang vrele(vp); 1337*a9643ea8Slogwang vp = vp1; 1338*a9643ea8Slogwang CACHE_RLOCK(); 1339*a9643ea8Slogwang continue; 1340*a9643ea8Slogwang } 1341*a9643ea8Slogwang if (vp->v_type != VDIR) { 1342*a9643ea8Slogwang CACHE_RUNLOCK(); 1343*a9643ea8Slogwang vrele(vp); 1344*a9643ea8Slogwang counter_u64_add(numfullpathfail1, 1); 1345*a9643ea8Slogwang error = ENOTDIR; 1346*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, fullpath, return, 1347*a9643ea8Slogwang error, vp, NULL); 1348*a9643ea8Slogwang break; 1349*a9643ea8Slogwang } 1350*a9643ea8Slogwang error = vn_vptocnp_locked(&vp, td->td_ucred, buf, &buflen); 1351*a9643ea8Slogwang if (error) 1352*a9643ea8Slogwang break; 1353*a9643ea8Slogwang if (buflen == 0) { 1354*a9643ea8Slogwang CACHE_RUNLOCK(); 1355*a9643ea8Slogwang vrele(vp); 1356*a9643ea8Slogwang error = ENOMEM; 1357*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, fullpath, return, error, 1358*a9643ea8Slogwang startvp, NULL); 1359*a9643ea8Slogwang break; 1360*a9643ea8Slogwang } 1361*a9643ea8Slogwang buf[--buflen] = '/'; 1362*a9643ea8Slogwang slash_prefixed = 1; 1363*a9643ea8Slogwang } 1364*a9643ea8Slogwang if (error) 1365*a9643ea8Slogwang return (error); 1366*a9643ea8Slogwang if (!slash_prefixed) { 1367*a9643ea8Slogwang if (buflen == 0) { 1368*a9643ea8Slogwang CACHE_RUNLOCK(); 1369*a9643ea8Slogwang vrele(vp); 1370*a9643ea8Slogwang counter_u64_add(numfullpathfail4, 1); 1371*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, fullpath, return, ENOMEM, 1372*a9643ea8Slogwang startvp, NULL); 1373*a9643ea8Slogwang return (ENOMEM); 1374*a9643ea8Slogwang } 1375*a9643ea8Slogwang buf[--buflen] = '/'; 1376*a9643ea8Slogwang } 1377*a9643ea8Slogwang counter_u64_add(numfullpathfound, 1); 1378*a9643ea8Slogwang CACHE_RUNLOCK(); 1379*a9643ea8Slogwang vrele(vp); 1380*a9643ea8Slogwang 1381*a9643ea8Slogwang SDT_PROBE3(vfs, namecache, fullpath, return, 0, startvp, buf + buflen); 1382*a9643ea8Slogwang *retbuf = buf + buflen; 1383*a9643ea8Slogwang return (0); 1384*a9643ea8Slogwang } 1385*a9643ea8Slogwang 1386*a9643ea8Slogwang struct vnode * 1387*a9643ea8Slogwang vn_dir_dd_ino(struct vnode *vp) 1388*a9643ea8Slogwang { 1389*a9643ea8Slogwang struct namecache *ncp; 1390*a9643ea8Slogwang struct vnode *ddvp; 1391*a9643ea8Slogwang 1392*a9643ea8Slogwang ASSERT_VOP_LOCKED(vp, "vn_dir_dd_ino"); 1393*a9643ea8Slogwang CACHE_RLOCK(); 1394*a9643ea8Slogwang TAILQ_FOREACH(ncp, &(vp->v_cache_dst), nc_dst) { 1395*a9643ea8Slogwang if ((ncp->nc_flag & NCF_ISDOTDOT) != 0) 1396*a9643ea8Slogwang continue; 1397*a9643ea8Slogwang ddvp = ncp->nc_dvp; 1398*a9643ea8Slogwang vhold(ddvp); 1399*a9643ea8Slogwang CACHE_RUNLOCK(); 1400*a9643ea8Slogwang if (vget(ddvp, LK_SHARED | LK_NOWAIT | LK_VNHELD, curthread)) 1401*a9643ea8Slogwang return (NULL); 1402*a9643ea8Slogwang return (ddvp); 1403*a9643ea8Slogwang } 1404*a9643ea8Slogwang CACHE_RUNLOCK(); 1405*a9643ea8Slogwang return (NULL); 1406*a9643ea8Slogwang } 1407*a9643ea8Slogwang 1408*a9643ea8Slogwang int 1409*a9643ea8Slogwang vn_commname(struct vnode *vp, char *buf, u_int buflen) 1410*a9643ea8Slogwang { 1411*a9643ea8Slogwang struct namecache *ncp; 1412*a9643ea8Slogwang int l; 1413*a9643ea8Slogwang 1414*a9643ea8Slogwang CACHE_RLOCK(); 1415*a9643ea8Slogwang TAILQ_FOREACH(ncp, &vp->v_cache_dst, nc_dst) 1416*a9643ea8Slogwang if ((ncp->nc_flag & NCF_ISDOTDOT) == 0) 1417*a9643ea8Slogwang break; 1418*a9643ea8Slogwang if (ncp == NULL) { 1419*a9643ea8Slogwang CACHE_RUNLOCK(); 1420*a9643ea8Slogwang return (ENOENT); 1421*a9643ea8Slogwang } 1422*a9643ea8Slogwang l = min(ncp->nc_nlen, buflen - 1); 1423*a9643ea8Slogwang memcpy(buf, nc_get_name(ncp), l); 1424*a9643ea8Slogwang CACHE_RUNLOCK(); 1425*a9643ea8Slogwang buf[l] = '\0'; 1426*a9643ea8Slogwang return (0); 1427*a9643ea8Slogwang } 1428*a9643ea8Slogwang 1429*a9643ea8Slogwang /* ABI compat shims for old kernel modules. */ 1430*a9643ea8Slogwang #undef cache_enter 1431*a9643ea8Slogwang 1432*a9643ea8Slogwang void cache_enter(struct vnode *dvp, struct vnode *vp, 1433*a9643ea8Slogwang struct componentname *cnp); 1434*a9643ea8Slogwang 1435*a9643ea8Slogwang void 1436*a9643ea8Slogwang cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) 1437*a9643ea8Slogwang { 1438*a9643ea8Slogwang 1439*a9643ea8Slogwang cache_enter_time(dvp, vp, cnp, NULL, NULL); 1440*a9643ea8Slogwang } 1441*a9643ea8Slogwang 1442*a9643ea8Slogwang /* 1443*a9643ea8Slogwang * This function updates path string to vnode's full global path 1444*a9643ea8Slogwang * and checks the size of the new path string against the pathlen argument. 1445*a9643ea8Slogwang * 1446*a9643ea8Slogwang * Requires a locked, referenced vnode. 1447*a9643ea8Slogwang * Vnode is re-locked on success or ENODEV, otherwise unlocked. 1448*a9643ea8Slogwang * 1449*a9643ea8Slogwang * If sysctl debug.disablefullpath is set, ENODEV is returned, 1450*a9643ea8Slogwang * vnode is left locked and path remain untouched. 1451*a9643ea8Slogwang * 1452*a9643ea8Slogwang * If vp is a directory, the call to vn_fullpath_global() always succeeds 1453*a9643ea8Slogwang * because it falls back to the ".." lookup if the namecache lookup fails. 1454*a9643ea8Slogwang */ 1455*a9643ea8Slogwang int 1456*a9643ea8Slogwang vn_path_to_global_path(struct thread *td, struct vnode *vp, char *path, 1457*a9643ea8Slogwang u_int pathlen) 1458*a9643ea8Slogwang { 1459*a9643ea8Slogwang struct nameidata nd; 1460*a9643ea8Slogwang struct vnode *vp1; 1461*a9643ea8Slogwang char *rpath, *fbuf; 1462*a9643ea8Slogwang int error; 1463*a9643ea8Slogwang 1464*a9643ea8Slogwang ASSERT_VOP_ELOCKED(vp, __func__); 1465*a9643ea8Slogwang 1466*a9643ea8Slogwang /* Return ENODEV if sysctl debug.disablefullpath==1 */ 1467*a9643ea8Slogwang if (disablefullpath) 1468*a9643ea8Slogwang return (ENODEV); 1469*a9643ea8Slogwang 1470*a9643ea8Slogwang /* Construct global filesystem path from vp. */ 1471*a9643ea8Slogwang VOP_UNLOCK(vp, 0); 1472*a9643ea8Slogwang error = vn_fullpath_global(td, vp, &rpath, &fbuf); 1473*a9643ea8Slogwang 1474*a9643ea8Slogwang if (error != 0) { 1475*a9643ea8Slogwang vrele(vp); 1476*a9643ea8Slogwang return (error); 1477*a9643ea8Slogwang } 1478*a9643ea8Slogwang 1479*a9643ea8Slogwang if (strlen(rpath) >= pathlen) { 1480*a9643ea8Slogwang vrele(vp); 1481*a9643ea8Slogwang error = ENAMETOOLONG; 1482*a9643ea8Slogwang goto out; 1483*a9643ea8Slogwang } 1484*a9643ea8Slogwang 1485*a9643ea8Slogwang /* 1486*a9643ea8Slogwang * Re-lookup the vnode by path to detect a possible rename. 1487*a9643ea8Slogwang * As a side effect, the vnode is relocked. 1488*a9643ea8Slogwang * If vnode was renamed, return ENOENT. 1489*a9643ea8Slogwang */ 1490*a9643ea8Slogwang NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, 1491*a9643ea8Slogwang UIO_SYSSPACE, path, td); 1492*a9643ea8Slogwang error = namei(&nd); 1493*a9643ea8Slogwang if (error != 0) { 1494*a9643ea8Slogwang vrele(vp); 1495*a9643ea8Slogwang goto out; 1496*a9643ea8Slogwang } 1497*a9643ea8Slogwang NDFREE(&nd, NDF_ONLY_PNBUF); 1498*a9643ea8Slogwang vp1 = nd.ni_vp; 1499*a9643ea8Slogwang vrele(vp); 1500*a9643ea8Slogwang if (vp1 == vp) 1501*a9643ea8Slogwang strcpy(path, rpath); 1502*a9643ea8Slogwang else { 1503*a9643ea8Slogwang vput(vp1); 1504*a9643ea8Slogwang error = ENOENT; 1505*a9643ea8Slogwang } 1506*a9643ea8Slogwang 1507*a9643ea8Slogwang out: 1508*a9643ea8Slogwang free(fbuf, M_TEMP); 1509*a9643ea8Slogwang return (error); 1510*a9643ea8Slogwang } 1511