xref: /xnu-11215.61.5/bsd/vfs/vfs_cache.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1*4f1223e8SApple OSS Distributions /*
2*4f1223e8SApple OSS Distributions  * Copyright (c) 2000-2015 Apple Inc. All rights reserved.
3*4f1223e8SApple OSS Distributions  *
4*4f1223e8SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*4f1223e8SApple OSS Distributions  *
6*4f1223e8SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*4f1223e8SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*4f1223e8SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*4f1223e8SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*4f1223e8SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*4f1223e8SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*4f1223e8SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*4f1223e8SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*4f1223e8SApple OSS Distributions  *
15*4f1223e8SApple OSS Distributions  * Please obtain a copy of the License at
16*4f1223e8SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*4f1223e8SApple OSS Distributions  *
18*4f1223e8SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*4f1223e8SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*4f1223e8SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*4f1223e8SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*4f1223e8SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*4f1223e8SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*4f1223e8SApple OSS Distributions  * limitations under the License.
25*4f1223e8SApple OSS Distributions  *
26*4f1223e8SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*4f1223e8SApple OSS Distributions  */
28*4f1223e8SApple OSS Distributions /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29*4f1223e8SApple OSS Distributions /*
30*4f1223e8SApple OSS Distributions  * Copyright (c) 1989, 1993, 1995
31*4f1223e8SApple OSS Distributions  *	The Regents of the University of California.  All rights reserved.
32*4f1223e8SApple OSS Distributions  *
33*4f1223e8SApple OSS Distributions  * This code is derived from software contributed to Berkeley by
34*4f1223e8SApple OSS Distributions  * Poul-Henning Kamp of the FreeBSD Project.
35*4f1223e8SApple OSS Distributions  *
36*4f1223e8SApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
37*4f1223e8SApple OSS Distributions  * modification, are permitted provided that the following conditions
38*4f1223e8SApple OSS Distributions  * are met:
39*4f1223e8SApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
40*4f1223e8SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
41*4f1223e8SApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
42*4f1223e8SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
43*4f1223e8SApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
44*4f1223e8SApple OSS Distributions  * 3. All advertising materials mentioning features or use of this software
45*4f1223e8SApple OSS Distributions  *    must display the following acknowledgement:
46*4f1223e8SApple OSS Distributions  *	This product includes software developed by the University of
47*4f1223e8SApple OSS Distributions  *	California, Berkeley and its contributors.
48*4f1223e8SApple OSS Distributions  * 4. Neither the name of the University nor the names of its contributors
49*4f1223e8SApple OSS Distributions  *    may be used to endorse or promote products derived from this software
50*4f1223e8SApple OSS Distributions  *    without specific prior written permission.
51*4f1223e8SApple OSS Distributions  *
52*4f1223e8SApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53*4f1223e8SApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54*4f1223e8SApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55*4f1223e8SApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56*4f1223e8SApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57*4f1223e8SApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58*4f1223e8SApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59*4f1223e8SApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60*4f1223e8SApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61*4f1223e8SApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62*4f1223e8SApple OSS Distributions  * SUCH DAMAGE.
63*4f1223e8SApple OSS Distributions  *
64*4f1223e8SApple OSS Distributions  *
65*4f1223e8SApple OSS Distributions  *	@(#)vfs_cache.c	8.5 (Berkeley) 3/22/95
66*4f1223e8SApple OSS Distributions  */
67*4f1223e8SApple OSS Distributions /*
68*4f1223e8SApple OSS Distributions  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
69*4f1223e8SApple OSS Distributions  * support for mandatory and extensible security protections.  This notice
70*4f1223e8SApple OSS Distributions  * is included in support of clause 2.2 (b) of the Apple Public License,
71*4f1223e8SApple OSS Distributions  * Version 2.0.
72*4f1223e8SApple OSS Distributions  */
73*4f1223e8SApple OSS Distributions #include <sys/param.h>
74*4f1223e8SApple OSS Distributions #include <sys/systm.h>
75*4f1223e8SApple OSS Distributions #include <sys/time.h>
76*4f1223e8SApple OSS Distributions #include <sys/mount_internal.h>
77*4f1223e8SApple OSS Distributions #include <sys/vnode_internal.h>
78*4f1223e8SApple OSS Distributions #include <miscfs/specfs/specdev.h>
79*4f1223e8SApple OSS Distributions #include <sys/namei.h>
80*4f1223e8SApple OSS Distributions #include <sys/errno.h>
81*4f1223e8SApple OSS Distributions #include <kern/kalloc.h>
82*4f1223e8SApple OSS Distributions #include <sys/kauth.h>
83*4f1223e8SApple OSS Distributions #include <sys/user.h>
84*4f1223e8SApple OSS Distributions #include <sys/paths.h>
85*4f1223e8SApple OSS Distributions #include <os/overflow.h>
86*4f1223e8SApple OSS Distributions 
87*4f1223e8SApple OSS Distributions #if CONFIG_MACF
88*4f1223e8SApple OSS Distributions #include <security/mac_framework.h>
89*4f1223e8SApple OSS Distributions #endif
90*4f1223e8SApple OSS Distributions 
91*4f1223e8SApple OSS Distributions /*
92*4f1223e8SApple OSS Distributions  * Name caching works as follows:
93*4f1223e8SApple OSS Distributions  *
94*4f1223e8SApple OSS Distributions  * Names found by directory scans are retained in a cache
95*4f1223e8SApple OSS Distributions  * for future reference.  It is managed LRU, so frequently
96*4f1223e8SApple OSS Distributions  * used names will hang around.  Cache is indexed by hash value
97*4f1223e8SApple OSS Distributions  * obtained from (vp, name) where vp refers to the directory
98*4f1223e8SApple OSS Distributions  * containing name.
99*4f1223e8SApple OSS Distributions  *
100*4f1223e8SApple OSS Distributions  * If it is a "negative" entry, (i.e. for a name that is known NOT to
101*4f1223e8SApple OSS Distributions  * exist) the vnode pointer will be NULL.
102*4f1223e8SApple OSS Distributions  *
103*4f1223e8SApple OSS Distributions  * Upon reaching the last segment of a path, if the reference
104*4f1223e8SApple OSS Distributions  * is for DELETE, or NOCACHE is set (rewrite), and the
105*4f1223e8SApple OSS Distributions  * name is located in the cache, it will be dropped.
106*4f1223e8SApple OSS Distributions  */
107*4f1223e8SApple OSS Distributions 
108*4f1223e8SApple OSS Distributions /*
109*4f1223e8SApple OSS Distributions  * Structures associated with name cacheing.
110*4f1223e8SApple OSS Distributions  */
111*4f1223e8SApple OSS Distributions 
112*4f1223e8SApple OSS Distributions ZONE_DEFINE_TYPE(namecache_zone, "namecache", struct namecache, ZC_NONE);
113*4f1223e8SApple OSS Distributions 
114*4f1223e8SApple OSS Distributions struct smrq_list_head *nchashtbl;       /* Hash Table */
115*4f1223e8SApple OSS Distributions u_long  nchashmask;
116*4f1223e8SApple OSS Distributions u_long  nchash;                         /* size of hash table - 1 */
117*4f1223e8SApple OSS Distributions long    numcache;                       /* number of cache entries allocated */
118*4f1223e8SApple OSS Distributions int     desiredNodes;
119*4f1223e8SApple OSS Distributions int     desiredNegNodes;
120*4f1223e8SApple OSS Distributions int     ncs_negtotal;
121*4f1223e8SApple OSS Distributions TUNABLE_WRITEABLE(int, nc_disabled, "-novfscache", 0);
122*4f1223e8SApple OSS Distributions __options_decl(nc_smr_level_t, uint32_t, {
123*4f1223e8SApple OSS Distributions 	NC_SMR_DISABLED = 0,
124*4f1223e8SApple OSS Distributions 	NC_SMR_LOOKUP = 1
125*4f1223e8SApple OSS Distributions });
126*4f1223e8SApple OSS Distributions TUNABLE(nc_smr_level_t, nc_smr_enabled, "ncsmr", NC_SMR_LOOKUP);
127*4f1223e8SApple OSS Distributions TAILQ_HEAD(, namecache) nchead;         /* chain of all name cache entries */
128*4f1223e8SApple OSS Distributions TAILQ_HEAD(, namecache) neghead;        /* chain of only negative cache entries */
129*4f1223e8SApple OSS Distributions 
130*4f1223e8SApple OSS Distributions 
131*4f1223e8SApple OSS Distributions #if COLLECT_STATS
132*4f1223e8SApple OSS Distributions 
133*4f1223e8SApple OSS Distributions struct  nchstats nchstats;              /* cache effectiveness statistics */
134*4f1223e8SApple OSS Distributions 
135*4f1223e8SApple OSS Distributions #define NCHSTAT(v) {            \
136*4f1223e8SApple OSS Distributions 	nchstats.v++;           \
137*4f1223e8SApple OSS Distributions }
138*4f1223e8SApple OSS Distributions #define NAME_CACHE_LOCK_SHARED()        name_cache_lock()
139*4f1223e8SApple OSS Distributions #define NAME_CACHE_LOCK_SHARED_TO_EXCLUSIVE() TRUE
140*4f1223e8SApple OSS Distributions 
141*4f1223e8SApple OSS Distributions #else
142*4f1223e8SApple OSS Distributions 
143*4f1223e8SApple OSS Distributions #define NCHSTAT(v)
144*4f1223e8SApple OSS Distributions #define NAME_CACHE_LOCK_SHARED()        name_cache_lock_shared()
145*4f1223e8SApple OSS Distributions #define NAME_CACHE_LOCK_SHARED_TO_EXCLUSIVE()             name_cache_lock_shared_to_exclusive()
146*4f1223e8SApple OSS Distributions 
147*4f1223e8SApple OSS Distributions #endif
148*4f1223e8SApple OSS Distributions 
149*4f1223e8SApple OSS Distributions #define NAME_CACHE_LOCK()               name_cache_lock()
150*4f1223e8SApple OSS Distributions #define NAME_CACHE_UNLOCK()             name_cache_unlock()
151*4f1223e8SApple OSS Distributions 
152*4f1223e8SApple OSS Distributions /* vars for name cache list lock */
153*4f1223e8SApple OSS Distributions static LCK_GRP_DECLARE(namecache_lck_grp, "Name Cache");
154*4f1223e8SApple OSS Distributions static LCK_RW_DECLARE(namecache_rw_lock, &namecache_lck_grp);
155*4f1223e8SApple OSS Distributions 
156*4f1223e8SApple OSS Distributions typedef struct string_t {
157*4f1223e8SApple OSS Distributions 	LIST_ENTRY(string_t)  hash_chain;
158*4f1223e8SApple OSS Distributions 	char                  *str;
159*4f1223e8SApple OSS Distributions 	uint32_t              strbuflen;
160*4f1223e8SApple OSS Distributions 	uint32_t              refcount;
161*4f1223e8SApple OSS Distributions } string_t;
162*4f1223e8SApple OSS Distributions 
163*4f1223e8SApple OSS Distributions ZONE_DEFINE_TYPE(stringcache_zone, "vfsstringcache", string_t, ZC_NONE);
164*4f1223e8SApple OSS Distributions 
165*4f1223e8SApple OSS Distributions static LCK_GRP_DECLARE(strcache_lck_grp, "String Cache");
166*4f1223e8SApple OSS Distributions static LCK_ATTR_DECLARE(strcache_lck_attr, 0, 0);
167*4f1223e8SApple OSS Distributions LCK_RW_DECLARE_ATTR(strtable_rw_lock, &strcache_lck_grp, &strcache_lck_attr);
168*4f1223e8SApple OSS Distributions 
169*4f1223e8SApple OSS Distributions static LCK_GRP_DECLARE(rootvnode_lck_grp, "rootvnode");
170*4f1223e8SApple OSS Distributions LCK_RW_DECLARE(rootvnode_rw_lock, &rootvnode_lck_grp);
171*4f1223e8SApple OSS Distributions 
172*4f1223e8SApple OSS Distributions #define NUM_STRCACHE_LOCKS 1024
173*4f1223e8SApple OSS Distributions 
174*4f1223e8SApple OSS Distributions lck_mtx_t strcache_mtx_locks[NUM_STRCACHE_LOCKS];
175*4f1223e8SApple OSS Distributions 
176*4f1223e8SApple OSS Distributions SYSCTL_NODE(_vfs, OID_AUTO, ncstats, CTLFLAG_RD | CTLFLAG_LOCKED, NULL, "vfs name cache stats");
177*4f1223e8SApple OSS Distributions 
178*4f1223e8SApple OSS Distributions SYSCTL_COMPAT_INT(_vfs_ncstats, OID_AUTO, nc_smr_enabled,
179*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
180*4f1223e8SApple OSS Distributions     &nc_smr_enabled, 0, "");
181*4f1223e8SApple OSS Distributions 
182*4f1223e8SApple OSS Distributions #if COLLECT_NC_SMR_STATS
183*4f1223e8SApple OSS Distributions struct ncstats {
184*4f1223e8SApple OSS Distributions 	uint64_t cl_smr_hits;
185*4f1223e8SApple OSS Distributions 	uint64_t cl_smr_miss;
186*4f1223e8SApple OSS Distributions 	uint64_t cl_smr_negative_hits;
187*4f1223e8SApple OSS Distributions 	uint64_t cl_smr_fallback;
188*4f1223e8SApple OSS Distributions 	uint64_t cl_lock_hits;
189*4f1223e8SApple OSS Distributions 	uint64_t clp_next;
190*4f1223e8SApple OSS Distributions 	uint64_t clp_next_fail;
191*4f1223e8SApple OSS Distributions 	uint64_t clp_smr_next;
192*4f1223e8SApple OSS Distributions 	uint64_t clp_smr_next_fail;
193*4f1223e8SApple OSS Distributions 	uint64_t clp_smr_fallback;
194*4f1223e8SApple OSS Distributions 	uint64_t nc_lock_shared;
195*4f1223e8SApple OSS Distributions 	uint64_t nc_lock;
196*4f1223e8SApple OSS Distributions } ncstats = {0};
197*4f1223e8SApple OSS Distributions 
198*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, cl_smr_hits,
199*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
200*4f1223e8SApple OSS Distributions     &ncstats.cl_smr_hits, "");
201*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, cl_smr_misses,
202*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
203*4f1223e8SApple OSS Distributions     &ncstats.cl_smr_miss, "");
204*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, cl_smr_negative_hits,
205*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
206*4f1223e8SApple OSS Distributions     &ncstats.cl_smr_negative_hits, "");
207*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, cl_smr_fallback,
208*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
209*4f1223e8SApple OSS Distributions     &ncstats.cl_smr_fallback, "");
210*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, cl_lock_hits,
211*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
212*4f1223e8SApple OSS Distributions     &ncstats.cl_lock_hits, "");
213*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, clp_next,
214*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
215*4f1223e8SApple OSS Distributions     &ncstats.clp_next, "");
216*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, clp_next_fail,
217*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
218*4f1223e8SApple OSS Distributions     &ncstats.clp_next_fail, "");
219*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, clp_smr_next,
220*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
221*4f1223e8SApple OSS Distributions     &ncstats.clp_smr_next, "");
222*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, clp_smr_next_fail,
223*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
224*4f1223e8SApple OSS Distributions     &ncstats.clp_smr_next_fail, "");
225*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, nc_lock_shared,
226*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
227*4f1223e8SApple OSS Distributions     &ncstats.nc_lock_shared, "");
228*4f1223e8SApple OSS Distributions SYSCTL_LONG(_vfs_ncstats, OID_AUTO, nc_lock,
229*4f1223e8SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED,
230*4f1223e8SApple OSS Distributions     &ncstats.nc_lock, "");
231*4f1223e8SApple OSS Distributions 
232*4f1223e8SApple OSS Distributions #define NC_SMR_STATS(v)  os_atomic_inc(&ncstats.v, relaxed)
233*4f1223e8SApple OSS Distributions #else
234*4f1223e8SApple OSS Distributions #define NC_SMR_STATS(v)
235*4f1223e8SApple OSS Distributions #endif /* COLLECT_NC_SMR_STATS */
236*4f1223e8SApple OSS Distributions 
237*4f1223e8SApple OSS Distributions static vnode_t cache_lookup_locked(vnode_t dvp, struct componentname *cnp, uint32_t *vidp);
238*4f1223e8SApple OSS Distributions static vnode_t cache_lookup_smr(vnode_t dvp, struct componentname *cnp, uint32_t *vidp);
239*4f1223e8SApple OSS Distributions static const char *add_name_internal(const char *, uint32_t, u_int, boolean_t, u_int);
240*4f1223e8SApple OSS Distributions static void init_string_table(void);
241*4f1223e8SApple OSS Distributions static void cache_delete(struct namecache *, int);
242*4f1223e8SApple OSS Distributions static void cache_enter_locked(vnode_t dvp, vnode_t vp, struct componentname *cnp, const char *strname);
243*4f1223e8SApple OSS Distributions static void cache_purge_locked(vnode_t vp, kauth_cred_t *credp);
244*4f1223e8SApple OSS Distributions static void namecache_smr_free(void *, size_t);
245*4f1223e8SApple OSS Distributions static void string_smr_free(void *, size_t);
246*4f1223e8SApple OSS Distributions 
247*4f1223e8SApple OSS Distributions 
248*4f1223e8SApple OSS Distributions #ifdef DUMP_STRING_TABLE
249*4f1223e8SApple OSS Distributions /*
250*4f1223e8SApple OSS Distributions  * Internal dump function used for debugging
251*4f1223e8SApple OSS Distributions  */
252*4f1223e8SApple OSS Distributions void dump_string_table(void);
253*4f1223e8SApple OSS Distributions #endif  /* DUMP_STRING_TABLE */
254*4f1223e8SApple OSS Distributions 
255*4f1223e8SApple OSS Distributions static void init_crc32(void);
256*4f1223e8SApple OSS Distributions static unsigned int crc32tab[256];
257*4f1223e8SApple OSS Distributions 
258*4f1223e8SApple OSS Distributions 
259*4f1223e8SApple OSS Distributions #define NCHHASH(dvp, hash_val) \
260*4f1223e8SApple OSS Distributions 	(&nchashtbl[(dvp->v_id ^ (hash_val)) & nchashmask])
261*4f1223e8SApple OSS Distributions 
262*4f1223e8SApple OSS Distributions /*
263*4f1223e8SApple OSS Distributions  * This function tries to check if a directory vp is a subdirectory of dvp
264*4f1223e8SApple OSS Distributions  * only from valid v_parent pointers. It is called with the name cache lock
265*4f1223e8SApple OSS Distributions  * held and does not drop the lock anytime inside the function.
266*4f1223e8SApple OSS Distributions  *
267*4f1223e8SApple OSS Distributions  * It returns a boolean that indicates whether or not it was able to
268*4f1223e8SApple OSS Distributions  * successfully infer the parent/descendent relationship via the v_parent
269*4f1223e8SApple OSS Distributions  * pointers, or if it could not infer such relationship and that the decision
270*4f1223e8SApple OSS Distributions  * must be delegated to the owning filesystem.
271*4f1223e8SApple OSS Distributions  *
272*4f1223e8SApple OSS Distributions  * If it does not defer the decision, i.e. it was successfuly able to determine
273*4f1223e8SApple OSS Distributions  * the parent/descendent relationship,  *is_subdir tells the caller if vp is a
274*4f1223e8SApple OSS Distributions  * subdirectory of dvp.
275*4f1223e8SApple OSS Distributions  *
276*4f1223e8SApple OSS Distributions  * If the decision is deferred, *next_vp is where it stopped i.e. *next_vp
277*4f1223e8SApple OSS Distributions  * is the vnode whose parent is to be determined from the filesystem.
278*4f1223e8SApple OSS Distributions  * *is_subdir, in this case, is not indicative of anything and should be
279*4f1223e8SApple OSS Distributions  * ignored.
280*4f1223e8SApple OSS Distributions  *
281*4f1223e8SApple OSS Distributions  * The return value and output args should be used as follows :
282*4f1223e8SApple OSS Distributions  *
283*4f1223e8SApple OSS Distributions  * defer = cache_check_vnode_issubdir(vp, dvp, is_subdir, next_vp);
284*4f1223e8SApple OSS Distributions  * if (!defer) {
285*4f1223e8SApple OSS Distributions  *      if (*is_subdir)
286*4f1223e8SApple OSS Distributions  *              vp is subdirectory;
287*4f1223e8SApple OSS Distributions  *      else
288*4f1223e8SApple OSS Distributions  *              vp is not a subdirectory;
289*4f1223e8SApple OSS Distributions  * } else {
290*4f1223e8SApple OSS Distributions  *      if (*next_vp)
291*4f1223e8SApple OSS Distributions  *              check this vnode's parent from the filesystem
292*4f1223e8SApple OSS Distributions  *      else
293*4f1223e8SApple OSS Distributions  *              error (likely because of forced unmount).
294*4f1223e8SApple OSS Distributions  * }
295*4f1223e8SApple OSS Distributions  *
296*4f1223e8SApple OSS Distributions  */
297*4f1223e8SApple OSS Distributions static boolean_t
cache_check_vnode_issubdir(vnode_t vp,vnode_t dvp,boolean_t * is_subdir,vnode_t * next_vp)298*4f1223e8SApple OSS Distributions cache_check_vnode_issubdir(vnode_t vp, vnode_t dvp, boolean_t *is_subdir,
299*4f1223e8SApple OSS Distributions     vnode_t *next_vp)
300*4f1223e8SApple OSS Distributions {
301*4f1223e8SApple OSS Distributions 	vnode_t tvp = vp;
302*4f1223e8SApple OSS Distributions 	int defer = FALSE;
303*4f1223e8SApple OSS Distributions 
304*4f1223e8SApple OSS Distributions 	*is_subdir = FALSE;
305*4f1223e8SApple OSS Distributions 	*next_vp = NULLVP;
306*4f1223e8SApple OSS Distributions 	while (1) {
307*4f1223e8SApple OSS Distributions 		mount_t tmp;
308*4f1223e8SApple OSS Distributions 
309*4f1223e8SApple OSS Distributions 		if (tvp == dvp) {
310*4f1223e8SApple OSS Distributions 			*is_subdir = TRUE;
311*4f1223e8SApple OSS Distributions 			break;
312*4f1223e8SApple OSS Distributions 		} else if (tvp == rootvnode) {
313*4f1223e8SApple OSS Distributions 			/* *is_subdir = FALSE */
314*4f1223e8SApple OSS Distributions 			break;
315*4f1223e8SApple OSS Distributions 		}
316*4f1223e8SApple OSS Distributions 
317*4f1223e8SApple OSS Distributions 		tmp = tvp->v_mount;
318*4f1223e8SApple OSS Distributions 		while ((tvp->v_flag & VROOT) && tmp && tmp->mnt_vnodecovered &&
319*4f1223e8SApple OSS Distributions 		    tvp != dvp && tvp != rootvnode) {
320*4f1223e8SApple OSS Distributions 			tvp = tmp->mnt_vnodecovered;
321*4f1223e8SApple OSS Distributions 			tmp = tvp->v_mount;
322*4f1223e8SApple OSS Distributions 		}
323*4f1223e8SApple OSS Distributions 
324*4f1223e8SApple OSS Distributions 		/*
325*4f1223e8SApple OSS Distributions 		 * If dvp is not at the top of a mount "stack" then
326*4f1223e8SApple OSS Distributions 		 * vp is not a subdirectory of dvp either.
327*4f1223e8SApple OSS Distributions 		 */
328*4f1223e8SApple OSS Distributions 		if (tvp == dvp || tvp == rootvnode) {
329*4f1223e8SApple OSS Distributions 			/* *is_subdir = FALSE */
330*4f1223e8SApple OSS Distributions 			break;
331*4f1223e8SApple OSS Distributions 		}
332*4f1223e8SApple OSS Distributions 
333*4f1223e8SApple OSS Distributions 		if (!tmp) {
334*4f1223e8SApple OSS Distributions 			defer = TRUE;
335*4f1223e8SApple OSS Distributions 			*next_vp = NULLVP;
336*4f1223e8SApple OSS Distributions 			break;
337*4f1223e8SApple OSS Distributions 		}
338*4f1223e8SApple OSS Distributions 
339*4f1223e8SApple OSS Distributions 		if ((tvp->v_flag & VISHARDLINK) || !(tvp->v_parent)) {
340*4f1223e8SApple OSS Distributions 			defer = TRUE;
341*4f1223e8SApple OSS Distributions 			*next_vp = tvp;
342*4f1223e8SApple OSS Distributions 			break;
343*4f1223e8SApple OSS Distributions 		}
344*4f1223e8SApple OSS Distributions 
345*4f1223e8SApple OSS Distributions 		tvp = tvp->v_parent;
346*4f1223e8SApple OSS Distributions 	}
347*4f1223e8SApple OSS Distributions 
348*4f1223e8SApple OSS Distributions 	return defer;
349*4f1223e8SApple OSS Distributions }
350*4f1223e8SApple OSS Distributions 
351*4f1223e8SApple OSS Distributions /* maximum times retry from potentially transient errors in vnode_issubdir */
352*4f1223e8SApple OSS Distributions #define MAX_ERROR_RETRY 3
353*4f1223e8SApple OSS Distributions 
354*4f1223e8SApple OSS Distributions /*
355*4f1223e8SApple OSS Distributions  * This function checks if a given directory (vp) is a subdirectory of dvp.
356*4f1223e8SApple OSS Distributions  * It walks backwards from vp and if it hits dvp in its parent chain,
357*4f1223e8SApple OSS Distributions  * it is a subdirectory. If it encounters the root directory, it is not
358*4f1223e8SApple OSS Distributions  * a subdirectory.
359*4f1223e8SApple OSS Distributions  *
360*4f1223e8SApple OSS Distributions  * This function returns an error if it is unsuccessful and 0 on success.
361*4f1223e8SApple OSS Distributions  *
362*4f1223e8SApple OSS Distributions  * On entry (and exit) vp has an iocount and if this function has to take
363*4f1223e8SApple OSS Distributions  * any iocounts on other vnodes in the parent chain traversal, it releases them.
364*4f1223e8SApple OSS Distributions  */
365*4f1223e8SApple OSS Distributions int
vnode_issubdir(vnode_t vp,vnode_t dvp,int * is_subdir,vfs_context_t ctx)366*4f1223e8SApple OSS Distributions vnode_issubdir(vnode_t vp, vnode_t dvp, int *is_subdir, vfs_context_t ctx)
367*4f1223e8SApple OSS Distributions {
368*4f1223e8SApple OSS Distributions 	vnode_t start_vp, tvp;
369*4f1223e8SApple OSS Distributions 	vnode_t vp_with_iocount;
370*4f1223e8SApple OSS Distributions 	int error = 0;
371*4f1223e8SApple OSS Distributions 	char dotdotbuf[] = "..";
372*4f1223e8SApple OSS Distributions 	int error_retry_count = 0; /* retry count for potentially transient
373*4f1223e8SApple OSS Distributions 	                            *  errors */
374*4f1223e8SApple OSS Distributions 
375*4f1223e8SApple OSS Distributions 	*is_subdir = FALSE;
376*4f1223e8SApple OSS Distributions 	tvp = start_vp = vp;
377*4f1223e8SApple OSS Distributions 	/*
378*4f1223e8SApple OSS Distributions 	 * Anytime we acquire an iocount in this function, we save the vnode
379*4f1223e8SApple OSS Distributions 	 * in this variable and release it before exiting.
380*4f1223e8SApple OSS Distributions 	 */
381*4f1223e8SApple OSS Distributions 	vp_with_iocount = NULLVP;
382*4f1223e8SApple OSS Distributions 
383*4f1223e8SApple OSS Distributions 	while (1) {
384*4f1223e8SApple OSS Distributions 		boolean_t defer;
385*4f1223e8SApple OSS Distributions 		vnode_t pvp;
386*4f1223e8SApple OSS Distributions 		uint32_t vid = 0;
387*4f1223e8SApple OSS Distributions 		struct componentname cn;
388*4f1223e8SApple OSS Distributions 		boolean_t is_subdir_locked = FALSE;
389*4f1223e8SApple OSS Distributions 
390*4f1223e8SApple OSS Distributions 		if (tvp == dvp) {
391*4f1223e8SApple OSS Distributions 			*is_subdir = TRUE;
392*4f1223e8SApple OSS Distributions 			break;
393*4f1223e8SApple OSS Distributions 		} else if (tvp == rootvnode) {
394*4f1223e8SApple OSS Distributions 			/* *is_subdir = FALSE */
395*4f1223e8SApple OSS Distributions 			break;
396*4f1223e8SApple OSS Distributions 		}
397*4f1223e8SApple OSS Distributions 
398*4f1223e8SApple OSS Distributions 		NAME_CACHE_LOCK_SHARED();
399*4f1223e8SApple OSS Distributions 
400*4f1223e8SApple OSS Distributions 		defer = cache_check_vnode_issubdir(tvp, dvp, &is_subdir_locked,
401*4f1223e8SApple OSS Distributions 		    &tvp);
402*4f1223e8SApple OSS Distributions 
403*4f1223e8SApple OSS Distributions 		if (defer && tvp) {
404*4f1223e8SApple OSS Distributions 			vid = vnode_vid(tvp);
405*4f1223e8SApple OSS Distributions 			vnode_hold(tvp);
406*4f1223e8SApple OSS Distributions 		}
407*4f1223e8SApple OSS Distributions 
408*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
409*4f1223e8SApple OSS Distributions 
410*4f1223e8SApple OSS Distributions 		if (!defer) {
411*4f1223e8SApple OSS Distributions 			*is_subdir = is_subdir_locked;
412*4f1223e8SApple OSS Distributions 			break;
413*4f1223e8SApple OSS Distributions 		}
414*4f1223e8SApple OSS Distributions 
415*4f1223e8SApple OSS Distributions 		if (!tvp) {
416*4f1223e8SApple OSS Distributions 			if (error_retry_count++ < MAX_ERROR_RETRY) {
417*4f1223e8SApple OSS Distributions 				tvp = vp;
418*4f1223e8SApple OSS Distributions 				continue;
419*4f1223e8SApple OSS Distributions 			}
420*4f1223e8SApple OSS Distributions 			error = ENOENT;
421*4f1223e8SApple OSS Distributions 			break;
422*4f1223e8SApple OSS Distributions 		}
423*4f1223e8SApple OSS Distributions 
424*4f1223e8SApple OSS Distributions 		if (tvp != start_vp) {
425*4f1223e8SApple OSS Distributions 			if (vp_with_iocount) {
426*4f1223e8SApple OSS Distributions 				vnode_put(vp_with_iocount);
427*4f1223e8SApple OSS Distributions 				vp_with_iocount = NULLVP;
428*4f1223e8SApple OSS Distributions 			}
429*4f1223e8SApple OSS Distributions 
430*4f1223e8SApple OSS Distributions 			error = vnode_getwithvid(tvp, vid);
431*4f1223e8SApple OSS Distributions 			vnode_drop(tvp);
432*4f1223e8SApple OSS Distributions 			if (error) {
433*4f1223e8SApple OSS Distributions 				if (error_retry_count++ < MAX_ERROR_RETRY) {
434*4f1223e8SApple OSS Distributions 					tvp = vp;
435*4f1223e8SApple OSS Distributions 					error = 0;
436*4f1223e8SApple OSS Distributions 					continue;
437*4f1223e8SApple OSS Distributions 				}
438*4f1223e8SApple OSS Distributions 				break;
439*4f1223e8SApple OSS Distributions 			}
440*4f1223e8SApple OSS Distributions 			vp_with_iocount = tvp;
441*4f1223e8SApple OSS Distributions 		} else {
442*4f1223e8SApple OSS Distributions 			tvp = vnode_drop(tvp);
443*4f1223e8SApple OSS Distributions 		}
444*4f1223e8SApple OSS Distributions 
445*4f1223e8SApple OSS Distributions 		bzero(&cn, sizeof(cn));
446*4f1223e8SApple OSS Distributions 		cn.cn_nameiop = LOOKUP;
447*4f1223e8SApple OSS Distributions 		cn.cn_flags = ISLASTCN | ISDOTDOT;
448*4f1223e8SApple OSS Distributions 		cn.cn_context = ctx;
449*4f1223e8SApple OSS Distributions 		cn.cn_pnbuf = &dotdotbuf[0];
450*4f1223e8SApple OSS Distributions 		cn.cn_pnlen = sizeof(dotdotbuf);
451*4f1223e8SApple OSS Distributions 		cn.cn_nameptr = cn.cn_pnbuf;
452*4f1223e8SApple OSS Distributions 		cn.cn_namelen = 2;
453*4f1223e8SApple OSS Distributions 
454*4f1223e8SApple OSS Distributions 		pvp = NULLVP;
455*4f1223e8SApple OSS Distributions 		if ((error = VNOP_LOOKUP(tvp, &pvp, &cn, ctx))) {
456*4f1223e8SApple OSS Distributions 			break;
457*4f1223e8SApple OSS Distributions 		}
458*4f1223e8SApple OSS Distributions 
459*4f1223e8SApple OSS Distributions 		if (!(tvp->v_flag & VISHARDLINK) && tvp->v_parent != pvp) {
460*4f1223e8SApple OSS Distributions 			(void)vnode_update_identity(tvp, pvp, NULL, 0, 0,
461*4f1223e8SApple OSS Distributions 			    VNODE_UPDATE_PARENT);
462*4f1223e8SApple OSS Distributions 		}
463*4f1223e8SApple OSS Distributions 
464*4f1223e8SApple OSS Distributions 		if (vp_with_iocount) {
465*4f1223e8SApple OSS Distributions 			vnode_put(vp_with_iocount);
466*4f1223e8SApple OSS Distributions 		}
467*4f1223e8SApple OSS Distributions 
468*4f1223e8SApple OSS Distributions 		vp_with_iocount = tvp = pvp;
469*4f1223e8SApple OSS Distributions 	}
470*4f1223e8SApple OSS Distributions 
471*4f1223e8SApple OSS Distributions 	if (vp_with_iocount) {
472*4f1223e8SApple OSS Distributions 		vnode_put(vp_with_iocount);
473*4f1223e8SApple OSS Distributions 	}
474*4f1223e8SApple OSS Distributions 
475*4f1223e8SApple OSS Distributions 	return error;
476*4f1223e8SApple OSS Distributions }
477*4f1223e8SApple OSS Distributions 
478*4f1223e8SApple OSS Distributions /*
479*4f1223e8SApple OSS Distributions  * This function builds the path in "buff" from the supplied vnode.
480*4f1223e8SApple OSS Distributions  * The length of the buffer *INCLUDING* the trailing zero byte is
481*4f1223e8SApple OSS Distributions  * returned in outlen.  NOTE: the length includes the trailing zero
482*4f1223e8SApple OSS Distributions  * byte and thus the length is one greater than what strlen would
483*4f1223e8SApple OSS Distributions  * return.  This is important and lots of code elsewhere in the kernel
484*4f1223e8SApple OSS Distributions  * assumes this behavior.
485*4f1223e8SApple OSS Distributions  *
486*4f1223e8SApple OSS Distributions  * This function can call vnop in file system if the parent vnode
487*4f1223e8SApple OSS Distributions  * does not exist or when called for hardlinks via volfs path.
488*4f1223e8SApple OSS Distributions  * If BUILDPATH_NO_FS_ENTER is set in flags, it only uses values present
489*4f1223e8SApple OSS Distributions  * in the name cache and does not enter the file system.
490*4f1223e8SApple OSS Distributions  *
491*4f1223e8SApple OSS Distributions  * If BUILDPATH_CHECK_MOVED is set in flags, we return EAGAIN when
492*4f1223e8SApple OSS Distributions  * we encounter ENOENT during path reconstruction.  ENOENT means that
493*4f1223e8SApple OSS Distributions  * one of the parents moved while we were building the path.  The
494*4f1223e8SApple OSS Distributions  * caller can special handle this case by calling build_path again.
495*4f1223e8SApple OSS Distributions  *
496*4f1223e8SApple OSS Distributions  * If BUILDPATH_VOLUME_RELATIVE is set in flags, we return path
497*4f1223e8SApple OSS Distributions  * that is relative to the nearest mount point, i.e. do not
498*4f1223e8SApple OSS Distributions  * cross over mount points during building the path.
499*4f1223e8SApple OSS Distributions  *
500*4f1223e8SApple OSS Distributions  * passed in vp must have a valid io_count reference
501*4f1223e8SApple OSS Distributions  *
502*4f1223e8SApple OSS Distributions  * If parent vnode is non-NULL it also must have an io count.  This
503*4f1223e8SApple OSS Distributions  * allows build_path_with_parent to be safely called for operations
504*4f1223e8SApple OSS Distributions  * unlink, rmdir and rename that already have io counts on the target
505*4f1223e8SApple OSS Distributions  * and the directory. In this way build_path_with_parent does not have
506*4f1223e8SApple OSS Distributions  * to try and obtain an additional io count on the parent.  Taking an
507*4f1223e8SApple OSS Distributions  * io count ont the parent can lead to dead lock if a forced unmount
508*4f1223e8SApple OSS Distributions  * occures at the right moment. For a fuller explaination on how this
509*4f1223e8SApple OSS Distributions  * can occur see the comment for vn_getpath_with_parent.
510*4f1223e8SApple OSS Distributions  *
511*4f1223e8SApple OSS Distributions  */
512*4f1223e8SApple OSS Distributions int
build_path_with_parent(vnode_t first_vp,vnode_t parent_vp,char * buff,int buflen,int * outlen,size_t * mntpt_outlen,int flags,vfs_context_t ctx)513*4f1223e8SApple OSS Distributions build_path_with_parent(vnode_t first_vp, vnode_t parent_vp, char *buff, int buflen,
514*4f1223e8SApple OSS Distributions     int *outlen, size_t *mntpt_outlen, int flags, vfs_context_t ctx)
515*4f1223e8SApple OSS Distributions {
516*4f1223e8SApple OSS Distributions 	vnode_t vp, tvp;
517*4f1223e8SApple OSS Distributions 	vnode_t vp_with_iocount;
518*4f1223e8SApple OSS Distributions 	vnode_t proc_root_dir_vp;
519*4f1223e8SApple OSS Distributions 	char *end;
520*4f1223e8SApple OSS Distributions 	char *mntpt_end;
521*4f1223e8SApple OSS Distributions 	const char *str;
522*4f1223e8SApple OSS Distributions 	unsigned int  len;
523*4f1223e8SApple OSS Distributions 	int  ret = 0;
524*4f1223e8SApple OSS Distributions 	int  fixhardlink;
525*4f1223e8SApple OSS Distributions 
526*4f1223e8SApple OSS Distributions 	if (first_vp == NULLVP) {
527*4f1223e8SApple OSS Distributions 		return EINVAL;
528*4f1223e8SApple OSS Distributions 	}
529*4f1223e8SApple OSS Distributions 
530*4f1223e8SApple OSS Distributions 	if (buflen <= 1) {
531*4f1223e8SApple OSS Distributions 		return ENOSPC;
532*4f1223e8SApple OSS Distributions 	}
533*4f1223e8SApple OSS Distributions 
534*4f1223e8SApple OSS Distributions 	/*
535*4f1223e8SApple OSS Distributions 	 * Grab the process fd so we can evaluate fd_rdir.
536*4f1223e8SApple OSS Distributions 	 */
537*4f1223e8SApple OSS Distributions 	if (!(flags & BUILDPATH_NO_PROCROOT)) {
538*4f1223e8SApple OSS Distributions 		proc_root_dir_vp = vfs_context_proc(ctx)->p_fd.fd_rdir;
539*4f1223e8SApple OSS Distributions 	} else {
540*4f1223e8SApple OSS Distributions 		proc_root_dir_vp = NULL;
541*4f1223e8SApple OSS Distributions 	}
542*4f1223e8SApple OSS Distributions 
543*4f1223e8SApple OSS Distributions 	vp_with_iocount = NULLVP;
544*4f1223e8SApple OSS Distributions again:
545*4f1223e8SApple OSS Distributions 	vp = first_vp;
546*4f1223e8SApple OSS Distributions 
547*4f1223e8SApple OSS Distributions 	end = &buff[buflen - 1];
548*4f1223e8SApple OSS Distributions 	*end = '\0';
549*4f1223e8SApple OSS Distributions 	mntpt_end = NULL;
550*4f1223e8SApple OSS Distributions 
551*4f1223e8SApple OSS Distributions 	/*
552*4f1223e8SApple OSS Distributions 	 * Catch a special corner case here: chroot to /full/path/to/dir, chdir to
553*4f1223e8SApple OSS Distributions 	 * it, then open it. Without this check, the path to it will be
554*4f1223e8SApple OSS Distributions 	 * /full/path/to/dir instead of "/".
555*4f1223e8SApple OSS Distributions 	 */
556*4f1223e8SApple OSS Distributions 	if (proc_root_dir_vp == first_vp) {
557*4f1223e8SApple OSS Distributions 		*--end = '/';
558*4f1223e8SApple OSS Distributions 		goto out;
559*4f1223e8SApple OSS Distributions 	}
560*4f1223e8SApple OSS Distributions 
561*4f1223e8SApple OSS Distributions 	/*
562*4f1223e8SApple OSS Distributions 	 * holding the NAME_CACHE_LOCK in shared mode is
563*4f1223e8SApple OSS Distributions 	 * sufficient to stabilize both the vp->v_parent chain
564*4f1223e8SApple OSS Distributions 	 * and the 'vp->v_mount->mnt_vnodecovered' chain
565*4f1223e8SApple OSS Distributions 	 *
566*4f1223e8SApple OSS Distributions 	 * if we need to drop this lock, we must first grab the v_id
567*4f1223e8SApple OSS Distributions 	 * from the vnode we're currently working with... if that
568*4f1223e8SApple OSS Distributions 	 * vnode doesn't already have an io_count reference (the vp
569*4f1223e8SApple OSS Distributions 	 * passed in comes with one), we must grab a reference
570*4f1223e8SApple OSS Distributions 	 * after we drop the NAME_CACHE_LOCK via vnode_getwithvid...
571*4f1223e8SApple OSS Distributions 	 * deadlocks may result if you call vnode_get while holding
572*4f1223e8SApple OSS Distributions 	 * the NAME_CACHE_LOCK... we lazily release the reference
573*4f1223e8SApple OSS Distributions 	 * we pick up the next time we encounter a need to drop
574*4f1223e8SApple OSS Distributions 	 * the NAME_CACHE_LOCK or before we return from this routine
575*4f1223e8SApple OSS Distributions 	 */
576*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK_SHARED();
577*4f1223e8SApple OSS Distributions 
578*4f1223e8SApple OSS Distributions #if CONFIG_FIRMLINKS
579*4f1223e8SApple OSS Distributions 	if (!(flags & BUILDPATH_NO_FIRMLINK) &&
580*4f1223e8SApple OSS Distributions 	    (vp->v_flag & VFMLINKTARGET) && vp->v_fmlink && (vp->v_fmlink->v_type == VDIR)) {
581*4f1223e8SApple OSS Distributions 		vp = vp->v_fmlink;
582*4f1223e8SApple OSS Distributions 	}
583*4f1223e8SApple OSS Distributions #endif
584*4f1223e8SApple OSS Distributions 
585*4f1223e8SApple OSS Distributions 	/*
586*4f1223e8SApple OSS Distributions 	 * Check if this is the root of a file system.
587*4f1223e8SApple OSS Distributions 	 */
588*4f1223e8SApple OSS Distributions 	while (vp && vp->v_flag & VROOT) {
589*4f1223e8SApple OSS Distributions 		if (vp->v_mount == NULL) {
590*4f1223e8SApple OSS Distributions 			ret = EINVAL;
591*4f1223e8SApple OSS Distributions 			goto out_unlock;
592*4f1223e8SApple OSS Distributions 		}
593*4f1223e8SApple OSS Distributions 		if ((vp->v_mount->mnt_flag & MNT_ROOTFS) || (vp == proc_root_dir_vp)) {
594*4f1223e8SApple OSS Distributions 			/*
595*4f1223e8SApple OSS Distributions 			 * It's the root of the root file system, so it's
596*4f1223e8SApple OSS Distributions 			 * just "/".
597*4f1223e8SApple OSS Distributions 			 */
598*4f1223e8SApple OSS Distributions 			*--end = '/';
599*4f1223e8SApple OSS Distributions 
600*4f1223e8SApple OSS Distributions 			goto out_unlock;
601*4f1223e8SApple OSS Distributions 		} else {
602*4f1223e8SApple OSS Distributions 			/*
603*4f1223e8SApple OSS Distributions 			 * This the root of the volume and the caller does not
604*4f1223e8SApple OSS Distributions 			 * want to cross mount points.  Therefore just return
605*4f1223e8SApple OSS Distributions 			 * '/' as the relative path.
606*4f1223e8SApple OSS Distributions 			 */
607*4f1223e8SApple OSS Distributions #if CONFIG_FIRMLINKS
608*4f1223e8SApple OSS Distributions 			if (!(flags & BUILDPATH_NO_FIRMLINK) &&
609*4f1223e8SApple OSS Distributions 			    (vp->v_flag & VFMLINKTARGET) && vp->v_fmlink && (vp->v_fmlink->v_type == VDIR)) {
610*4f1223e8SApple OSS Distributions 				vp = vp->v_fmlink;
611*4f1223e8SApple OSS Distributions 			} else
612*4f1223e8SApple OSS Distributions #endif
613*4f1223e8SApple OSS Distributions 			if (flags & BUILDPATH_VOLUME_RELATIVE) {
614*4f1223e8SApple OSS Distributions 				*--end = '/';
615*4f1223e8SApple OSS Distributions 				goto out_unlock;
616*4f1223e8SApple OSS Distributions 			} else {
617*4f1223e8SApple OSS Distributions 				vp = vp->v_mount->mnt_vnodecovered;
618*4f1223e8SApple OSS Distributions 				if (!mntpt_end && vp) {
619*4f1223e8SApple OSS Distributions 					mntpt_end = end;
620*4f1223e8SApple OSS Distributions 				}
621*4f1223e8SApple OSS Distributions 			}
622*4f1223e8SApple OSS Distributions 		}
623*4f1223e8SApple OSS Distributions 	}
624*4f1223e8SApple OSS Distributions 
625*4f1223e8SApple OSS Distributions 	while ((vp != NULLVP) && (vp->v_parent != vp)) {
626*4f1223e8SApple OSS Distributions 		int  vid;
627*4f1223e8SApple OSS Distributions 
628*4f1223e8SApple OSS Distributions 		/*
629*4f1223e8SApple OSS Distributions 		 * For hardlinks the v_name may be stale, so if its OK
630*4f1223e8SApple OSS Distributions 		 * to enter a file system, ask the file system for the
631*4f1223e8SApple OSS Distributions 		 * name and parent (below).
632*4f1223e8SApple OSS Distributions 		 */
633*4f1223e8SApple OSS Distributions 		fixhardlink = (vp->v_flag & VISHARDLINK) &&
634*4f1223e8SApple OSS Distributions 		    (vp->v_mount->mnt_kern_flag & MNTK_PATH_FROM_ID) &&
635*4f1223e8SApple OSS Distributions 		    !(flags & BUILDPATH_NO_FS_ENTER);
636*4f1223e8SApple OSS Distributions 
637*4f1223e8SApple OSS Distributions 		if (!fixhardlink) {
638*4f1223e8SApple OSS Distributions 			str = vp->v_name;
639*4f1223e8SApple OSS Distributions 
640*4f1223e8SApple OSS Distributions 			if (str == NULL || *str == '\0') {
641*4f1223e8SApple OSS Distributions 				if (vp->v_parent != NULL) {
642*4f1223e8SApple OSS Distributions 					ret = EINVAL;
643*4f1223e8SApple OSS Distributions 				} else {
644*4f1223e8SApple OSS Distributions 					ret = ENOENT;
645*4f1223e8SApple OSS Distributions 				}
646*4f1223e8SApple OSS Distributions 				goto out_unlock;
647*4f1223e8SApple OSS Distributions 			}
648*4f1223e8SApple OSS Distributions 			len = (unsigned int)strlen(str);
649*4f1223e8SApple OSS Distributions 			/*
650*4f1223e8SApple OSS Distributions 			 * Check that there's enough space (including space for the '/')
651*4f1223e8SApple OSS Distributions 			 */
652*4f1223e8SApple OSS Distributions 			if ((unsigned int)(end - buff) < (len + 1)) {
653*4f1223e8SApple OSS Distributions 				ret = ENOSPC;
654*4f1223e8SApple OSS Distributions 				goto out_unlock;
655*4f1223e8SApple OSS Distributions 			}
656*4f1223e8SApple OSS Distributions 			/*
657*4f1223e8SApple OSS Distributions 			 * Copy the name backwards.
658*4f1223e8SApple OSS Distributions 			 */
659*4f1223e8SApple OSS Distributions 			str += len;
660*4f1223e8SApple OSS Distributions 
661*4f1223e8SApple OSS Distributions 			for (; len > 0; len--) {
662*4f1223e8SApple OSS Distributions 				*--end = *--str;
663*4f1223e8SApple OSS Distributions 			}
664*4f1223e8SApple OSS Distributions 			/*
665*4f1223e8SApple OSS Distributions 			 * Add a path separator.
666*4f1223e8SApple OSS Distributions 			 */
667*4f1223e8SApple OSS Distributions 			*--end = '/';
668*4f1223e8SApple OSS Distributions 		}
669*4f1223e8SApple OSS Distributions 
670*4f1223e8SApple OSS Distributions 		/*
671*4f1223e8SApple OSS Distributions 		 * Walk up the parent chain.
672*4f1223e8SApple OSS Distributions 		 */
673*4f1223e8SApple OSS Distributions 		if (((vp->v_parent != NULLVP) && !fixhardlink) ||
674*4f1223e8SApple OSS Distributions 		    (flags & BUILDPATH_NO_FS_ENTER)) {
675*4f1223e8SApple OSS Distributions 			/*
676*4f1223e8SApple OSS Distributions 			 * In this if () block we are not allowed to enter the filesystem
677*4f1223e8SApple OSS Distributions 			 * to conclusively get the most accurate parent identifier.
678*4f1223e8SApple OSS Distributions 			 * As a result, if 'vp' does not identify '/' and it
679*4f1223e8SApple OSS Distributions 			 * does not have a valid v_parent, then error out
680*4f1223e8SApple OSS Distributions 			 * and disallow further path construction
681*4f1223e8SApple OSS Distributions 			 */
682*4f1223e8SApple OSS Distributions 			if ((vp->v_parent == NULLVP) && (rootvnode != vp)) {
683*4f1223e8SApple OSS Distributions 				/*
684*4f1223e8SApple OSS Distributions 				 * Only '/' is allowed to have a NULL parent
685*4f1223e8SApple OSS Distributions 				 * pointer. Upper level callers should ideally
686*4f1223e8SApple OSS Distributions 				 * re-drive name lookup on receiving a ENOENT.
687*4f1223e8SApple OSS Distributions 				 */
688*4f1223e8SApple OSS Distributions 				ret = ENOENT;
689*4f1223e8SApple OSS Distributions 
690*4f1223e8SApple OSS Distributions 				/* The code below will exit early if 'tvp = vp' == NULL */
691*4f1223e8SApple OSS Distributions 			}
692*4f1223e8SApple OSS Distributions 			vp = vp->v_parent;
693*4f1223e8SApple OSS Distributions 
694*4f1223e8SApple OSS Distributions 			/*
695*4f1223e8SApple OSS Distributions 			 * if the vnode we have in hand isn't a directory and it
696*4f1223e8SApple OSS Distributions 			 * has a v_parent, then we started with the resource fork
697*4f1223e8SApple OSS Distributions 			 * so skip up to avoid getting a duplicate copy of the
698*4f1223e8SApple OSS Distributions 			 * file name in the path.
699*4f1223e8SApple OSS Distributions 			 */
700*4f1223e8SApple OSS Distributions 			if (vp && !vnode_isdir(vp) && vp->v_parent) {
701*4f1223e8SApple OSS Distributions 				vp = vp->v_parent;
702*4f1223e8SApple OSS Distributions 			}
703*4f1223e8SApple OSS Distributions 		} else {
704*4f1223e8SApple OSS Distributions 			/*
705*4f1223e8SApple OSS Distributions 			 * No parent, go get it if supported.
706*4f1223e8SApple OSS Distributions 			 */
707*4f1223e8SApple OSS Distributions 			struct vnode_attr  va;
708*4f1223e8SApple OSS Distributions 			vnode_t  dvp;
709*4f1223e8SApple OSS Distributions 
710*4f1223e8SApple OSS Distributions 			/*
711*4f1223e8SApple OSS Distributions 			 * Make sure file system supports obtaining a path from id.
712*4f1223e8SApple OSS Distributions 			 */
713*4f1223e8SApple OSS Distributions 			if (!(vp->v_mount->mnt_kern_flag & MNTK_PATH_FROM_ID)) {
714*4f1223e8SApple OSS Distributions 				ret = ENOENT;
715*4f1223e8SApple OSS Distributions 				goto out_unlock;
716*4f1223e8SApple OSS Distributions 			}
717*4f1223e8SApple OSS Distributions 			vid = vp->v_id;
718*4f1223e8SApple OSS Distributions 
719*4f1223e8SApple OSS Distributions 			vnode_hold(vp);
720*4f1223e8SApple OSS Distributions 			NAME_CACHE_UNLOCK();
721*4f1223e8SApple OSS Distributions 
722*4f1223e8SApple OSS Distributions 			if (vp != first_vp && vp != parent_vp && vp != vp_with_iocount) {
723*4f1223e8SApple OSS Distributions 				if (vp_with_iocount) {
724*4f1223e8SApple OSS Distributions 					vnode_put(vp_with_iocount);
725*4f1223e8SApple OSS Distributions 					vp_with_iocount = NULLVP;
726*4f1223e8SApple OSS Distributions 				}
727*4f1223e8SApple OSS Distributions 				if (vnode_getwithvid(vp, vid)) {
728*4f1223e8SApple OSS Distributions 					vnode_drop(vp);
729*4f1223e8SApple OSS Distributions 					goto again;
730*4f1223e8SApple OSS Distributions 				}
731*4f1223e8SApple OSS Distributions 				vp_with_iocount = vp;
732*4f1223e8SApple OSS Distributions 			}
733*4f1223e8SApple OSS Distributions 
734*4f1223e8SApple OSS Distributions 			vnode_drop(vp);
735*4f1223e8SApple OSS Distributions 
736*4f1223e8SApple OSS Distributions 			VATTR_INIT(&va);
737*4f1223e8SApple OSS Distributions 			VATTR_WANTED(&va, va_parentid);
738*4f1223e8SApple OSS Distributions 
739*4f1223e8SApple OSS Distributions 			if (fixhardlink) {
740*4f1223e8SApple OSS Distributions 				VATTR_WANTED(&va, va_name);
741*4f1223e8SApple OSS Distributions 				va.va_name = zalloc(ZV_NAMEI);
742*4f1223e8SApple OSS Distributions 			} else {
743*4f1223e8SApple OSS Distributions 				va.va_name = NULL;
744*4f1223e8SApple OSS Distributions 			}
745*4f1223e8SApple OSS Distributions 			/*
746*4f1223e8SApple OSS Distributions 			 * Ask the file system for its parent id and for its name (optional).
747*4f1223e8SApple OSS Distributions 			 */
748*4f1223e8SApple OSS Distributions 			ret = vnode_getattr(vp, &va, ctx);
749*4f1223e8SApple OSS Distributions 
750*4f1223e8SApple OSS Distributions 			if (ret || !VATTR_IS_SUPPORTED(&va, va_parentid)) {
751*4f1223e8SApple OSS Distributions 				ret = ENOENT;
752*4f1223e8SApple OSS Distributions 				goto out;
753*4f1223e8SApple OSS Distributions 			}
754*4f1223e8SApple OSS Distributions 
755*4f1223e8SApple OSS Distributions 			/*
756*4f1223e8SApple OSS Distributions 			 * Ask the file system for the parent vnode.
757*4f1223e8SApple OSS Distributions 			 */
758*4f1223e8SApple OSS Distributions 			if ((ret = VFS_VGET(vp->v_mount, (ino64_t)va.va_parentid, &dvp, ctx))) {
759*4f1223e8SApple OSS Distributions 				goto out;
760*4f1223e8SApple OSS Distributions 			}
761*4f1223e8SApple OSS Distributions 
762*4f1223e8SApple OSS Distributions 			/* No exit from here before switching vp_with_iocount to dvp */
763*4f1223e8SApple OSS Distributions 
764*4f1223e8SApple OSS Distributions 			if (fixhardlink) {
765*4f1223e8SApple OSS Distributions 				if (VATTR_IS_SUPPORTED(&va, va_name)) {
766*4f1223e8SApple OSS Distributions 					str = va.va_name;
767*4f1223e8SApple OSS Distributions 				} else {
768*4f1223e8SApple OSS Distributions 					ret = ENOENT;
769*4f1223e8SApple OSS Distributions 					goto bad_news;
770*4f1223e8SApple OSS Distributions 				}
771*4f1223e8SApple OSS Distributions 				len = (unsigned int)strlen(str);
772*4f1223e8SApple OSS Distributions 
773*4f1223e8SApple OSS Distributions 				/* Don't update parent for namedstream vnode. */
774*4f1223e8SApple OSS Distributions 				if (vp->v_flag & VISNAMEDSTREAM) {
775*4f1223e8SApple OSS Distributions 					vnode_update_identity(vp, NULL, str, len, 0,
776*4f1223e8SApple OSS Distributions 					    VNODE_UPDATE_NAME);
777*4f1223e8SApple OSS Distributions 				} else {
778*4f1223e8SApple OSS Distributions 					vnode_update_identity(vp, dvp, str, len, 0,
779*4f1223e8SApple OSS Distributions 					    VNODE_UPDATE_NAME | VNODE_UPDATE_PARENT);
780*4f1223e8SApple OSS Distributions 				}
781*4f1223e8SApple OSS Distributions 
782*4f1223e8SApple OSS Distributions 				/*
783*4f1223e8SApple OSS Distributions 				 * Check that there's enough space.
784*4f1223e8SApple OSS Distributions 				 */
785*4f1223e8SApple OSS Distributions 				if ((unsigned int)(end - buff) < (len + 1)) {
786*4f1223e8SApple OSS Distributions 					ret = ENOSPC;
787*4f1223e8SApple OSS Distributions 				} else {
788*4f1223e8SApple OSS Distributions 					/* Copy the name backwards. */
789*4f1223e8SApple OSS Distributions 					str += len;
790*4f1223e8SApple OSS Distributions 
791*4f1223e8SApple OSS Distributions 					for (; len > 0; len--) {
792*4f1223e8SApple OSS Distributions 						*--end = *--str;
793*4f1223e8SApple OSS Distributions 					}
794*4f1223e8SApple OSS Distributions 					/*
795*4f1223e8SApple OSS Distributions 					 * Add a path separator.
796*4f1223e8SApple OSS Distributions 					 */
797*4f1223e8SApple OSS Distributions 					*--end = '/';
798*4f1223e8SApple OSS Distributions 				}
799*4f1223e8SApple OSS Distributions bad_news:
800*4f1223e8SApple OSS Distributions 				zfree(ZV_NAMEI, va.va_name);
801*4f1223e8SApple OSS Distributions 			} else if (vp->v_parent != dvp) {
802*4f1223e8SApple OSS Distributions 				vnode_update_identity(vp, dvp, NULL, 0, 0, VNODE_UPDATE_PARENT);
803*4f1223e8SApple OSS Distributions 			}
804*4f1223e8SApple OSS Distributions 
805*4f1223e8SApple OSS Distributions 			if (vp_with_iocount) {
806*4f1223e8SApple OSS Distributions 				vnode_put(vp_with_iocount);
807*4f1223e8SApple OSS Distributions 			}
808*4f1223e8SApple OSS Distributions 			vp = dvp;
809*4f1223e8SApple OSS Distributions 			vp_with_iocount = vp;
810*4f1223e8SApple OSS Distributions 
811*4f1223e8SApple OSS Distributions 			NAME_CACHE_LOCK_SHARED();
812*4f1223e8SApple OSS Distributions 
813*4f1223e8SApple OSS Distributions 			/*
814*4f1223e8SApple OSS Distributions 			 * if the vnode we have in hand isn't a directory and it
815*4f1223e8SApple OSS Distributions 			 * has a v_parent, then we started with the resource fork
816*4f1223e8SApple OSS Distributions 			 * so skip up to avoid getting a duplicate copy of the
817*4f1223e8SApple OSS Distributions 			 * file name in the path.
818*4f1223e8SApple OSS Distributions 			 */
819*4f1223e8SApple OSS Distributions 			if (vp && !vnode_isdir(vp) && vp->v_parent) {
820*4f1223e8SApple OSS Distributions 				vp = vp->v_parent;
821*4f1223e8SApple OSS Distributions 			}
822*4f1223e8SApple OSS Distributions 		}
823*4f1223e8SApple OSS Distributions 
824*4f1223e8SApple OSS Distributions 		if (vp && (flags & BUILDPATH_CHECKACCESS)) {
825*4f1223e8SApple OSS Distributions 			vid = vp->v_id;
826*4f1223e8SApple OSS Distributions 
827*4f1223e8SApple OSS Distributions 			vnode_hold(vp);
828*4f1223e8SApple OSS Distributions 			NAME_CACHE_UNLOCK();
829*4f1223e8SApple OSS Distributions 
830*4f1223e8SApple OSS Distributions 			if (vp != first_vp && vp != parent_vp && vp != vp_with_iocount) {
831*4f1223e8SApple OSS Distributions 				if (vp_with_iocount) {
832*4f1223e8SApple OSS Distributions 					vnode_put(vp_with_iocount);
833*4f1223e8SApple OSS Distributions 					vp_with_iocount = NULLVP;
834*4f1223e8SApple OSS Distributions 				}
835*4f1223e8SApple OSS Distributions 				if (vnode_getwithvid(vp, vid)) {
836*4f1223e8SApple OSS Distributions 					vnode_drop(vp);
837*4f1223e8SApple OSS Distributions 					goto again;
838*4f1223e8SApple OSS Distributions 				}
839*4f1223e8SApple OSS Distributions 				vp_with_iocount = vp;
840*4f1223e8SApple OSS Distributions 			}
841*4f1223e8SApple OSS Distributions 			vnode_drop(vp);
842*4f1223e8SApple OSS Distributions 
843*4f1223e8SApple OSS Distributions 			if ((ret = vnode_authorize(vp, NULL, KAUTH_VNODE_SEARCH, ctx))) {
844*4f1223e8SApple OSS Distributions 				goto out;       /* no peeking */
845*4f1223e8SApple OSS Distributions 			}
846*4f1223e8SApple OSS Distributions 			NAME_CACHE_LOCK_SHARED();
847*4f1223e8SApple OSS Distributions 		}
848*4f1223e8SApple OSS Distributions 
849*4f1223e8SApple OSS Distributions 		/*
850*4f1223e8SApple OSS Distributions 		 * When a mount point is crossed switch the vp.
851*4f1223e8SApple OSS Distributions 		 * Continue until we find the root or we find
852*4f1223e8SApple OSS Distributions 		 * a vnode that's not the root of a mounted
853*4f1223e8SApple OSS Distributions 		 * file system.
854*4f1223e8SApple OSS Distributions 		 */
855*4f1223e8SApple OSS Distributions 		tvp = vp;
856*4f1223e8SApple OSS Distributions 
857*4f1223e8SApple OSS Distributions 		while (tvp) {
858*4f1223e8SApple OSS Distributions 			if (tvp == proc_root_dir_vp) {
859*4f1223e8SApple OSS Distributions 				goto out_unlock;        /* encountered the root */
860*4f1223e8SApple OSS Distributions 			}
861*4f1223e8SApple OSS Distributions 
862*4f1223e8SApple OSS Distributions #if CONFIG_FIRMLINKS
863*4f1223e8SApple OSS Distributions 			if (!(flags & BUILDPATH_NO_FIRMLINK) &&
864*4f1223e8SApple OSS Distributions 			    (tvp->v_flag & VFMLINKTARGET) && tvp->v_fmlink && (tvp->v_fmlink->v_type == VDIR)) {
865*4f1223e8SApple OSS Distributions 				tvp = tvp->v_fmlink;
866*4f1223e8SApple OSS Distributions 				break;
867*4f1223e8SApple OSS Distributions 			}
868*4f1223e8SApple OSS Distributions #endif
869*4f1223e8SApple OSS Distributions 
870*4f1223e8SApple OSS Distributions 			if (!(tvp->v_flag & VROOT) || !tvp->v_mount) {
871*4f1223e8SApple OSS Distributions 				break;                  /* not the root of a mounted FS */
872*4f1223e8SApple OSS Distributions 			}
873*4f1223e8SApple OSS Distributions 			if (flags & BUILDPATH_VOLUME_RELATIVE) {
874*4f1223e8SApple OSS Distributions 				/* Do not cross over mount points */
875*4f1223e8SApple OSS Distributions 				tvp = NULL;
876*4f1223e8SApple OSS Distributions 			} else {
877*4f1223e8SApple OSS Distributions 				tvp = tvp->v_mount->mnt_vnodecovered;
878*4f1223e8SApple OSS Distributions 				if (!mntpt_end && tvp) {
879*4f1223e8SApple OSS Distributions 					mntpt_end = end;
880*4f1223e8SApple OSS Distributions 				}
881*4f1223e8SApple OSS Distributions 			}
882*4f1223e8SApple OSS Distributions 		}
883*4f1223e8SApple OSS Distributions 		if (tvp == NULLVP) {
884*4f1223e8SApple OSS Distributions 			goto out_unlock;
885*4f1223e8SApple OSS Distributions 		}
886*4f1223e8SApple OSS Distributions 		vp = tvp;
887*4f1223e8SApple OSS Distributions 	}
888*4f1223e8SApple OSS Distributions out_unlock:
889*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
890*4f1223e8SApple OSS Distributions out:
891*4f1223e8SApple OSS Distributions 	if (vp_with_iocount) {
892*4f1223e8SApple OSS Distributions 		vnode_put(vp_with_iocount);
893*4f1223e8SApple OSS Distributions 	}
894*4f1223e8SApple OSS Distributions 	/*
895*4f1223e8SApple OSS Distributions 	 * Slide the name down to the beginning of the buffer.
896*4f1223e8SApple OSS Distributions 	 */
897*4f1223e8SApple OSS Distributions 	memmove(buff, end, &buff[buflen] - end);
898*4f1223e8SApple OSS Distributions 
899*4f1223e8SApple OSS Distributions 	/*
900*4f1223e8SApple OSS Distributions 	 * length includes the trailing zero byte
901*4f1223e8SApple OSS Distributions 	 */
902*4f1223e8SApple OSS Distributions 	*outlen = (int)(&buff[buflen] - end);
903*4f1223e8SApple OSS Distributions 	if (mntpt_outlen && mntpt_end) {
904*4f1223e8SApple OSS Distributions 		*mntpt_outlen = (size_t)*outlen - (size_t)(&buff[buflen] - mntpt_end);
905*4f1223e8SApple OSS Distributions 	}
906*4f1223e8SApple OSS Distributions 
907*4f1223e8SApple OSS Distributions 	/* One of the parents was moved during path reconstruction.
908*4f1223e8SApple OSS Distributions 	 * The caller is interested in knowing whether any of the
909*4f1223e8SApple OSS Distributions 	 * parents moved via BUILDPATH_CHECK_MOVED, so return EAGAIN.
910*4f1223e8SApple OSS Distributions 	 */
911*4f1223e8SApple OSS Distributions 	if ((ret == ENOENT) && (flags & BUILDPATH_CHECK_MOVED)) {
912*4f1223e8SApple OSS Distributions 		ret = EAGAIN;
913*4f1223e8SApple OSS Distributions 	}
914*4f1223e8SApple OSS Distributions 
915*4f1223e8SApple OSS Distributions 	return ret;
916*4f1223e8SApple OSS Distributions }
917*4f1223e8SApple OSS Distributions 
918*4f1223e8SApple OSS Distributions int
build_path(vnode_t first_vp,char * buff,int buflen,int * outlen,int flags,vfs_context_t ctx)919*4f1223e8SApple OSS Distributions build_path(vnode_t first_vp, char *buff, int buflen, int *outlen, int flags, vfs_context_t ctx)
920*4f1223e8SApple OSS Distributions {
921*4f1223e8SApple OSS Distributions 	return build_path_with_parent(first_vp, NULL, buff, buflen, outlen, NULL, flags, ctx);
922*4f1223e8SApple OSS Distributions }
923*4f1223e8SApple OSS Distributions 
924*4f1223e8SApple OSS Distributions /*
925*4f1223e8SApple OSS Distributions  * Combined version of vnode_getparent() and vnode_getname() to acquire both vnode name and parent
926*4f1223e8SApple OSS Distributions  * without releasing the name cache lock in interim.
927*4f1223e8SApple OSS Distributions  */
928*4f1223e8SApple OSS Distributions void
vnode_getparent_and_name(vnode_t vp,vnode_t * out_pvp,const char ** out_name)929*4f1223e8SApple OSS Distributions vnode_getparent_and_name(vnode_t vp, vnode_t *out_pvp, const char **out_name)
930*4f1223e8SApple OSS Distributions {
931*4f1223e8SApple OSS Distributions 	vnode_t pvp = NULLVP;
932*4f1223e8SApple OSS Distributions 	int     locked = 0;
933*4f1223e8SApple OSS Distributions 	int     pvid;
934*4f1223e8SApple OSS Distributions 
935*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK_SHARED();
936*4f1223e8SApple OSS Distributions 	locked = 1;
937*4f1223e8SApple OSS Distributions 
938*4f1223e8SApple OSS Distributions 	if (out_name) {
939*4f1223e8SApple OSS Distributions 		const char *name = NULL;
940*4f1223e8SApple OSS Distributions 		if (vp->v_name) {
941*4f1223e8SApple OSS Distributions 			name = vfs_addname(vp->v_name, (unsigned int)strlen(vp->v_name), 0, 0);
942*4f1223e8SApple OSS Distributions 		}
943*4f1223e8SApple OSS Distributions 		*out_name = name;
944*4f1223e8SApple OSS Distributions 	}
945*4f1223e8SApple OSS Distributions 
946*4f1223e8SApple OSS Distributions 	if (!out_pvp) {
947*4f1223e8SApple OSS Distributions 		goto out;
948*4f1223e8SApple OSS Distributions 	}
949*4f1223e8SApple OSS Distributions 
950*4f1223e8SApple OSS Distributions 	pvp = vp->v_parent;
951*4f1223e8SApple OSS Distributions 
952*4f1223e8SApple OSS Distributions 	/*
953*4f1223e8SApple OSS Distributions 	 * v_parent is stable behind the name_cache lock
954*4f1223e8SApple OSS Distributions 	 * however, the only thing we can really guarantee
955*4f1223e8SApple OSS Distributions 	 * is that we've grabbed a valid iocount on the
956*4f1223e8SApple OSS Distributions 	 * parent of 'vp' at the time we took the name_cache lock...
957*4f1223e8SApple OSS Distributions 	 * once we drop the lock, vp could get re-parented
958*4f1223e8SApple OSS Distributions 	 */
959*4f1223e8SApple OSS Distributions 	if (pvp != NULLVP) {
960*4f1223e8SApple OSS Distributions 		pvid = pvp->v_id;
961*4f1223e8SApple OSS Distributions 
962*4f1223e8SApple OSS Distributions 		vnode_hold(pvp);
963*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
964*4f1223e8SApple OSS Distributions 		locked = 0;
965*4f1223e8SApple OSS Distributions 
966*4f1223e8SApple OSS Distributions 		if (vnode_getwithvid(pvp, pvid) != 0) {
967*4f1223e8SApple OSS Distributions 			vnode_drop(pvp);
968*4f1223e8SApple OSS Distributions 			pvp = NULL;
969*4f1223e8SApple OSS Distributions 		} else {
970*4f1223e8SApple OSS Distributions 			vnode_drop(pvp);
971*4f1223e8SApple OSS Distributions 		}
972*4f1223e8SApple OSS Distributions 	}
973*4f1223e8SApple OSS Distributions 	*out_pvp = pvp;
974*4f1223e8SApple OSS Distributions 
975*4f1223e8SApple OSS Distributions out:
976*4f1223e8SApple OSS Distributions 	if (locked) {
977*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
978*4f1223e8SApple OSS Distributions 	}
979*4f1223e8SApple OSS Distributions }
980*4f1223e8SApple OSS Distributions 
981*4f1223e8SApple OSS Distributions /*
982*4f1223e8SApple OSS Distributions  * return NULLVP if vp's parent doesn't
983*4f1223e8SApple OSS Distributions  * exist, or we can't get a valid iocount
984*4f1223e8SApple OSS Distributions  * else return the parent of vp
985*4f1223e8SApple OSS Distributions  */
986*4f1223e8SApple OSS Distributions vnode_t
vnode_getparent(vnode_t vp)987*4f1223e8SApple OSS Distributions vnode_getparent(vnode_t vp)
988*4f1223e8SApple OSS Distributions {
989*4f1223e8SApple OSS Distributions 	vnode_t pvp = NULLVP;
990*4f1223e8SApple OSS Distributions 	vnode_getparent_and_name(vp, &pvp, NULL);
991*4f1223e8SApple OSS Distributions 
992*4f1223e8SApple OSS Distributions 	return pvp;
993*4f1223e8SApple OSS Distributions }
994*4f1223e8SApple OSS Distributions 
995*4f1223e8SApple OSS Distributions /*
996*4f1223e8SApple OSS Distributions  * Similar to vnode_getparent() but only returned parent vnode (with iocount
997*4f1223e8SApple OSS Distributions  * held) if the actual parent vnode is different than the given 'pvp'.
998*4f1223e8SApple OSS Distributions  */
999*4f1223e8SApple OSS Distributions __private_extern__ vnode_t
vnode_getparent_if_different(vnode_t vp,vnode_t pvp)1000*4f1223e8SApple OSS Distributions vnode_getparent_if_different(vnode_t vp, vnode_t pvp)
1001*4f1223e8SApple OSS Distributions {
1002*4f1223e8SApple OSS Distributions 	vnode_t real_pvp = NULLVP;
1003*4f1223e8SApple OSS Distributions 	int     pvid;
1004*4f1223e8SApple OSS Distributions 
1005*4f1223e8SApple OSS Distributions 	if (vp->v_parent == pvp) {
1006*4f1223e8SApple OSS Distributions 		goto out;
1007*4f1223e8SApple OSS Distributions 	}
1008*4f1223e8SApple OSS Distributions 
1009*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK_SHARED();
1010*4f1223e8SApple OSS Distributions 
1011*4f1223e8SApple OSS Distributions 	real_pvp = vp->v_parent;
1012*4f1223e8SApple OSS Distributions 	if (real_pvp == NULLVP) {
1013*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
1014*4f1223e8SApple OSS Distributions 		goto out;
1015*4f1223e8SApple OSS Distributions 	}
1016*4f1223e8SApple OSS Distributions 
1017*4f1223e8SApple OSS Distributions 	/*
1018*4f1223e8SApple OSS Distributions 	 * Do the check again after namecache lock is acquired as the parent vnode
1019*4f1223e8SApple OSS Distributions 	 * could have changed.
1020*4f1223e8SApple OSS Distributions 	 */
1021*4f1223e8SApple OSS Distributions 	if (real_pvp != pvp) {
1022*4f1223e8SApple OSS Distributions 		pvid = real_pvp->v_id;
1023*4f1223e8SApple OSS Distributions 
1024*4f1223e8SApple OSS Distributions 		vnode_hold(real_pvp);
1025*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
1026*4f1223e8SApple OSS Distributions 
1027*4f1223e8SApple OSS Distributions 		if (vnode_getwithvid(real_pvp, pvid) != 0) {
1028*4f1223e8SApple OSS Distributions 			vnode_drop(real_pvp);
1029*4f1223e8SApple OSS Distributions 			real_pvp = NULLVP;
1030*4f1223e8SApple OSS Distributions 		} else {
1031*4f1223e8SApple OSS Distributions 			vnode_drop(real_pvp);
1032*4f1223e8SApple OSS Distributions 		}
1033*4f1223e8SApple OSS Distributions 	} else {
1034*4f1223e8SApple OSS Distributions 		real_pvp = NULLVP;
1035*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
1036*4f1223e8SApple OSS Distributions 	}
1037*4f1223e8SApple OSS Distributions 
1038*4f1223e8SApple OSS Distributions out:
1039*4f1223e8SApple OSS Distributions 	return real_pvp;
1040*4f1223e8SApple OSS Distributions }
1041*4f1223e8SApple OSS Distributions 
1042*4f1223e8SApple OSS Distributions const char *
vnode_getname(vnode_t vp)1043*4f1223e8SApple OSS Distributions vnode_getname(vnode_t vp)
1044*4f1223e8SApple OSS Distributions {
1045*4f1223e8SApple OSS Distributions 	const char *name = NULL;
1046*4f1223e8SApple OSS Distributions 	vnode_getparent_and_name(vp, NULL, &name);
1047*4f1223e8SApple OSS Distributions 
1048*4f1223e8SApple OSS Distributions 	return name;
1049*4f1223e8SApple OSS Distributions }
1050*4f1223e8SApple OSS Distributions 
1051*4f1223e8SApple OSS Distributions void
vnode_putname(const char * name)1052*4f1223e8SApple OSS Distributions vnode_putname(const char *name)
1053*4f1223e8SApple OSS Distributions {
1054*4f1223e8SApple OSS Distributions 	if (name) {
1055*4f1223e8SApple OSS Distributions 		vfs_removename(name);
1056*4f1223e8SApple OSS Distributions 	}
1057*4f1223e8SApple OSS Distributions }
1058*4f1223e8SApple OSS Distributions 
1059*4f1223e8SApple OSS Distributions static const char unknown_vnodename[] = "(unknown vnode name)";
1060*4f1223e8SApple OSS Distributions 
1061*4f1223e8SApple OSS Distributions const char *
vnode_getname_printable(vnode_t vp)1062*4f1223e8SApple OSS Distributions vnode_getname_printable(vnode_t vp)
1063*4f1223e8SApple OSS Distributions {
1064*4f1223e8SApple OSS Distributions 	const char *name = vnode_getname(vp);
1065*4f1223e8SApple OSS Distributions 	if (name != NULL) {
1066*4f1223e8SApple OSS Distributions 		return name;
1067*4f1223e8SApple OSS Distributions 	}
1068*4f1223e8SApple OSS Distributions 
1069*4f1223e8SApple OSS Distributions 	switch (vp->v_type) {
1070*4f1223e8SApple OSS Distributions 	case VCHR:
1071*4f1223e8SApple OSS Distributions 	case VBLK:
1072*4f1223e8SApple OSS Distributions 	{
1073*4f1223e8SApple OSS Distributions 		/*
1074*4f1223e8SApple OSS Distributions 		 * Create an artificial dev name from
1075*4f1223e8SApple OSS Distributions 		 * major and minor device number
1076*4f1223e8SApple OSS Distributions 		 */
1077*4f1223e8SApple OSS Distributions 		char dev_name[64];
1078*4f1223e8SApple OSS Distributions 		(void) snprintf(dev_name, sizeof(dev_name),
1079*4f1223e8SApple OSS Distributions 		    "%c(%u, %u)", VCHR == vp->v_type ? 'c':'b',
1080*4f1223e8SApple OSS Distributions 		    major(vp->v_rdev), minor(vp->v_rdev));
1081*4f1223e8SApple OSS Distributions 		/*
1082*4f1223e8SApple OSS Distributions 		 * Add the newly created dev name to the name
1083*4f1223e8SApple OSS Distributions 		 * cache to allow easier cleanup. Also,
1084*4f1223e8SApple OSS Distributions 		 * vfs_addname allocates memory for the new name
1085*4f1223e8SApple OSS Distributions 		 * and returns it.
1086*4f1223e8SApple OSS Distributions 		 */
1087*4f1223e8SApple OSS Distributions 		NAME_CACHE_LOCK_SHARED();
1088*4f1223e8SApple OSS Distributions 		name = vfs_addname(dev_name, (unsigned int)strlen(dev_name), 0, 0);
1089*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
1090*4f1223e8SApple OSS Distributions 		return name;
1091*4f1223e8SApple OSS Distributions 	}
1092*4f1223e8SApple OSS Distributions 	default:
1093*4f1223e8SApple OSS Distributions 		return unknown_vnodename;
1094*4f1223e8SApple OSS Distributions 	}
1095*4f1223e8SApple OSS Distributions }
1096*4f1223e8SApple OSS Distributions 
1097*4f1223e8SApple OSS Distributions void
vnode_putname_printable(const char * name)1098*4f1223e8SApple OSS Distributions vnode_putname_printable(const char *name)
1099*4f1223e8SApple OSS Distributions {
1100*4f1223e8SApple OSS Distributions 	if (name == unknown_vnodename) {
1101*4f1223e8SApple OSS Distributions 		return;
1102*4f1223e8SApple OSS Distributions 	}
1103*4f1223e8SApple OSS Distributions 	vnode_putname(name);
1104*4f1223e8SApple OSS Distributions }
1105*4f1223e8SApple OSS Distributions 
1106*4f1223e8SApple OSS Distributions 
1107*4f1223e8SApple OSS Distributions /*
1108*4f1223e8SApple OSS Distributions  * if VNODE_UPDATE_PARENT, and we can take
1109*4f1223e8SApple OSS Distributions  * a reference on dvp, then update vp with
1110*4f1223e8SApple OSS Distributions  * it's new parent... if vp already has a parent,
1111*4f1223e8SApple OSS Distributions  * then drop the reference vp held on it
1112*4f1223e8SApple OSS Distributions  *
1113*4f1223e8SApple OSS Distributions  * if VNODE_UPDATE_NAME,
1114*4f1223e8SApple OSS Distributions  * then drop string ref on v_name if it exists, and if name is non-NULL
1115*4f1223e8SApple OSS Distributions  * then pick up a string reference on name and record it in v_name...
1116*4f1223e8SApple OSS Distributions  * optionally pass in the length and hashval of name if known
1117*4f1223e8SApple OSS Distributions  *
1118*4f1223e8SApple OSS Distributions  * if VNODE_UPDATE_CACHE, flush the name cache entries associated with vp
1119*4f1223e8SApple OSS Distributions  */
1120*4f1223e8SApple OSS Distributions void
vnode_update_identity(vnode_t vp,vnode_t dvp,const char * name,int name_len,uint32_t name_hashval,int flags)1121*4f1223e8SApple OSS Distributions vnode_update_identity(vnode_t vp, vnode_t dvp, const char *name, int name_len, uint32_t name_hashval, int flags)
1122*4f1223e8SApple OSS Distributions {
1123*4f1223e8SApple OSS Distributions 	struct  namecache *ncp;
1124*4f1223e8SApple OSS Distributions 	vnode_t old_parentvp = NULLVP;
1125*4f1223e8SApple OSS Distributions 	int isstream = (vp->v_flag & VISNAMEDSTREAM);
1126*4f1223e8SApple OSS Distributions 	int kusecountbumped = 0;
1127*4f1223e8SApple OSS Distributions 	kauth_cred_t tcred = NULL;
1128*4f1223e8SApple OSS Distributions 	const char *vname = NULL;
1129*4f1223e8SApple OSS Distributions 	const char *tname = NULL;
1130*4f1223e8SApple OSS Distributions 
1131*4f1223e8SApple OSS Distributions 	if (name_len < 0) {
1132*4f1223e8SApple OSS Distributions 		return;
1133*4f1223e8SApple OSS Distributions 	}
1134*4f1223e8SApple OSS Distributions 
1135*4f1223e8SApple OSS Distributions 	if (flags & VNODE_UPDATE_PARENT) {
1136*4f1223e8SApple OSS Distributions 		if (dvp && vnode_ref(dvp) != 0) {
1137*4f1223e8SApple OSS Distributions 			dvp = NULLVP;
1138*4f1223e8SApple OSS Distributions 		}
1139*4f1223e8SApple OSS Distributions 		/* Don't count a stream's parent ref during unmounts */
1140*4f1223e8SApple OSS Distributions 		if (isstream && dvp && (dvp != vp) && (dvp != vp->v_parent) && (dvp->v_type == VREG)) {
1141*4f1223e8SApple OSS Distributions 			vnode_lock_spin(dvp);
1142*4f1223e8SApple OSS Distributions 			++dvp->v_kusecount;
1143*4f1223e8SApple OSS Distributions 			kusecountbumped = 1;
1144*4f1223e8SApple OSS Distributions 			vnode_unlock(dvp);
1145*4f1223e8SApple OSS Distributions 		}
1146*4f1223e8SApple OSS Distributions 	} else {
1147*4f1223e8SApple OSS Distributions 		dvp = NULLVP;
1148*4f1223e8SApple OSS Distributions 	}
1149*4f1223e8SApple OSS Distributions 	if ((flags & VNODE_UPDATE_NAME)) {
1150*4f1223e8SApple OSS Distributions 		if (name != vp->v_name) {
1151*4f1223e8SApple OSS Distributions 			if (name && *name) {
1152*4f1223e8SApple OSS Distributions 				if (name_len == 0) {
1153*4f1223e8SApple OSS Distributions 					name_len = (int)strlen(name);
1154*4f1223e8SApple OSS Distributions 				}
1155*4f1223e8SApple OSS Distributions 				tname = vfs_addname(name, name_len, name_hashval, 0);
1156*4f1223e8SApple OSS Distributions 			}
1157*4f1223e8SApple OSS Distributions 		} else {
1158*4f1223e8SApple OSS Distributions 			flags &= ~VNODE_UPDATE_NAME;
1159*4f1223e8SApple OSS Distributions 		}
1160*4f1223e8SApple OSS Distributions 	}
1161*4f1223e8SApple OSS Distributions 	if ((flags & (VNODE_UPDATE_PURGE | VNODE_UPDATE_PARENT | VNODE_UPDATE_CACHE | VNODE_UPDATE_NAME | VNODE_UPDATE_PURGEFIRMLINK))) {
1162*4f1223e8SApple OSS Distributions 		NAME_CACHE_LOCK();
1163*4f1223e8SApple OSS Distributions 
1164*4f1223e8SApple OSS Distributions #if CONFIG_FIRMLINKS
1165*4f1223e8SApple OSS Distributions 		if (flags & VNODE_UPDATE_PURGEFIRMLINK) {
1166*4f1223e8SApple OSS Distributions 			vnode_t old_fvp = vp->v_fmlink;
1167*4f1223e8SApple OSS Distributions 			if (old_fvp) {
1168*4f1223e8SApple OSS Distributions 				vnode_lock_spin(vp);
1169*4f1223e8SApple OSS Distributions 				vp->v_flag &= ~VFMLINKTARGET;
1170*4f1223e8SApple OSS Distributions 				vp->v_fmlink = NULLVP;
1171*4f1223e8SApple OSS Distributions 				vnode_unlock(vp);
1172*4f1223e8SApple OSS Distributions 				NAME_CACHE_UNLOCK();
1173*4f1223e8SApple OSS Distributions 
1174*4f1223e8SApple OSS Distributions 				/*
1175*4f1223e8SApple OSS Distributions 				 * vnode_rele can result in cascading series of
1176*4f1223e8SApple OSS Distributions 				 * usecount releases. The combination of calling
1177*4f1223e8SApple OSS Distributions 				 * vnode_recycle and dont_reenter (3rd arg to
1178*4f1223e8SApple OSS Distributions 				 * vnode_rele_internal) ensures we don't have
1179*4f1223e8SApple OSS Distributions 				 * that issue.
1180*4f1223e8SApple OSS Distributions 				 */
1181*4f1223e8SApple OSS Distributions 				vnode_recycle(old_fvp);
1182*4f1223e8SApple OSS Distributions 				vnode_rele_internal(old_fvp, O_EVTONLY, 1, 0);
1183*4f1223e8SApple OSS Distributions 
1184*4f1223e8SApple OSS Distributions 				NAME_CACHE_LOCK();
1185*4f1223e8SApple OSS Distributions 			}
1186*4f1223e8SApple OSS Distributions 		}
1187*4f1223e8SApple OSS Distributions #endif
1188*4f1223e8SApple OSS Distributions 
1189*4f1223e8SApple OSS Distributions 		if ((flags & VNODE_UPDATE_PURGE)) {
1190*4f1223e8SApple OSS Distributions 			if (vp->v_parent) {
1191*4f1223e8SApple OSS Distributions 				vp->v_parent->v_nc_generation++;
1192*4f1223e8SApple OSS Distributions 			}
1193*4f1223e8SApple OSS Distributions 
1194*4f1223e8SApple OSS Distributions 			while ((ncp = LIST_FIRST(&vp->v_nclinks))) {
1195*4f1223e8SApple OSS Distributions 				cache_delete(ncp, 1);
1196*4f1223e8SApple OSS Distributions 			}
1197*4f1223e8SApple OSS Distributions 
1198*4f1223e8SApple OSS Distributions 			while ((ncp = TAILQ_FIRST(&vp->v_ncchildren))) {
1199*4f1223e8SApple OSS Distributions 				cache_delete(ncp, 1);
1200*4f1223e8SApple OSS Distributions 			}
1201*4f1223e8SApple OSS Distributions 
1202*4f1223e8SApple OSS Distributions 			/*
1203*4f1223e8SApple OSS Distributions 			 * Use a temp variable to avoid kauth_cred_drop() while NAME_CACHE_LOCK is held
1204*4f1223e8SApple OSS Distributions 			 */
1205*4f1223e8SApple OSS Distributions 			tcred = vnode_cred(vp);
1206*4f1223e8SApple OSS Distributions 			vp->v_cred = NOCRED;
1207*4f1223e8SApple OSS Distributions 			vp->v_authorized_actions = 0;
1208*4f1223e8SApple OSS Distributions 			vp->v_cred_timestamp = 0;
1209*4f1223e8SApple OSS Distributions 		}
1210*4f1223e8SApple OSS Distributions 		if ((flags & VNODE_UPDATE_NAME)) {
1211*4f1223e8SApple OSS Distributions 			vname = vp->v_name;
1212*4f1223e8SApple OSS Distributions 			vp->v_name = tname;
1213*4f1223e8SApple OSS Distributions 		}
1214*4f1223e8SApple OSS Distributions 		if (flags & VNODE_UPDATE_PARENT) {
1215*4f1223e8SApple OSS Distributions 			if (dvp != vp && dvp != vp->v_parent) {
1216*4f1223e8SApple OSS Distributions 				old_parentvp = vp->v_parent;
1217*4f1223e8SApple OSS Distributions 				vp->v_parent = dvp;
1218*4f1223e8SApple OSS Distributions 				dvp = NULLVP;
1219*4f1223e8SApple OSS Distributions 
1220*4f1223e8SApple OSS Distributions 				if (old_parentvp) {
1221*4f1223e8SApple OSS Distributions 					flags |= VNODE_UPDATE_CACHE;
1222*4f1223e8SApple OSS Distributions 				}
1223*4f1223e8SApple OSS Distributions 			}
1224*4f1223e8SApple OSS Distributions 		}
1225*4f1223e8SApple OSS Distributions 		if (flags & VNODE_UPDATE_CACHE) {
1226*4f1223e8SApple OSS Distributions 			while ((ncp = LIST_FIRST(&vp->v_nclinks))) {
1227*4f1223e8SApple OSS Distributions 				cache_delete(ncp, 1);
1228*4f1223e8SApple OSS Distributions 			}
1229*4f1223e8SApple OSS Distributions 		}
1230*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
1231*4f1223e8SApple OSS Distributions 
1232*4f1223e8SApple OSS Distributions 		if (vname != NULL) {
1233*4f1223e8SApple OSS Distributions 			vfs_removename(vname);
1234*4f1223e8SApple OSS Distributions 		}
1235*4f1223e8SApple OSS Distributions 
1236*4f1223e8SApple OSS Distributions 		if (IS_VALID_CRED(tcred)) {
1237*4f1223e8SApple OSS Distributions 			kauth_cred_unref(&tcred);
1238*4f1223e8SApple OSS Distributions 		}
1239*4f1223e8SApple OSS Distributions 	}
1240*4f1223e8SApple OSS Distributions 	if (dvp != NULLVP) {
1241*4f1223e8SApple OSS Distributions 		/* Back-out the ref we took if we lost a race for vp->v_parent. */
1242*4f1223e8SApple OSS Distributions 		if (kusecountbumped) {
1243*4f1223e8SApple OSS Distributions 			vnode_lock_spin(dvp);
1244*4f1223e8SApple OSS Distributions 			if (dvp->v_kusecount > 0) {
1245*4f1223e8SApple OSS Distributions 				--dvp->v_kusecount;
1246*4f1223e8SApple OSS Distributions 			}
1247*4f1223e8SApple OSS Distributions 			vnode_unlock(dvp);
1248*4f1223e8SApple OSS Distributions 		}
1249*4f1223e8SApple OSS Distributions 		vnode_rele(dvp);
1250*4f1223e8SApple OSS Distributions 	}
1251*4f1223e8SApple OSS Distributions 	if (old_parentvp) {
1252*4f1223e8SApple OSS Distributions 		struct  uthread *ut;
1253*4f1223e8SApple OSS Distributions 		vnode_t vreclaims = NULLVP;
1254*4f1223e8SApple OSS Distributions 
1255*4f1223e8SApple OSS Distributions 		if (isstream) {
1256*4f1223e8SApple OSS Distributions 			vnode_lock_spin(old_parentvp);
1257*4f1223e8SApple OSS Distributions 			if ((old_parentvp->v_type != VDIR) && (old_parentvp->v_kusecount > 0)) {
1258*4f1223e8SApple OSS Distributions 				--old_parentvp->v_kusecount;
1259*4f1223e8SApple OSS Distributions 			}
1260*4f1223e8SApple OSS Distributions 			vnode_unlock(old_parentvp);
1261*4f1223e8SApple OSS Distributions 		}
1262*4f1223e8SApple OSS Distributions 		ut = current_uthread();
1263*4f1223e8SApple OSS Distributions 
1264*4f1223e8SApple OSS Distributions 		/*
1265*4f1223e8SApple OSS Distributions 		 * indicated to vnode_rele that it shouldn't do a
1266*4f1223e8SApple OSS Distributions 		 * vnode_reclaim at this time... instead it will
1267*4f1223e8SApple OSS Distributions 		 * chain the vnode to the uu_vreclaims list...
1268*4f1223e8SApple OSS Distributions 		 * we'll be responsible for calling vnode_reclaim
1269*4f1223e8SApple OSS Distributions 		 * on each of the vnodes in this list...
1270*4f1223e8SApple OSS Distributions 		 */
1271*4f1223e8SApple OSS Distributions 		ut->uu_defer_reclaims = 1;
1272*4f1223e8SApple OSS Distributions 		ut->uu_vreclaims = NULLVP;
1273*4f1223e8SApple OSS Distributions 
1274*4f1223e8SApple OSS Distributions 		while ((vp = old_parentvp) != NULLVP) {
1275*4f1223e8SApple OSS Distributions 			vnode_hold(vp);
1276*4f1223e8SApple OSS Distributions 			vnode_lock_spin(vp);
1277*4f1223e8SApple OSS Distributions 			vnode_rele_internal(vp, 0, 0, 1);
1278*4f1223e8SApple OSS Distributions 
1279*4f1223e8SApple OSS Distributions 			/*
1280*4f1223e8SApple OSS Distributions 			 * check to see if the vnode is now in the state
1281*4f1223e8SApple OSS Distributions 			 * that would have triggered a vnode_reclaim in vnode_rele
1282*4f1223e8SApple OSS Distributions 			 * if it is, we save it's parent pointer and then NULL
1283*4f1223e8SApple OSS Distributions 			 * out the v_parent field... we'll drop the reference
1284*4f1223e8SApple OSS Distributions 			 * that was held on the next iteration of this loop...
1285*4f1223e8SApple OSS Distributions 			 * this short circuits a potential deep recursion if we
1286*4f1223e8SApple OSS Distributions 			 * have a long chain of parents in this state...
1287*4f1223e8SApple OSS Distributions 			 * we'll sit in this loop until we run into
1288*4f1223e8SApple OSS Distributions 			 * a parent in this chain that is not in this state
1289*4f1223e8SApple OSS Distributions 			 *
1290*4f1223e8SApple OSS Distributions 			 * make our check and the vnode_rele atomic
1291*4f1223e8SApple OSS Distributions 			 * with respect to the current vnode we're working on
1292*4f1223e8SApple OSS Distributions 			 * by holding the vnode lock
1293*4f1223e8SApple OSS Distributions 			 * if vnode_rele deferred the vnode_reclaim and has put
1294*4f1223e8SApple OSS Distributions 			 * this vnode on the list to be reaped by us, than
1295*4f1223e8SApple OSS Distributions 			 * it has left this vnode with an iocount == 1
1296*4f1223e8SApple OSS Distributions 			 */
1297*4f1223e8SApple OSS Distributions 			if (ut->uu_vreclaims == vp) {
1298*4f1223e8SApple OSS Distributions 				/*
1299*4f1223e8SApple OSS Distributions 				 * This vnode is on the head of the uu_vreclaims chain
1300*4f1223e8SApple OSS Distributions 				 * which means vnode_rele wanted to do a vnode_reclaim
1301*4f1223e8SApple OSS Distributions 				 * on this vnode. Pull the parent pointer now so that when we do the
1302*4f1223e8SApple OSS Distributions 				 * vnode_reclaim for each of the vnodes in the uu_vreclaims
1303*4f1223e8SApple OSS Distributions 				 * list, we won't recurse back through here
1304*4f1223e8SApple OSS Distributions 				 *
1305*4f1223e8SApple OSS Distributions 				 * need to do a convert here in case vnode_rele_internal
1306*4f1223e8SApple OSS Distributions 				 * returns with the lock held in the spin mode... it
1307*4f1223e8SApple OSS Distributions 				 * can drop and retake the lock under certain circumstances
1308*4f1223e8SApple OSS Distributions 				 */
1309*4f1223e8SApple OSS Distributions 				vnode_lock_convert(vp);
1310*4f1223e8SApple OSS Distributions 
1311*4f1223e8SApple OSS Distributions 				NAME_CACHE_LOCK();
1312*4f1223e8SApple OSS Distributions 				old_parentvp = vp->v_parent;
1313*4f1223e8SApple OSS Distributions 				vp->v_parent = NULLVP;
1314*4f1223e8SApple OSS Distributions 				NAME_CACHE_UNLOCK();
1315*4f1223e8SApple OSS Distributions 			} else {
1316*4f1223e8SApple OSS Distributions 				/*
1317*4f1223e8SApple OSS Distributions 				 * we're done... we ran into a vnode that isn't
1318*4f1223e8SApple OSS Distributions 				 * being terminated
1319*4f1223e8SApple OSS Distributions 				 */
1320*4f1223e8SApple OSS Distributions 				old_parentvp = NULLVP;
1321*4f1223e8SApple OSS Distributions 			}
1322*4f1223e8SApple OSS Distributions 			vnode_drop_and_unlock(vp);
1323*4f1223e8SApple OSS Distributions 		}
1324*4f1223e8SApple OSS Distributions 		vreclaims = ut->uu_vreclaims;
1325*4f1223e8SApple OSS Distributions 		ut->uu_vreclaims = NULLVP;
1326*4f1223e8SApple OSS Distributions 		ut->uu_defer_reclaims = 0;
1327*4f1223e8SApple OSS Distributions 
1328*4f1223e8SApple OSS Distributions 		while ((vp = vreclaims) != NULLVP) {
1329*4f1223e8SApple OSS Distributions 			vreclaims = vp->v_defer_reclaimlist;
1330*4f1223e8SApple OSS Distributions 
1331*4f1223e8SApple OSS Distributions 			/*
1332*4f1223e8SApple OSS Distributions 			 * vnode_put will drive the vnode_reclaim if
1333*4f1223e8SApple OSS Distributions 			 * we are still the only reference on this vnode
1334*4f1223e8SApple OSS Distributions 			 */
1335*4f1223e8SApple OSS Distributions 			vnode_put(vp);
1336*4f1223e8SApple OSS Distributions 		}
1337*4f1223e8SApple OSS Distributions 	}
1338*4f1223e8SApple OSS Distributions }
1339*4f1223e8SApple OSS Distributions 
1340*4f1223e8SApple OSS Distributions #if CONFIG_FIRMLINKS
1341*4f1223e8SApple OSS Distributions errno_t
vnode_setasfirmlink(vnode_t vp,vnode_t target_vp)1342*4f1223e8SApple OSS Distributions vnode_setasfirmlink(vnode_t vp, vnode_t target_vp)
1343*4f1223e8SApple OSS Distributions {
1344*4f1223e8SApple OSS Distributions 	int error = 0;
1345*4f1223e8SApple OSS Distributions 	vnode_t old_target_vp = NULLVP;
1346*4f1223e8SApple OSS Distributions 	vnode_t old_target_vp_v_fmlink = NULLVP;
1347*4f1223e8SApple OSS Distributions 	kauth_cred_t target_vp_cred = NULL;
1348*4f1223e8SApple OSS Distributions 	kauth_cred_t old_target_vp_cred = NULL;
1349*4f1223e8SApple OSS Distributions 
1350*4f1223e8SApple OSS Distributions 	if (!vp) {
1351*4f1223e8SApple OSS Distributions 		return EINVAL;
1352*4f1223e8SApple OSS Distributions 	}
1353*4f1223e8SApple OSS Distributions 
1354*4f1223e8SApple OSS Distributions 	if (target_vp) {
1355*4f1223e8SApple OSS Distributions 		if (vp->v_fmlink == target_vp) { /* Will be checked again under the name cache lock */
1356*4f1223e8SApple OSS Distributions 			return 0;
1357*4f1223e8SApple OSS Distributions 		}
1358*4f1223e8SApple OSS Distributions 
1359*4f1223e8SApple OSS Distributions 		/*
1360*4f1223e8SApple OSS Distributions 		 * Firmlink source and target will take both a usecount
1361*4f1223e8SApple OSS Distributions 		 * and kusecount on each other.
1362*4f1223e8SApple OSS Distributions 		 */
1363*4f1223e8SApple OSS Distributions 		if ((error = vnode_ref_ext(target_vp, O_EVTONLY, VNODE_REF_FORCE))) {
1364*4f1223e8SApple OSS Distributions 			return error;
1365*4f1223e8SApple OSS Distributions 		}
1366*4f1223e8SApple OSS Distributions 
1367*4f1223e8SApple OSS Distributions 		if ((error = vnode_ref_ext(vp, O_EVTONLY, VNODE_REF_FORCE))) {
1368*4f1223e8SApple OSS Distributions 			vnode_rele_ext(target_vp, O_EVTONLY, 1);
1369*4f1223e8SApple OSS Distributions 			return error;
1370*4f1223e8SApple OSS Distributions 		}
1371*4f1223e8SApple OSS Distributions 	}
1372*4f1223e8SApple OSS Distributions 
1373*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
1374*4f1223e8SApple OSS Distributions 
1375*4f1223e8SApple OSS Distributions 	old_target_vp = vp->v_fmlink;
1376*4f1223e8SApple OSS Distributions 	if (target_vp && (target_vp == old_target_vp)) {
1377*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
1378*4f1223e8SApple OSS Distributions 		return 0;
1379*4f1223e8SApple OSS Distributions 	}
1380*4f1223e8SApple OSS Distributions 	vp->v_fmlink = target_vp;
1381*4f1223e8SApple OSS Distributions 
1382*4f1223e8SApple OSS Distributions 	vnode_lock_spin(vp);
1383*4f1223e8SApple OSS Distributions 	vp->v_flag &= ~VFMLINKTARGET;
1384*4f1223e8SApple OSS Distributions 	vnode_unlock(vp);
1385*4f1223e8SApple OSS Distributions 
1386*4f1223e8SApple OSS Distributions 	if (target_vp) {
1387*4f1223e8SApple OSS Distributions 		target_vp->v_fmlink = vp;
1388*4f1223e8SApple OSS Distributions 		vnode_lock_spin(target_vp);
1389*4f1223e8SApple OSS Distributions 		target_vp->v_flag |= VFMLINKTARGET;
1390*4f1223e8SApple OSS Distributions 		vnode_unlock(target_vp);
1391*4f1223e8SApple OSS Distributions 		cache_purge_locked(vp, &target_vp_cred);
1392*4f1223e8SApple OSS Distributions 	}
1393*4f1223e8SApple OSS Distributions 
1394*4f1223e8SApple OSS Distributions 	if (old_target_vp) {
1395*4f1223e8SApple OSS Distributions 		old_target_vp_v_fmlink = old_target_vp->v_fmlink;
1396*4f1223e8SApple OSS Distributions 		old_target_vp->v_fmlink = NULLVP;
1397*4f1223e8SApple OSS Distributions 		vnode_lock_spin(old_target_vp);
1398*4f1223e8SApple OSS Distributions 		old_target_vp->v_flag &= ~VFMLINKTARGET;
1399*4f1223e8SApple OSS Distributions 		vnode_unlock(old_target_vp);
1400*4f1223e8SApple OSS Distributions 		cache_purge_locked(vp, &old_target_vp_cred);
1401*4f1223e8SApple OSS Distributions 	}
1402*4f1223e8SApple OSS Distributions 
1403*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
1404*4f1223e8SApple OSS Distributions 
1405*4f1223e8SApple OSS Distributions 	if (IS_VALID_CRED(target_vp_cred)) {
1406*4f1223e8SApple OSS Distributions 		kauth_cred_unref(&target_vp_cred);
1407*4f1223e8SApple OSS Distributions 	}
1408*4f1223e8SApple OSS Distributions 
1409*4f1223e8SApple OSS Distributions 	if (old_target_vp) {
1410*4f1223e8SApple OSS Distributions 		if (IS_VALID_CRED(old_target_vp_cred)) {
1411*4f1223e8SApple OSS Distributions 			kauth_cred_unref(&old_target_vp_cred);
1412*4f1223e8SApple OSS Distributions 		}
1413*4f1223e8SApple OSS Distributions 
1414*4f1223e8SApple OSS Distributions 		vnode_rele_ext(old_target_vp, O_EVTONLY, 1);
1415*4f1223e8SApple OSS Distributions 		if (old_target_vp_v_fmlink) {
1416*4f1223e8SApple OSS Distributions 			vnode_rele_ext(old_target_vp_v_fmlink, O_EVTONLY, 1);
1417*4f1223e8SApple OSS Distributions 		}
1418*4f1223e8SApple OSS Distributions 	}
1419*4f1223e8SApple OSS Distributions 
1420*4f1223e8SApple OSS Distributions 	return 0;
1421*4f1223e8SApple OSS Distributions }
1422*4f1223e8SApple OSS Distributions 
1423*4f1223e8SApple OSS Distributions errno_t
vnode_getfirmlink(vnode_t vp,vnode_t * target_vp)1424*4f1223e8SApple OSS Distributions vnode_getfirmlink(vnode_t vp, vnode_t *target_vp)
1425*4f1223e8SApple OSS Distributions {
1426*4f1223e8SApple OSS Distributions 	int error;
1427*4f1223e8SApple OSS Distributions 
1428*4f1223e8SApple OSS Distributions 	if (!vp->v_fmlink) {
1429*4f1223e8SApple OSS Distributions 		return ENODEV;
1430*4f1223e8SApple OSS Distributions 	}
1431*4f1223e8SApple OSS Distributions 
1432*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK_SHARED();
1433*4f1223e8SApple OSS Distributions 	if (vp->v_fmlink && !(vp->v_flag & VFMLINKTARGET) &&
1434*4f1223e8SApple OSS Distributions 	    (vnode_get(vp->v_fmlink) == 0)) {
1435*4f1223e8SApple OSS Distributions 		vnode_t tvp = vp->v_fmlink;
1436*4f1223e8SApple OSS Distributions 
1437*4f1223e8SApple OSS Distributions 		vnode_lock_spin(tvp);
1438*4f1223e8SApple OSS Distributions 		if (tvp->v_lflag & (VL_TERMINATE | VL_DEAD)) {
1439*4f1223e8SApple OSS Distributions 			vnode_unlock(tvp);
1440*4f1223e8SApple OSS Distributions 			NAME_CACHE_UNLOCK();
1441*4f1223e8SApple OSS Distributions 			vnode_put(tvp);
1442*4f1223e8SApple OSS Distributions 			return ENOENT;
1443*4f1223e8SApple OSS Distributions 		}
1444*4f1223e8SApple OSS Distributions 		if (!(tvp->v_flag & VFMLINKTARGET)) {
1445*4f1223e8SApple OSS Distributions 			panic("firmlink target for vnode %p does not have flag set", vp);
1446*4f1223e8SApple OSS Distributions 		}
1447*4f1223e8SApple OSS Distributions 		vnode_unlock(tvp);
1448*4f1223e8SApple OSS Distributions 		*target_vp = tvp;
1449*4f1223e8SApple OSS Distributions 		error = 0;
1450*4f1223e8SApple OSS Distributions 	} else {
1451*4f1223e8SApple OSS Distributions 		*target_vp = NULLVP;
1452*4f1223e8SApple OSS Distributions 		error = ENODEV;
1453*4f1223e8SApple OSS Distributions 	}
1454*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
1455*4f1223e8SApple OSS Distributions 	return error;
1456*4f1223e8SApple OSS Distributions }
1457*4f1223e8SApple OSS Distributions 
1458*4f1223e8SApple OSS Distributions #else /* CONFIG_FIRMLINKS */
1459*4f1223e8SApple OSS Distributions 
1460*4f1223e8SApple OSS Distributions errno_t
vnode_setasfirmlink(__unused vnode_t vp,__unused vnode_t src_vp)1461*4f1223e8SApple OSS Distributions vnode_setasfirmlink(__unused vnode_t vp, __unused vnode_t src_vp)
1462*4f1223e8SApple OSS Distributions {
1463*4f1223e8SApple OSS Distributions 	return ENOTSUP;
1464*4f1223e8SApple OSS Distributions }
1465*4f1223e8SApple OSS Distributions 
1466*4f1223e8SApple OSS Distributions errno_t
vnode_getfirmlink(__unused vnode_t vp,__unused vnode_t * target_vp)1467*4f1223e8SApple OSS Distributions vnode_getfirmlink(__unused vnode_t vp, __unused vnode_t *target_vp)
1468*4f1223e8SApple OSS Distributions {
1469*4f1223e8SApple OSS Distributions 	return ENOTSUP;
1470*4f1223e8SApple OSS Distributions }
1471*4f1223e8SApple OSS Distributions 
1472*4f1223e8SApple OSS Distributions #endif
1473*4f1223e8SApple OSS Distributions 
1474*4f1223e8SApple OSS Distributions /*
1475*4f1223e8SApple OSS Distributions  * Mark a vnode as having multiple hard links.  HFS makes use of this
1476*4f1223e8SApple OSS Distributions  * because it keeps track of each link separately, and wants to know
1477*4f1223e8SApple OSS Distributions  * which link was actually used.
1478*4f1223e8SApple OSS Distributions  *
1479*4f1223e8SApple OSS Distributions  * This will cause the name cache to force a VNOP_LOOKUP on the vnode
1480*4f1223e8SApple OSS Distributions  * so that HFS can post-process the lookup.  Also, volfs will call
1481*4f1223e8SApple OSS Distributions  * VNOP_GETATTR2 to determine the parent, instead of using v_parent.
1482*4f1223e8SApple OSS Distributions  */
1483*4f1223e8SApple OSS Distributions void
vnode_setmultipath(vnode_t vp)1484*4f1223e8SApple OSS Distributions vnode_setmultipath(vnode_t vp)
1485*4f1223e8SApple OSS Distributions {
1486*4f1223e8SApple OSS Distributions 	vnode_lock_spin(vp);
1487*4f1223e8SApple OSS Distributions 
1488*4f1223e8SApple OSS Distributions 	/*
1489*4f1223e8SApple OSS Distributions 	 * In theory, we're changing the vnode's identity as far as the
1490*4f1223e8SApple OSS Distributions 	 * name cache is concerned, so we ought to grab the name cache lock
1491*4f1223e8SApple OSS Distributions 	 * here.  However, there is already a race, and grabbing the name
1492*4f1223e8SApple OSS Distributions 	 * cache lock only makes the race window slightly smaller.
1493*4f1223e8SApple OSS Distributions 	 *
1494*4f1223e8SApple OSS Distributions 	 * The race happens because the vnode already exists in the name
1495*4f1223e8SApple OSS Distributions 	 * cache, and could be found by one thread before another thread
1496*4f1223e8SApple OSS Distributions 	 * can set the hard link flag.
1497*4f1223e8SApple OSS Distributions 	 */
1498*4f1223e8SApple OSS Distributions 
1499*4f1223e8SApple OSS Distributions 	vp->v_flag |= VISHARDLINK;
1500*4f1223e8SApple OSS Distributions 
1501*4f1223e8SApple OSS Distributions 	vnode_unlock(vp);
1502*4f1223e8SApple OSS Distributions }
1503*4f1223e8SApple OSS Distributions 
1504*4f1223e8SApple OSS Distributions 
1505*4f1223e8SApple OSS Distributions 
1506*4f1223e8SApple OSS Distributions /*
1507*4f1223e8SApple OSS Distributions  * backwards compatibility
1508*4f1223e8SApple OSS Distributions  */
1509*4f1223e8SApple OSS Distributions void
vnode_uncache_credentials(vnode_t vp)1510*4f1223e8SApple OSS Distributions vnode_uncache_credentials(vnode_t vp)
1511*4f1223e8SApple OSS Distributions {
1512*4f1223e8SApple OSS Distributions 	vnode_uncache_authorized_action(vp, KAUTH_INVALIDATE_CACHED_RIGHTS);
1513*4f1223e8SApple OSS Distributions }
1514*4f1223e8SApple OSS Distributions 
1515*4f1223e8SApple OSS Distributions 
1516*4f1223e8SApple OSS Distributions /*
1517*4f1223e8SApple OSS Distributions  * use the exclusive form of NAME_CACHE_LOCK to protect the update of the
1518*4f1223e8SApple OSS Distributions  * following fields in the vnode: v_cred_timestamp, v_cred, v_authorized_actions
1519*4f1223e8SApple OSS Distributions  * we use this lock so that we can look at the v_cred and v_authorized_actions
1520*4f1223e8SApple OSS Distributions  * atomically while behind the NAME_CACHE_LOCK in shared mode in 'cache_lookup_path',
1521*4f1223e8SApple OSS Distributions  * which is the super-hot path... if we are updating the authorized actions for this
1522*4f1223e8SApple OSS Distributions  * vnode, we are already in the super-slow and far less frequented path so its not
1523*4f1223e8SApple OSS Distributions  * that bad that we take the lock exclusive for this case... of course we strive
1524*4f1223e8SApple OSS Distributions  * to hold it for the minimum amount of time possible
1525*4f1223e8SApple OSS Distributions  */
1526*4f1223e8SApple OSS Distributions 
1527*4f1223e8SApple OSS Distributions void
vnode_uncache_authorized_action(vnode_t vp,kauth_action_t action)1528*4f1223e8SApple OSS Distributions vnode_uncache_authorized_action(vnode_t vp, kauth_action_t action)
1529*4f1223e8SApple OSS Distributions {
1530*4f1223e8SApple OSS Distributions 	kauth_cred_t tcred = NOCRED;
1531*4f1223e8SApple OSS Distributions 
1532*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
1533*4f1223e8SApple OSS Distributions 
1534*4f1223e8SApple OSS Distributions 	vp->v_authorized_actions &= ~action;
1535*4f1223e8SApple OSS Distributions 
1536*4f1223e8SApple OSS Distributions 	if (action == KAUTH_INVALIDATE_CACHED_RIGHTS &&
1537*4f1223e8SApple OSS Distributions 	    IS_VALID_CRED(vp->v_cred)) {
1538*4f1223e8SApple OSS Distributions 		/*
1539*4f1223e8SApple OSS Distributions 		 * Use a temp variable to avoid kauth_cred_unref() while NAME_CACHE_LOCK is held
1540*4f1223e8SApple OSS Distributions 		 */
1541*4f1223e8SApple OSS Distributions 		tcred = vnode_cred(vp);
1542*4f1223e8SApple OSS Distributions 		vp->v_cred = NOCRED;
1543*4f1223e8SApple OSS Distributions 	}
1544*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
1545*4f1223e8SApple OSS Distributions 
1546*4f1223e8SApple OSS Distributions 	if (IS_VALID_CRED(tcred)) {
1547*4f1223e8SApple OSS Distributions 		kauth_cred_unref(&tcred);
1548*4f1223e8SApple OSS Distributions 	}
1549*4f1223e8SApple OSS Distributions }
1550*4f1223e8SApple OSS Distributions 
1551*4f1223e8SApple OSS Distributions 
1552*4f1223e8SApple OSS Distributions /* disable vnode_cache_is_authorized() by setting vnode_cache_defeat */
1553*4f1223e8SApple OSS Distributions static TUNABLE(int, bootarg_vnode_cache_defeat, "-vnode_cache_defeat", 0);
1554*4f1223e8SApple OSS Distributions 
1555*4f1223e8SApple OSS Distributions boolean_t
vnode_cache_is_authorized(vnode_t vp,vfs_context_t ctx,kauth_action_t action)1556*4f1223e8SApple OSS Distributions vnode_cache_is_authorized(vnode_t vp, vfs_context_t ctx, kauth_action_t action)
1557*4f1223e8SApple OSS Distributions {
1558*4f1223e8SApple OSS Distributions 	kauth_cred_t    ucred;
1559*4f1223e8SApple OSS Distributions 	boolean_t       retval = FALSE;
1560*4f1223e8SApple OSS Distributions 
1561*4f1223e8SApple OSS Distributions 	/* Boot argument to defeat rights caching */
1562*4f1223e8SApple OSS Distributions 	if (bootarg_vnode_cache_defeat) {
1563*4f1223e8SApple OSS Distributions 		return FALSE;
1564*4f1223e8SApple OSS Distributions 	}
1565*4f1223e8SApple OSS Distributions 
1566*4f1223e8SApple OSS Distributions 	if ((vp->v_mount->mnt_kern_flag & (MNTK_AUTH_OPAQUE | MNTK_AUTH_CACHE_TTL))) {
1567*4f1223e8SApple OSS Distributions 		/*
1568*4f1223e8SApple OSS Distributions 		 * a TTL is enabled on the rights cache... handle it here
1569*4f1223e8SApple OSS Distributions 		 * a TTL of 0 indicates that no rights should be cached
1570*4f1223e8SApple OSS Distributions 		 */
1571*4f1223e8SApple OSS Distributions 		if (vp->v_mount->mnt_authcache_ttl) {
1572*4f1223e8SApple OSS Distributions 			if (!(vp->v_mount->mnt_kern_flag & MNTK_AUTH_CACHE_TTL)) {
1573*4f1223e8SApple OSS Distributions 				/*
1574*4f1223e8SApple OSS Distributions 				 * For filesystems marked only MNTK_AUTH_OPAQUE (generally network ones),
1575*4f1223e8SApple OSS Distributions 				 * we will only allow a SEARCH right on a directory to be cached...
1576*4f1223e8SApple OSS Distributions 				 * that cached right always has a default TTL associated with it
1577*4f1223e8SApple OSS Distributions 				 */
1578*4f1223e8SApple OSS Distributions 				if (action != KAUTH_VNODE_SEARCH || vp->v_type != VDIR) {
1579*4f1223e8SApple OSS Distributions 					vp = NULLVP;
1580*4f1223e8SApple OSS Distributions 				}
1581*4f1223e8SApple OSS Distributions 			}
1582*4f1223e8SApple OSS Distributions 			if (vp != NULLVP && vnode_cache_is_stale(vp) == TRUE) {
1583*4f1223e8SApple OSS Distributions 				vnode_uncache_authorized_action(vp, vp->v_authorized_actions);
1584*4f1223e8SApple OSS Distributions 				vp = NULLVP;
1585*4f1223e8SApple OSS Distributions 			}
1586*4f1223e8SApple OSS Distributions 		} else {
1587*4f1223e8SApple OSS Distributions 			vp = NULLVP;
1588*4f1223e8SApple OSS Distributions 		}
1589*4f1223e8SApple OSS Distributions 	}
1590*4f1223e8SApple OSS Distributions 	if (vp != NULLVP) {
1591*4f1223e8SApple OSS Distributions 		ucred = vfs_context_ucred(ctx);
1592*4f1223e8SApple OSS Distributions 
1593*4f1223e8SApple OSS Distributions 		NAME_CACHE_LOCK_SHARED();
1594*4f1223e8SApple OSS Distributions 
1595*4f1223e8SApple OSS Distributions 		if (vnode_cred(vp) == ucred && (vp->v_authorized_actions & action) == action) {
1596*4f1223e8SApple OSS Distributions 			retval = TRUE;
1597*4f1223e8SApple OSS Distributions 		}
1598*4f1223e8SApple OSS Distributions 
1599*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
1600*4f1223e8SApple OSS Distributions 	}
1601*4f1223e8SApple OSS Distributions 	return retval;
1602*4f1223e8SApple OSS Distributions }
1603*4f1223e8SApple OSS Distributions 
1604*4f1223e8SApple OSS Distributions 
1605*4f1223e8SApple OSS Distributions void
vnode_cache_authorized_action(vnode_t vp,vfs_context_t ctx,kauth_action_t action)1606*4f1223e8SApple OSS Distributions vnode_cache_authorized_action(vnode_t vp, vfs_context_t ctx, kauth_action_t action)
1607*4f1223e8SApple OSS Distributions {
1608*4f1223e8SApple OSS Distributions 	kauth_cred_t tcred = NOCRED;
1609*4f1223e8SApple OSS Distributions 	kauth_cred_t ucred;
1610*4f1223e8SApple OSS Distributions 	struct timeval tv;
1611*4f1223e8SApple OSS Distributions 	boolean_t ttl_active = FALSE;
1612*4f1223e8SApple OSS Distributions 
1613*4f1223e8SApple OSS Distributions 	ucred = vfs_context_ucred(ctx);
1614*4f1223e8SApple OSS Distributions 
1615*4f1223e8SApple OSS Distributions 	if (!IS_VALID_CRED(ucred) || action == 0) {
1616*4f1223e8SApple OSS Distributions 		return;
1617*4f1223e8SApple OSS Distributions 	}
1618*4f1223e8SApple OSS Distributions 
1619*4f1223e8SApple OSS Distributions 	if ((vp->v_mount->mnt_kern_flag & (MNTK_AUTH_OPAQUE | MNTK_AUTH_CACHE_TTL))) {
1620*4f1223e8SApple OSS Distributions 		/*
1621*4f1223e8SApple OSS Distributions 		 * a TTL is enabled on the rights cache... handle it here
1622*4f1223e8SApple OSS Distributions 		 * a TTL of 0 indicates that no rights should be cached
1623*4f1223e8SApple OSS Distributions 		 */
1624*4f1223e8SApple OSS Distributions 		if (vp->v_mount->mnt_authcache_ttl == 0) {
1625*4f1223e8SApple OSS Distributions 			return;
1626*4f1223e8SApple OSS Distributions 		}
1627*4f1223e8SApple OSS Distributions 
1628*4f1223e8SApple OSS Distributions 		if (!(vp->v_mount->mnt_kern_flag & MNTK_AUTH_CACHE_TTL)) {
1629*4f1223e8SApple OSS Distributions 			/*
1630*4f1223e8SApple OSS Distributions 			 * only cache SEARCH action for filesystems marked
1631*4f1223e8SApple OSS Distributions 			 * MNTK_AUTH_OPAQUE on VDIRs...
1632*4f1223e8SApple OSS Distributions 			 * the lookup_path code will time these out
1633*4f1223e8SApple OSS Distributions 			 */
1634*4f1223e8SApple OSS Distributions 			if ((action & ~KAUTH_VNODE_SEARCH) || vp->v_type != VDIR) {
1635*4f1223e8SApple OSS Distributions 				return;
1636*4f1223e8SApple OSS Distributions 			}
1637*4f1223e8SApple OSS Distributions 		}
1638*4f1223e8SApple OSS Distributions 		ttl_active = TRUE;
1639*4f1223e8SApple OSS Distributions 
1640*4f1223e8SApple OSS Distributions 		microuptime(&tv);
1641*4f1223e8SApple OSS Distributions 	}
1642*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
1643*4f1223e8SApple OSS Distributions 
1644*4f1223e8SApple OSS Distributions 	tcred = vnode_cred(vp);
1645*4f1223e8SApple OSS Distributions 	if (tcred == ucred) {
1646*4f1223e8SApple OSS Distributions 		tcred = NOCRED;
1647*4f1223e8SApple OSS Distributions 	} else {
1648*4f1223e8SApple OSS Distributions 		/*
1649*4f1223e8SApple OSS Distributions 		 * Use a temp variable to avoid kauth_cred_drop() while NAME_CACHE_LOCK is held
1650*4f1223e8SApple OSS Distributions 		 */
1651*4f1223e8SApple OSS Distributions 		kauth_cred_ref(ucred);
1652*4f1223e8SApple OSS Distributions 		vp->v_cred = ucred;
1653*4f1223e8SApple OSS Distributions 		vp->v_authorized_actions = 0;
1654*4f1223e8SApple OSS Distributions 	}
1655*4f1223e8SApple OSS Distributions 	if (ttl_active == TRUE && vp->v_authorized_actions == 0) {
1656*4f1223e8SApple OSS Distributions 		/*
1657*4f1223e8SApple OSS Distributions 		 * only reset the timestamnp on the
1658*4f1223e8SApple OSS Distributions 		 * first authorization cached after the previous
1659*4f1223e8SApple OSS Distributions 		 * timer has expired or we're switching creds...
1660*4f1223e8SApple OSS Distributions 		 * 'vnode_cache_is_authorized' will clear the
1661*4f1223e8SApple OSS Distributions 		 * authorized actions if the TTL is active and
1662*4f1223e8SApple OSS Distributions 		 * it has expired
1663*4f1223e8SApple OSS Distributions 		 */
1664*4f1223e8SApple OSS Distributions 		vp->v_cred_timestamp = (int)tv.tv_sec;
1665*4f1223e8SApple OSS Distributions 	}
1666*4f1223e8SApple OSS Distributions 	vp->v_authorized_actions |= action;
1667*4f1223e8SApple OSS Distributions 
1668*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
1669*4f1223e8SApple OSS Distributions 
1670*4f1223e8SApple OSS Distributions 	if (IS_VALID_CRED(tcred)) {
1671*4f1223e8SApple OSS Distributions 		kauth_cred_unref(&tcred);
1672*4f1223e8SApple OSS Distributions 	}
1673*4f1223e8SApple OSS Distributions }
1674*4f1223e8SApple OSS Distributions 
1675*4f1223e8SApple OSS Distributions 
1676*4f1223e8SApple OSS Distributions boolean_t
vnode_cache_is_stale(vnode_t vp)1677*4f1223e8SApple OSS Distributions vnode_cache_is_stale(vnode_t vp)
1678*4f1223e8SApple OSS Distributions {
1679*4f1223e8SApple OSS Distributions 	struct timeval  tv;
1680*4f1223e8SApple OSS Distributions 	boolean_t       retval;
1681*4f1223e8SApple OSS Distributions 
1682*4f1223e8SApple OSS Distributions 	microuptime(&tv);
1683*4f1223e8SApple OSS Distributions 
1684*4f1223e8SApple OSS Distributions 	if ((tv.tv_sec - vp->v_cred_timestamp) > vp->v_mount->mnt_authcache_ttl) {
1685*4f1223e8SApple OSS Distributions 		retval = TRUE;
1686*4f1223e8SApple OSS Distributions 	} else {
1687*4f1223e8SApple OSS Distributions 		retval = FALSE;
1688*4f1223e8SApple OSS Distributions 	}
1689*4f1223e8SApple OSS Distributions 
1690*4f1223e8SApple OSS Distributions 	return retval;
1691*4f1223e8SApple OSS Distributions }
1692*4f1223e8SApple OSS Distributions 
1693*4f1223e8SApple OSS Distributions VFS_SMR_DECLARE;
1694*4f1223e8SApple OSS Distributions 
1695*4f1223e8SApple OSS Distributions /*
1696*4f1223e8SApple OSS Distributions  * Components of nameidata (or objects it can point to) which may
1697*4f1223e8SApple OSS Distributions  * need restoring in case fast path lookup fails.
1698*4f1223e8SApple OSS Distributions  */
1699*4f1223e8SApple OSS Distributions struct nameidata_state {
1700*4f1223e8SApple OSS Distributions 	u_long  ni_loopcnt;
1701*4f1223e8SApple OSS Distributions 	char *ni_next;
1702*4f1223e8SApple OSS Distributions 	u_int ni_pathlen;
1703*4f1223e8SApple OSS Distributions 	int32_t ni_flag;
1704*4f1223e8SApple OSS Distributions 	char *cn_nameptr;
1705*4f1223e8SApple OSS Distributions 	int cn_namelen;
1706*4f1223e8SApple OSS Distributions 	int cn_flags;
1707*4f1223e8SApple OSS Distributions 	uint32_t cn_hash;
1708*4f1223e8SApple OSS Distributions };
1709*4f1223e8SApple OSS Distributions 
1710*4f1223e8SApple OSS Distributions static void
save_ndp_state(struct nameidata * ndp,struct componentname * cnp,struct nameidata_state * saved_statep)1711*4f1223e8SApple OSS Distributions save_ndp_state(struct nameidata *ndp, struct componentname *cnp, struct nameidata_state *saved_statep)
1712*4f1223e8SApple OSS Distributions {
1713*4f1223e8SApple OSS Distributions 	saved_statep->ni_loopcnt = ndp->ni_loopcnt;
1714*4f1223e8SApple OSS Distributions 	saved_statep->ni_next = ndp->ni_next;
1715*4f1223e8SApple OSS Distributions 	saved_statep->ni_pathlen = ndp->ni_pathlen;
1716*4f1223e8SApple OSS Distributions 	saved_statep->ni_flag = ndp->ni_flag;
1717*4f1223e8SApple OSS Distributions 	saved_statep->cn_nameptr = cnp->cn_nameptr;
1718*4f1223e8SApple OSS Distributions 	saved_statep->cn_namelen = cnp->cn_namelen;
1719*4f1223e8SApple OSS Distributions 	saved_statep->cn_flags = cnp->cn_flags;
1720*4f1223e8SApple OSS Distributions 	saved_statep->cn_hash = cnp->cn_hash;
1721*4f1223e8SApple OSS Distributions }
1722*4f1223e8SApple OSS Distributions 
1723*4f1223e8SApple OSS Distributions static void
restore_ndp_state(struct nameidata * ndp,struct componentname * cnp,struct nameidata_state * saved_statep)1724*4f1223e8SApple OSS Distributions restore_ndp_state(struct nameidata *ndp, struct componentname *cnp, struct nameidata_state *saved_statep)
1725*4f1223e8SApple OSS Distributions {
1726*4f1223e8SApple OSS Distributions 	ndp->ni_loopcnt = saved_statep->ni_loopcnt;
1727*4f1223e8SApple OSS Distributions 	ndp->ni_next = saved_statep->ni_next;
1728*4f1223e8SApple OSS Distributions 	ndp->ni_pathlen = saved_statep->ni_pathlen;
1729*4f1223e8SApple OSS Distributions 	ndp->ni_flag = saved_statep->ni_flag;
1730*4f1223e8SApple OSS Distributions 	cnp->cn_nameptr = saved_statep->cn_nameptr;
1731*4f1223e8SApple OSS Distributions 	cnp->cn_namelen = saved_statep->cn_namelen;
1732*4f1223e8SApple OSS Distributions 	cnp->cn_flags = saved_statep->cn_flags;
1733*4f1223e8SApple OSS Distributions 	cnp->cn_hash = saved_statep->cn_hash;
1734*4f1223e8SApple OSS Distributions }
1735*4f1223e8SApple OSS Distributions 
1736*4f1223e8SApple OSS Distributions static inline bool
vid_is_same(vnode_t vp,uint32_t vid)1737*4f1223e8SApple OSS Distributions vid_is_same(vnode_t vp, uint32_t vid)
1738*4f1223e8SApple OSS Distributions {
1739*4f1223e8SApple OSS Distributions 	return !(os_atomic_load(&vp->v_lflag, relaxed) & (VL_DRAIN | VL_TERMINATE | VL_DEAD)) && (vnode_vid(vp) == vid);
1740*4f1223e8SApple OSS Distributions }
1741*4f1223e8SApple OSS Distributions 
1742*4f1223e8SApple OSS Distributions static inline bool
can_check_v_mountedhere(vnode_t vp)1743*4f1223e8SApple OSS Distributions can_check_v_mountedhere(vnode_t vp)
1744*4f1223e8SApple OSS Distributions {
1745*4f1223e8SApple OSS Distributions 	return (os_atomic_load(&vp->v_usecount, relaxed) > 0) &&
1746*4f1223e8SApple OSS Distributions 	       (os_atomic_load(&vp->v_flag, relaxed) & VMOUNTEDHERE) &&
1747*4f1223e8SApple OSS Distributions 	       !(os_atomic_load(&vp->v_lflag, relaxed) & (VL_TERMINATE | VL_DEAD) &&
1748*4f1223e8SApple OSS Distributions 	       (vp->v_type == VDIR));
1749*4f1223e8SApple OSS Distributions }
1750*4f1223e8SApple OSS Distributions 
1751*4f1223e8SApple OSS Distributions /*
1752*4f1223e8SApple OSS Distributions  * Returns:	0			Success
1753*4f1223e8SApple OSS Distributions  *		ERECYCLE		vnode was recycled from underneath us.  Force lookup to be re-driven from namei.
1754*4f1223e8SApple OSS Distributions  *                                              This errno value should not be seen by anyone outside of the kernel.
1755*4f1223e8SApple OSS Distributions  */
1756*4f1223e8SApple OSS Distributions int
cache_lookup_path(struct nameidata * ndp,struct componentname * cnp,vnode_t dp,vfs_context_t ctx,int * dp_authorized,vnode_t last_dp)1757*4f1223e8SApple OSS Distributions cache_lookup_path(struct nameidata *ndp, struct componentname *cnp, vnode_t dp,
1758*4f1223e8SApple OSS Distributions     vfs_context_t ctx, int *dp_authorized, vnode_t last_dp)
1759*4f1223e8SApple OSS Distributions {
1760*4f1223e8SApple OSS Distributions 	struct nameidata_state saved_state;
1761*4f1223e8SApple OSS Distributions 	char            *cp;            /* pointer into pathname argument */
1762*4f1223e8SApple OSS Distributions 	uint32_t        vid;
1763*4f1223e8SApple OSS Distributions 	uint32_t        vvid = 0;       /* protected by vp != NULLVP */
1764*4f1223e8SApple OSS Distributions 	vnode_t         vp = NULLVP;
1765*4f1223e8SApple OSS Distributions 	vnode_t         tdp = NULLVP;
1766*4f1223e8SApple OSS Distributions 	vnode_t         start_dp = dp;
1767*4f1223e8SApple OSS Distributions 	kauth_cred_t    ucred;
1768*4f1223e8SApple OSS Distributions 	boolean_t       ttl_enabled = FALSE;
1769*4f1223e8SApple OSS Distributions 	struct timeval  tv;
1770*4f1223e8SApple OSS Distributions 	mount_t         mp;
1771*4f1223e8SApple OSS Distributions 	mount_t         dmp;
1772*4f1223e8SApple OSS Distributions 	unsigned int    hash;
1773*4f1223e8SApple OSS Distributions 	int             error = 0;
1774*4f1223e8SApple OSS Distributions 	boolean_t       dotdotchecked = FALSE;
1775*4f1223e8SApple OSS Distributions 	bool            locked = false;
1776*4f1223e8SApple OSS Distributions 	bool            needs_lock = false;
1777*4f1223e8SApple OSS Distributions 	bool            dp_iocount_taken = false;
1778*4f1223e8SApple OSS Distributions 
1779*4f1223e8SApple OSS Distributions #if CONFIG_TRIGGERS
1780*4f1223e8SApple OSS Distributions 	vnode_t         trigger_vp;
1781*4f1223e8SApple OSS Distributions #endif /* CONFIG_TRIGGERS */
1782*4f1223e8SApple OSS Distributions 
1783*4f1223e8SApple OSS Distributions 	ucred = vfs_context_ucred(ctx);
1784*4f1223e8SApple OSS Distributions retry:
1785*4f1223e8SApple OSS Distributions 	if (nc_smr_enabled && !needs_lock) {
1786*4f1223e8SApple OSS Distributions 		save_ndp_state(ndp, cnp, &saved_state);
1787*4f1223e8SApple OSS Distributions 		vfs_smr_enter();
1788*4f1223e8SApple OSS Distributions 	} else {
1789*4f1223e8SApple OSS Distributions 		NAME_CACHE_LOCK_SHARED();
1790*4f1223e8SApple OSS Distributions 		locked = true;
1791*4f1223e8SApple OSS Distributions 	}
1792*4f1223e8SApple OSS Distributions 	ndp->ni_flag &= ~(NAMEI_TRAILINGSLASH);
1793*4f1223e8SApple OSS Distributions 
1794*4f1223e8SApple OSS Distributions 	dmp = dp->v_mount;
1795*4f1223e8SApple OSS Distributions 	vid = dp->v_id;
1796*4f1223e8SApple OSS Distributions 	if (dmp && (dmp->mnt_kern_flag & (MNTK_AUTH_OPAQUE | MNTK_AUTH_CACHE_TTL))) {
1797*4f1223e8SApple OSS Distributions 		ttl_enabled = TRUE;
1798*4f1223e8SApple OSS Distributions 		microuptime(&tv);
1799*4f1223e8SApple OSS Distributions 	}
1800*4f1223e8SApple OSS Distributions 	for (;;) {
1801*4f1223e8SApple OSS Distributions 		/*
1802*4f1223e8SApple OSS Distributions 		 * Search a directory.
1803*4f1223e8SApple OSS Distributions 		 *
1804*4f1223e8SApple OSS Distributions 		 * The cn_hash value is for use by cache_lookup
1805*4f1223e8SApple OSS Distributions 		 * The last component of the filename is left accessible via
1806*4f1223e8SApple OSS Distributions 		 * cnp->cn_nameptr for callers that need the name.
1807*4f1223e8SApple OSS Distributions 		 */
1808*4f1223e8SApple OSS Distributions 		hash = 0;
1809*4f1223e8SApple OSS Distributions 		cp = cnp->cn_nameptr;
1810*4f1223e8SApple OSS Distributions 
1811*4f1223e8SApple OSS Distributions 		while (*cp && (*cp != '/')) {
1812*4f1223e8SApple OSS Distributions 			hash = crc32tab[((hash >> 24) ^ (unsigned char)*cp++)] ^ hash << 8;
1813*4f1223e8SApple OSS Distributions 		}
1814*4f1223e8SApple OSS Distributions 		/*
1815*4f1223e8SApple OSS Distributions 		 * the crc generator can legitimately generate
1816*4f1223e8SApple OSS Distributions 		 * a 0... however, 0 for us means that we
1817*4f1223e8SApple OSS Distributions 		 * haven't computed a hash, so use 1 instead
1818*4f1223e8SApple OSS Distributions 		 */
1819*4f1223e8SApple OSS Distributions 		if (hash == 0) {
1820*4f1223e8SApple OSS Distributions 			hash = 1;
1821*4f1223e8SApple OSS Distributions 		}
1822*4f1223e8SApple OSS Distributions 		cnp->cn_hash = hash;
1823*4f1223e8SApple OSS Distributions 		cnp->cn_namelen = (int)(cp - cnp->cn_nameptr);
1824*4f1223e8SApple OSS Distributions 
1825*4f1223e8SApple OSS Distributions 		ndp->ni_pathlen -= cnp->cn_namelen;
1826*4f1223e8SApple OSS Distributions 		ndp->ni_next = cp;
1827*4f1223e8SApple OSS Distributions 
1828*4f1223e8SApple OSS Distributions 		/*
1829*4f1223e8SApple OSS Distributions 		 * Replace multiple slashes by a single slash and trailing slashes
1830*4f1223e8SApple OSS Distributions 		 * by a null.  This must be done before VNOP_LOOKUP() because some
1831*4f1223e8SApple OSS Distributions 		 * fs's don't know about trailing slashes.  Remember if there were
1832*4f1223e8SApple OSS Distributions 		 * trailing slashes to handle symlinks, existing non-directories
1833*4f1223e8SApple OSS Distributions 		 * and non-existing files that won't be directories specially later.
1834*4f1223e8SApple OSS Distributions 		 */
1835*4f1223e8SApple OSS Distributions 		while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
1836*4f1223e8SApple OSS Distributions 			cp++;
1837*4f1223e8SApple OSS Distributions 			ndp->ni_pathlen--;
1838*4f1223e8SApple OSS Distributions 
1839*4f1223e8SApple OSS Distributions 			if (*cp == '\0') {
1840*4f1223e8SApple OSS Distributions 				ndp->ni_flag |= NAMEI_TRAILINGSLASH;
1841*4f1223e8SApple OSS Distributions 				*ndp->ni_next = '\0';
1842*4f1223e8SApple OSS Distributions 			}
1843*4f1223e8SApple OSS Distributions 		}
1844*4f1223e8SApple OSS Distributions 		ndp->ni_next = cp;
1845*4f1223e8SApple OSS Distributions 
1846*4f1223e8SApple OSS Distributions 		cnp->cn_flags &= ~(MAKEENTRY | ISLASTCN | ISDOTDOT);
1847*4f1223e8SApple OSS Distributions 
1848*4f1223e8SApple OSS Distributions 		if (*cp == '\0') {
1849*4f1223e8SApple OSS Distributions 			cnp->cn_flags |= ISLASTCN;
1850*4f1223e8SApple OSS Distributions 		}
1851*4f1223e8SApple OSS Distributions 
1852*4f1223e8SApple OSS Distributions 		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') {
1853*4f1223e8SApple OSS Distributions 			cnp->cn_flags |= ISDOTDOT;
1854*4f1223e8SApple OSS Distributions 		}
1855*4f1223e8SApple OSS Distributions 
1856*4f1223e8SApple OSS Distributions #if NAMEDRSRCFORK
1857*4f1223e8SApple OSS Distributions 		/*
1858*4f1223e8SApple OSS Distributions 		 * Process a request for a file's resource fork.
1859*4f1223e8SApple OSS Distributions 		 *
1860*4f1223e8SApple OSS Distributions 		 * Consume the _PATH_RSRCFORKSPEC suffix and tag the path.
1861*4f1223e8SApple OSS Distributions 		 */
1862*4f1223e8SApple OSS Distributions 		if ((ndp->ni_pathlen == sizeof(_PATH_RSRCFORKSPEC)) &&
1863*4f1223e8SApple OSS Distributions 		    (cp[1] == '.' && cp[2] == '.') &&
1864*4f1223e8SApple OSS Distributions 		    bcmp(cp, _PATH_RSRCFORKSPEC, sizeof(_PATH_RSRCFORKSPEC)) == 0) {
1865*4f1223e8SApple OSS Distributions 			/* Skip volfs file systems that don't support native streams. */
1866*4f1223e8SApple OSS Distributions 			if ((dmp != NULL) &&
1867*4f1223e8SApple OSS Distributions 			    (dmp->mnt_flag & MNT_DOVOLFS) &&
1868*4f1223e8SApple OSS Distributions 			    (dmp->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
1869*4f1223e8SApple OSS Distributions 				goto skiprsrcfork;
1870*4f1223e8SApple OSS Distributions 			}
1871*4f1223e8SApple OSS Distributions 			cnp->cn_flags |= CN_WANTSRSRCFORK;
1872*4f1223e8SApple OSS Distributions 			cnp->cn_flags |= ISLASTCN;
1873*4f1223e8SApple OSS Distributions 			ndp->ni_next[0] = '\0';
1874*4f1223e8SApple OSS Distributions 			ndp->ni_pathlen = 1;
1875*4f1223e8SApple OSS Distributions 		}
1876*4f1223e8SApple OSS Distributions skiprsrcfork:
1877*4f1223e8SApple OSS Distributions #endif
1878*4f1223e8SApple OSS Distributions 
1879*4f1223e8SApple OSS Distributions 		*dp_authorized = 0;
1880*4f1223e8SApple OSS Distributions 
1881*4f1223e8SApple OSS Distributions #if CONFIG_FIRMLINKS
1882*4f1223e8SApple OSS Distributions 		if ((cnp->cn_flags & ISDOTDOT) && (dp->v_flag & VFMLINKTARGET) && dp->v_fmlink) {
1883*4f1223e8SApple OSS Distributions 			/*
1884*4f1223e8SApple OSS Distributions 			 * If this is a firmlink target then dp has to be switched to the
1885*4f1223e8SApple OSS Distributions 			 * firmlink "source" before exiting this loop.
1886*4f1223e8SApple OSS Distributions 			 *
1887*4f1223e8SApple OSS Distributions 			 * For a firmlink "target", the policy is to pick the parent of the
1888*4f1223e8SApple OSS Distributions 			 * firmlink "source" as the parent. This means that you can never
1889*4f1223e8SApple OSS Distributions 			 * get to the "real" parent of firmlink target via a dotdot lookup.
1890*4f1223e8SApple OSS Distributions 			 */
1891*4f1223e8SApple OSS Distributions 			vnode_t v_fmlink = dp->v_fmlink;
1892*4f1223e8SApple OSS Distributions 			uint32_t old_vid = vid;
1893*4f1223e8SApple OSS Distributions 			mp = dmp;
1894*4f1223e8SApple OSS Distributions 			if (v_fmlink) {
1895*4f1223e8SApple OSS Distributions 				vid = v_fmlink->v_id;
1896*4f1223e8SApple OSS Distributions 				dmp = v_fmlink->v_mount;
1897*4f1223e8SApple OSS Distributions 				if ((dp->v_fmlink == v_fmlink) && dmp) {
1898*4f1223e8SApple OSS Distributions 					dp = v_fmlink;
1899*4f1223e8SApple OSS Distributions 				} else {
1900*4f1223e8SApple OSS Distributions 					vid = old_vid;
1901*4f1223e8SApple OSS Distributions 					dmp = mp;
1902*4f1223e8SApple OSS Distributions 				}
1903*4f1223e8SApple OSS Distributions 			}
1904*4f1223e8SApple OSS Distributions 		}
1905*4f1223e8SApple OSS Distributions #endif
1906*4f1223e8SApple OSS Distributions 
1907*4f1223e8SApple OSS Distributions 
1908*4f1223e8SApple OSS Distributions 		if (ttl_enabled &&
1909*4f1223e8SApple OSS Distributions 		    (dmp->mnt_authcache_ttl == 0 ||
1910*4f1223e8SApple OSS Distributions 		    ((tv.tv_sec - dp->v_cred_timestamp) > dmp->mnt_authcache_ttl))) {
1911*4f1223e8SApple OSS Distributions 			break;
1912*4f1223e8SApple OSS Distributions 		}
1913*4f1223e8SApple OSS Distributions 
1914*4f1223e8SApple OSS Distributions 		/*
1915*4f1223e8SApple OSS Distributions 		 * NAME_CACHE_LOCK holds these fields stable
1916*4f1223e8SApple OSS Distributions 		 *
1917*4f1223e8SApple OSS Distributions 		 * We can't cache KAUTH_VNODE_SEARCHBYANYONE for root correctly
1918*4f1223e8SApple OSS Distributions 		 * so we make an ugly check for root here. root is always
1919*4f1223e8SApple OSS Distributions 		 * allowed and breaking out of here only to find out that is
1920*4f1223e8SApple OSS Distributions 		 * authorized by virtue of being root is very very expensive.
1921*4f1223e8SApple OSS Distributions 		 * However, the check for not root is valid only for filesystems
1922*4f1223e8SApple OSS Distributions 		 * which use local authorization.
1923*4f1223e8SApple OSS Distributions 		 *
1924*4f1223e8SApple OSS Distributions 		 * XXX: Remove the check for root when we can reliably set
1925*4f1223e8SApple OSS Distributions 		 * KAUTH_VNODE_SEARCHBYANYONE as root.
1926*4f1223e8SApple OSS Distributions 		 */
1927*4f1223e8SApple OSS Distributions 		int v_authorized_actions = os_atomic_load(&dp->v_authorized_actions, relaxed);
1928*4f1223e8SApple OSS Distributions 		if ((vnode_cred(dp) != ucred || !(v_authorized_actions & KAUTH_VNODE_SEARCH)) &&
1929*4f1223e8SApple OSS Distributions 		    !(v_authorized_actions & KAUTH_VNODE_SEARCHBYANYONE) &&
1930*4f1223e8SApple OSS Distributions 		    (ttl_enabled || !vfs_context_issuser(ctx))) {
1931*4f1223e8SApple OSS Distributions 			break;
1932*4f1223e8SApple OSS Distributions 		}
1933*4f1223e8SApple OSS Distributions 
1934*4f1223e8SApple OSS Distributions 		/*
1935*4f1223e8SApple OSS Distributions 		 * indicate that we're allowed to traverse this directory...
1936*4f1223e8SApple OSS Distributions 		 * even if we fail the cache lookup or decide to bail for
1937*4f1223e8SApple OSS Distributions 		 * some other reason, this information is valid and is used
1938*4f1223e8SApple OSS Distributions 		 * to avoid doing a vnode_authorize before the call to VNOP_LOOKUP
1939*4f1223e8SApple OSS Distributions 		 */
1940*4f1223e8SApple OSS Distributions 		*dp_authorized = 1;
1941*4f1223e8SApple OSS Distributions 
1942*4f1223e8SApple OSS Distributions 		if ((cnp->cn_flags & (ISLASTCN | ISDOTDOT))) {
1943*4f1223e8SApple OSS Distributions 			if (cnp->cn_nameiop != LOOKUP) {
1944*4f1223e8SApple OSS Distributions 				break;
1945*4f1223e8SApple OSS Distributions 			}
1946*4f1223e8SApple OSS Distributions 			if (cnp->cn_flags & LOCKPARENT) {
1947*4f1223e8SApple OSS Distributions 				break;
1948*4f1223e8SApple OSS Distributions 			}
1949*4f1223e8SApple OSS Distributions 			if (cnp->cn_flags & NOCACHE) {
1950*4f1223e8SApple OSS Distributions 				break;
1951*4f1223e8SApple OSS Distributions 			}
1952*4f1223e8SApple OSS Distributions 
1953*4f1223e8SApple OSS Distributions 			if (cnp->cn_flags & ISDOTDOT) {
1954*4f1223e8SApple OSS Distributions 				/*
1955*4f1223e8SApple OSS Distributions 				 * Force directory hardlinks to go to
1956*4f1223e8SApple OSS Distributions 				 * file system for ".." requests.
1957*4f1223e8SApple OSS Distributions 				 */
1958*4f1223e8SApple OSS Distributions 				if ((dp->v_flag & VISHARDLINK)) {
1959*4f1223e8SApple OSS Distributions 					break;
1960*4f1223e8SApple OSS Distributions 				}
1961*4f1223e8SApple OSS Distributions 				/*
1962*4f1223e8SApple OSS Distributions 				 * Quit here only if we can't use
1963*4f1223e8SApple OSS Distributions 				 * the parent directory pointer or
1964*4f1223e8SApple OSS Distributions 				 * don't have one.  Otherwise, we'll
1965*4f1223e8SApple OSS Distributions 				 * use it below.
1966*4f1223e8SApple OSS Distributions 				 */
1967*4f1223e8SApple OSS Distributions 				if ((dp->v_flag & VROOT) ||
1968*4f1223e8SApple OSS Distributions 				    dp == ndp->ni_rootdir ||
1969*4f1223e8SApple OSS Distributions 				    dp->v_parent == NULLVP) {
1970*4f1223e8SApple OSS Distributions 					break;
1971*4f1223e8SApple OSS Distributions 				}
1972*4f1223e8SApple OSS Distributions 			}
1973*4f1223e8SApple OSS Distributions 		}
1974*4f1223e8SApple OSS Distributions 
1975*4f1223e8SApple OSS Distributions 		if ((cnp->cn_flags & CN_SKIPNAMECACHE)) {
1976*4f1223e8SApple OSS Distributions 			/*
1977*4f1223e8SApple OSS Distributions 			 * Force lookup to go to the filesystem with
1978*4f1223e8SApple OSS Distributions 			 * all cnp fields set up.
1979*4f1223e8SApple OSS Distributions 			 */
1980*4f1223e8SApple OSS Distributions 			break;
1981*4f1223e8SApple OSS Distributions 		}
1982*4f1223e8SApple OSS Distributions 
1983*4f1223e8SApple OSS Distributions 		/*
1984*4f1223e8SApple OSS Distributions 		 * "." and ".." aren't supposed to be cached, so check
1985*4f1223e8SApple OSS Distributions 		 * for them before checking the cache.
1986*4f1223e8SApple OSS Distributions 		 */
1987*4f1223e8SApple OSS Distributions 		if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
1988*4f1223e8SApple OSS Distributions 			vp = dp;
1989*4f1223e8SApple OSS Distributions 			vvid = vid;
1990*4f1223e8SApple OSS Distributions 		} else if ((cnp->cn_flags & ISDOTDOT)) {
1991*4f1223e8SApple OSS Distributions 			/*
1992*4f1223e8SApple OSS Distributions 			 * If this is a chrooted process, we need to check if
1993*4f1223e8SApple OSS Distributions 			 * the process is trying to break out of its chrooted
1994*4f1223e8SApple OSS Distributions 			 * jail. We do that by trying to determine if dp is
1995*4f1223e8SApple OSS Distributions 			 * a subdirectory of ndp->ni_rootdir. If we aren't
1996*4f1223e8SApple OSS Distributions 			 * able to determine that by the v_parent pointers, we
1997*4f1223e8SApple OSS Distributions 			 * will leave the fast path.
1998*4f1223e8SApple OSS Distributions 			 *
1999*4f1223e8SApple OSS Distributions 			 * Since this function may see dotdot components
2000*4f1223e8SApple OSS Distributions 			 * many times and it has the name cache lock held for
2001*4f1223e8SApple OSS Distributions 			 * the entire duration, we optimise this by doing this
2002*4f1223e8SApple OSS Distributions 			 * check only once per cache_lookup_path call.
2003*4f1223e8SApple OSS Distributions 			 * If dotdotchecked is set, it means we've done this
2004*4f1223e8SApple OSS Distributions 			 * check once already and don't need to do it again.
2005*4f1223e8SApple OSS Distributions 			 */
2006*4f1223e8SApple OSS Distributions 			if (!locked && (ndp->ni_rootdir != rootvnode)) {
2007*4f1223e8SApple OSS Distributions 				vfs_smr_leave();
2008*4f1223e8SApple OSS Distributions 				needs_lock = true;
2009*4f1223e8SApple OSS Distributions 				goto prep_lock_retry;
2010*4f1223e8SApple OSS Distributions 			} else if (locked && !dotdotchecked && (ndp->ni_rootdir != rootvnode)) {
2011*4f1223e8SApple OSS Distributions 				vnode_t tvp = dp;
2012*4f1223e8SApple OSS Distributions 				boolean_t defer = FALSE;
2013*4f1223e8SApple OSS Distributions 				boolean_t is_subdir = FALSE;
2014*4f1223e8SApple OSS Distributions 
2015*4f1223e8SApple OSS Distributions 				defer = cache_check_vnode_issubdir(tvp,
2016*4f1223e8SApple OSS Distributions 				    ndp->ni_rootdir, &is_subdir, &tvp);
2017*4f1223e8SApple OSS Distributions 
2018*4f1223e8SApple OSS Distributions 				if (defer) {
2019*4f1223e8SApple OSS Distributions 					/* defer to Filesystem */
2020*4f1223e8SApple OSS Distributions 					break;
2021*4f1223e8SApple OSS Distributions 				} else if (!is_subdir) {
2022*4f1223e8SApple OSS Distributions 					/*
2023*4f1223e8SApple OSS Distributions 					 * This process is trying to break  out
2024*4f1223e8SApple OSS Distributions 					 * of its chrooted jail, so all its
2025*4f1223e8SApple OSS Distributions 					 * dotdot accesses will be translated to
2026*4f1223e8SApple OSS Distributions 					 * its root directory.
2027*4f1223e8SApple OSS Distributions 					 */
2028*4f1223e8SApple OSS Distributions 					vp = ndp->ni_rootdir;
2029*4f1223e8SApple OSS Distributions 				} else {
2030*4f1223e8SApple OSS Distributions 					/*
2031*4f1223e8SApple OSS Distributions 					 * All good, let this dotdot access
2032*4f1223e8SApple OSS Distributions 					 * proceed normally
2033*4f1223e8SApple OSS Distributions 					 */
2034*4f1223e8SApple OSS Distributions 					vp = dp->v_parent;
2035*4f1223e8SApple OSS Distributions 				}
2036*4f1223e8SApple OSS Distributions 				dotdotchecked = TRUE;
2037*4f1223e8SApple OSS Distributions 			} else {
2038*4f1223e8SApple OSS Distributions 				vp = dp->v_parent;
2039*4f1223e8SApple OSS Distributions 			}
2040*4f1223e8SApple OSS Distributions 			if (!vp) {
2041*4f1223e8SApple OSS Distributions 				break;
2042*4f1223e8SApple OSS Distributions 			}
2043*4f1223e8SApple OSS Distributions 			vvid = vp->v_id;
2044*4f1223e8SApple OSS Distributions 		} else {
2045*4f1223e8SApple OSS Distributions 			if (!locked) {
2046*4f1223e8SApple OSS Distributions 				vp = cache_lookup_smr(dp, cnp, &vvid);
2047*4f1223e8SApple OSS Distributions 				if (!vid_is_same(dp, vid)) {
2048*4f1223e8SApple OSS Distributions 					vp = NULLVP;
2049*4f1223e8SApple OSS Distributions 					needs_lock = true;
2050*4f1223e8SApple OSS Distributions 					vfs_smr_leave();
2051*4f1223e8SApple OSS Distributions 					goto prep_lock_retry;
2052*4f1223e8SApple OSS Distributions 				}
2053*4f1223e8SApple OSS Distributions 			} else {
2054*4f1223e8SApple OSS Distributions 				vp = cache_lookup_locked(dp, cnp, &vvid);
2055*4f1223e8SApple OSS Distributions 			}
2056*4f1223e8SApple OSS Distributions 
2057*4f1223e8SApple OSS Distributions 
2058*4f1223e8SApple OSS Distributions 			if (!vp) {
2059*4f1223e8SApple OSS Distributions 				break;
2060*4f1223e8SApple OSS Distributions 			}
2061*4f1223e8SApple OSS Distributions 
2062*4f1223e8SApple OSS Distributions 			if ((vp->v_flag & VISHARDLINK)) {
2063*4f1223e8SApple OSS Distributions 				/*
2064*4f1223e8SApple OSS Distributions 				 * The file system wants a VNOP_LOOKUP on this vnode
2065*4f1223e8SApple OSS Distributions 				 */
2066*4f1223e8SApple OSS Distributions 				vp = NULL;
2067*4f1223e8SApple OSS Distributions 				break;
2068*4f1223e8SApple OSS Distributions 			}
2069*4f1223e8SApple OSS Distributions 
2070*4f1223e8SApple OSS Distributions #if CONFIG_FIRMLINKS
2071*4f1223e8SApple OSS Distributions 			vnode_t v_fmlink = vp->v_fmlink;
2072*4f1223e8SApple OSS Distributions 			if (v_fmlink && !(vp->v_flag & VFMLINKTARGET)) {
2073*4f1223e8SApple OSS Distributions 				if (cnp->cn_flags & CN_FIRMLINK_NOFOLLOW ||
2074*4f1223e8SApple OSS Distributions 				    ((vp->v_type != VDIR) && (vp->v_type != VLNK))) {
2075*4f1223e8SApple OSS Distributions 					/* Leave it to the filesystem */
2076*4f1223e8SApple OSS Distributions 					vp = NULLVP;
2077*4f1223e8SApple OSS Distributions 					break;
2078*4f1223e8SApple OSS Distributions 				}
2079*4f1223e8SApple OSS Distributions 
2080*4f1223e8SApple OSS Distributions 				/*
2081*4f1223e8SApple OSS Distributions 				 * Always switch to the target unless it is a VLNK
2082*4f1223e8SApple OSS Distributions 				 * and it is the last component and we have NOFOLLOW
2083*4f1223e8SApple OSS Distributions 				 * semantics
2084*4f1223e8SApple OSS Distributions 				 */
2085*4f1223e8SApple OSS Distributions 				if (vp->v_type == VDIR) {
2086*4f1223e8SApple OSS Distributions 					vp = v_fmlink;
2087*4f1223e8SApple OSS Distributions 					vvid = vnode_vid(vp);
2088*4f1223e8SApple OSS Distributions 				} else if ((cnp->cn_flags & FOLLOW) ||
2089*4f1223e8SApple OSS Distributions 				    (ndp->ni_flag & NAMEI_TRAILINGSLASH) || *ndp->ni_next == '/') {
2090*4f1223e8SApple OSS Distributions 					if (ndp->ni_loopcnt >= MAXSYMLINKS - 1) {
2091*4f1223e8SApple OSS Distributions 						vp = NULLVP;
2092*4f1223e8SApple OSS Distributions 						break;
2093*4f1223e8SApple OSS Distributions 					}
2094*4f1223e8SApple OSS Distributions 					ndp->ni_loopcnt++;
2095*4f1223e8SApple OSS Distributions 					vp = v_fmlink;
2096*4f1223e8SApple OSS Distributions 					vvid = vnode_vid(vp);
2097*4f1223e8SApple OSS Distributions 				}
2098*4f1223e8SApple OSS Distributions 			}
2099*4f1223e8SApple OSS Distributions #endif
2100*4f1223e8SApple OSS Distributions 		}
2101*4f1223e8SApple OSS Distributions 		if ((cnp->cn_flags & ISLASTCN)) {
2102*4f1223e8SApple OSS Distributions 			break;
2103*4f1223e8SApple OSS Distributions 		}
2104*4f1223e8SApple OSS Distributions 
2105*4f1223e8SApple OSS Distributions 		if (vp->v_type != VDIR) {
2106*4f1223e8SApple OSS Distributions 			if (vp->v_type != VLNK) {
2107*4f1223e8SApple OSS Distributions 				vp = NULL;
2108*4f1223e8SApple OSS Distributions 			}
2109*4f1223e8SApple OSS Distributions 			break;
2110*4f1223e8SApple OSS Distributions 		}
2111*4f1223e8SApple OSS Distributions 
2112*4f1223e8SApple OSS Distributions 		/*
2113*4f1223e8SApple OSS Distributions 		 * v_mountedhere is PAC protected which means vp has to be a VDIR
2114*4f1223e8SApple OSS Distributions 		 * to access that pointer as v_mountedhere. However, if we don't
2115*4f1223e8SApple OSS Distributions 		 * have the name cache lock or an iocount (which we won't in the
2116*4f1223e8SApple OSS Distributions 		 * !locked case) we can't guarantee that. So we try to detect it
2117*4f1223e8SApple OSS Distributions 		 * via other fields to avoid having to dereference v_mountedhere
2118*4f1223e8SApple OSS Distributions 		 * when we don't need to. Note that in theory if entire reclaim
2119*4f1223e8SApple OSS Distributions 		 * happens between the time we check can_check_v_mountedhere()
2120*4f1223e8SApple OSS Distributions 		 * and the subsequent access this will still fail but the fields
2121*4f1223e8SApple OSS Distributions 		 * we check make that exceedingly unlikely and will result in
2122*4f1223e8SApple OSS Distributions 		 * the chances of that happening being practically zero (but not
2123*4f1223e8SApple OSS Distributions 		 * zero).
2124*4f1223e8SApple OSS Distributions 		 */
2125*4f1223e8SApple OSS Distributions 		if ((locked || can_check_v_mountedhere(vp)) &&
2126*4f1223e8SApple OSS Distributions 		    (mp = vp->v_mountedhere) && ((cnp->cn_flags & NOCROSSMOUNT) == 0)) {
2127*4f1223e8SApple OSS Distributions 			vnode_t tmp_vp;
2128*4f1223e8SApple OSS Distributions 			int tmp_vid;
2129*4f1223e8SApple OSS Distributions 
2130*4f1223e8SApple OSS Distributions 			if (!(locked || vid_is_same(vp, vvid))) {
2131*4f1223e8SApple OSS Distributions 				vp = NULL;
2132*4f1223e8SApple OSS Distributions 				break;
2133*4f1223e8SApple OSS Distributions 			}
2134*4f1223e8SApple OSS Distributions 			tmp_vp = mp->mnt_realrootvp;
2135*4f1223e8SApple OSS Distributions 			tmp_vid = mp->mnt_realrootvp_vid;
2136*4f1223e8SApple OSS Distributions 			if (tmp_vp == NULLVP || mp->mnt_generation != mount_generation ||
2137*4f1223e8SApple OSS Distributions 			    tmp_vid != tmp_vp->v_id) {
2138*4f1223e8SApple OSS Distributions 				break;
2139*4f1223e8SApple OSS Distributions 			}
2140*4f1223e8SApple OSS Distributions 
2141*4f1223e8SApple OSS Distributions 			if ((mp = tmp_vp->v_mount) == NULL) {
2142*4f1223e8SApple OSS Distributions 				break;
2143*4f1223e8SApple OSS Distributions 			}
2144*4f1223e8SApple OSS Distributions 
2145*4f1223e8SApple OSS Distributions 			vp = tmp_vp;
2146*4f1223e8SApple OSS Distributions 			vvid = tmp_vid;
2147*4f1223e8SApple OSS Distributions 			dmp = mp;
2148*4f1223e8SApple OSS Distributions 			if (dmp->mnt_kern_flag & (MNTK_AUTH_OPAQUE | MNTK_AUTH_CACHE_TTL)) {
2149*4f1223e8SApple OSS Distributions 				ttl_enabled = TRUE;
2150*4f1223e8SApple OSS Distributions 				microuptime(&tv);
2151*4f1223e8SApple OSS Distributions 			} else {
2152*4f1223e8SApple OSS Distributions 				ttl_enabled = FALSE;
2153*4f1223e8SApple OSS Distributions 			}
2154*4f1223e8SApple OSS Distributions 		}
2155*4f1223e8SApple OSS Distributions 
2156*4f1223e8SApple OSS Distributions #if CONFIG_TRIGGERS
2157*4f1223e8SApple OSS Distributions 		/*
2158*4f1223e8SApple OSS Distributions 		 * After traversing all mountpoints stacked here, if we have a
2159*4f1223e8SApple OSS Distributions 		 * trigger in hand, resolve it.  Note that we don't need to
2160*4f1223e8SApple OSS Distributions 		 * leave the fast path if the mount has already happened.
2161*4f1223e8SApple OSS Distributions 		 */
2162*4f1223e8SApple OSS Distributions 		if (vp->v_resolve) {
2163*4f1223e8SApple OSS Distributions 			break;
2164*4f1223e8SApple OSS Distributions 		}
2165*4f1223e8SApple OSS Distributions #endif /* CONFIG_TRIGGERS */
2166*4f1223e8SApple OSS Distributions 
2167*4f1223e8SApple OSS Distributions 		if (!(locked || vid_is_same(vp, vvid))) {
2168*4f1223e8SApple OSS Distributions 			vp = NULL;
2169*4f1223e8SApple OSS Distributions 			break;
2170*4f1223e8SApple OSS Distributions 		}
2171*4f1223e8SApple OSS Distributions 
2172*4f1223e8SApple OSS Distributions 		dp = vp;
2173*4f1223e8SApple OSS Distributions 		vid = vvid;
2174*4f1223e8SApple OSS Distributions 		vp = NULLVP;
2175*4f1223e8SApple OSS Distributions 		vvid = 0;
2176*4f1223e8SApple OSS Distributions 
2177*4f1223e8SApple OSS Distributions 		cnp->cn_nameptr = ndp->ni_next + 1;
2178*4f1223e8SApple OSS Distributions 		ndp->ni_pathlen--;
2179*4f1223e8SApple OSS Distributions 		while (*cnp->cn_nameptr == '/') {
2180*4f1223e8SApple OSS Distributions 			cnp->cn_nameptr++;
2181*4f1223e8SApple OSS Distributions 			ndp->ni_pathlen--;
2182*4f1223e8SApple OSS Distributions 		}
2183*4f1223e8SApple OSS Distributions 	}
2184*4f1223e8SApple OSS Distributions 	if (!locked) {
2185*4f1223e8SApple OSS Distributions 		if (vp && !vnode_hold_smr(vp)) {
2186*4f1223e8SApple OSS Distributions 			vp = NULLVP;
2187*4f1223e8SApple OSS Distributions 			vvid = 0;
2188*4f1223e8SApple OSS Distributions 		}
2189*4f1223e8SApple OSS Distributions 		if (!vnode_hold_smr(dp)) {
2190*4f1223e8SApple OSS Distributions 			vfs_smr_leave();
2191*4f1223e8SApple OSS Distributions 			if (vp) {
2192*4f1223e8SApple OSS Distributions 				vnode_drop(vp);
2193*4f1223e8SApple OSS Distributions 				vp = NULLVP;
2194*4f1223e8SApple OSS Distributions 				vvid = 0;
2195*4f1223e8SApple OSS Distributions 			}
2196*4f1223e8SApple OSS Distributions 			goto prep_lock_retry;
2197*4f1223e8SApple OSS Distributions 		}
2198*4f1223e8SApple OSS Distributions 		vfs_smr_leave();
2199*4f1223e8SApple OSS Distributions 	} else {
2200*4f1223e8SApple OSS Distributions 		if (vp != NULLVP) {
2201*4f1223e8SApple OSS Distributions 			vvid = vp->v_id;
2202*4f1223e8SApple OSS Distributions 			vnode_hold(vp);
2203*4f1223e8SApple OSS Distributions 		}
2204*4f1223e8SApple OSS Distributions 		vid = dp->v_id;
2205*4f1223e8SApple OSS Distributions 
2206*4f1223e8SApple OSS Distributions 		vnode_hold(dp);
2207*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
2208*4f1223e8SApple OSS Distributions 	}
2209*4f1223e8SApple OSS Distributions 
2210*4f1223e8SApple OSS Distributions 	tdp = NULLVP;
2211*4f1223e8SApple OSS Distributions 	if (!(cnp->cn_flags & DONOTAUTH) &&
2212*4f1223e8SApple OSS Distributions 	    (vp != NULLVP) && (vp->v_type != VLNK) &&
2213*4f1223e8SApple OSS Distributions 	    ((cnp->cn_flags & (ISLASTCN | LOCKPARENT | WANTPARENT | SAVESTART)) == ISLASTCN)) {
2214*4f1223e8SApple OSS Distributions 		/*
2215*4f1223e8SApple OSS Distributions 		 * if we've got a child and it's the last component, and
2216*4f1223e8SApple OSS Distributions 		 * the lookup doesn't need to return the parent then we
2217*4f1223e8SApple OSS Distributions 		 * can skip grabbing an iocount on the parent, since all
2218*4f1223e8SApple OSS Distributions 		 * we're going to do with it is a vnode_put just before
2219*4f1223e8SApple OSS Distributions 		 * we return from 'lookup'.  If it's a symbolic link,
2220*4f1223e8SApple OSS Distributions 		 * we need the parent in case the link happens to be
2221*4f1223e8SApple OSS Distributions 		 * a relative pathname.
2222*4f1223e8SApple OSS Distributions 		 *
2223*4f1223e8SApple OSS Distributions 		 * However, we can't make this optimisation if we have to call
2224*4f1223e8SApple OSS Distributions 		 * a MAC hook.
2225*4f1223e8SApple OSS Distributions 		 */
2226*4f1223e8SApple OSS Distributions 		tdp = dp;
2227*4f1223e8SApple OSS Distributions 		dp = NULLVP;
2228*4f1223e8SApple OSS Distributions 	} else {
2229*4f1223e8SApple OSS Distributions need_dp:
2230*4f1223e8SApple OSS Distributions 		/*
2231*4f1223e8SApple OSS Distributions 		 * return the last directory we looked at
2232*4f1223e8SApple OSS Distributions 		 * with an io reference held. If it was the one passed
2233*4f1223e8SApple OSS Distributions 		 * in as a result of the last iteration of VNOP_LOOKUP,
2234*4f1223e8SApple OSS Distributions 		 * it should already hold an io ref. No need to increase ref.
2235*4f1223e8SApple OSS Distributions 		 */
2236*4f1223e8SApple OSS Distributions 		if (last_dp != dp) {
2237*4f1223e8SApple OSS Distributions 			if (dp == ndp->ni_usedvp) {
2238*4f1223e8SApple OSS Distributions 				/*
2239*4f1223e8SApple OSS Distributions 				 * if this vnode matches the one passed in via USEDVP
2240*4f1223e8SApple OSS Distributions 				 * than this context already holds an io_count... just
2241*4f1223e8SApple OSS Distributions 				 * use vnode_get to get an extra ref for lookup to play
2242*4f1223e8SApple OSS Distributions 				 * with... can't use the getwithvid variant here because
2243*4f1223e8SApple OSS Distributions 				 * it will block behind a vnode_drain which would result
2244*4f1223e8SApple OSS Distributions 				 * in a deadlock (since we already own an io_count that the
2245*4f1223e8SApple OSS Distributions 				 * vnode_drain is waiting on)... vnode_get grabs the io_count
2246*4f1223e8SApple OSS Distributions 				 * immediately w/o waiting... it always succeeds
2247*4f1223e8SApple OSS Distributions 				 */
2248*4f1223e8SApple OSS Distributions 				vnode_get(dp);
2249*4f1223e8SApple OSS Distributions 			} else if ((error = vnode_getwithvid_drainok(dp, vid))) {
2250*4f1223e8SApple OSS Distributions 				/*
2251*4f1223e8SApple OSS Distributions 				 * failure indicates the vnode
2252*4f1223e8SApple OSS Distributions 				 * changed identity or is being
2253*4f1223e8SApple OSS Distributions 				 * TERMINATED... in either case
2254*4f1223e8SApple OSS Distributions 				 * punt this lookup.
2255*4f1223e8SApple OSS Distributions 				 *
2256*4f1223e8SApple OSS Distributions 				 * don't necessarily return ENOENT, though, because
2257*4f1223e8SApple OSS Distributions 				 * we really want to go back to disk and make sure it's
2258*4f1223e8SApple OSS Distributions 				 * there or not if someone else is changing this
2259*4f1223e8SApple OSS Distributions 				 * vnode. That being said, the one case where we do want
2260*4f1223e8SApple OSS Distributions 				 * to return ENOENT is when the vnode's mount point is
2261*4f1223e8SApple OSS Distributions 				 * in the process of unmounting and we might cause a deadlock
2262*4f1223e8SApple OSS Distributions 				 * in our attempt to take an iocount. An ENODEV error return
2263*4f1223e8SApple OSS Distributions 				 * is from vnode_get* is an indication this but we change that
2264*4f1223e8SApple OSS Distributions 				 * ENOENT for upper layers.
2265*4f1223e8SApple OSS Distributions 				 */
2266*4f1223e8SApple OSS Distributions 				if (error == ENODEV) {
2267*4f1223e8SApple OSS Distributions 					error = ENOENT;
2268*4f1223e8SApple OSS Distributions 				} else {
2269*4f1223e8SApple OSS Distributions 					error = ERECYCLE;
2270*4f1223e8SApple OSS Distributions 				}
2271*4f1223e8SApple OSS Distributions 				vnode_drop(dp);
2272*4f1223e8SApple OSS Distributions 				if (vp) {
2273*4f1223e8SApple OSS Distributions 					vnode_drop(vp);
2274*4f1223e8SApple OSS Distributions 				}
2275*4f1223e8SApple OSS Distributions 				goto errorout;
2276*4f1223e8SApple OSS Distributions 			}
2277*4f1223e8SApple OSS Distributions 			dp_iocount_taken = true;
2278*4f1223e8SApple OSS Distributions 		}
2279*4f1223e8SApple OSS Distributions 		vnode_drop(dp);
2280*4f1223e8SApple OSS Distributions 	}
2281*4f1223e8SApple OSS Distributions 
2282*4f1223e8SApple OSS Distributions #if CONFIG_MACF
2283*4f1223e8SApple OSS Distributions 	/*
2284*4f1223e8SApple OSS Distributions 	 * Name cache provides authorization caching (see below)
2285*4f1223e8SApple OSS Distributions 	 * that will short circuit MAC checks in lookup().
2286*4f1223e8SApple OSS Distributions 	 * We must perform MAC check here.  On denial
2287*4f1223e8SApple OSS Distributions 	 * dp_authorized will remain 0 and second check will
2288*4f1223e8SApple OSS Distributions 	 * be perfomed in lookup().
2289*4f1223e8SApple OSS Distributions 	 */
2290*4f1223e8SApple OSS Distributions 	if (!(cnp->cn_flags & DONOTAUTH)) {
2291*4f1223e8SApple OSS Distributions 		error = mac_vnode_check_lookup(ctx, dp, cnp);
2292*4f1223e8SApple OSS Distributions 		if (error) {
2293*4f1223e8SApple OSS Distributions 			*dp_authorized = 0;
2294*4f1223e8SApple OSS Distributions 			if (dp_iocount_taken) {
2295*4f1223e8SApple OSS Distributions 				vnode_put(dp);
2296*4f1223e8SApple OSS Distributions 			}
2297*4f1223e8SApple OSS Distributions 			if (vp) {
2298*4f1223e8SApple OSS Distributions 				vnode_drop(vp);
2299*4f1223e8SApple OSS Distributions 				vp = NULLVP;
2300*4f1223e8SApple OSS Distributions 			}
2301*4f1223e8SApple OSS Distributions 			goto errorout;
2302*4f1223e8SApple OSS Distributions 		}
2303*4f1223e8SApple OSS Distributions 	}
2304*4f1223e8SApple OSS Distributions #endif /* MAC */
2305*4f1223e8SApple OSS Distributions 
2306*4f1223e8SApple OSS Distributions 	if (vp != NULLVP) {
2307*4f1223e8SApple OSS Distributions 		if ((vnode_getwithvid_drainok(vp, vvid))) {
2308*4f1223e8SApple OSS Distributions 			vnode_drop(vp);
2309*4f1223e8SApple OSS Distributions 			vp = NULLVP;
2310*4f1223e8SApple OSS Distributions 
2311*4f1223e8SApple OSS Distributions 			/*
2312*4f1223e8SApple OSS Distributions 			 * can't get reference on the vp we'd like
2313*4f1223e8SApple OSS Distributions 			 * to return... if we didn't grab a reference
2314*4f1223e8SApple OSS Distributions 			 * on the directory (due to fast path bypass),
2315*4f1223e8SApple OSS Distributions 			 * then we need to do it now... we can't return
2316*4f1223e8SApple OSS Distributions 			 * with both ni_dvp and ni_vp NULL, and no
2317*4f1223e8SApple OSS Distributions 			 * error condition
2318*4f1223e8SApple OSS Distributions 			 */
2319*4f1223e8SApple OSS Distributions 			if (dp == NULLVP) {
2320*4f1223e8SApple OSS Distributions 				dp = tdp;
2321*4f1223e8SApple OSS Distributions 				tdp = NULLVP;
2322*4f1223e8SApple OSS Distributions 				goto need_dp;
2323*4f1223e8SApple OSS Distributions 			}
2324*4f1223e8SApple OSS Distributions 		} else {
2325*4f1223e8SApple OSS Distributions 			vnode_drop(vp);
2326*4f1223e8SApple OSS Distributions 		}
2327*4f1223e8SApple OSS Distributions 		if (dp_iocount_taken && vp && (vp->v_type != VLNK) &&
2328*4f1223e8SApple OSS Distributions 		    ((cnp->cn_flags & (ISLASTCN | LOCKPARENT | WANTPARENT | SAVESTART)) == ISLASTCN)) {
2329*4f1223e8SApple OSS Distributions 			vnode_put(dp);
2330*4f1223e8SApple OSS Distributions 			dp = NULLVP;
2331*4f1223e8SApple OSS Distributions 		}
2332*4f1223e8SApple OSS Distributions 	}
2333*4f1223e8SApple OSS Distributions 
2334*4f1223e8SApple OSS Distributions 	if (tdp) {
2335*4f1223e8SApple OSS Distributions 		vnode_drop(tdp);
2336*4f1223e8SApple OSS Distributions 		tdp = NULLVP;
2337*4f1223e8SApple OSS Distributions 	}
2338*4f1223e8SApple OSS Distributions 
2339*4f1223e8SApple OSS Distributions 	ndp->ni_dvp = dp;
2340*4f1223e8SApple OSS Distributions 	ndp->ni_vp  = vp;
2341*4f1223e8SApple OSS Distributions 
2342*4f1223e8SApple OSS Distributions #if CONFIG_TRIGGERS
2343*4f1223e8SApple OSS Distributions 	trigger_vp = vp ? vp : dp;
2344*4f1223e8SApple OSS Distributions 	if ((error == 0) && (trigger_vp != NULLVP) && vnode_isdir(trigger_vp)) {
2345*4f1223e8SApple OSS Distributions 		error = vnode_trigger_resolve(trigger_vp, ndp, ctx);
2346*4f1223e8SApple OSS Distributions 		if (error) {
2347*4f1223e8SApple OSS Distributions 			if (vp) {
2348*4f1223e8SApple OSS Distributions 				vnode_put(vp);
2349*4f1223e8SApple OSS Distributions 			}
2350*4f1223e8SApple OSS Distributions 			if (dp) {
2351*4f1223e8SApple OSS Distributions 				vnode_put(dp);
2352*4f1223e8SApple OSS Distributions 			}
2353*4f1223e8SApple OSS Distributions 			goto errorout;
2354*4f1223e8SApple OSS Distributions 		}
2355*4f1223e8SApple OSS Distributions 	}
2356*4f1223e8SApple OSS Distributions #endif /* CONFIG_TRIGGERS */
2357*4f1223e8SApple OSS Distributions 
2358*4f1223e8SApple OSS Distributions errorout:
2359*4f1223e8SApple OSS Distributions 	/*
2360*4f1223e8SApple OSS Distributions 	 * If we came into cache_lookup_path after an iteration of the lookup loop that
2361*4f1223e8SApple OSS Distributions 	 * resulted in a call to VNOP_LOOKUP, then VNOP_LOOKUP returned a vnode with a io ref
2362*4f1223e8SApple OSS Distributions 	 * on it.  It is now the job of cache_lookup_path to drop the ref on this vnode
2363*4f1223e8SApple OSS Distributions 	 * when it is no longer needed.  If we get to this point, and last_dp is not NULL
2364*4f1223e8SApple OSS Distributions 	 * and it is ALSO not the dvp we want to return to caller of this function, it MUST be
2365*4f1223e8SApple OSS Distributions 	 * the case that we got to a subsequent path component and this previous vnode is
2366*4f1223e8SApple OSS Distributions 	 * no longer needed.  We can then drop the io ref on it.
2367*4f1223e8SApple OSS Distributions 	 */
2368*4f1223e8SApple OSS Distributions 	if ((last_dp != NULLVP) && (last_dp != ndp->ni_dvp)) {
2369*4f1223e8SApple OSS Distributions 		vnode_put(last_dp);
2370*4f1223e8SApple OSS Distributions 	}
2371*4f1223e8SApple OSS Distributions 
2372*4f1223e8SApple OSS Distributions 	//initialized to 0, should be the same if no error cases occurred.
2373*4f1223e8SApple OSS Distributions 	return error;
2374*4f1223e8SApple OSS Distributions 
2375*4f1223e8SApple OSS Distributions prep_lock_retry:
2376*4f1223e8SApple OSS Distributions 	restore_ndp_state(ndp, cnp, &saved_state);
2377*4f1223e8SApple OSS Distributions 	dp = start_dp;
2378*4f1223e8SApple OSS Distributions 	goto retry;
2379*4f1223e8SApple OSS Distributions }
2380*4f1223e8SApple OSS Distributions 
2381*4f1223e8SApple OSS Distributions 
2382*4f1223e8SApple OSS Distributions static vnode_t
cache_lookup_locked(vnode_t dvp,struct componentname * cnp,uint32_t * vidp)2383*4f1223e8SApple OSS Distributions cache_lookup_locked(vnode_t dvp, struct componentname *cnp, uint32_t *vidp)
2384*4f1223e8SApple OSS Distributions {
2385*4f1223e8SApple OSS Distributions 	struct namecache *ncp;
2386*4f1223e8SApple OSS Distributions 	long namelen = cnp->cn_namelen;
2387*4f1223e8SApple OSS Distributions 	unsigned int hashval = cnp->cn_hash;
2388*4f1223e8SApple OSS Distributions 
2389*4f1223e8SApple OSS Distributions 	if (nc_disabled) {
2390*4f1223e8SApple OSS Distributions 		return NULL;
2391*4f1223e8SApple OSS Distributions 	}
2392*4f1223e8SApple OSS Distributions 
2393*4f1223e8SApple OSS Distributions 	smrq_serialized_foreach(ncp, NCHHASH(dvp, cnp->cn_hash), nc_hash) {
2394*4f1223e8SApple OSS Distributions 		if ((ncp->nc_dvp == dvp) && (ncp->nc_hashval == hashval)) {
2395*4f1223e8SApple OSS Distributions 			if (strncmp(ncp->nc_name, cnp->cn_nameptr, namelen) == 0 && ncp->nc_name[namelen] == 0) {
2396*4f1223e8SApple OSS Distributions 				break;
2397*4f1223e8SApple OSS Distributions 			}
2398*4f1223e8SApple OSS Distributions 		}
2399*4f1223e8SApple OSS Distributions 	}
2400*4f1223e8SApple OSS Distributions 	if (ncp == 0) {
2401*4f1223e8SApple OSS Distributions 		/*
2402*4f1223e8SApple OSS Distributions 		 * We failed to find an entry
2403*4f1223e8SApple OSS Distributions 		 */
2404*4f1223e8SApple OSS Distributions 		NCHSTAT(ncs_miss);
2405*4f1223e8SApple OSS Distributions 		NC_SMR_STATS(clp_next_fail);
2406*4f1223e8SApple OSS Distributions 		return NULL;
2407*4f1223e8SApple OSS Distributions 	}
2408*4f1223e8SApple OSS Distributions 	NCHSTAT(ncs_goodhits);
2409*4f1223e8SApple OSS Distributions 
2410*4f1223e8SApple OSS Distributions 	if (!ncp->nc_vp) {
2411*4f1223e8SApple OSS Distributions 		return NULL;
2412*4f1223e8SApple OSS Distributions 	}
2413*4f1223e8SApple OSS Distributions 
2414*4f1223e8SApple OSS Distributions 	*vidp = ncp->nc_vid;
2415*4f1223e8SApple OSS Distributions 	NC_SMR_STATS(clp_next);
2416*4f1223e8SApple OSS Distributions 
2417*4f1223e8SApple OSS Distributions 	return ncp->nc_vp;
2418*4f1223e8SApple OSS Distributions }
2419*4f1223e8SApple OSS Distributions 
2420*4f1223e8SApple OSS Distributions static vnode_t
cache_lookup_smr(vnode_t dvp,struct componentname * cnp,uint32_t * vidp)2421*4f1223e8SApple OSS Distributions cache_lookup_smr(vnode_t dvp, struct componentname *cnp, uint32_t *vidp)
2422*4f1223e8SApple OSS Distributions {
2423*4f1223e8SApple OSS Distributions 	struct namecache *ncp;
2424*4f1223e8SApple OSS Distributions 	long namelen = cnp->cn_namelen;
2425*4f1223e8SApple OSS Distributions 	unsigned int hashval = cnp->cn_hash;
2426*4f1223e8SApple OSS Distributions 	vnode_t vp = NULLVP;
2427*4f1223e8SApple OSS Distributions 	uint32_t vid = 0;
2428*4f1223e8SApple OSS Distributions 	uint32_t counter = 1;
2429*4f1223e8SApple OSS Distributions 
2430*4f1223e8SApple OSS Distributions 	if (nc_disabled) {
2431*4f1223e8SApple OSS Distributions 		return NULL;
2432*4f1223e8SApple OSS Distributions 	}
2433*4f1223e8SApple OSS Distributions 
2434*4f1223e8SApple OSS Distributions 	smrq_entered_foreach(ncp, NCHHASH(dvp, cnp->cn_hash), nc_hash) {
2435*4f1223e8SApple OSS Distributions 		counter = os_atomic_load(&ncp->nc_counter, acquire);
2436*4f1223e8SApple OSS Distributions 		if (!(counter & NC_VALID)) {
2437*4f1223e8SApple OSS Distributions 			ncp = NULL;
2438*4f1223e8SApple OSS Distributions 			goto out;
2439*4f1223e8SApple OSS Distributions 		}
2440*4f1223e8SApple OSS Distributions 		if ((ncp->nc_dvp == dvp) && (ncp->nc_hashval == hashval)) {
2441*4f1223e8SApple OSS Distributions 			const char *nc_name =
2442*4f1223e8SApple OSS Distributions 			    os_atomic_load(&ncp->nc_name, relaxed);
2443*4f1223e8SApple OSS Distributions 			if (nc_name &&
2444*4f1223e8SApple OSS Distributions 			    strncmp(nc_name, cnp->cn_nameptr, namelen) == 0 &&
2445*4f1223e8SApple OSS Distributions 			    nc_name[namelen] == 0) {
2446*4f1223e8SApple OSS Distributions 				break;
2447*4f1223e8SApple OSS Distributions 			} else if (!nc_name) {
2448*4f1223e8SApple OSS Distributions 				ncp = NULL;
2449*4f1223e8SApple OSS Distributions 				goto out;
2450*4f1223e8SApple OSS Distributions 			}
2451*4f1223e8SApple OSS Distributions 		}
2452*4f1223e8SApple OSS Distributions 	}
2453*4f1223e8SApple OSS Distributions 
2454*4f1223e8SApple OSS Distributions 	/* We failed to find an entry */
2455*4f1223e8SApple OSS Distributions 	if (ncp == 0) {
2456*4f1223e8SApple OSS Distributions 		goto out;
2457*4f1223e8SApple OSS Distributions 	}
2458*4f1223e8SApple OSS Distributions 
2459*4f1223e8SApple OSS Distributions 	vp = ncp->nc_vp;
2460*4f1223e8SApple OSS Distributions 	vid = ncp->nc_vid;
2461*4f1223e8SApple OSS Distributions 
2462*4f1223e8SApple OSS Distributions 	/*
2463*4f1223e8SApple OSS Distributions 	 * The validity of vp and vid depends on the value of the counter being
2464*4f1223e8SApple OSS Distributions 	 * the same when we read it first in the loop and now. Anything else
2465*4f1223e8SApple OSS Distributions 	 * and we can't use this vp & vid.
2466*4f1223e8SApple OSS Distributions 	 * Hopefully this ncp wasn't reused 2 billion times between the time
2467*4f1223e8SApple OSS Distributions 	 * we read it first and when we the counter value again.
2468*4f1223e8SApple OSS Distributions 	 */
2469*4f1223e8SApple OSS Distributions 	if (os_atomic_load(&ncp->nc_counter, acquire) != counter) {
2470*4f1223e8SApple OSS Distributions 		vp = NULLVP;
2471*4f1223e8SApple OSS Distributions 		goto out;
2472*4f1223e8SApple OSS Distributions 	}
2473*4f1223e8SApple OSS Distributions 
2474*4f1223e8SApple OSS Distributions 	*vidp = vid;
2475*4f1223e8SApple OSS Distributions 	NC_SMR_STATS(clp_smr_next);
2476*4f1223e8SApple OSS Distributions 
2477*4f1223e8SApple OSS Distributions 	return vp;
2478*4f1223e8SApple OSS Distributions 
2479*4f1223e8SApple OSS Distributions out:
2480*4f1223e8SApple OSS Distributions 	NC_SMR_STATS(clp_smr_next_fail);
2481*4f1223e8SApple OSS Distributions 	return NULL;
2482*4f1223e8SApple OSS Distributions }
2483*4f1223e8SApple OSS Distributions 
2484*4f1223e8SApple OSS Distributions 
2485*4f1223e8SApple OSS Distributions unsigned int hash_string(const char *cp, int len);
2486*4f1223e8SApple OSS Distributions //
2487*4f1223e8SApple OSS Distributions // Have to take a len argument because we may only need to
2488*4f1223e8SApple OSS Distributions // hash part of a componentname.
2489*4f1223e8SApple OSS Distributions //
2490*4f1223e8SApple OSS Distributions unsigned int
hash_string(const char * cp,int len)2491*4f1223e8SApple OSS Distributions hash_string(const char *cp, int len)
2492*4f1223e8SApple OSS Distributions {
2493*4f1223e8SApple OSS Distributions 	unsigned hash = 0;
2494*4f1223e8SApple OSS Distributions 
2495*4f1223e8SApple OSS Distributions 	if (len) {
2496*4f1223e8SApple OSS Distributions 		while (len--) {
2497*4f1223e8SApple OSS Distributions 			hash = crc32tab[((hash >> 24) ^ (unsigned char)*cp++)] ^ hash << 8;
2498*4f1223e8SApple OSS Distributions 		}
2499*4f1223e8SApple OSS Distributions 	} else {
2500*4f1223e8SApple OSS Distributions 		while (*cp != '\0') {
2501*4f1223e8SApple OSS Distributions 			hash = crc32tab[((hash >> 24) ^ (unsigned char)*cp++)] ^ hash << 8;
2502*4f1223e8SApple OSS Distributions 		}
2503*4f1223e8SApple OSS Distributions 	}
2504*4f1223e8SApple OSS Distributions 	/*
2505*4f1223e8SApple OSS Distributions 	 * the crc generator can legitimately generate
2506*4f1223e8SApple OSS Distributions 	 * a 0... however, 0 for us means that we
2507*4f1223e8SApple OSS Distributions 	 * haven't computed a hash, so use 1 instead
2508*4f1223e8SApple OSS Distributions 	 */
2509*4f1223e8SApple OSS Distributions 	if (hash == 0) {
2510*4f1223e8SApple OSS Distributions 		hash = 1;
2511*4f1223e8SApple OSS Distributions 	}
2512*4f1223e8SApple OSS Distributions 	return hash;
2513*4f1223e8SApple OSS Distributions }
2514*4f1223e8SApple OSS Distributions 
2515*4f1223e8SApple OSS Distributions 
2516*4f1223e8SApple OSS Distributions /*
2517*4f1223e8SApple OSS Distributions  * Lookup an entry in the cache
2518*4f1223e8SApple OSS Distributions  *
2519*4f1223e8SApple OSS Distributions  * We don't do this if the segment name is long, simply so the cache
2520*4f1223e8SApple OSS Distributions  * can avoid holding long names (which would either waste space, or
2521*4f1223e8SApple OSS Distributions  * add greatly to the complexity).
2522*4f1223e8SApple OSS Distributions  *
2523*4f1223e8SApple OSS Distributions  * Lookup is called with dvp pointing to the directory to search,
2524*4f1223e8SApple OSS Distributions  * cnp pointing to the name of the entry being sought. If the lookup
2525*4f1223e8SApple OSS Distributions  * succeeds, the vnode is returned in *vpp, and a status of -1 is
2526*4f1223e8SApple OSS Distributions  * returned. If the lookup determines that the name does not exist
2527*4f1223e8SApple OSS Distributions  * (negative cacheing), a status of ENOENT is returned. If the lookup
2528*4f1223e8SApple OSS Distributions  * fails, a status of zero is returned.
2529*4f1223e8SApple OSS Distributions  */
2530*4f1223e8SApple OSS Distributions 
2531*4f1223e8SApple OSS Distributions static int
cache_lookup_fallback(struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp,int flags)2532*4f1223e8SApple OSS Distributions cache_lookup_fallback(struct vnode *dvp, struct vnode **vpp,
2533*4f1223e8SApple OSS Distributions     struct componentname *cnp, int flags)
2534*4f1223e8SApple OSS Distributions {
2535*4f1223e8SApple OSS Distributions 	struct namecache *ncp;
2536*4f1223e8SApple OSS Distributions 	long namelen = cnp->cn_namelen;
2537*4f1223e8SApple OSS Distributions 	unsigned int hashval = cnp->cn_hash;
2538*4f1223e8SApple OSS Distributions 	boolean_t       have_exclusive = FALSE;
2539*4f1223e8SApple OSS Distributions 	uint32_t vid;
2540*4f1223e8SApple OSS Distributions 	vnode_t  vp;
2541*4f1223e8SApple OSS Distributions 
2542*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK_SHARED();
2543*4f1223e8SApple OSS Distributions 
2544*4f1223e8SApple OSS Distributions relook:
2545*4f1223e8SApple OSS Distributions 	smrq_serialized_foreach(ncp, NCHHASH(dvp, cnp->cn_hash), nc_hash) {
2546*4f1223e8SApple OSS Distributions 		if ((ncp->nc_dvp == dvp) && (ncp->nc_hashval == hashval)) {
2547*4f1223e8SApple OSS Distributions 			if (strncmp(ncp->nc_name, cnp->cn_nameptr, namelen) == 0 && ncp->nc_name[namelen] == 0) {
2548*4f1223e8SApple OSS Distributions 				break;
2549*4f1223e8SApple OSS Distributions 			}
2550*4f1223e8SApple OSS Distributions 		}
2551*4f1223e8SApple OSS Distributions 	}
2552*4f1223e8SApple OSS Distributions 	/* We failed to find an entry */
2553*4f1223e8SApple OSS Distributions 	if (ncp == 0) {
2554*4f1223e8SApple OSS Distributions 		NCHSTAT(ncs_miss);
2555*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
2556*4f1223e8SApple OSS Distributions 		return 0;
2557*4f1223e8SApple OSS Distributions 	}
2558*4f1223e8SApple OSS Distributions 
2559*4f1223e8SApple OSS Distributions 	/* We don't want to have an entry, so dump it */
2560*4f1223e8SApple OSS Distributions 	if ((cnp->cn_flags & MAKEENTRY) == 0) {
2561*4f1223e8SApple OSS Distributions 		if (have_exclusive == TRUE) {
2562*4f1223e8SApple OSS Distributions 			NCHSTAT(ncs_badhits);
2563*4f1223e8SApple OSS Distributions 			cache_delete(ncp, 1);
2564*4f1223e8SApple OSS Distributions 			NAME_CACHE_UNLOCK();
2565*4f1223e8SApple OSS Distributions 			return 0;
2566*4f1223e8SApple OSS Distributions 		}
2567*4f1223e8SApple OSS Distributions 		if (!NAME_CACHE_LOCK_SHARED_TO_EXCLUSIVE()) {
2568*4f1223e8SApple OSS Distributions 			NAME_CACHE_LOCK();
2569*4f1223e8SApple OSS Distributions 		}
2570*4f1223e8SApple OSS Distributions 		have_exclusive = TRUE;
2571*4f1223e8SApple OSS Distributions 		goto relook;
2572*4f1223e8SApple OSS Distributions 	}
2573*4f1223e8SApple OSS Distributions 	vp = ncp->nc_vp;
2574*4f1223e8SApple OSS Distributions 
2575*4f1223e8SApple OSS Distributions 	/* We found a "positive" match, return the vnode */
2576*4f1223e8SApple OSS Distributions 	if (vp) {
2577*4f1223e8SApple OSS Distributions 		NCHSTAT(ncs_goodhits);
2578*4f1223e8SApple OSS Distributions 
2579*4f1223e8SApple OSS Distributions 		vid = ncp->nc_vid;
2580*4f1223e8SApple OSS Distributions 		vnode_hold(vp);
2581*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
2582*4f1223e8SApple OSS Distributions 
2583*4f1223e8SApple OSS Distributions 		if (vnode_getwithvid(vp, vid)) {
2584*4f1223e8SApple OSS Distributions 			vnode_drop(vp);
2585*4f1223e8SApple OSS Distributions #if COLLECT_STATS
2586*4f1223e8SApple OSS Distributions 			NAME_CACHE_LOCK();
2587*4f1223e8SApple OSS Distributions 			NCHSTAT(ncs_badvid);
2588*4f1223e8SApple OSS Distributions 			NAME_CACHE_UNLOCK();
2589*4f1223e8SApple OSS Distributions #endif
2590*4f1223e8SApple OSS Distributions 			return 0;
2591*4f1223e8SApple OSS Distributions 		}
2592*4f1223e8SApple OSS Distributions 		vnode_drop(vp);
2593*4f1223e8SApple OSS Distributions 		*vpp = vp;
2594*4f1223e8SApple OSS Distributions 		NC_SMR_STATS(cl_lock_hits);
2595*4f1223e8SApple OSS Distributions 		return -1;
2596*4f1223e8SApple OSS Distributions 	}
2597*4f1223e8SApple OSS Distributions 
2598*4f1223e8SApple OSS Distributions 	/* We found a negative match, and want to create it, so purge */
2599*4f1223e8SApple OSS Distributions 	if (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) {
2600*4f1223e8SApple OSS Distributions 		if (have_exclusive == TRUE) {
2601*4f1223e8SApple OSS Distributions 			NCHSTAT(ncs_badhits);
2602*4f1223e8SApple OSS Distributions 			cache_delete(ncp, 1);
2603*4f1223e8SApple OSS Distributions 			NAME_CACHE_UNLOCK();
2604*4f1223e8SApple OSS Distributions 			/*
2605*4f1223e8SApple OSS Distributions 			 * Even though we're purging the entry, it
2606*4f1223e8SApple OSS Distributions 			 * may be useful to the caller to know that
2607*4f1223e8SApple OSS Distributions 			 * we got a neg hit (to, for example, avoid
2608*4f1223e8SApple OSS Distributions 			 * an expensive IPC/RPC).
2609*4f1223e8SApple OSS Distributions 			 */
2610*4f1223e8SApple OSS Distributions 			return (flags & CACHE_LOOKUP_ALLHITS) ? ENOENT : 0;
2611*4f1223e8SApple OSS Distributions 		}
2612*4f1223e8SApple OSS Distributions 		if (!NAME_CACHE_LOCK_SHARED_TO_EXCLUSIVE()) {
2613*4f1223e8SApple OSS Distributions 			NAME_CACHE_LOCK();
2614*4f1223e8SApple OSS Distributions 		}
2615*4f1223e8SApple OSS Distributions 		have_exclusive = TRUE;
2616*4f1223e8SApple OSS Distributions 		goto relook;
2617*4f1223e8SApple OSS Distributions 	}
2618*4f1223e8SApple OSS Distributions 
2619*4f1223e8SApple OSS Distributions 	/*
2620*4f1223e8SApple OSS Distributions 	 * We found a "negative" match, ENOENT notifies client of this match.
2621*4f1223e8SApple OSS Distributions 	 */
2622*4f1223e8SApple OSS Distributions 	NCHSTAT(ncs_neghits);
2623*4f1223e8SApple OSS Distributions 
2624*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
2625*4f1223e8SApple OSS Distributions 	return ENOENT;
2626*4f1223e8SApple OSS Distributions }
2627*4f1223e8SApple OSS Distributions 
2628*4f1223e8SApple OSS Distributions 
2629*4f1223e8SApple OSS Distributions 
2630*4f1223e8SApple OSS Distributions /*
2631*4f1223e8SApple OSS Distributions  * Lookup an entry in the cache
2632*4f1223e8SApple OSS Distributions  *
2633*4f1223e8SApple OSS Distributions  * Lookup is called with dvp pointing to the directory to search,
2634*4f1223e8SApple OSS Distributions  * cnp pointing to the name of the entry being sought. If the lookup
2635*4f1223e8SApple OSS Distributions  * succeeds, the vnode is returned in *vpp, and a status of -1 is
2636*4f1223e8SApple OSS Distributions  * returned. If the lookup determines that the name does not exist
2637*4f1223e8SApple OSS Distributions  * (negative cacheing), a status of ENOENT is returned. If the lookup
2638*4f1223e8SApple OSS Distributions  * fails, a status of zero is returned.
2639*4f1223e8SApple OSS Distributions  */
2640*4f1223e8SApple OSS Distributions int
cache_lookup_ext(struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp,int flags)2641*4f1223e8SApple OSS Distributions cache_lookup_ext(struct vnode *dvp, struct vnode **vpp,
2642*4f1223e8SApple OSS Distributions     struct componentname *cnp, int flags)
2643*4f1223e8SApple OSS Distributions {
2644*4f1223e8SApple OSS Distributions 	struct namecache *ncp;
2645*4f1223e8SApple OSS Distributions 	long namelen = cnp->cn_namelen;
2646*4f1223e8SApple OSS Distributions 	vnode_t  vp;
2647*4f1223e8SApple OSS Distributions 	uint32_t vid = 0;
2648*4f1223e8SApple OSS Distributions 	uint32_t counter = 1;
2649*4f1223e8SApple OSS Distributions 	unsigned int hashval;
2650*4f1223e8SApple OSS Distributions 
2651*4f1223e8SApple OSS Distributions 	*vpp = NULLVP;
2652*4f1223e8SApple OSS Distributions 
2653*4f1223e8SApple OSS Distributions 	if (cnp->cn_hash == 0) {
2654*4f1223e8SApple OSS Distributions 		cnp->cn_hash = hash_string(cnp->cn_nameptr, cnp->cn_namelen);
2655*4f1223e8SApple OSS Distributions 	}
2656*4f1223e8SApple OSS Distributions 	hashval = cnp->cn_hash;
2657*4f1223e8SApple OSS Distributions 
2658*4f1223e8SApple OSS Distributions 	if (nc_disabled) {
2659*4f1223e8SApple OSS Distributions 		return 0;
2660*4f1223e8SApple OSS Distributions 	}
2661*4f1223e8SApple OSS Distributions 
2662*4f1223e8SApple OSS Distributions 	if (!nc_smr_enabled) {
2663*4f1223e8SApple OSS Distributions 		goto out_fallback;
2664*4f1223e8SApple OSS Distributions 	}
2665*4f1223e8SApple OSS Distributions 
2666*4f1223e8SApple OSS Distributions 	/* We don't want to have an entry, so dump it */
2667*4f1223e8SApple OSS Distributions 	if ((cnp->cn_flags & MAKEENTRY) == 0) {
2668*4f1223e8SApple OSS Distributions 		goto out_fallback;
2669*4f1223e8SApple OSS Distributions 	}
2670*4f1223e8SApple OSS Distributions 
2671*4f1223e8SApple OSS Distributions 	vfs_smr_enter();
2672*4f1223e8SApple OSS Distributions 
2673*4f1223e8SApple OSS Distributions 	smrq_entered_foreach(ncp, NCHHASH(dvp, cnp->cn_hash), nc_hash) {
2674*4f1223e8SApple OSS Distributions 		counter = os_atomic_load(&ncp->nc_counter, acquire);
2675*4f1223e8SApple OSS Distributions 		if (!(counter & NC_VALID)) {
2676*4f1223e8SApple OSS Distributions 			vfs_smr_leave();
2677*4f1223e8SApple OSS Distributions 			goto out_fallback;
2678*4f1223e8SApple OSS Distributions 		}
2679*4f1223e8SApple OSS Distributions 		if ((ncp->nc_dvp == dvp) && (ncp->nc_hashval == hashval)) {
2680*4f1223e8SApple OSS Distributions 			const char *nc_name =
2681*4f1223e8SApple OSS Distributions 			    os_atomic_load(&ncp->nc_name, relaxed);
2682*4f1223e8SApple OSS Distributions 			if (nc_name &&
2683*4f1223e8SApple OSS Distributions 			    strncmp(nc_name, cnp->cn_nameptr, namelen) == 0 &&
2684*4f1223e8SApple OSS Distributions 			    nc_name[namelen] == 0) {
2685*4f1223e8SApple OSS Distributions 				break;
2686*4f1223e8SApple OSS Distributions 			} else if (!nc_name) {
2687*4f1223e8SApple OSS Distributions 				vfs_smr_leave();
2688*4f1223e8SApple OSS Distributions 				goto out_fallback;
2689*4f1223e8SApple OSS Distributions 			}
2690*4f1223e8SApple OSS Distributions 		}
2691*4f1223e8SApple OSS Distributions 	}
2692*4f1223e8SApple OSS Distributions 
2693*4f1223e8SApple OSS Distributions 	/* We failed to find an entry */
2694*4f1223e8SApple OSS Distributions 	if (ncp == 0) {
2695*4f1223e8SApple OSS Distributions 		NCHSTAT(ncs_miss);
2696*4f1223e8SApple OSS Distributions 		vfs_smr_leave();
2697*4f1223e8SApple OSS Distributions 		NC_SMR_STATS(cl_smr_miss);
2698*4f1223e8SApple OSS Distributions 		return 0;
2699*4f1223e8SApple OSS Distributions 	}
2700*4f1223e8SApple OSS Distributions 
2701*4f1223e8SApple OSS Distributions 	vp = ncp->nc_vp;
2702*4f1223e8SApple OSS Distributions 	vid = ncp->nc_vid;
2703*4f1223e8SApple OSS Distributions 
2704*4f1223e8SApple OSS Distributions 	/*
2705*4f1223e8SApple OSS Distributions 	 * The validity of vp and vid depends on the value of the counter being
2706*4f1223e8SApple OSS Distributions 	 * the same when we read it first in the loop and now. Anything else
2707*4f1223e8SApple OSS Distributions 	 * and we can't use this vp & vid.
2708*4f1223e8SApple OSS Distributions 	 * Hopefully this ncp wasn't reused 2 billion times between the time
2709*4f1223e8SApple OSS Distributions 	 * we read it first and when we the counter value again.
2710*4f1223e8SApple OSS Distributions 	 */
2711*4f1223e8SApple OSS Distributions 	if (os_atomic_load(&ncp->nc_counter, acquire) != counter) {
2712*4f1223e8SApple OSS Distributions 		vfs_smr_leave();
2713*4f1223e8SApple OSS Distributions 		goto out_fallback;
2714*4f1223e8SApple OSS Distributions 	}
2715*4f1223e8SApple OSS Distributions 
2716*4f1223e8SApple OSS Distributions 	if (vp) {
2717*4f1223e8SApple OSS Distributions 		bool holdcount_acquired = vnode_hold_smr(vp);
2718*4f1223e8SApple OSS Distributions 
2719*4f1223e8SApple OSS Distributions 		vfs_smr_leave();
2720*4f1223e8SApple OSS Distributions 
2721*4f1223e8SApple OSS Distributions 		if (!holdcount_acquired) {
2722*4f1223e8SApple OSS Distributions 			goto out_fallback;
2723*4f1223e8SApple OSS Distributions 		}
2724*4f1223e8SApple OSS Distributions 
2725*4f1223e8SApple OSS Distributions 		if (vnode_getwithvid(vp, vid) != 0) {
2726*4f1223e8SApple OSS Distributions 			vnode_drop(vp);
2727*4f1223e8SApple OSS Distributions 			goto out_fallback;
2728*4f1223e8SApple OSS Distributions 		}
2729*4f1223e8SApple OSS Distributions 		vnode_drop(vp);
2730*4f1223e8SApple OSS Distributions 		NCHSTAT(ncs_goodhits);
2731*4f1223e8SApple OSS Distributions 
2732*4f1223e8SApple OSS Distributions 		*vpp = vp;
2733*4f1223e8SApple OSS Distributions 		NC_SMR_STATS(cl_smr_hits);
2734*4f1223e8SApple OSS Distributions 		return -1;
2735*4f1223e8SApple OSS Distributions 	}
2736*4f1223e8SApple OSS Distributions 
2737*4f1223e8SApple OSS Distributions 	vfs_smr_leave();
2738*4f1223e8SApple OSS Distributions 
2739*4f1223e8SApple OSS Distributions 	/* We found a negative match, and want to create it, so purge */
2740*4f1223e8SApple OSS Distributions 	if (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) {
2741*4f1223e8SApple OSS Distributions 		goto out_fallback;
2742*4f1223e8SApple OSS Distributions 	}
2743*4f1223e8SApple OSS Distributions 
2744*4f1223e8SApple OSS Distributions 	/*
2745*4f1223e8SApple OSS Distributions 	 * We found a "negative" match, ENOENT notifies client of this match.
2746*4f1223e8SApple OSS Distributions 	 */
2747*4f1223e8SApple OSS Distributions 	NCHSTAT(ncs_neghits);
2748*4f1223e8SApple OSS Distributions 	NC_SMR_STATS(cl_smr_negative_hits);
2749*4f1223e8SApple OSS Distributions 	return ENOENT;
2750*4f1223e8SApple OSS Distributions 
2751*4f1223e8SApple OSS Distributions out_fallback:
2752*4f1223e8SApple OSS Distributions 	NC_SMR_STATS(cl_smr_fallback);
2753*4f1223e8SApple OSS Distributions 	return cache_lookup_fallback(dvp, vpp, cnp, flags);
2754*4f1223e8SApple OSS Distributions }
2755*4f1223e8SApple OSS Distributions 
2756*4f1223e8SApple OSS Distributions int
cache_lookup(struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp)2757*4f1223e8SApple OSS Distributions cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
2758*4f1223e8SApple OSS Distributions {
2759*4f1223e8SApple OSS Distributions 	return cache_lookup_ext(dvp, vpp, cnp, 0);
2760*4f1223e8SApple OSS Distributions }
2761*4f1223e8SApple OSS Distributions 
2762*4f1223e8SApple OSS Distributions const char *
cache_enter_create(vnode_t dvp,vnode_t vp,struct componentname * cnp)2763*4f1223e8SApple OSS Distributions cache_enter_create(vnode_t dvp, vnode_t vp, struct componentname *cnp)
2764*4f1223e8SApple OSS Distributions {
2765*4f1223e8SApple OSS Distributions 	const char *strname;
2766*4f1223e8SApple OSS Distributions 
2767*4f1223e8SApple OSS Distributions 	if (cnp->cn_hash == 0) {
2768*4f1223e8SApple OSS Distributions 		cnp->cn_hash = hash_string(cnp->cn_nameptr, cnp->cn_namelen);
2769*4f1223e8SApple OSS Distributions 	}
2770*4f1223e8SApple OSS Distributions 
2771*4f1223e8SApple OSS Distributions 	/*
2772*4f1223e8SApple OSS Distributions 	 * grab 2 references on the string entered
2773*4f1223e8SApple OSS Distributions 	 * one for the cache_enter_locked to consume
2774*4f1223e8SApple OSS Distributions 	 * and the second to be consumed by v_name (vnode_create call point)
2775*4f1223e8SApple OSS Distributions 	 */
2776*4f1223e8SApple OSS Distributions 	strname = add_name_internal(cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_hash, TRUE, 0);
2777*4f1223e8SApple OSS Distributions 
2778*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
2779*4f1223e8SApple OSS Distributions 
2780*4f1223e8SApple OSS Distributions 	cache_enter_locked(dvp, vp, cnp, strname);
2781*4f1223e8SApple OSS Distributions 
2782*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
2783*4f1223e8SApple OSS Distributions 
2784*4f1223e8SApple OSS Distributions 	return strname;
2785*4f1223e8SApple OSS Distributions }
2786*4f1223e8SApple OSS Distributions 
2787*4f1223e8SApple OSS Distributions 
2788*4f1223e8SApple OSS Distributions /*
2789*4f1223e8SApple OSS Distributions  * Add an entry to the cache...
2790*4f1223e8SApple OSS Distributions  * but first check to see if the directory
2791*4f1223e8SApple OSS Distributions  * that this entry is to be associated with has
2792*4f1223e8SApple OSS Distributions  * had any cache_purges applied since we took
2793*4f1223e8SApple OSS Distributions  * our identity snapshot... this check needs to
2794*4f1223e8SApple OSS Distributions  * be done behind the name cache lock
2795*4f1223e8SApple OSS Distributions  */
2796*4f1223e8SApple OSS Distributions void
cache_enter_with_gen(struct vnode * dvp,struct vnode * vp,struct componentname * cnp,int gen)2797*4f1223e8SApple OSS Distributions cache_enter_with_gen(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, int gen)
2798*4f1223e8SApple OSS Distributions {
2799*4f1223e8SApple OSS Distributions 	if (cnp->cn_hash == 0) {
2800*4f1223e8SApple OSS Distributions 		cnp->cn_hash = hash_string(cnp->cn_nameptr, cnp->cn_namelen);
2801*4f1223e8SApple OSS Distributions 	}
2802*4f1223e8SApple OSS Distributions 
2803*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
2804*4f1223e8SApple OSS Distributions 
2805*4f1223e8SApple OSS Distributions 	if (dvp->v_nc_generation == gen) {
2806*4f1223e8SApple OSS Distributions 		(void)cache_enter_locked(dvp, vp, cnp, NULL);
2807*4f1223e8SApple OSS Distributions 	}
2808*4f1223e8SApple OSS Distributions 
2809*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
2810*4f1223e8SApple OSS Distributions }
2811*4f1223e8SApple OSS Distributions 
2812*4f1223e8SApple OSS Distributions 
2813*4f1223e8SApple OSS Distributions /*
2814*4f1223e8SApple OSS Distributions  * Add an entry to the cache.
2815*4f1223e8SApple OSS Distributions  */
2816*4f1223e8SApple OSS Distributions void
cache_enter(struct vnode * dvp,struct vnode * vp,struct componentname * cnp)2817*4f1223e8SApple OSS Distributions cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
2818*4f1223e8SApple OSS Distributions {
2819*4f1223e8SApple OSS Distributions 	const char *strname;
2820*4f1223e8SApple OSS Distributions 
2821*4f1223e8SApple OSS Distributions 	if (cnp->cn_hash == 0) {
2822*4f1223e8SApple OSS Distributions 		cnp->cn_hash = hash_string(cnp->cn_nameptr, cnp->cn_namelen);
2823*4f1223e8SApple OSS Distributions 	}
2824*4f1223e8SApple OSS Distributions 
2825*4f1223e8SApple OSS Distributions 	/*
2826*4f1223e8SApple OSS Distributions 	 * grab 1 reference on the string entered
2827*4f1223e8SApple OSS Distributions 	 * for the cache_enter_locked to consume
2828*4f1223e8SApple OSS Distributions 	 */
2829*4f1223e8SApple OSS Distributions 	strname = add_name_internal(cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_hash, FALSE, 0);
2830*4f1223e8SApple OSS Distributions 
2831*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
2832*4f1223e8SApple OSS Distributions 
2833*4f1223e8SApple OSS Distributions 	cache_enter_locked(dvp, vp, cnp, strname);
2834*4f1223e8SApple OSS Distributions 
2835*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
2836*4f1223e8SApple OSS Distributions }
2837*4f1223e8SApple OSS Distributions 
2838*4f1223e8SApple OSS Distributions 
2839*4f1223e8SApple OSS Distributions static void
cache_enter_locked(struct vnode * dvp,struct vnode * vp,struct componentname * cnp,const char * strname)2840*4f1223e8SApple OSS Distributions cache_enter_locked(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, const char *strname)
2841*4f1223e8SApple OSS Distributions {
2842*4f1223e8SApple OSS Distributions 	struct namecache *ncp, *negp;
2843*4f1223e8SApple OSS Distributions 	struct smrq_list_head  *ncpp;
2844*4f1223e8SApple OSS Distributions 
2845*4f1223e8SApple OSS Distributions 	if (nc_disabled) {
2846*4f1223e8SApple OSS Distributions 		return;
2847*4f1223e8SApple OSS Distributions 	}
2848*4f1223e8SApple OSS Distributions 
2849*4f1223e8SApple OSS Distributions 	/*
2850*4f1223e8SApple OSS Distributions 	 * if the entry is for -ve caching vp is null
2851*4f1223e8SApple OSS Distributions 	 */
2852*4f1223e8SApple OSS Distributions 	if ((vp != NULLVP) && (LIST_FIRST(&vp->v_nclinks))) {
2853*4f1223e8SApple OSS Distributions 		/*
2854*4f1223e8SApple OSS Distributions 		 * someone beat us to the punch..
2855*4f1223e8SApple OSS Distributions 		 * this vnode is already in the cache
2856*4f1223e8SApple OSS Distributions 		 */
2857*4f1223e8SApple OSS Distributions 		if (strname != NULL) {
2858*4f1223e8SApple OSS Distributions 			vfs_removename(strname);
2859*4f1223e8SApple OSS Distributions 		}
2860*4f1223e8SApple OSS Distributions 		return;
2861*4f1223e8SApple OSS Distributions 	}
2862*4f1223e8SApple OSS Distributions 	/*
2863*4f1223e8SApple OSS Distributions 	 * We allocate a new entry if we are less than the maximum
2864*4f1223e8SApple OSS Distributions 	 * allowed and the one at the front of the list is in use.
2865*4f1223e8SApple OSS Distributions 	 * Otherwise we use the one at the front of the list.
2866*4f1223e8SApple OSS Distributions 	 */
2867*4f1223e8SApple OSS Distributions 	if (numcache < desiredNodes &&
2868*4f1223e8SApple OSS Distributions 	    ((ncp = nchead.tqh_first) == NULL ||
2869*4f1223e8SApple OSS Distributions 	    (ncp->nc_counter & NC_VALID))) {
2870*4f1223e8SApple OSS Distributions 		/*
2871*4f1223e8SApple OSS Distributions 		 * Allocate one more entry
2872*4f1223e8SApple OSS Distributions 		 */
2873*4f1223e8SApple OSS Distributions 		if (nc_smr_enabled) {
2874*4f1223e8SApple OSS Distributions 			ncp = zalloc_smr(namecache_zone, Z_WAITOK_ZERO_NOFAIL);
2875*4f1223e8SApple OSS Distributions 		} else {
2876*4f1223e8SApple OSS Distributions 			ncp = zalloc(namecache_zone);
2877*4f1223e8SApple OSS Distributions 		}
2878*4f1223e8SApple OSS Distributions 		ncp->nc_counter = 0;
2879*4f1223e8SApple OSS Distributions 		numcache++;
2880*4f1223e8SApple OSS Distributions 	} else {
2881*4f1223e8SApple OSS Distributions 		/*
2882*4f1223e8SApple OSS Distributions 		 * reuse an old entry
2883*4f1223e8SApple OSS Distributions 		 */
2884*4f1223e8SApple OSS Distributions 		ncp = TAILQ_FIRST(&nchead);
2885*4f1223e8SApple OSS Distributions 		TAILQ_REMOVE(&nchead, ncp, nc_entry);
2886*4f1223e8SApple OSS Distributions 
2887*4f1223e8SApple OSS Distributions 		if (ncp->nc_counter & NC_VALID) {
2888*4f1223e8SApple OSS Distributions 			/*
2889*4f1223e8SApple OSS Distributions 			 * still in use... we need to
2890*4f1223e8SApple OSS Distributions 			 * delete it before re-using it
2891*4f1223e8SApple OSS Distributions 			 */
2892*4f1223e8SApple OSS Distributions 			NCHSTAT(ncs_stolen);
2893*4f1223e8SApple OSS Distributions 			cache_delete(ncp, 0);
2894*4f1223e8SApple OSS Distributions 		}
2895*4f1223e8SApple OSS Distributions 	}
2896*4f1223e8SApple OSS Distributions 	NCHSTAT(ncs_enters);
2897*4f1223e8SApple OSS Distributions 
2898*4f1223e8SApple OSS Distributions 	/*
2899*4f1223e8SApple OSS Distributions 	 * Fill in cache info, if vp is NULL this is a "negative" cache entry.
2900*4f1223e8SApple OSS Distributions 	 */
2901*4f1223e8SApple OSS Distributions 	if (vp) {
2902*4f1223e8SApple OSS Distributions 		ncp->nc_vid = vnode_vid(vp);
2903*4f1223e8SApple OSS Distributions 		vnode_hold(vp);
2904*4f1223e8SApple OSS Distributions 	}
2905*4f1223e8SApple OSS Distributions 	ncp->nc_vp = vp;
2906*4f1223e8SApple OSS Distributions 	ncp->nc_dvp = dvp;
2907*4f1223e8SApple OSS Distributions 	ncp->nc_hashval = cnp->cn_hash;
2908*4f1223e8SApple OSS Distributions 
2909*4f1223e8SApple OSS Distributions 	if (strname == NULL) {
2910*4f1223e8SApple OSS Distributions 		ncp->nc_name = add_name_internal(cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_hash, FALSE, 0);
2911*4f1223e8SApple OSS Distributions 	} else {
2912*4f1223e8SApple OSS Distributions 		ncp->nc_name = strname;
2913*4f1223e8SApple OSS Distributions 	}
2914*4f1223e8SApple OSS Distributions 
2915*4f1223e8SApple OSS Distributions 	//
2916*4f1223e8SApple OSS Distributions 	// If the bytes of the name associated with the vnode differ,
2917*4f1223e8SApple OSS Distributions 	// use the name associated with the vnode since the file system
2918*4f1223e8SApple OSS Distributions 	// may have set that explicitly in the case of a lookup on a
2919*4f1223e8SApple OSS Distributions 	// case-insensitive file system where the case of the looked up
2920*4f1223e8SApple OSS Distributions 	// name differs from what is on disk.  For more details, see:
2921*4f1223e8SApple OSS Distributions 	//   <rdar://problem/8044697> FSEvents doesn't always decompose diacritical unicode chars in the paths of the changed directories
2922*4f1223e8SApple OSS Distributions 	//
2923*4f1223e8SApple OSS Distributions 	const char *vn_name = vp ? vp->v_name : NULL;
2924*4f1223e8SApple OSS Distributions 	unsigned int len = vn_name ? (unsigned int)strlen(vn_name) : 0;
2925*4f1223e8SApple OSS Distributions 	if (vn_name && ncp && ncp->nc_name && strncmp(ncp->nc_name, vn_name, len) != 0) {
2926*4f1223e8SApple OSS Distributions 		unsigned int hash = hash_string(vn_name, len);
2927*4f1223e8SApple OSS Distributions 
2928*4f1223e8SApple OSS Distributions 		vfs_removename(ncp->nc_name);
2929*4f1223e8SApple OSS Distributions 		ncp->nc_name = add_name_internal(vn_name, len, hash, FALSE, 0);
2930*4f1223e8SApple OSS Distributions 		ncp->nc_hashval = hash;
2931*4f1223e8SApple OSS Distributions 	}
2932*4f1223e8SApple OSS Distributions 
2933*4f1223e8SApple OSS Distributions 	/*
2934*4f1223e8SApple OSS Distributions 	 * make us the newest entry in the cache
2935*4f1223e8SApple OSS Distributions 	 * i.e. we'll be the last to be stolen
2936*4f1223e8SApple OSS Distributions 	 */
2937*4f1223e8SApple OSS Distributions 	TAILQ_INSERT_TAIL(&nchead, ncp, nc_entry);
2938*4f1223e8SApple OSS Distributions 
2939*4f1223e8SApple OSS Distributions 	ncpp = NCHHASH(dvp, cnp->cn_hash);
2940*4f1223e8SApple OSS Distributions #if DIAGNOSTIC
2941*4f1223e8SApple OSS Distributions 	{
2942*4f1223e8SApple OSS Distributions 		struct namecache *p;
2943*4f1223e8SApple OSS Distributions 
2944*4f1223e8SApple OSS Distributions 		smrq_serialized_foreach(p, ncpp, nc_hash) {
2945*4f1223e8SApple OSS Distributions 			if (p == ncp) {
2946*4f1223e8SApple OSS Distributions 				panic("cache_enter: duplicate");
2947*4f1223e8SApple OSS Distributions 			}
2948*4f1223e8SApple OSS Distributions 		}
2949*4f1223e8SApple OSS Distributions 	}
2950*4f1223e8SApple OSS Distributions #endif
2951*4f1223e8SApple OSS Distributions 	/*
2952*4f1223e8SApple OSS Distributions 	 * make us available to be found via lookup
2953*4f1223e8SApple OSS Distributions 	 */
2954*4f1223e8SApple OSS Distributions 	smrq_serialized_insert_head(ncpp, &ncp->nc_hash);
2955*4f1223e8SApple OSS Distributions 
2956*4f1223e8SApple OSS Distributions 	if (vp) {
2957*4f1223e8SApple OSS Distributions 		/*
2958*4f1223e8SApple OSS Distributions 		 * add to the list of name cache entries
2959*4f1223e8SApple OSS Distributions 		 * that point at vp
2960*4f1223e8SApple OSS Distributions 		 */
2961*4f1223e8SApple OSS Distributions 		LIST_INSERT_HEAD(&vp->v_nclinks, ncp, nc_un.nc_link);
2962*4f1223e8SApple OSS Distributions 	} else {
2963*4f1223e8SApple OSS Distributions 		/*
2964*4f1223e8SApple OSS Distributions 		 * this is a negative cache entry (vp == NULL)
2965*4f1223e8SApple OSS Distributions 		 * stick it on the negative cache list.
2966*4f1223e8SApple OSS Distributions 		 */
2967*4f1223e8SApple OSS Distributions 		TAILQ_INSERT_TAIL(&neghead, ncp, nc_un.nc_negentry);
2968*4f1223e8SApple OSS Distributions 
2969*4f1223e8SApple OSS Distributions 		ncs_negtotal++;
2970*4f1223e8SApple OSS Distributions 
2971*4f1223e8SApple OSS Distributions 		if (ncs_negtotal > desiredNegNodes) {
2972*4f1223e8SApple OSS Distributions 			/*
2973*4f1223e8SApple OSS Distributions 			 * if we've reached our desired limit
2974*4f1223e8SApple OSS Distributions 			 * of negative cache entries, delete
2975*4f1223e8SApple OSS Distributions 			 * the oldest
2976*4f1223e8SApple OSS Distributions 			 */
2977*4f1223e8SApple OSS Distributions 			negp = TAILQ_FIRST(&neghead);
2978*4f1223e8SApple OSS Distributions 			cache_delete(negp, 1);
2979*4f1223e8SApple OSS Distributions 		}
2980*4f1223e8SApple OSS Distributions 	}
2981*4f1223e8SApple OSS Distributions 
2982*4f1223e8SApple OSS Distributions 	/*
2983*4f1223e8SApple OSS Distributions 	 * add us to the list of name cache entries that
2984*4f1223e8SApple OSS Distributions 	 * are children of dvp
2985*4f1223e8SApple OSS Distributions 	 */
2986*4f1223e8SApple OSS Distributions 	if (vp) {
2987*4f1223e8SApple OSS Distributions 		TAILQ_INSERT_TAIL(&dvp->v_ncchildren, ncp, nc_child);
2988*4f1223e8SApple OSS Distributions 	} else {
2989*4f1223e8SApple OSS Distributions 		TAILQ_INSERT_HEAD(&dvp->v_ncchildren, ncp, nc_child);
2990*4f1223e8SApple OSS Distributions 	}
2991*4f1223e8SApple OSS Distributions 
2992*4f1223e8SApple OSS Distributions 	/*
2993*4f1223e8SApple OSS Distributions 	 * nc_counter represents a sequence counter and 1 bit valid flag.
2994*4f1223e8SApple OSS Distributions 	 * When the counter value is odd, it represents a valid and in use
2995*4f1223e8SApple OSS Distributions 	 * namecache structure. We increment the value on every state transition
2996*4f1223e8SApple OSS Distributions 	 * (invalid to valid (here) and valid to invalid (in cache delete).
2997*4f1223e8SApple OSS Distributions 	 * Lockless readers have to read the value before reading other fields
2998*4f1223e8SApple OSS Distributions 	 * and ensure that the field is valid and remains the same after the fields
2999*4f1223e8SApple OSS Distributions 	 * have been read.
3000*4f1223e8SApple OSS Distributions 	 */
3001*4f1223e8SApple OSS Distributions 	uint32_t old_count = os_atomic_inc_orig(&ncp->nc_counter, release);
3002*4f1223e8SApple OSS Distributions 	if (old_count & NC_VALID) {
3003*4f1223e8SApple OSS Distributions 		/* This is a invalid to valid transition */
3004*4f1223e8SApple OSS Distributions 		panic("Incorrect state for old nc_counter(%d), should be even", old_count);
3005*4f1223e8SApple OSS Distributions 	}
3006*4f1223e8SApple OSS Distributions }
3007*4f1223e8SApple OSS Distributions 
3008*4f1223e8SApple OSS Distributions 
3009*4f1223e8SApple OSS Distributions /*
3010*4f1223e8SApple OSS Distributions  * Initialize CRC-32 remainder table.
3011*4f1223e8SApple OSS Distributions  */
3012*4f1223e8SApple OSS Distributions static void
init_crc32(void)3013*4f1223e8SApple OSS Distributions init_crc32(void)
3014*4f1223e8SApple OSS Distributions {
3015*4f1223e8SApple OSS Distributions 	/*
3016*4f1223e8SApple OSS Distributions 	 * the CRC-32 generator polynomial is:
3017*4f1223e8SApple OSS Distributions 	 *   x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^10
3018*4f1223e8SApple OSS Distributions 	 *        + x^8  + x^7  + x^5  + x^4  + x^2  + x + 1
3019*4f1223e8SApple OSS Distributions 	 */
3020*4f1223e8SApple OSS Distributions 	unsigned int crc32_polynomial = 0x04c11db7;
3021*4f1223e8SApple OSS Distributions 	unsigned int i, j;
3022*4f1223e8SApple OSS Distributions 
3023*4f1223e8SApple OSS Distributions 	/*
3024*4f1223e8SApple OSS Distributions 	 * pre-calculate the CRC-32 remainder for each possible octet encoding
3025*4f1223e8SApple OSS Distributions 	 */
3026*4f1223e8SApple OSS Distributions 	for (i = 0; i < 256; i++) {
3027*4f1223e8SApple OSS Distributions 		unsigned int crc_rem = i << 24;
3028*4f1223e8SApple OSS Distributions 
3029*4f1223e8SApple OSS Distributions 		for (j = 0; j < 8; j++) {
3030*4f1223e8SApple OSS Distributions 			if (crc_rem & 0x80000000) {
3031*4f1223e8SApple OSS Distributions 				crc_rem = (crc_rem << 1) ^ crc32_polynomial;
3032*4f1223e8SApple OSS Distributions 			} else {
3033*4f1223e8SApple OSS Distributions 				crc_rem = (crc_rem << 1);
3034*4f1223e8SApple OSS Distributions 			}
3035*4f1223e8SApple OSS Distributions 		}
3036*4f1223e8SApple OSS Distributions 		crc32tab[i] = crc_rem;
3037*4f1223e8SApple OSS Distributions 	}
3038*4f1223e8SApple OSS Distributions }
3039*4f1223e8SApple OSS Distributions 
3040*4f1223e8SApple OSS Distributions 
3041*4f1223e8SApple OSS Distributions /*
3042*4f1223e8SApple OSS Distributions  * Name cache initialization, from vfs_init() when we are booting
3043*4f1223e8SApple OSS Distributions  */
3044*4f1223e8SApple OSS Distributions void
nchinit(void)3045*4f1223e8SApple OSS Distributions nchinit(void)
3046*4f1223e8SApple OSS Distributions {
3047*4f1223e8SApple OSS Distributions 	desiredNegNodes = (desiredvnodes / 10);
3048*4f1223e8SApple OSS Distributions 	desiredNodes = desiredvnodes + desiredNegNodes;
3049*4f1223e8SApple OSS Distributions 
3050*4f1223e8SApple OSS Distributions 	if (nc_smr_enabled) {
3051*4f1223e8SApple OSS Distributions 		zone_enable_smr(namecache_zone, VFS_SMR(), &namecache_smr_free);
3052*4f1223e8SApple OSS Distributions 		zone_enable_smr(stringcache_zone, VFS_SMR(), &string_smr_free);
3053*4f1223e8SApple OSS Distributions 	}
3054*4f1223e8SApple OSS Distributions 	TAILQ_INIT(&nchead);
3055*4f1223e8SApple OSS Distributions 	TAILQ_INIT(&neghead);
3056*4f1223e8SApple OSS Distributions 
3057*4f1223e8SApple OSS Distributions 	init_crc32();
3058*4f1223e8SApple OSS Distributions 
3059*4f1223e8SApple OSS Distributions 	nchashtbl = hashinit(MAX(CONFIG_NC_HASH, (2 * desiredNodes)), M_CACHE, &nchash);
3060*4f1223e8SApple OSS Distributions 	nchashmask = nchash;
3061*4f1223e8SApple OSS Distributions 	nchash++;
3062*4f1223e8SApple OSS Distributions 
3063*4f1223e8SApple OSS Distributions 	init_string_table();
3064*4f1223e8SApple OSS Distributions 
3065*4f1223e8SApple OSS Distributions 	for (int i = 0; i < NUM_STRCACHE_LOCKS; i++) {
3066*4f1223e8SApple OSS Distributions 		lck_mtx_init(&strcache_mtx_locks[i], &strcache_lck_grp, &strcache_lck_attr);
3067*4f1223e8SApple OSS Distributions 	}
3068*4f1223e8SApple OSS Distributions }
3069*4f1223e8SApple OSS Distributions 
3070*4f1223e8SApple OSS Distributions void
name_cache_lock_shared(void)3071*4f1223e8SApple OSS Distributions name_cache_lock_shared(void)
3072*4f1223e8SApple OSS Distributions {
3073*4f1223e8SApple OSS Distributions 	lck_rw_lock_shared(&namecache_rw_lock);
3074*4f1223e8SApple OSS Distributions 	NC_SMR_STATS(nc_lock_shared);
3075*4f1223e8SApple OSS Distributions }
3076*4f1223e8SApple OSS Distributions 
3077*4f1223e8SApple OSS Distributions void
name_cache_lock(void)3078*4f1223e8SApple OSS Distributions name_cache_lock(void)
3079*4f1223e8SApple OSS Distributions {
3080*4f1223e8SApple OSS Distributions 	lck_rw_lock_exclusive(&namecache_rw_lock);
3081*4f1223e8SApple OSS Distributions 	NC_SMR_STATS(nc_lock);
3082*4f1223e8SApple OSS Distributions }
3083*4f1223e8SApple OSS Distributions 
3084*4f1223e8SApple OSS Distributions boolean_t
name_cache_lock_shared_to_exclusive(void)3085*4f1223e8SApple OSS Distributions name_cache_lock_shared_to_exclusive(void)
3086*4f1223e8SApple OSS Distributions {
3087*4f1223e8SApple OSS Distributions 	return lck_rw_lock_shared_to_exclusive(&namecache_rw_lock);
3088*4f1223e8SApple OSS Distributions }
3089*4f1223e8SApple OSS Distributions 
3090*4f1223e8SApple OSS Distributions void
name_cache_unlock(void)3091*4f1223e8SApple OSS Distributions name_cache_unlock(void)
3092*4f1223e8SApple OSS Distributions {
3093*4f1223e8SApple OSS Distributions 	lck_rw_done(&namecache_rw_lock);
3094*4f1223e8SApple OSS Distributions }
3095*4f1223e8SApple OSS Distributions 
3096*4f1223e8SApple OSS Distributions 
3097*4f1223e8SApple OSS Distributions int
resize_namecache(int newsize)3098*4f1223e8SApple OSS Distributions resize_namecache(int newsize)
3099*4f1223e8SApple OSS Distributions {
3100*4f1223e8SApple OSS Distributions 	struct smrq_list_head   *new_table;
3101*4f1223e8SApple OSS Distributions 	struct smrq_list_head   *old_table;
3102*4f1223e8SApple OSS Distributions 	struct smrq_list_head   *old_head;
3103*4f1223e8SApple OSS Distributions 	struct namecache    *entry;
3104*4f1223e8SApple OSS Distributions 	uint32_t            i, hashval;
3105*4f1223e8SApple OSS Distributions 	int                 dNodes, dNegNodes, nelements;
3106*4f1223e8SApple OSS Distributions 	u_long              new_size, old_size;
3107*4f1223e8SApple OSS Distributions 
3108*4f1223e8SApple OSS Distributions 	if (newsize < 0) {
3109*4f1223e8SApple OSS Distributions 		return EINVAL;
3110*4f1223e8SApple OSS Distributions 	}
3111*4f1223e8SApple OSS Distributions 
3112*4f1223e8SApple OSS Distributions 	dNegNodes = (newsize / 10);
3113*4f1223e8SApple OSS Distributions 	dNodes = newsize + dNegNodes;
3114*4f1223e8SApple OSS Distributions 	// we don't support shrinking yet
3115*4f1223e8SApple OSS Distributions 	if (dNodes <= desiredNodes) {
3116*4f1223e8SApple OSS Distributions 		return 0;
3117*4f1223e8SApple OSS Distributions 	}
3118*4f1223e8SApple OSS Distributions 
3119*4f1223e8SApple OSS Distributions 	if (os_mul_overflow(dNodes, 2, &nelements)) {
3120*4f1223e8SApple OSS Distributions 		return EINVAL;
3121*4f1223e8SApple OSS Distributions 	}
3122*4f1223e8SApple OSS Distributions 
3123*4f1223e8SApple OSS Distributions 	new_table = hashinit(nelements, M_CACHE, &nchashmask);
3124*4f1223e8SApple OSS Distributions 	new_size  = nchashmask + 1;
3125*4f1223e8SApple OSS Distributions 
3126*4f1223e8SApple OSS Distributions 	if (new_table == NULL) {
3127*4f1223e8SApple OSS Distributions 		return ENOMEM;
3128*4f1223e8SApple OSS Distributions 	}
3129*4f1223e8SApple OSS Distributions 
3130*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
3131*4f1223e8SApple OSS Distributions 
3132*4f1223e8SApple OSS Distributions 	/* No need to switch if the hash table size hasn't changed. */
3133*4f1223e8SApple OSS Distributions 	if (new_size == nchash) {
3134*4f1223e8SApple OSS Distributions 		NAME_CACHE_UNLOCK();
3135*4f1223e8SApple OSS Distributions 		hashdestroy(new_table, M_CACHE, new_size - 1);
3136*4f1223e8SApple OSS Distributions 		return 0;
3137*4f1223e8SApple OSS Distributions 	}
3138*4f1223e8SApple OSS Distributions 
3139*4f1223e8SApple OSS Distributions 	// do the switch!
3140*4f1223e8SApple OSS Distributions 	old_table = nchashtbl;
3141*4f1223e8SApple OSS Distributions 	nchashtbl = new_table;
3142*4f1223e8SApple OSS Distributions 	old_size  = nchash;
3143*4f1223e8SApple OSS Distributions 	nchash    = new_size;
3144*4f1223e8SApple OSS Distributions 
3145*4f1223e8SApple OSS Distributions 	// walk the old table and insert all the entries into
3146*4f1223e8SApple OSS Distributions 	// the new table
3147*4f1223e8SApple OSS Distributions 	//
3148*4f1223e8SApple OSS Distributions 	for (i = 0; i < old_size; i++) {
3149*4f1223e8SApple OSS Distributions 		old_head = &old_table[i];
3150*4f1223e8SApple OSS Distributions 		smrq_serialized_foreach_safe(entry, old_head, nc_hash) {
3151*4f1223e8SApple OSS Distributions 			//
3152*4f1223e8SApple OSS Distributions 			// XXXdbg - Beware: this assumes that hash_string() does
3153*4f1223e8SApple OSS Distributions 			//                  the same thing as what happens in
3154*4f1223e8SApple OSS Distributions 			//                  lookup() over in vfs_lookup.c
3155*4f1223e8SApple OSS Distributions 			hashval = hash_string(entry->nc_name, 0);
3156*4f1223e8SApple OSS Distributions 			entry->nc_hashval = hashval;
3157*4f1223e8SApple OSS Distributions 
3158*4f1223e8SApple OSS Distributions 			smrq_serialized_insert_head(NCHHASH(entry->nc_dvp, hashval), &entry->nc_hash);
3159*4f1223e8SApple OSS Distributions 		}
3160*4f1223e8SApple OSS Distributions 	}
3161*4f1223e8SApple OSS Distributions 	desiredNodes = dNodes;
3162*4f1223e8SApple OSS Distributions 	desiredNegNodes = dNegNodes;
3163*4f1223e8SApple OSS Distributions 
3164*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
3165*4f1223e8SApple OSS Distributions 	hashdestroy(old_table, M_CACHE, old_size - 1);
3166*4f1223e8SApple OSS Distributions 
3167*4f1223e8SApple OSS Distributions 	return 0;
3168*4f1223e8SApple OSS Distributions }
3169*4f1223e8SApple OSS Distributions 
3170*4f1223e8SApple OSS Distributions static void
namecache_smr_free(void * _ncp,__unused size_t _size)3171*4f1223e8SApple OSS Distributions namecache_smr_free(void *_ncp, __unused size_t _size)
3172*4f1223e8SApple OSS Distributions {
3173*4f1223e8SApple OSS Distributions 	struct namecache *ncp = _ncp;
3174*4f1223e8SApple OSS Distributions 
3175*4f1223e8SApple OSS Distributions 	bzero(ncp, sizeof(*ncp));
3176*4f1223e8SApple OSS Distributions }
3177*4f1223e8SApple OSS Distributions 
3178*4f1223e8SApple OSS Distributions static void
cache_delete(struct namecache * ncp,int free_entry)3179*4f1223e8SApple OSS Distributions cache_delete(struct namecache *ncp, int free_entry)
3180*4f1223e8SApple OSS Distributions {
3181*4f1223e8SApple OSS Distributions 	NCHSTAT(ncs_deletes);
3182*4f1223e8SApple OSS Distributions 
3183*4f1223e8SApple OSS Distributions 	/*
3184*4f1223e8SApple OSS Distributions 	 * See comment at the end of cache_enter_locked expalining the usage of
3185*4f1223e8SApple OSS Distributions 	 * nc_counter.
3186*4f1223e8SApple OSS Distributions 	 */
3187*4f1223e8SApple OSS Distributions 	uint32_t old_count = os_atomic_inc_orig(&ncp->nc_counter, release);
3188*4f1223e8SApple OSS Distributions 	if (!(old_count & NC_VALID)) {
3189*4f1223e8SApple OSS Distributions 		/* This should be a valid to invalid transition */
3190*4f1223e8SApple OSS Distributions 		panic("Incorrect state for old nc_counter(%d), should be odd", old_count);
3191*4f1223e8SApple OSS Distributions 	}
3192*4f1223e8SApple OSS Distributions 
3193*4f1223e8SApple OSS Distributions 	if (ncp->nc_vp) {
3194*4f1223e8SApple OSS Distributions 		LIST_REMOVE(ncp, nc_un.nc_link);
3195*4f1223e8SApple OSS Distributions 	} else {
3196*4f1223e8SApple OSS Distributions 		TAILQ_REMOVE(&neghead, ncp, nc_un.nc_negentry);
3197*4f1223e8SApple OSS Distributions 		ncs_negtotal--;
3198*4f1223e8SApple OSS Distributions 	}
3199*4f1223e8SApple OSS Distributions 	TAILQ_REMOVE(&(ncp->nc_dvp->v_ncchildren), ncp, nc_child);
3200*4f1223e8SApple OSS Distributions 
3201*4f1223e8SApple OSS Distributions 	smrq_serialized_remove((NCHHASH(ncp->nc_dvp, ncp->nc_hashval)), &ncp->nc_hash);
3202*4f1223e8SApple OSS Distributions 
3203*4f1223e8SApple OSS Distributions 	const char *nc_name = ncp->nc_name;
3204*4f1223e8SApple OSS Distributions 	ncp->nc_name = NULL;
3205*4f1223e8SApple OSS Distributions 	vfs_removename(nc_name);
3206*4f1223e8SApple OSS Distributions 	if (ncp->nc_vp) {
3207*4f1223e8SApple OSS Distributions 		vnode_t vp = ncp->nc_vp;
3208*4f1223e8SApple OSS Distributions 
3209*4f1223e8SApple OSS Distributions 		ncp->nc_vp = NULLVP;
3210*4f1223e8SApple OSS Distributions 		vnode_drop(vp);
3211*4f1223e8SApple OSS Distributions 	}
3212*4f1223e8SApple OSS Distributions 
3213*4f1223e8SApple OSS Distributions 	if (free_entry) {
3214*4f1223e8SApple OSS Distributions 		TAILQ_REMOVE(&nchead, ncp, nc_entry);
3215*4f1223e8SApple OSS Distributions 		if (nc_smr_enabled) {
3216*4f1223e8SApple OSS Distributions 			zfree_smr(namecache_zone, ncp);
3217*4f1223e8SApple OSS Distributions 		} else {
3218*4f1223e8SApple OSS Distributions 			zfree(namecache_zone, ncp);
3219*4f1223e8SApple OSS Distributions 		}
3220*4f1223e8SApple OSS Distributions 		numcache--;
3221*4f1223e8SApple OSS Distributions 	}
3222*4f1223e8SApple OSS Distributions }
3223*4f1223e8SApple OSS Distributions 
3224*4f1223e8SApple OSS Distributions 
3225*4f1223e8SApple OSS Distributions /*
3226*4f1223e8SApple OSS Distributions  * purge the entry associated with the
3227*4f1223e8SApple OSS Distributions  * specified vnode from the name cache
3228*4f1223e8SApple OSS Distributions  */
3229*4f1223e8SApple OSS Distributions static void
cache_purge_locked(vnode_t vp,kauth_cred_t * credp)3230*4f1223e8SApple OSS Distributions cache_purge_locked(vnode_t vp, kauth_cred_t *credp)
3231*4f1223e8SApple OSS Distributions {
3232*4f1223e8SApple OSS Distributions 	struct namecache *ncp;
3233*4f1223e8SApple OSS Distributions 
3234*4f1223e8SApple OSS Distributions 	*credp = NULL;
3235*4f1223e8SApple OSS Distributions 	if ((LIST_FIRST(&vp->v_nclinks) == NULL) &&
3236*4f1223e8SApple OSS Distributions 	    (TAILQ_FIRST(&vp->v_ncchildren) == NULL) &&
3237*4f1223e8SApple OSS Distributions 	    (vnode_cred(vp) == NOCRED) &&
3238*4f1223e8SApple OSS Distributions 	    (vp->v_parent == NULLVP)) {
3239*4f1223e8SApple OSS Distributions 		return;
3240*4f1223e8SApple OSS Distributions 	}
3241*4f1223e8SApple OSS Distributions 
3242*4f1223e8SApple OSS Distributions 	if (vp->v_parent) {
3243*4f1223e8SApple OSS Distributions 		vp->v_parent->v_nc_generation++;
3244*4f1223e8SApple OSS Distributions 	}
3245*4f1223e8SApple OSS Distributions 
3246*4f1223e8SApple OSS Distributions 	while ((ncp = LIST_FIRST(&vp->v_nclinks))) {
3247*4f1223e8SApple OSS Distributions 		cache_delete(ncp, 1);
3248*4f1223e8SApple OSS Distributions 	}
3249*4f1223e8SApple OSS Distributions 
3250*4f1223e8SApple OSS Distributions 	while ((ncp = TAILQ_FIRST(&vp->v_ncchildren))) {
3251*4f1223e8SApple OSS Distributions 		cache_delete(ncp, 1);
3252*4f1223e8SApple OSS Distributions 	}
3253*4f1223e8SApple OSS Distributions 
3254*4f1223e8SApple OSS Distributions 	/*
3255*4f1223e8SApple OSS Distributions 	 * Use a temp variable to avoid kauth_cred_unref() while NAME_CACHE_LOCK is held
3256*4f1223e8SApple OSS Distributions 	 */
3257*4f1223e8SApple OSS Distributions 	*credp = vnode_cred(vp);
3258*4f1223e8SApple OSS Distributions 	vp->v_cred = NOCRED;
3259*4f1223e8SApple OSS Distributions 	vp->v_authorized_actions = 0;
3260*4f1223e8SApple OSS Distributions }
3261*4f1223e8SApple OSS Distributions 
3262*4f1223e8SApple OSS Distributions void
cache_purge(vnode_t vp)3263*4f1223e8SApple OSS Distributions cache_purge(vnode_t vp)
3264*4f1223e8SApple OSS Distributions {
3265*4f1223e8SApple OSS Distributions 	kauth_cred_t tcred = NULL;
3266*4f1223e8SApple OSS Distributions 
3267*4f1223e8SApple OSS Distributions 	if ((LIST_FIRST(&vp->v_nclinks) == NULL) &&
3268*4f1223e8SApple OSS Distributions 	    (TAILQ_FIRST(&vp->v_ncchildren) == NULL) &&
3269*4f1223e8SApple OSS Distributions 	    (vnode_cred(vp) == NOCRED) &&
3270*4f1223e8SApple OSS Distributions 	    (vp->v_parent == NULLVP)) {
3271*4f1223e8SApple OSS Distributions 		return;
3272*4f1223e8SApple OSS Distributions 	}
3273*4f1223e8SApple OSS Distributions 
3274*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
3275*4f1223e8SApple OSS Distributions 
3276*4f1223e8SApple OSS Distributions 	cache_purge_locked(vp, &tcred);
3277*4f1223e8SApple OSS Distributions 
3278*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
3279*4f1223e8SApple OSS Distributions 
3280*4f1223e8SApple OSS Distributions 	if (IS_VALID_CRED(tcred)) {
3281*4f1223e8SApple OSS Distributions 		kauth_cred_unref(&tcred);
3282*4f1223e8SApple OSS Distributions 	}
3283*4f1223e8SApple OSS Distributions }
3284*4f1223e8SApple OSS Distributions 
3285*4f1223e8SApple OSS Distributions /*
3286*4f1223e8SApple OSS Distributions  * Purge all negative cache entries that are children of the
3287*4f1223e8SApple OSS Distributions  * given vnode.  A case-insensitive file system (or any file
3288*4f1223e8SApple OSS Distributions  * system that has multiple equivalent names for the same
3289*4f1223e8SApple OSS Distributions  * directory entry) can use this when creating or renaming
3290*4f1223e8SApple OSS Distributions  * to remove negative entries that may no longer apply.
3291*4f1223e8SApple OSS Distributions  */
3292*4f1223e8SApple OSS Distributions void
cache_purge_negatives(vnode_t vp)3293*4f1223e8SApple OSS Distributions cache_purge_negatives(vnode_t vp)
3294*4f1223e8SApple OSS Distributions {
3295*4f1223e8SApple OSS Distributions 	struct namecache *ncp, *next_ncp;
3296*4f1223e8SApple OSS Distributions 
3297*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
3298*4f1223e8SApple OSS Distributions 
3299*4f1223e8SApple OSS Distributions 	TAILQ_FOREACH_SAFE(ncp, &vp->v_ncchildren, nc_child, next_ncp) {
3300*4f1223e8SApple OSS Distributions 		if (ncp->nc_vp) {
3301*4f1223e8SApple OSS Distributions 			break;
3302*4f1223e8SApple OSS Distributions 		}
3303*4f1223e8SApple OSS Distributions 
3304*4f1223e8SApple OSS Distributions 		cache_delete(ncp, 1);
3305*4f1223e8SApple OSS Distributions 	}
3306*4f1223e8SApple OSS Distributions 
3307*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
3308*4f1223e8SApple OSS Distributions }
3309*4f1223e8SApple OSS Distributions 
3310*4f1223e8SApple OSS Distributions /*
3311*4f1223e8SApple OSS Distributions  * Flush all entries referencing a particular filesystem.
3312*4f1223e8SApple OSS Distributions  *
3313*4f1223e8SApple OSS Distributions  * Since we need to check it anyway, we will flush all the invalid
3314*4f1223e8SApple OSS Distributions  * entries at the same time.
3315*4f1223e8SApple OSS Distributions  */
3316*4f1223e8SApple OSS Distributions void
cache_purgevfs(struct mount * mp)3317*4f1223e8SApple OSS Distributions cache_purgevfs(struct mount *mp)
3318*4f1223e8SApple OSS Distributions {
3319*4f1223e8SApple OSS Distributions 	struct smrq_list_head *ncpp;
3320*4f1223e8SApple OSS Distributions 	struct namecache *ncp;
3321*4f1223e8SApple OSS Distributions 
3322*4f1223e8SApple OSS Distributions 	NAME_CACHE_LOCK();
3323*4f1223e8SApple OSS Distributions 	/* Scan hash tables for applicable entries */
3324*4f1223e8SApple OSS Distributions 	for (ncpp = &nchashtbl[nchash - 1]; ncpp >= nchashtbl; ncpp--) {
3325*4f1223e8SApple OSS Distributions restart:
3326*4f1223e8SApple OSS Distributions 		smrq_serialized_foreach(ncp, ncpp, nc_hash) {
3327*4f1223e8SApple OSS Distributions 			if (ncp->nc_dvp->v_mount == mp) {
3328*4f1223e8SApple OSS Distributions 				cache_delete(ncp, 0);
3329*4f1223e8SApple OSS Distributions 				goto restart;
3330*4f1223e8SApple OSS Distributions 			}
3331*4f1223e8SApple OSS Distributions 		}
3332*4f1223e8SApple OSS Distributions 	}
3333*4f1223e8SApple OSS Distributions 	NAME_CACHE_UNLOCK();
3334*4f1223e8SApple OSS Distributions }
3335*4f1223e8SApple OSS Distributions 
3336*4f1223e8SApple OSS Distributions 
3337*4f1223e8SApple OSS Distributions 
3338*4f1223e8SApple OSS Distributions //
3339*4f1223e8SApple OSS Distributions // String ref routines
3340*4f1223e8SApple OSS Distributions //
3341*4f1223e8SApple OSS Distributions static LIST_HEAD(stringhead, string_t) * string_ref_table;
3342*4f1223e8SApple OSS Distributions static u_long   string_table_mask;
3343*4f1223e8SApple OSS Distributions static uint32_t filled_buckets = 0;
3344*4f1223e8SApple OSS Distributions 
3345*4f1223e8SApple OSS Distributions 
3346*4f1223e8SApple OSS Distributions 
3347*4f1223e8SApple OSS Distributions 
3348*4f1223e8SApple OSS Distributions static void
resize_string_ref_table(void)3349*4f1223e8SApple OSS Distributions resize_string_ref_table(void)
3350*4f1223e8SApple OSS Distributions {
3351*4f1223e8SApple OSS Distributions 	struct stringhead *new_table;
3352*4f1223e8SApple OSS Distributions 	struct stringhead *old_table;
3353*4f1223e8SApple OSS Distributions 	struct stringhead *old_head, *head;
3354*4f1223e8SApple OSS Distributions 	string_t          *entry, *next;
3355*4f1223e8SApple OSS Distributions 	uint32_t           i, hashval;
3356*4f1223e8SApple OSS Distributions 	u_long             new_mask, old_mask;
3357*4f1223e8SApple OSS Distributions 
3358*4f1223e8SApple OSS Distributions 	/*
3359*4f1223e8SApple OSS Distributions 	 * need to hold the table lock exclusively
3360*4f1223e8SApple OSS Distributions 	 * in order to grow the table... need to recheck
3361*4f1223e8SApple OSS Distributions 	 * the need to resize again after we've taken
3362*4f1223e8SApple OSS Distributions 	 * the lock exclusively in case some other thread
3363*4f1223e8SApple OSS Distributions 	 * beat us to the punch
3364*4f1223e8SApple OSS Distributions 	 */
3365*4f1223e8SApple OSS Distributions 	lck_rw_lock_exclusive(&strtable_rw_lock);
3366*4f1223e8SApple OSS Distributions 
3367*4f1223e8SApple OSS Distributions 	if (4 * filled_buckets < ((string_table_mask + 1) * 3)) {
3368*4f1223e8SApple OSS Distributions 		lck_rw_done(&strtable_rw_lock);
3369*4f1223e8SApple OSS Distributions 		return;
3370*4f1223e8SApple OSS Distributions 	}
3371*4f1223e8SApple OSS Distributions 	assert(string_table_mask < INT32_MAX);
3372*4f1223e8SApple OSS Distributions 	new_table = hashinit((int)(string_table_mask + 1) * 2, M_CACHE, &new_mask);
3373*4f1223e8SApple OSS Distributions 
3374*4f1223e8SApple OSS Distributions 	if (new_table == NULL) {
3375*4f1223e8SApple OSS Distributions 		printf("failed to resize the hash table.\n");
3376*4f1223e8SApple OSS Distributions 		lck_rw_done(&strtable_rw_lock);
3377*4f1223e8SApple OSS Distributions 		return;
3378*4f1223e8SApple OSS Distributions 	}
3379*4f1223e8SApple OSS Distributions 
3380*4f1223e8SApple OSS Distributions 	// do the switch!
3381*4f1223e8SApple OSS Distributions 	old_table         = string_ref_table;
3382*4f1223e8SApple OSS Distributions 	string_ref_table  = new_table;
3383*4f1223e8SApple OSS Distributions 	old_mask          = string_table_mask;
3384*4f1223e8SApple OSS Distributions 	string_table_mask = new_mask;
3385*4f1223e8SApple OSS Distributions 	filled_buckets    = 0;
3386*4f1223e8SApple OSS Distributions 
3387*4f1223e8SApple OSS Distributions 	// walk the old table and insert all the entries into
3388*4f1223e8SApple OSS Distributions 	// the new table
3389*4f1223e8SApple OSS Distributions 	//
3390*4f1223e8SApple OSS Distributions 	for (i = 0; i <= old_mask; i++) {
3391*4f1223e8SApple OSS Distributions 		old_head = &old_table[i];
3392*4f1223e8SApple OSS Distributions 		for (entry = old_head->lh_first; entry != NULL; entry = next) {
3393*4f1223e8SApple OSS Distributions 			hashval = hash_string((const char *)entry->str, 0);
3394*4f1223e8SApple OSS Distributions 			head = &string_ref_table[hashval & string_table_mask];
3395*4f1223e8SApple OSS Distributions 			if (head->lh_first == NULL) {
3396*4f1223e8SApple OSS Distributions 				filled_buckets++;
3397*4f1223e8SApple OSS Distributions 			}
3398*4f1223e8SApple OSS Distributions 			next = entry->hash_chain.le_next;
3399*4f1223e8SApple OSS Distributions 			LIST_INSERT_HEAD(head, entry, hash_chain);
3400*4f1223e8SApple OSS Distributions 		}
3401*4f1223e8SApple OSS Distributions 	}
3402*4f1223e8SApple OSS Distributions 	lck_rw_done(&strtable_rw_lock);
3403*4f1223e8SApple OSS Distributions 
3404*4f1223e8SApple OSS Distributions 	hashdestroy(old_table, M_CACHE, old_mask);
3405*4f1223e8SApple OSS Distributions }
3406*4f1223e8SApple OSS Distributions 
3407*4f1223e8SApple OSS Distributions 
3408*4f1223e8SApple OSS Distributions static void
init_string_table(void)3409*4f1223e8SApple OSS Distributions init_string_table(void)
3410*4f1223e8SApple OSS Distributions {
3411*4f1223e8SApple OSS Distributions 	string_ref_table = hashinit(CONFIG_VFS_NAMES, M_CACHE, &string_table_mask);
3412*4f1223e8SApple OSS Distributions }
3413*4f1223e8SApple OSS Distributions 
3414*4f1223e8SApple OSS Distributions 
3415*4f1223e8SApple OSS Distributions const char *
vfs_addname(const char * name,uint32_t len,u_int hashval,u_int flags)3416*4f1223e8SApple OSS Distributions vfs_addname(const char *name, uint32_t len, u_int hashval, u_int flags)
3417*4f1223e8SApple OSS Distributions {
3418*4f1223e8SApple OSS Distributions 	return add_name_internal(name, len, hashval, FALSE, flags);
3419*4f1223e8SApple OSS Distributions }
3420*4f1223e8SApple OSS Distributions 
3421*4f1223e8SApple OSS Distributions 
3422*4f1223e8SApple OSS Distributions static const char *
add_name_internal(const char * name,uint32_t len,u_int hashval,boolean_t need_extra_ref,__unused u_int flags)3423*4f1223e8SApple OSS Distributions add_name_internal(const char *name, uint32_t len, u_int hashval, boolean_t need_extra_ref, __unused u_int flags)
3424*4f1223e8SApple OSS Distributions {
3425*4f1223e8SApple OSS Distributions 	struct stringhead *head;
3426*4f1223e8SApple OSS Distributions 	string_t          *entry;
3427*4f1223e8SApple OSS Distributions 	uint32_t          chain_len = 0;
3428*4f1223e8SApple OSS Distributions 	uint32_t          hash_index;
3429*4f1223e8SApple OSS Distributions 	uint32_t          lock_index;
3430*4f1223e8SApple OSS Distributions 	char              *ptr;
3431*4f1223e8SApple OSS Distributions 
3432*4f1223e8SApple OSS Distributions 	if (len > MAXPATHLEN) {
3433*4f1223e8SApple OSS Distributions 		len = MAXPATHLEN;
3434*4f1223e8SApple OSS Distributions 	}
3435*4f1223e8SApple OSS Distributions 
3436*4f1223e8SApple OSS Distributions 	/*
3437*4f1223e8SApple OSS Distributions 	 * if the length already accounts for the null-byte, then
3438*4f1223e8SApple OSS Distributions 	 * subtract one so later on we don't index past the end
3439*4f1223e8SApple OSS Distributions 	 * of the string.
3440*4f1223e8SApple OSS Distributions 	 */
3441*4f1223e8SApple OSS Distributions 	if (len > 0 && name[len - 1] == '\0') {
3442*4f1223e8SApple OSS Distributions 		len--;
3443*4f1223e8SApple OSS Distributions 	}
3444*4f1223e8SApple OSS Distributions 	if (hashval == 0) {
3445*4f1223e8SApple OSS Distributions 		hashval = hash_string(name, len);
3446*4f1223e8SApple OSS Distributions 	}
3447*4f1223e8SApple OSS Distributions 
3448*4f1223e8SApple OSS Distributions 	/*
3449*4f1223e8SApple OSS Distributions 	 * take this lock 'shared' to keep the hash stable
3450*4f1223e8SApple OSS Distributions 	 * if someone else decides to grow the pool they
3451*4f1223e8SApple OSS Distributions 	 * will take this lock exclusively
3452*4f1223e8SApple OSS Distributions 	 */
3453*4f1223e8SApple OSS Distributions 	lck_rw_lock_shared(&strtable_rw_lock);
3454*4f1223e8SApple OSS Distributions 
3455*4f1223e8SApple OSS Distributions 	/*
3456*4f1223e8SApple OSS Distributions 	 * If the table gets more than 3/4 full, resize it
3457*4f1223e8SApple OSS Distributions 	 */
3458*4f1223e8SApple OSS Distributions 	if (4 * filled_buckets >= ((string_table_mask + 1) * 3)) {
3459*4f1223e8SApple OSS Distributions 		lck_rw_done(&strtable_rw_lock);
3460*4f1223e8SApple OSS Distributions 
3461*4f1223e8SApple OSS Distributions 		resize_string_ref_table();
3462*4f1223e8SApple OSS Distributions 
3463*4f1223e8SApple OSS Distributions 		lck_rw_lock_shared(&strtable_rw_lock);
3464*4f1223e8SApple OSS Distributions 	}
3465*4f1223e8SApple OSS Distributions 	hash_index = hashval & string_table_mask;
3466*4f1223e8SApple OSS Distributions 	lock_index = hash_index % NUM_STRCACHE_LOCKS;
3467*4f1223e8SApple OSS Distributions 
3468*4f1223e8SApple OSS Distributions 	head = &string_ref_table[hash_index];
3469*4f1223e8SApple OSS Distributions 
3470*4f1223e8SApple OSS Distributions 	lck_mtx_lock_spin(&strcache_mtx_locks[lock_index]);
3471*4f1223e8SApple OSS Distributions 
3472*4f1223e8SApple OSS Distributions 	for (entry = head->lh_first; entry != NULL; chain_len++, entry = entry->hash_chain.le_next) {
3473*4f1223e8SApple OSS Distributions 		if (strncmp(entry->str, name, len) == 0 && entry->str[len] == 0) {
3474*4f1223e8SApple OSS Distributions 			entry->refcount++;
3475*4f1223e8SApple OSS Distributions 			break;
3476*4f1223e8SApple OSS Distributions 		}
3477*4f1223e8SApple OSS Distributions 	}
3478*4f1223e8SApple OSS Distributions 	if (entry == NULL) {
3479*4f1223e8SApple OSS Distributions 		const uint32_t buflen = len + 1;
3480*4f1223e8SApple OSS Distributions 
3481*4f1223e8SApple OSS Distributions 		lck_mtx_convert_spin(&strcache_mtx_locks[lock_index]);
3482*4f1223e8SApple OSS Distributions 		/*
3483*4f1223e8SApple OSS Distributions 		 * it wasn't already there so add it.
3484*4f1223e8SApple OSS Distributions 		 */
3485*4f1223e8SApple OSS Distributions 		if (nc_smr_enabled) {
3486*4f1223e8SApple OSS Distributions 			entry = zalloc_smr(stringcache_zone, Z_WAITOK_ZERO_NOFAIL);
3487*4f1223e8SApple OSS Distributions 		} else {
3488*4f1223e8SApple OSS Distributions 			entry = zalloc(stringcache_zone);
3489*4f1223e8SApple OSS Distributions 		}
3490*4f1223e8SApple OSS Distributions 
3491*4f1223e8SApple OSS Distributions 		if (head->lh_first == NULL) {
3492*4f1223e8SApple OSS Distributions 			OSAddAtomic(1, &filled_buckets);
3493*4f1223e8SApple OSS Distributions 		}
3494*4f1223e8SApple OSS Distributions 		ptr = kalloc_data(buflen, Z_WAITOK);
3495*4f1223e8SApple OSS Distributions 		strncpy(ptr, name, len);
3496*4f1223e8SApple OSS Distributions 		ptr[len] = '\0';
3497*4f1223e8SApple OSS Distributions 		entry->str = ptr;
3498*4f1223e8SApple OSS Distributions 		entry->strbuflen = buflen;
3499*4f1223e8SApple OSS Distributions 		entry->refcount = 1;
3500*4f1223e8SApple OSS Distributions 		LIST_INSERT_HEAD(head, entry, hash_chain);
3501*4f1223e8SApple OSS Distributions 	}
3502*4f1223e8SApple OSS Distributions 	if (need_extra_ref == TRUE) {
3503*4f1223e8SApple OSS Distributions 		entry->refcount++;
3504*4f1223e8SApple OSS Distributions 	}
3505*4f1223e8SApple OSS Distributions 
3506*4f1223e8SApple OSS Distributions 	lck_mtx_unlock(&strcache_mtx_locks[lock_index]);
3507*4f1223e8SApple OSS Distributions 	lck_rw_done(&strtable_rw_lock);
3508*4f1223e8SApple OSS Distributions 
3509*4f1223e8SApple OSS Distributions 	return (const char *)entry->str;
3510*4f1223e8SApple OSS Distributions }
3511*4f1223e8SApple OSS Distributions 
3512*4f1223e8SApple OSS Distributions static void
string_smr_free(void * _entry,__unused size_t size)3513*4f1223e8SApple OSS Distributions string_smr_free(void *_entry, __unused size_t size)
3514*4f1223e8SApple OSS Distributions {
3515*4f1223e8SApple OSS Distributions 	string_t *entry = _entry;
3516*4f1223e8SApple OSS Distributions 
3517*4f1223e8SApple OSS Distributions 	kfree_data(entry->str, entry->strbuflen);
3518*4f1223e8SApple OSS Distributions 	bzero(entry, sizeof(*entry));
3519*4f1223e8SApple OSS Distributions }
3520*4f1223e8SApple OSS Distributions 
3521*4f1223e8SApple OSS Distributions int
vfs_removename(const char * nameref)3522*4f1223e8SApple OSS Distributions vfs_removename(const char *nameref)
3523*4f1223e8SApple OSS Distributions {
3524*4f1223e8SApple OSS Distributions 	struct stringhead *head;
3525*4f1223e8SApple OSS Distributions 	string_t          *entry;
3526*4f1223e8SApple OSS Distributions 	uint32_t           hashval;
3527*4f1223e8SApple OSS Distributions 	uint32_t           hash_index;
3528*4f1223e8SApple OSS Distributions 	uint32_t           lock_index;
3529*4f1223e8SApple OSS Distributions 	int                retval = ENOENT;
3530*4f1223e8SApple OSS Distributions 
3531*4f1223e8SApple OSS Distributions 	hashval = hash_string(nameref, 0);
3532*4f1223e8SApple OSS Distributions 
3533*4f1223e8SApple OSS Distributions 	/*
3534*4f1223e8SApple OSS Distributions 	 * take this lock 'shared' to keep the hash stable
3535*4f1223e8SApple OSS Distributions 	 * if someone else decides to grow the pool they
3536*4f1223e8SApple OSS Distributions 	 * will take this lock exclusively
3537*4f1223e8SApple OSS Distributions 	 */
3538*4f1223e8SApple OSS Distributions 	lck_rw_lock_shared(&strtable_rw_lock);
3539*4f1223e8SApple OSS Distributions 	/*
3540*4f1223e8SApple OSS Distributions 	 * must compute the head behind the table lock
3541*4f1223e8SApple OSS Distributions 	 * since the size and location of the table
3542*4f1223e8SApple OSS Distributions 	 * can change on the fly
3543*4f1223e8SApple OSS Distributions 	 */
3544*4f1223e8SApple OSS Distributions 	hash_index = hashval & string_table_mask;
3545*4f1223e8SApple OSS Distributions 	lock_index = hash_index % NUM_STRCACHE_LOCKS;
3546*4f1223e8SApple OSS Distributions 
3547*4f1223e8SApple OSS Distributions 	head = &string_ref_table[hash_index];
3548*4f1223e8SApple OSS Distributions 
3549*4f1223e8SApple OSS Distributions 	lck_mtx_lock_spin(&strcache_mtx_locks[lock_index]);
3550*4f1223e8SApple OSS Distributions 
3551*4f1223e8SApple OSS Distributions 	for (entry = head->lh_first; entry != NULL; entry = entry->hash_chain.le_next) {
3552*4f1223e8SApple OSS Distributions 		if (entry->str == nameref) {
3553*4f1223e8SApple OSS Distributions 			entry->refcount--;
3554*4f1223e8SApple OSS Distributions 
3555*4f1223e8SApple OSS Distributions 			if (entry->refcount == 0) {
3556*4f1223e8SApple OSS Distributions 				LIST_REMOVE(entry, hash_chain);
3557*4f1223e8SApple OSS Distributions 
3558*4f1223e8SApple OSS Distributions 				if (head->lh_first == NULL) {
3559*4f1223e8SApple OSS Distributions 					OSAddAtomic(-1, &filled_buckets);
3560*4f1223e8SApple OSS Distributions 				}
3561*4f1223e8SApple OSS Distributions 			} else {
3562*4f1223e8SApple OSS Distributions 				entry = NULL;
3563*4f1223e8SApple OSS Distributions 			}
3564*4f1223e8SApple OSS Distributions 			retval = 0;
3565*4f1223e8SApple OSS Distributions 			break;
3566*4f1223e8SApple OSS Distributions 		}
3567*4f1223e8SApple OSS Distributions 	}
3568*4f1223e8SApple OSS Distributions 	lck_mtx_unlock(&strcache_mtx_locks[lock_index]);
3569*4f1223e8SApple OSS Distributions 	lck_rw_done(&strtable_rw_lock);
3570*4f1223e8SApple OSS Distributions 
3571*4f1223e8SApple OSS Distributions 	if (entry) {
3572*4f1223e8SApple OSS Distributions 		assert(entry->refcount == 0);
3573*4f1223e8SApple OSS Distributions 		if (nc_smr_enabled) {
3574*4f1223e8SApple OSS Distributions 			zfree_smr(stringcache_zone, entry);
3575*4f1223e8SApple OSS Distributions 		} else {
3576*4f1223e8SApple OSS Distributions 			kfree_data(entry->str, entry->strbuflen);
3577*4f1223e8SApple OSS Distributions 			entry->str = NULL;
3578*4f1223e8SApple OSS Distributions 			entry->strbuflen = 0;
3579*4f1223e8SApple OSS Distributions 			zfree(stringcache_zone, entry);
3580*4f1223e8SApple OSS Distributions 		}
3581*4f1223e8SApple OSS Distributions 	}
3582*4f1223e8SApple OSS Distributions 
3583*4f1223e8SApple OSS Distributions 	return retval;
3584*4f1223e8SApple OSS Distributions }
3585*4f1223e8SApple OSS Distributions 
3586*4f1223e8SApple OSS Distributions 
3587*4f1223e8SApple OSS Distributions #ifdef DUMP_STRING_TABLE
3588*4f1223e8SApple OSS Distributions void
dump_string_table(void)3589*4f1223e8SApple OSS Distributions dump_string_table(void)
3590*4f1223e8SApple OSS Distributions {
3591*4f1223e8SApple OSS Distributions 	struct stringhead *head;
3592*4f1223e8SApple OSS Distributions 	string_t          *entry;
3593*4f1223e8SApple OSS Distributions 	u_long            i;
3594*4f1223e8SApple OSS Distributions 
3595*4f1223e8SApple OSS Distributions 	lck_rw_lock_shared(&strtable_rw_lock);
3596*4f1223e8SApple OSS Distributions 
3597*4f1223e8SApple OSS Distributions 	for (i = 0; i <= string_table_mask; i++) {
3598*4f1223e8SApple OSS Distributions 		head = &string_ref_table[i];
3599*4f1223e8SApple OSS Distributions 		for (entry = head->lh_first; entry != NULL; entry = entry->hash_chain.le_next) {
3600*4f1223e8SApple OSS Distributions 			printf("%6d - %s\n", entry->refcount, entry->str);
3601*4f1223e8SApple OSS Distributions 		}
3602*4f1223e8SApple OSS Distributions 	}
3603*4f1223e8SApple OSS Distributions 	lck_rw_done(&strtable_rw_lock);
3604*4f1223e8SApple OSS Distributions }
3605*4f1223e8SApple OSS Distributions #endif  /* DUMP_STRING_TABLE */
3606