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