]> git.saurik.com Git - apple/xnu.git/blame - bsd/vfs/vfs_cache.c
xnu-792.22.5.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_cache.c
CommitLineData
1c79356b 1/*
55e303ae 2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1989, 1993, 1995
31 * The Regents of the University of California. All rights reserved.
32 *
33 * This code is derived from software contributed to Berkeley by
34 * Poul-Henning Kamp of the FreeBSD Project.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 *
65 * @(#)vfs_cache.c 8.5 (Berkeley) 3/22/95
66 */
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/time.h>
91447636
A
70#include <sys/mount_internal.h>
71#include <sys/vnode_internal.h>
1c79356b
A
72#include <sys/namei.h>
73#include <sys/errno.h>
74#include <sys/malloc.h>
91447636
A
75#include <sys/kauth.h>
76#include <sys/user.h>
1c79356b
A
77
78/*
79 * Name caching works as follows:
80 *
81 * Names found by directory scans are retained in a cache
82 * for future reference. It is managed LRU, so frequently
83 * used names will hang around. Cache is indexed by hash value
84 * obtained from (vp, name) where vp refers to the directory
85 * containing name.
86 *
87 * If it is a "negative" entry, (i.e. for a name that is known NOT to
88 * exist) the vnode pointer will be NULL.
89 *
1c79356b
A
90 * Upon reaching the last segment of a path, if the reference
91 * is for DELETE, or NOCACHE is set (rewrite), and the
92 * name is located in the cache, it will be dropped.
93 */
94
95/*
96 * Structures associated with name cacheing.
97 */
91447636 98
1c79356b 99LIST_HEAD(nchashhead, namecache) *nchashtbl; /* Hash Table */
91447636 100u_long nchashmask;
1c79356b
A
101u_long nchash; /* size of hash table - 1 */
102long numcache; /* number of cache entries allocated */
91447636
A
103int desiredNodes;
104int desiredNegNodes;
4452a7af 105int ncs_negtotal;
91447636
A
106TAILQ_HEAD(, namecache) nchead; /* chain of all name cache entries */
107TAILQ_HEAD(, namecache) neghead; /* chain of only negative cache entries */
4452a7af
A
108
109
110#if COLLECT_STATS
111
1c79356b 112struct nchstats nchstats; /* cache effectiveness statistics */
91447636 113
4452a7af
A
114#define NCHSTAT(v) { \
115 nchstats.v++; \
116}
117#define NAME_CACHE_LOCK() name_cache_lock()
118#define NAME_CACHE_UNLOCK() name_cache_unlock()
119#define NAME_CACHE_LOCK_SHARED() name_cache_lock()
120
121#else
122
123#define NCHSTAT(v)
124#define NAME_CACHE_LOCK() name_cache_lock()
125#define NAME_CACHE_UNLOCK() name_cache_unlock()
126#define NAME_CACHE_LOCK_SHARED() name_cache_lock_shared()
127
128#endif
129
130
91447636
A
131/* vars for name cache list lock */
132lck_grp_t * namecache_lck_grp;
133lck_grp_attr_t * namecache_lck_grp_attr;
134lck_attr_t * namecache_lck_attr;
4452a7af 135lck_rw_t * namecache_rw_lock;
91447636
A
136
137static vnode_t cache_lookup_locked(vnode_t dvp, struct componentname *cnp);
138static int remove_name_locked(const char *);
139static char *add_name_locked(const char *, size_t, u_int, u_int);
140static void init_string_table(void);
141static void cache_delete(struct namecache *, int);
142static void dump_string_table(void);
143
144static void init_crc32(void);
145static unsigned int crc32tab[256];
146
147
148#define NCHHASH(dvp, hash_val) \
149 (&nchashtbl[(dvp->v_id ^ (hash_val)) & nchashmask])
150
151
152
153//
154// This function builds the path to a filename in "buff". The
155// length of the buffer *INCLUDING* the trailing zero byte is
156// returned in outlen. NOTE: the length includes the trailing
157// zero byte and thus the length is one greater than what strlen
158// would return. This is important and lots of code elsewhere
159// in the kernel assumes this behavior.
160//
161int
162build_path(vnode_t first_vp, char *buff, int buflen, int *outlen)
163{
164 vnode_t vp = first_vp;
165 char *end, *str;
166 int len, ret=0, counter=0;
167
168 end = &buff[buflen-1];
169 *end = '\0';
170
171 /*
172 * if this is the root dir of a file system...
173 */
174 if (vp && (vp->v_flag & VROOT) && vp->v_mount) {
175 /*
176 * then if it's the root fs, just put in a '/' and get out of here
177 */
178 if (vp->v_mount->mnt_flag & MNT_ROOTFS) {
179 *--end = '/';
180 goto out;
181 } else {
182 /*
183 * else just use the covered vnode to get the mount path
184 */
185 vp = vp->v_mount->mnt_vnodecovered;
186 }
187 }
4452a7af 188 NAME_CACHE_LOCK_SHARED();
91447636
A
189
190 while (vp && vp->v_parent != vp) {
191 /*
192 * the maximum depth of a file system hierarchy is MAXPATHLEN/2
193 * (with single-char names separated by slashes). we panic if
194 * we've ever looped more than that.
195 */
196 if (counter++ > MAXPATHLEN/2) {
197 panic("build_path: vnode parent chain is too long! vp 0x%x\n", vp);
198 }
199 str = vp->v_name;
200
201 if (str == NULL) {
202 if (vp->v_parent != NULL) {
203 ret = EINVAL;
204 }
205 break;
206 }
207 len = strlen(str);
208
209 /*
210 * check that there's enough space (make sure to include space for the '/')
211 */
212 if ((end - buff) < (len + 1)) {
213 ret = ENOSPC;
214 break;
215 }
216 /*
217 * copy it backwards
218 */
219 str += len;
220
221 for (; len > 0; len--) {
222 *--end = *--str;
223 }
224 /*
225 * put in the path separator
226 */
227 *--end = '/';
228
229 /*
230 * walk up the chain (as long as we're not the root)
231 */
232 if (vp == first_vp && (vp->v_flag & VROOT)) {
233 if (vp->v_mount && vp->v_mount->mnt_vnodecovered) {
234 vp = vp->v_mount->mnt_vnodecovered->v_parent;
235 } else {
236 vp = NULLVP;
237 }
238 } else {
239 vp = vp->v_parent;
240 }
241 /*
242 * check if we're crossing a mount point and
243 * switch the vp if we are.
244 */
245 if (vp && (vp->v_flag & VROOT) && vp->v_mount) {
246 vp = vp->v_mount->mnt_vnodecovered;
247 }
248 }
4452a7af 249 NAME_CACHE_UNLOCK();
91447636
A
250out:
251 /*
252 * slide it down to the beginning of the buffer
253 */
254 memmove(buff, end, &buff[buflen] - end);
255
256 *outlen = &buff[buflen] - end; // length includes the trailing zero byte
257
258 return ret;
259}
260
1c79356b
A
261
262/*
91447636
A
263 * return NULLVP if vp's parent doesn't
264 * exist, or we can't get a valid iocount
265 * else return the parent of vp
1c79356b 266 */
91447636
A
267vnode_t
268vnode_getparent(vnode_t vp)
269{
270 vnode_t pvp = NULLVP;
271 int pvid;
272
4452a7af 273 NAME_CACHE_LOCK_SHARED();
91447636
A
274 /*
275 * v_parent is stable behind the name_cache lock
276 * however, the only thing we can really guarantee
277 * is that we've grabbed a valid iocount on the
278 * parent of 'vp' at the time we took the name_cache lock...
279 * once we drop the lock, vp could get re-parented
280 */
281 if ( (pvp = vp->v_parent) != NULLVP ) {
282 pvid = pvp->v_id;
283
4452a7af 284 NAME_CACHE_UNLOCK();
91447636
A
285
286 if (vnode_getwithvid(pvp, pvid) != 0)
287 pvp = NULL;
288 } else
4452a7af 289 NAME_CACHE_UNLOCK();
91447636
A
290 return (pvp);
291}
292
293char *
294vnode_getname(vnode_t vp)
295{
296 char *name = NULL;
297
4452a7af 298 NAME_CACHE_LOCK();
91447636
A
299
300 if (vp->v_name)
301 name = add_name_locked(vp->v_name, strlen(vp->v_name), 0, 0);
4452a7af 302 NAME_CACHE_UNLOCK();
91447636
A
303
304 return (name);
1c79356b 305}
91447636
A
306
307void
308vnode_putname(char *name)
309{
4452a7af 310 NAME_CACHE_LOCK();
91447636
A
311
312 remove_name_locked(name);
313
4452a7af 314 NAME_CACHE_UNLOCK();
91447636
A
315}
316
317
318/*
319 * if VNODE_UPDATE_PARENT, and we can take
320 * a reference on dvp, then update vp with
321 * it's new parent... if vp already has a parent,
322 * then drop the reference vp held on it
323 *
324 * if VNODE_UPDATE_NAME,
325 * then drop string ref on v_name if it exists, and if name is non-NULL
326 * then pick up a string reference on name and record it in v_name...
327 * optionally pass in the length and hashval of name if known
328 *
329 * if VNODE_UPDATE_CACHE, flush the name cache entries associated with vp
330 */
331void
332vnode_update_identity(vnode_t vp, vnode_t dvp, char *name, int name_len, int name_hashval, int flags)
333{
334 struct namecache *ncp;
335 vnode_t old_parentvp = NULLVP;
336
337
338 if (flags & VNODE_UPDATE_PARENT) {
339 if (dvp && vnode_ref(dvp) != 0)
340 dvp = NULLVP;
341 } else
342 dvp = NULLVP;
4452a7af 343 NAME_CACHE_LOCK();
91447636
A
344
345 if ( (flags & VNODE_UPDATE_NAME) && (name != vp->v_name) ) {
346 if (vp->v_name != NULL) {
347 remove_name_locked(vp->v_name);
348 vp->v_name = NULL;
349 }
350 if (name && *name) {
351 if (name_len == 0)
352 name_len = strlen(name);
353 vp->v_name = add_name_locked(name, name_len, name_hashval, 0);
354 }
355 }
356 if (flags & VNODE_UPDATE_PARENT) {
357 if (dvp != vp && dvp != vp->v_parent) {
358 old_parentvp = vp->v_parent;
359 vp->v_parent = dvp;
360 dvp = NULLVP;
361
362 if (old_parentvp)
363 flags |= VNODE_UPDATE_CACHE;
364 }
365 }
366 if (flags & VNODE_UPDATE_CACHE) {
367 while ( (ncp = LIST_FIRST(&vp->v_nclinks)) )
368 cache_delete(ncp, 1);
369 }
4452a7af 370 NAME_CACHE_UNLOCK();
91447636
A
371
372 if (dvp != NULLVP)
373 vnode_rele(dvp);
374
375 if (old_parentvp) {
376 struct uthread *ut;
377
378 ut = get_bsdthread_info(current_thread());
379
380 /*
381 * indicated to vnode_rele that it shouldn't do a
382 * vnode_reclaim at this time... instead it will
383 * chain the vnode to the uu_vreclaims list...
384 * we'll be responsible for calling vnode_reclaim
385 * on each of the vnodes in this list...
386 */
387 ut->uu_defer_reclaims = 1;
388 ut->uu_vreclaims = NULLVP;
389
390 while ( (vp = old_parentvp) != NULLVP ) {
391
392 vnode_lock(vp);
393
394 vnode_rele_internal(vp, 0, 0, 1);
395
396 /*
397 * check to see if the vnode is now in the state
398 * that would have triggered a vnode_reclaim in vnode_rele
399 * if it is, we save it's parent pointer and then NULL
400 * out the v_parent field... we'll drop the reference
401 * that was held on the next iteration of this loop...
402 * this short circuits a potential deep recursion if we
403 * have a long chain of parents in this state...
404 * we'll sit in this loop until we run into
405 * a parent in this chain that is not in this state
406 *
407 * make our check and the node_rele atomic
408 * with respect to the current vnode we're working on
409 * by holding the vnode lock
410 * if vnode_rele deferred the vnode_reclaim and has put
411 * this vnode on the list to be reaped by us, than
412 * it has left this vnode with an iocount == 1
413 */
414 if ( (vp->v_iocount == 1) && (vp->v_usecount == 0) &&
415 ((vp->v_lflag & (VL_MARKTERM | VL_TERMINATE | VL_DEAD)) == VL_MARKTERM)) {
416 /*
417 * vnode_rele wanted to do a vnode_reclaim on this vnode
418 * it should be sitting on the head of the uu_vreclaims chain
419 * pull the parent pointer now so that when we do the
420 * vnode_reclaim for each of the vnodes in the uu_vreclaims
421 * list, we won't recurse back through here
422 */
4452a7af 423 NAME_CACHE_LOCK();
91447636
A
424 old_parentvp = vp->v_parent;
425 vp->v_parent = NULLVP;
4452a7af 426 NAME_CACHE_UNLOCK();
91447636
A
427 } else {
428 /*
429 * we're done... we ran into a vnode that isn't
430 * being terminated
431 */
432 old_parentvp = NULLVP;
433 }
434 vnode_unlock(vp);
435 }
436 ut->uu_defer_reclaims = 0;
437
438 while ( (vp = ut->uu_vreclaims) != NULLVP) {
439 ut->uu_vreclaims = vp->v_defer_reclaimlist;
440
441 /*
442 * vnode_put will drive the vnode_reclaim if
443 * we are still the only reference on this vnode
444 */
445 vnode_put(vp);
446 }
447 }
1c79356b 448}
91447636 449
1c79356b
A
450
451/*
91447636
A
452 * Mark a vnode as having multiple hard links. HFS makes use of this
453 * because it keeps track of each link separately, and wants to know
454 * which link was actually used.
455 *
456 * This will cause the name cache to force a VNOP_LOOKUP on the vnode
457 * so that HFS can post-process the lookup. Also, volfs will call
458 * VNOP_GETATTR2 to determine the parent, instead of using v_parent.
1c79356b 459 */
91447636
A
460void vnode_set_hard_link(vnode_t vp)
461{
462 vnode_lock(vp);
463
464 /*
465 * In theory, we're changing the vnode's identity as far as the
466 * name cache is concerned, so we ought to grab the name cache lock
467 * here. However, there is already a race, and grabbing the name
468 * cache lock only makes the race window slightly smaller.
469 *
470 * The race happens because the vnode already exists in the name
471 * cache, and could be found by one thread before another thread
472 * can set the hard link flag.
473 */
474
475 vp->v_flag |= VISHARDLINK;
476
477 vnode_unlock(vp);
478}
479
480
481void vnode_uncache_credentials(vnode_t vp)
482{
4452a7af 483 kauth_cred_t ucred = NOCRED;
91447636 484
4452a7af
A
485 vnode_lock(vp);
486 if (IS_VALID_CRED(vp->v_cred)) {
91447636 487 ucred = vp->v_cred;
4452a7af 488 vp->v_cred = NOCRED;
21362eb3 489 }
4452a7af
A
490 vnode_unlock(vp);
491
492 if (ucred != NOCRED)
493 kauth_cred_unref(&ucred);
91447636
A
494}
495
496
497void vnode_cache_credentials(vnode_t vp, vfs_context_t context)
498{
499 kauth_cred_t ucred;
500 kauth_cred_t tcred = NOCRED;
501 struct timeval tv;
502
503 ucred = vfs_context_ucred(context);
504
4452a7af
A
505 vnode_lock(vp);
506 if (IS_VALID_CRED(ucred) && (vp->v_cred != ucred || (vp->v_mount->mnt_kern_flag & MNTK_AUTH_OPAQUE))) {
91447636
A
507
508 microuptime(&tv);
509 vp->v_cred_timestamp = tv.tv_sec;
510
511 if (vp->v_cred != ucred) {
512 kauth_cred_ref(ucred);
513
514 tcred = vp->v_cred;
515 vp->v_cred = ucred;
516 }
91447636 517 }
4452a7af
A
518 vnode_unlock(vp);
519
520 if (IS_VALID_CRED(tcred))
521 kauth_cred_unref(&tcred);
91447636
A
522}
523
524/* reverse_lookup - lookup by walking back up the parent chain while leveraging
525 * use of the name cache lock in order to protect our starting vnode.
526 * NOTE - assumes you already have search access to starting point.
527 * returns 0 when we have reached the root, current working dir, or chroot root
528 *
529 */
530int
531reverse_lookup(vnode_t start_vp, vnode_t *lookup_vpp, struct filedesc *fdp, vfs_context_t context, int *dp_authorized)
532{
533 int vid, done = 0;
534 int auth_opaque = 0;
535 vnode_t dp = start_vp;
536 vnode_t vp = NULLVP;
537 kauth_cred_t ucred;
538 struct timeval tv;
539
540 ucred = vfs_context_ucred(context);
541 *lookup_vpp = start_vp;
542
4452a7af 543 NAME_CACHE_LOCK_SHARED();
91447636
A
544
545 if ( dp->v_mount && (dp->v_mount->mnt_kern_flag & MNTK_AUTH_OPAQUE) ) {
546 auth_opaque = 1;
547 microuptime(&tv);
548 }
549 for (;;) {
550 *dp_authorized = 0;
551
552 if (auth_opaque && ((tv.tv_sec - dp->v_cred_timestamp) > VCRED_EXPIRED))
553 break;
4452a7af 554 /* XXX should be safe without vnode_lock() */
91447636
A
555 if (dp->v_cred != ucred)
556 break;
557 /*
558 * indicate that we're allowed to traverse this directory...
559 * even if we bail for some reason, this information is valid and is used
560 * to avoid doing a vnode_authorize
561 */
562 *dp_authorized = 1;
563
564 if ((dp->v_flag & VROOT) != 0 || /* Hit "/" */
565 (dp == fdp->fd_cdir) || /* Hit process's working directory */
566 (dp == fdp->fd_rdir)) { /* Hit process chroot()-ed root */
567 done = 1;
568 break;
569 }
570
571 if ( (vp = dp->v_parent) == NULLVP)
572 break;
573
574 dp = vp;
575 *lookup_vpp = dp;
576 } /* for (;;) */
577
578 vid = dp->v_id;
579
4452a7af 580 NAME_CACHE_UNLOCK();
91447636
A
581
582 if (done == 0 && dp != start_vp) {
583 if (vnode_getwithvid(dp, vid) != 0) {
584 *lookup_vpp = start_vp;
585 }
586 }
587
588 return((done == 1) ? 0 : -1);
589}
590
591int
592cache_lookup_path(struct nameidata *ndp, struct componentname *cnp, vnode_t dp, vfs_context_t context, int *trailing_slash, int *dp_authorized)
593{
594 char *cp; /* pointer into pathname argument */
595 int vid, vvid;
596 int auth_opaque = 0;
597 vnode_t vp = NULLVP;
598 vnode_t tdp = NULLVP;
599 kauth_cred_t ucred;
600 struct timeval tv;
601 unsigned int hash;
602
603 ucred = vfs_context_ucred(context);
604 *trailing_slash = 0;
605
4452a7af 606 NAME_CACHE_LOCK_SHARED();
91447636
A
607
608 if ( dp->v_mount && (dp->v_mount->mnt_kern_flag & MNTK_AUTH_OPAQUE) ) {
609 auth_opaque = 1;
610 microuptime(&tv);
611 }
612 for (;;) {
613 /*
614 * Search a directory.
615 *
616 * The cn_hash value is for use by cache_lookup
617 * The last component of the filename is left accessible via
618 * cnp->cn_nameptr for callers that need the name.
619 */
620 hash = 0;
621 cp = cnp->cn_nameptr;
622
623 while (*cp && (*cp != '/')) {
624 hash ^= crc32tab[((hash >> 24) ^ (unsigned char)*cp++)];
625 }
626 /*
627 * the crc generator can legitimately generate
628 * a 0... however, 0 for us means that we
629 * haven't computed a hash, so use 1 instead
630 */
631 if (hash == 0)
632 hash = 1;
633 cnp->cn_hash = hash;
634 cnp->cn_namelen = cp - cnp->cn_nameptr;
635
636 ndp->ni_pathlen -= cnp->cn_namelen;
637 ndp->ni_next = cp;
638
639 /*
640 * Replace multiple slashes by a single slash and trailing slashes
641 * by a null. This must be done before VNOP_LOOKUP() because some
642 * fs's don't know about trailing slashes. Remember if there were
643 * trailing slashes to handle symlinks, existing non-directories
644 * and non-existing files that won't be directories specially later.
645 */
646 while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
647 cp++;
648 ndp->ni_pathlen--;
649
650 if (*cp == '\0') {
651 *trailing_slash = 1;
652 *ndp->ni_next = '\0';
653 }
654 }
655 ndp->ni_next = cp;
656
657 cnp->cn_flags &= ~(MAKEENTRY | ISLASTCN | ISDOTDOT);
658
659 if (*cp == '\0')
660 cnp->cn_flags |= ISLASTCN;
661
662 if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
663 cnp->cn_flags |= ISDOTDOT;
664
665 *dp_authorized = 0;
666
667 if (auth_opaque && ((tv.tv_sec - dp->v_cred_timestamp) > VCRED_EXPIRED))
668 break;
669
4452a7af 670 /* XXX should be safe without vnode_lock() */
91447636
A
671 if (dp->v_cred != ucred)
672 break;
673 /*
674 * indicate that we're allowed to traverse this directory...
675 * even if we fail the cache lookup or decide to bail for
676 * some other reason, this information is valid and is used
677 * to avoid doing a vnode_authorize before the call to VNOP_LOOKUP
678 */
679 *dp_authorized = 1;
680
681 if ( (cnp->cn_flags & (ISLASTCN | ISDOTDOT)) ) {
682 if (cnp->cn_nameiop != LOOKUP)
683 break;
743b1565 684 if (cnp->cn_flags & (LOCKPARENT | NOCACHE))
91447636 685 break;
743b1565
A
686 if (cnp->cn_flags & ISDOTDOT) {
687 /*
688 * Quit here only if we can't use
689 * the parent directory pointer or
690 * don't have one. Otherwise, we'll
691 * use it below.
692 */
693 if ((dp->v_flag & VROOT) ||
694 dp->v_parent == NULLVP)
695 break;
696 }
697 }
698
699 /*
700 * "." and ".." aren't supposed to be cached, so check
701 * for them before checking the cache.
702 */
703 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')
704 vp = dp;
705 else if (cnp->cn_flags & ISDOTDOT)
706 vp = dp->v_parent;
707 else {
708 if ( (vp = cache_lookup_locked(dp, cnp)) == NULLVP)
709 break;
91447636 710 }
91447636
A
711
712 if ( (cnp->cn_flags & ISLASTCN) )
713 break;
714
715 if (vp->v_type != VDIR) {
716 if (vp->v_type != VLNK)
717 vp = NULL;
718 break;
719 }
720 if (vp->v_mountedhere && ((cnp->cn_flags & NOCROSSMOUNT) == 0))
721 break;
722
723 dp = vp;
724 vp = NULLVP;
725
726 cnp->cn_nameptr = ndp->ni_next + 1;
727 ndp->ni_pathlen--;
728 while (*cnp->cn_nameptr == '/') {
729 cnp->cn_nameptr++;
730 ndp->ni_pathlen--;
731 }
732 }
733 if (vp != NULLVP)
734 vvid = vp->v_id;
735 vid = dp->v_id;
736
4452a7af 737 NAME_CACHE_UNLOCK();
91447636
A
738
739
740 if ((vp != NULLVP) && (vp->v_type != VLNK) &&
741 ((cnp->cn_flags & (ISLASTCN | LOCKPARENT | WANTPARENT | SAVESTART)) == ISLASTCN)) {
742 /*
743 * if we've got a child and it's the last component, and
744 * the lookup doesn't need to return the parent then we
745 * can skip grabbing an iocount on the parent, since all
746 * we're going to do with it is a vnode_put just before
747 * we return from 'lookup'. If it's a symbolic link,
748 * we need the parent in case the link happens to be
749 * a relative pathname.
750 */
751 tdp = dp;
752 dp = NULLVP;
753 } else {
754need_dp:
755 /*
756 * return the last directory we looked at
757 * with an io reference held
758 */
759 if (dp == ndp->ni_usedvp) {
760 /*
761 * if this vnode matches the one passed in via USEDVP
762 * than this context already holds an io_count... just
763 * use vnode_get to get an extra ref for lookup to play
764 * with... can't use the getwithvid variant here because
765 * it will block behind a vnode_drain which would result
766 * in a deadlock (since we already own an io_count that the
767 * vnode_drain is waiting on)... vnode_get grabs the io_count
768 * immediately w/o waiting... it always succeeds
769 */
770 vnode_get(dp);
771 } else if ( (vnode_getwithvid(dp, vid)) ) {
772 /*
773 * failure indicates the vnode
774 * changed identity or is being
775 * TERMINATED... in either case
776 * punt this lookup
777 */
778 return (ENOENT);
779 }
780 }
781 if (vp != NULLVP) {
782 if ( (vnode_getwithvid(vp, vvid)) ) {
783 vp = NULLVP;
784
785 /*
786 * can't get reference on the vp we'd like
787 * to return... if we didn't grab a reference
788 * on the directory (due to fast path bypass),
789 * then we need to do it now... we can't return
790 * with both ni_dvp and ni_vp NULL, and no
791 * error condition
792 */
793 if (dp == NULLVP) {
794 dp = tdp;
795 goto need_dp;
796 }
797 }
798 }
799 ndp->ni_dvp = dp;
800 ndp->ni_vp = vp;
801
802 return (0);
803}
804
805
806static vnode_t
807cache_lookup_locked(vnode_t dvp, struct componentname *cnp)
808{
809 register struct namecache *ncp;
810 register struct nchashhead *ncpp;
811 register long namelen = cnp->cn_namelen;
812 char *nameptr = cnp->cn_nameptr;
813 unsigned int hashval = (cnp->cn_hash & NCHASHMASK);
814 vnode_t vp;
815
816 ncpp = NCHHASH(dvp, cnp->cn_hash);
817 LIST_FOREACH(ncp, ncpp, nc_hash) {
818 if ((ncp->nc_dvp == dvp) && (ncp->nc_hashval == hashval)) {
819 if (memcmp(ncp->nc_name, nameptr, namelen) == 0 && ncp->nc_name[namelen] == 0)
820 break;
821 }
822 }
4452a7af 823 if (ncp == 0) {
91447636
A
824 /*
825 * We failed to find an entry
826 */
4452a7af 827 NCHSTAT(ncs_miss);
91447636 828 return (NULL);
4452a7af
A
829 }
830 NCHSTAT(ncs_goodhits);
91447636
A
831
832 vp = ncp->nc_vp;
833 if (vp && (vp->v_flag & VISHARDLINK)) {
834 /*
835 * The file system wants a VNOP_LOOKUP on this vnode
836 */
837 vp = NULL;
838 }
839
840 return (vp);
1c79356b
A
841}
842
55e303ae
A
843
844//
845// Have to take a len argument because we may only need to
846// hash part of a componentname.
847//
848static unsigned int
91447636 849hash_string(const char *cp, int len)
55e303ae 850{
91447636 851 unsigned hash = 0;
55e303ae 852
91447636
A
853 if (len) {
854 while (len--) {
855 hash ^= crc32tab[((hash >> 24) ^ (unsigned char)*cp++)];
856 }
55e303ae 857 } else {
91447636
A
858 while (*cp != '\0') {
859 hash ^= crc32tab[((hash >> 24) ^ (unsigned char)*cp++)];
860 }
55e303ae 861 }
91447636
A
862 /*
863 * the crc generator can legitimately generate
864 * a 0... however, 0 for us means that we
865 * haven't computed a hash, so use 1 instead
866 */
867 if (hash == 0)
868 hash = 1;
869 return hash;
55e303ae
A
870}
871
872
1c79356b
A
873/*
874 * Lookup an entry in the cache
875 *
876 * We don't do this if the segment name is long, simply so the cache
877 * can avoid holding long names (which would either waste space, or
878 * add greatly to the complexity).
879 *
880 * Lookup is called with dvp pointing to the directory to search,
881 * cnp pointing to the name of the entry being sought. If the lookup
882 * succeeds, the vnode is returned in *vpp, and a status of -1 is
883 * returned. If the lookup determines that the name does not exist
884 * (negative cacheing), a status of ENOENT is returned. If the lookup
885 * fails, a status of zero is returned.
886 */
887
888int
889cache_lookup(dvp, vpp, cnp)
890 struct vnode *dvp;
891 struct vnode **vpp;
892 struct componentname *cnp;
893{
91447636 894 register struct namecache *ncp;
1c79356b 895 register struct nchashhead *ncpp;
55e303ae
A
896 register long namelen = cnp->cn_namelen;
897 char *nameptr = cnp->cn_nameptr;
91447636 898 unsigned int hashval = (cnp->cn_hash & NCHASHMASK);
4452a7af 899 boolean_t have_exclusive = FALSE;
91447636
A
900 uint32_t vid;
901 vnode_t vp;
1c79356b 902
4452a7af 903 NAME_CACHE_LOCK_SHARED();
1c79356b 904
55e303ae 905 ncpp = NCHHASH(dvp, cnp->cn_hash);
4452a7af 906relook:
91447636
A
907 LIST_FOREACH(ncp, ncpp, nc_hash) {
908 if ((ncp->nc_dvp == dvp) && (ncp->nc_hashval == hashval)) {
909 if (memcmp(ncp->nc_name, nameptr, namelen) == 0 && ncp->nc_name[namelen] == 0)
910 break;
55e303ae 911 }
1c79356b 912 }
1c79356b
A
913 /* We failed to find an entry */
914 if (ncp == 0) {
4452a7af
A
915 NCHSTAT(ncs_miss);
916 NAME_CACHE_UNLOCK();
1c79356b
A
917 return (0);
918 }
919
920 /* We don't want to have an entry, so dump it */
921 if ((cnp->cn_flags & MAKEENTRY) == 0) {
4452a7af
A
922 if (have_exclusive == TRUE) {
923 NCHSTAT(ncs_badhits);
924 cache_delete(ncp, 1);
925 NAME_CACHE_UNLOCK();
926 return (0);
927 }
928 NAME_CACHE_UNLOCK();
929 NAME_CACHE_LOCK();
930 have_exclusive = TRUE;
931 goto relook;
1c79356b 932 }
91447636 933 vp = ncp->nc_vp;
1c79356b
A
934
935 /* We found a "positive" match, return the vnode */
91447636 936 if (vp) {
4452a7af 937 NCHSTAT(ncs_goodhits);
91447636
A
938
939 vid = vp->v_id;
4452a7af 940 NAME_CACHE_UNLOCK();
91447636
A
941
942 if (vnode_getwithvid(vp, vid)) {
4452a7af
A
943#if COLLECT_STATS
944 NAME_CACHE_LOCK();
945 NCHSTAT(ncs_badvid);
946 NAME_CACHE_UNLOCK();
947#endif
91447636
A
948 return (0);
949 }
950 *vpp = vp;
1c79356b
A
951 return (-1);
952 }
953
954 /* We found a negative match, and want to create it, so purge */
91447636 955 if (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) {
4452a7af
A
956 if (have_exclusive == TRUE) {
957 NCHSTAT(ncs_badhits);
958 cache_delete(ncp, 1);
959 NAME_CACHE_UNLOCK();
960 return (0);
961 }
962 NAME_CACHE_UNLOCK();
963 NAME_CACHE_LOCK();
964 have_exclusive = TRUE;
965 goto relook;
1c79356b
A
966 }
967
968 /*
969 * We found a "negative" match, ENOENT notifies client of this match.
91447636 970 * The nc_whiteout field records whether this is a whiteout.
1c79356b 971 */
4452a7af 972 NCHSTAT(ncs_neghits);
91447636
A
973
974 if (ncp->nc_whiteout)
975 cnp->cn_flags |= ISWHITEOUT;
4452a7af 976 NAME_CACHE_UNLOCK();
1c79356b
A
977 return (ENOENT);
978}
979
980/*
981 * Add an entry to the cache.
982 */
983void
984cache_enter(dvp, vp, cnp)
985 struct vnode *dvp;
986 struct vnode *vp;
987 struct componentname *cnp;
988{
91447636 989 register struct namecache *ncp, *negp;
1c79356b
A
990 register struct nchashhead *ncpp;
991
91447636
A
992 if (cnp->cn_hash == 0)
993 cnp->cn_hash = hash_string(cnp->cn_nameptr, cnp->cn_namelen);
994
4452a7af 995 NAME_CACHE_LOCK();
1c79356b 996
91447636
A
997 /* if the entry is for -ve caching vp is null */
998 if ((vp != NULLVP) && (LIST_FIRST(&vp->v_nclinks))) {
999 /*
1000 * someone beat us to the punch..
1001 * this vnode is already in the cache
1002 */
4452a7af
A
1003 NAME_CACHE_UNLOCK();
1004 return;
91447636 1005 }
1c79356b
A
1006 /*
1007 * We allocate a new entry if we are less than the maximum
91447636
A
1008 * allowed and the one at the front of the list is in use.
1009 * Otherwise we use the one at the front of the list.
1c79356b 1010 */
91447636
A
1011 if (numcache < desiredNodes &&
1012 ((ncp = nchead.tqh_first) == NULL ||
1013 ncp->nc_hash.le_prev != 0)) {
1014 /*
1015 * Allocate one more entry
1016 */
1017 ncp = (struct namecache *)_MALLOC_ZONE((u_long)sizeof *ncp, M_CACHE, M_WAITOK);
1c79356b 1018 numcache++;
91447636
A
1019 } else {
1020 /*
1021 * reuse an old entry
1022 */
1023 ncp = TAILQ_FIRST(&nchead);
1024 TAILQ_REMOVE(&nchead, ncp, nc_entry);
1025
1c79356b 1026 if (ncp->nc_hash.le_prev != 0) {
91447636
A
1027 /*
1028 * still in use... we need to
1029 * delete it before re-using it
1030 */
4452a7af 1031 NCHSTAT(ncs_stolen);
91447636 1032 cache_delete(ncp, 0);
1c79356b 1033 }
1c79356b 1034 }
4452a7af 1035 NCHSTAT(ncs_enters);
1c79356b
A
1036
1037 /*
1038 * Fill in cache info, if vp is NULL this is a "negative" cache entry.
1c79356b
A
1039 */
1040 ncp->nc_vp = vp;
1c79356b 1041 ncp->nc_dvp = dvp;
91447636
A
1042 ncp->nc_hashval = cnp->cn_hash;
1043 ncp->nc_whiteout = FALSE;
1044 ncp->nc_name = add_name_locked(cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_hash, 0);
1045
1046 /*
1047 * make us the newest entry in the cache
1048 * i.e. we'll be the last to be stolen
1049 */
1050 TAILQ_INSERT_TAIL(&nchead, ncp, nc_entry);
1051
55e303ae 1052 ncpp = NCHHASH(dvp, cnp->cn_hash);
1c79356b
A
1053#if DIAGNOSTIC
1054 {
1055 register struct namecache *p;
1056
1057 for (p = ncpp->lh_first; p != 0; p = p->nc_hash.le_next)
1058 if (p == ncp)
1059 panic("cache_enter: duplicate");
1060 }
1061#endif
91447636
A
1062 /*
1063 * make us available to be found via lookup
1064 */
1c79356b 1065 LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
91447636
A
1066
1067 if (vp) {
1068 /*
1069 * add to the list of name cache entries
1070 * that point at vp
1071 */
1072 LIST_INSERT_HEAD(&vp->v_nclinks, ncp, nc_un.nc_link);
1073 } else {
1074 /*
1075 * this is a negative cache entry (vp == NULL)
1076 * stick it on the negative cache list
1077 * and record the whiteout state
1078 */
1079 TAILQ_INSERT_TAIL(&neghead, ncp, nc_un.nc_negentry);
1080
1081 if (cnp->cn_flags & ISWHITEOUT)
1082 ncp->nc_whiteout = TRUE;
4452a7af 1083 ncs_negtotal++;
91447636 1084
4452a7af 1085 if (ncs_negtotal > desiredNegNodes) {
91447636
A
1086 /*
1087 * if we've reached our desired limit
1088 * of negative cache entries, delete
1089 * the oldest
1090 */
1091 negp = TAILQ_FIRST(&neghead);
1092 TAILQ_REMOVE(&neghead, negp, nc_un.nc_negentry);
1093
1094 cache_delete(negp, 1);
1095 }
1096 }
1097 /*
1098 * add us to the list of name cache entries that
1099 * are children of dvp
1100 */
1101 LIST_INSERT_HEAD(&dvp->v_ncchildren, ncp, nc_child);
1102
4452a7af 1103 NAME_CACHE_UNLOCK();
1c79356b
A
1104}
1105
91447636
A
1106
1107/*
1108 * Initialize CRC-32 remainder table.
1109 */
1110static void init_crc32(void)
1111{
1112 /*
1113 * the CRC-32 generator polynomial is:
1114 * x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^10
1115 * + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
1116 */
1117 unsigned int crc32_polynomial = 0x04c11db7;
1118 unsigned int i,j;
1119
1120 /*
1121 * pre-calculate the CRC-32 remainder for each possible octet encoding
1122 */
1123 for (i = 0; i < 256; i++) {
1124 unsigned int crc_rem = i << 24;
1125
1126 for (j = 0; j < 8; j++) {
1127 if (crc_rem & 0x80000000)
1128 crc_rem = (crc_rem << 1) ^ crc32_polynomial;
1129 else
1130 crc_rem = (crc_rem << 1);
1131 }
1132 crc32tab[i] = crc_rem;
1133 }
1134}
1135
1136
1c79356b
A
1137/*
1138 * Name cache initialization, from vfs_init() when we are booting
1139 */
1140void
91447636
A
1141nchinit(void)
1142{
1143 desiredNegNodes = (desiredvnodes / 10);
1144 desiredNodes = desiredvnodes + desiredNegNodes;
1145
1146 TAILQ_INIT(&nchead);
1147 TAILQ_INIT(&neghead);
1148
1149 init_crc32();
1150
1151 nchashtbl = hashinit(MAX(4096, (2 *desiredNodes)), M_CACHE, &nchash);
1152 nchashmask = nchash;
1153 nchash++;
1154
1155 init_string_table();
1156
1157 /* Allocate mount list lock group attribute and group */
1158 namecache_lck_grp_attr= lck_grp_attr_alloc_init();
91447636
A
1159
1160 namecache_lck_grp = lck_grp_alloc_init("Name Cache", namecache_lck_grp_attr);
1161
1162 /* Allocate mount list lock attribute */
1163 namecache_lck_attr = lck_attr_alloc_init();
91447636
A
1164
1165 /* Allocate mount list lock */
4452a7af 1166 namecache_rw_lock = lck_rw_alloc_init(namecache_lck_grp, namecache_lck_attr);
91447636
A
1167
1168
1169}
1170
4452a7af
A
1171void
1172name_cache_lock_shared(void)
1173{
1174 lck_rw_lock_shared(namecache_rw_lock);
1175}
1176
91447636
A
1177void
1178name_cache_lock(void)
1c79356b 1179{
4452a7af 1180 lck_rw_lock_exclusive(namecache_rw_lock);
91447636 1181}
55e303ae 1182
91447636
A
1183void
1184name_cache_unlock(void)
1185{
4452a7af 1186 lck_rw_done(namecache_rw_lock);
1c79356b
A
1187}
1188
55e303ae
A
1189
1190int
1191resize_namecache(u_int newsize)
1192{
91447636
A
1193 struct nchashhead *new_table;
1194 struct nchashhead *old_table;
1195 struct nchashhead *old_head, *head;
1196 struct namecache *entry, *next;
1197 uint32_t i, hashval;
1198 int dNodes, dNegNodes;
1199 u_long new_size, old_size;
1200
1201 dNegNodes = (newsize / 10);
1202 dNodes = newsize + dNegNodes;
55e303ae
A
1203
1204 // we don't support shrinking yet
91447636 1205 if (dNodes < desiredNodes) {
55e303ae
A
1206 return 0;
1207 }
91447636
A
1208 new_table = hashinit(2 * dNodes, M_CACHE, &nchashmask);
1209 new_size = nchashmask + 1;
55e303ae 1210
55e303ae
A
1211 if (new_table == NULL) {
1212 return ENOMEM;
1213 }
1214
4452a7af 1215 NAME_CACHE_LOCK();
55e303ae
A
1216 // do the switch!
1217 old_table = nchashtbl;
1218 nchashtbl = new_table;
91447636
A
1219 old_size = nchash;
1220 nchash = new_size;
55e303ae
A
1221
1222 // walk the old table and insert all the entries into
1223 // the new table
1224 //
91447636 1225 for(i=0; i < old_size; i++) {
55e303ae
A
1226 old_head = &old_table[i];
1227 for (entry=old_head->lh_first; entry != NULL; entry=next) {
1228 //
1229 // XXXdbg - Beware: this assumes that hash_string() does
1230 // the same thing as what happens in
1231 // lookup() over in vfs_lookup.c
91447636
A
1232 hashval = hash_string(entry->nc_name, 0);
1233 entry->nc_hashval = hashval;
1234 head = NCHHASH(entry->nc_dvp, hashval);
1235
55e303ae
A
1236 next = entry->nc_hash.le_next;
1237 LIST_INSERT_HEAD(head, entry, nc_hash);
1238 }
1239 }
91447636
A
1240 desiredNodes = dNodes;
1241 desiredNegNodes = dNegNodes;
55e303ae 1242
4452a7af 1243 NAME_CACHE_UNLOCK();
55e303ae
A
1244 FREE(old_table, M_CACHE);
1245
1246 return 0;
1247}
1248
91447636
A
1249static void
1250cache_delete(struct namecache *ncp, int age_entry)
1251{
4452a7af 1252 NCHSTAT(ncs_deletes);
91447636
A
1253
1254 if (ncp->nc_vp) {
1255 LIST_REMOVE(ncp, nc_un.nc_link);
1256 } else {
1257 TAILQ_REMOVE(&neghead, ncp, nc_un.nc_negentry);
4452a7af 1258 ncs_negtotal--;
91447636
A
1259 }
1260 LIST_REMOVE(ncp, nc_child);
1261
1262 LIST_REMOVE(ncp, nc_hash);
1263 /*
1264 * this field is used to indicate
1265 * that the entry is in use and
1266 * must be deleted before it can
1267 * be reused...
1268 */
1269 ncp->nc_hash.le_prev = NULL;
1270
1271 if (age_entry) {
1272 /*
1273 * make it the next one available
1274 * for cache_enter's use
1275 */
1276 TAILQ_REMOVE(&nchead, ncp, nc_entry);
1277 TAILQ_INSERT_HEAD(&nchead, ncp, nc_entry);
1278 }
1279 remove_name_locked(ncp->nc_name);
1280 ncp->nc_name = NULL;
1281}
1282
1283
1284/*
1285 * purge the entry associated with the
1286 * specified vnode from the name cache
1287 */
1288void
1289cache_purge(vnode_t vp)
1290{
1291 struct namecache *ncp;
1292
1293 if ((LIST_FIRST(&vp->v_nclinks) == NULL) && (LIST_FIRST(&vp->v_ncchildren) == NULL))
1294 return;
1295
4452a7af 1296 NAME_CACHE_LOCK();
55e303ae 1297
91447636
A
1298 while ( (ncp = LIST_FIRST(&vp->v_nclinks)) )
1299 cache_delete(ncp, 1);
55e303ae 1300
91447636
A
1301 while ( (ncp = LIST_FIRST(&vp->v_ncchildren)) )
1302 cache_delete(ncp, 1);
1303
4452a7af 1304 NAME_CACHE_UNLOCK();
91447636 1305}
55e303ae 1306
1c79356b 1307/*
91447636
A
1308 * Purge all negative cache entries that are children of the
1309 * given vnode. A case-insensitive file system (or any file
1310 * system that has multiple equivalent names for the same
1311 * directory entry) can use this when creating or renaming
1312 * to remove negative entries that may no longer apply.
1c79356b
A
1313 */
1314void
91447636 1315cache_purge_negatives(vnode_t vp)
1c79356b
A
1316{
1317 struct namecache *ncp;
1c79356b 1318
4452a7af 1319 NAME_CACHE_LOCK();
91447636
A
1320
1321 LIST_FOREACH(ncp, &vp->v_ncchildren, nc_child)
1322 if (ncp->nc_vp == NULL)
1323 cache_delete(ncp , 1);
1324
4452a7af 1325 NAME_CACHE_UNLOCK();
1c79356b
A
1326}
1327
1328/*
1329 * Flush all entries referencing a particular filesystem.
1330 *
1331 * Since we need to check it anyway, we will flush all the invalid
91447636 1332 * entries at the same time.
1c79356b
A
1333 */
1334void
1335cache_purgevfs(mp)
1336 struct mount *mp;
1337{
1338 struct nchashhead *ncpp;
91447636 1339 struct namecache *ncp;
1c79356b 1340
4452a7af 1341 NAME_CACHE_LOCK();
1c79356b 1342 /* Scan hash tables for applicable entries */
91447636
A
1343 for (ncpp = &nchashtbl[nchash - 1]; ncpp >= nchashtbl; ncpp--) {
1344restart:
1345 for (ncp = ncpp->lh_first; ncp != 0; ncp = ncp->nc_hash.le_next) {
1346 if (ncp->nc_dvp->v_mount == mp) {
1347 cache_delete(ncp, 0);
1348 goto restart;
1c79356b
A
1349 }
1350 }
1351 }
4452a7af 1352 NAME_CACHE_UNLOCK();
1c79356b 1353}
55e303ae
A
1354
1355
1356
1357//
1358// String ref routines
1359//
1360static LIST_HEAD(stringhead, string_t) *string_ref_table;
1361static u_long string_table_mask;
1362static uint32_t max_chain_len=0;
1363static struct stringhead *long_chain_head=NULL;
1364static uint32_t filled_buckets=0;
1365static uint32_t num_dups=0;
1366static uint32_t nstrings=0;
1367
1368typedef struct string_t {
1369 LIST_ENTRY(string_t) hash_chain;
1370 unsigned char *str;
1371 uint32_t refcount;
1372} string_t;
1373
1374
1375
1376static int
91447636 1377resize_string_ref_table(void)
55e303ae
A
1378{
1379 struct stringhead *new_table;
1380 struct stringhead *old_table;
1381 struct stringhead *old_head, *head;
1382 string_t *entry, *next;
1383 uint32_t i, hashval;
1384 u_long new_mask, old_mask;
1385
1386 new_table = hashinit((string_table_mask + 1) * 2, M_CACHE, &new_mask);
1387 if (new_table == NULL) {
1388 return ENOMEM;
1389 }
1390
1391 // do the switch!
1392 old_table = string_ref_table;
1393 string_ref_table = new_table;
1394 old_mask = string_table_mask;
1395 string_table_mask = new_mask;
1396
1397 printf("resize: max chain len %d, new table size %d\n",
1398 max_chain_len, new_mask + 1);
1399 max_chain_len = 0;
1400 long_chain_head = NULL;
1401 filled_buckets = 0;
1402
1403 // walk the old table and insert all the entries into
1404 // the new table
1405 //
1406 for(i=0; i <= old_mask; i++) {
1407 old_head = &old_table[i];
1408 for (entry=old_head->lh_first; entry != NULL; entry=next) {
1409 hashval = hash_string(entry->str, 0);
1410 head = &string_ref_table[hashval & string_table_mask];
1411 if (head->lh_first == NULL) {
1412 filled_buckets++;
1413 }
1414
1415 next = entry->hash_chain.le_next;
1416 LIST_INSERT_HEAD(head, entry, hash_chain);
1417 }
1418 }
1419
1420 FREE(old_table, M_CACHE);
1421
1422 return 0;
1423}
1424
1425
1426static void
1427init_string_table(void)
1428{
1429 string_ref_table = hashinit(4096, M_CACHE, &string_table_mask);
1430}
1431
1432
1433char *
91447636
A
1434vfs_addname(const char *name, size_t len, u_int hashval, u_int flags)
1435{
1436 char * ptr;
1437
4452a7af 1438 NAME_CACHE_LOCK();
91447636 1439 ptr = add_name_locked(name, len, hashval, flags);
4452a7af 1440 NAME_CACHE_UNLOCK();
91447636
A
1441
1442 return(ptr);
1443}
1444
1445static char *
1446add_name_locked(const char *name, size_t len, u_int hashval, __unused u_int flags)
55e303ae
A
1447{
1448 struct stringhead *head;
1449 string_t *entry;
91447636 1450 uint32_t chain_len = 0;
55e303ae
A
1451
1452 //
1453 // If the table gets more than 3/4 full, resize it
1454 //
1455 if (4*filled_buckets >= ((string_table_mask + 1) * 3)) {
1456 if (resize_string_ref_table() != 0) {
1457 printf("failed to resize the hash table.\n");
1458 }
1459 }
55e303ae 1460 if (hashval == 0) {
91447636 1461 hashval = hash_string(name, 0);
55e303ae
A
1462 }
1463
1464 head = &string_ref_table[hashval & string_table_mask];
1465 for (entry=head->lh_first; entry != NULL; chain_len++, entry=entry->hash_chain.le_next) {
91447636 1466 if (memcmp(entry->str, name, len) == 0 && entry->str[len] == '\0') {
55e303ae
A
1467 entry->refcount++;
1468 num_dups++;
1469 break;
1470 }
1471 }
1472
1473 if (entry == NULL) {
1474 // it wasn't already there so add it.
1475 MALLOC(entry, string_t *, sizeof(string_t) + len + 1, M_TEMP, M_WAITOK);
1476
1477 // have to get "head" again because we could have blocked
1478 // in malloc and thus head could have changed.
1479 //
1480 head = &string_ref_table[hashval & string_table_mask];
1481 if (head->lh_first == NULL) {
1482 filled_buckets++;
1483 }
1484
55e303ae
A
1485 entry->str = (char *)((char *)entry + sizeof(string_t));
1486 strncpy(entry->str, name, len);
1487 entry->str[len] = '\0';
1488 entry->refcount = 1;
91447636 1489 LIST_INSERT_HEAD(head, entry, hash_chain);
55e303ae
A
1490
1491 if (chain_len > max_chain_len) {
1492 max_chain_len = chain_len;
1493 long_chain_head = head;
1494 }
1495
1496 nstrings++;
1497 }
1498
1499 return entry->str;
1500}
1501
1502int
91447636
A
1503vfs_removename(const char *nameref)
1504{
1505 int i;
1506
4452a7af 1507 NAME_CACHE_LOCK();
91447636 1508 i = remove_name_locked(nameref);
4452a7af 1509 NAME_CACHE_UNLOCK();
91447636
A
1510
1511 return(i);
1512
1513}
1514
1515
1516static int
1517remove_name_locked(const char *nameref)
55e303ae
A
1518{
1519 struct stringhead *head;
1520 string_t *entry;
1521 uint32_t hashval;
91447636 1522 char * ptr;
55e303ae
A
1523
1524 hashval = hash_string(nameref, 0);
1525 head = &string_ref_table[hashval & string_table_mask];
1526 for (entry=head->lh_first; entry != NULL; entry=entry->hash_chain.le_next) {
1527 if (entry->str == (unsigned char *)nameref) {
1528 entry->refcount--;
1529 if (entry->refcount == 0) {
1530 LIST_REMOVE(entry, hash_chain);
1531 if (head->lh_first == NULL) {
1532 filled_buckets--;
1533 }
91447636 1534 ptr = entry->str;
55e303ae
A
1535 entry->str = NULL;
1536 nstrings--;
1537
1538 FREE(entry, M_TEMP);
1539 } else {
1540 num_dups--;
1541 }
1542
1543 return 0;
1544 }
1545 }
1546
1547 return ENOENT;
1548}
1549
1550
1551void
1552dump_string_table(void)
1553{
1554 struct stringhead *head;
1555 string_t *entry;
91447636 1556 u_long i;
55e303ae 1557
4452a7af
A
1558 NAME_CACHE_LOCK_SHARED();
1559
91447636 1560 for (i = 0; i <= string_table_mask; i++) {
55e303ae
A
1561 head = &string_ref_table[i];
1562 for (entry=head->lh_first; entry != NULL; entry=entry->hash_chain.le_next) {
1563 printf("%6d - %s\n", entry->refcount, entry->str);
1564 }
1565 }
4452a7af 1566 NAME_CACHE_UNLOCK();
55e303ae 1567}