1/*- 2 * Copyright (c) 1989, 1993, 1995 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Poul-Henning Kamp of the FreeBSD Project. 7 * 8 * Redistribution and use in source and binary forms, with or without --- 19 unchanged lines hidden (view full) --- 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)vfs_cache.c 8.5 (Berkeley) 3/22/95 33 */ 34 35#include <sys/cdefs.h> |
36__FBSDID("$FreeBSD: head/sys/kern/vfs_cache.c 230394 2012-01-20 20:02:01Z jhb $"); |
37 38#include "opt_kdtrace.h" 39#include "opt_ktrace.h" 40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/filedesc.h> 44#include <sys/fnv_hash.h> --- 47 unchanged lines hidden (view full) --- 92 */ 93 94struct namecache { 95 LIST_ENTRY(namecache) nc_hash; /* hash chain */ 96 LIST_ENTRY(namecache) nc_src; /* source vnode list */ 97 TAILQ_ENTRY(namecache) nc_dst; /* destination vnode list */ 98 struct vnode *nc_dvp; /* vnode of parent of name */ 99 struct vnode *nc_vp; /* vnode the name refers to */ |
100 struct timespec nc_time; /* timespec provided by fs */ 101 int nc_ticks; /* ticks value when entry was added */ |
102 u_char nc_flag; /* flag bits */ 103 u_char nc_nlen; /* length of name */ 104 char nc_name[0]; /* segment name + nul */ 105}; 106 107/* 108 * Name caching works as follows: 109 * --- 281 unchanged lines hidden (view full) --- 391 * ENOENT is returned. 392 * 393 * vpp is locked and ref'd on return. If we're looking up DOTDOT, dvp is 394 * unlocked. If we're looking up . an extra ref is taken, but the lock is 395 * not recursively acquired. 396 */ 397 398int |
399cache_lookup_times(dvp, vpp, cnp, tsp, ticksp) |
400 struct vnode *dvp; 401 struct vnode **vpp; 402 struct componentname *cnp; |
403 struct timespec *tsp; 404 int *ticksp; |
405{ 406 struct namecache *ncp; 407 uint32_t hash; 408 int error, ltype, wlocked; 409 410 if (!doingcache) { 411 cnp->cn_flags &= ~MAKEENTRY; 412 return (0); --- 8 unchanged lines hidden (view full) --- 421 if (cnp->cn_nameptr[0] == '.') { 422 if (cnp->cn_namelen == 1) { 423 *vpp = dvp; 424 CTR2(KTR_VFS, "cache_lookup(%p, %s) found via .", 425 dvp, cnp->cn_nameptr); 426 dothits++; 427 SDT_PROBE(vfs, namecache, lookup, hit, dvp, ".", 428 *vpp, 0, 0); |
429 if (tsp != NULL) 430 timespecclear(tsp); 431 if (ticksp != NULL) 432 *ticksp = ticks; |
433 goto success; 434 } 435 if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') { 436 dotdothits++; 437 if (dvp->v_cache_dd == NULL) { 438 SDT_PROBE(vfs, namecache, lookup, miss, dvp, 439 "..", NULL, 0, 0); 440 goto unlock; 441 } 442 if ((cnp->cn_flags & MAKEENTRY) == 0) { 443 if (!wlocked && !CACHE_UPGRADE_LOCK()) 444 goto wlock; 445 if (dvp->v_cache_dd->nc_flag & NCF_ISDOTDOT) 446 cache_zap(dvp->v_cache_dd); 447 dvp->v_cache_dd = NULL; 448 CACHE_WUNLOCK(); 449 return (0); 450 } |
451 ncp = dvp->v_cache_dd; 452 if (ncp->nc_flag & NCF_ISDOTDOT) 453 *vpp = ncp->nc_vp; |
454 else |
455 *vpp = ncp->nc_dvp; |
456 /* Return failure if negative entry was found. */ |
457 if (*vpp == NULL) |
458 goto negative_success; |
459 CTR3(KTR_VFS, "cache_lookup(%p, %s) found %p via ..", 460 dvp, cnp->cn_nameptr, *vpp); 461 SDT_PROBE(vfs, namecache, lookup, hit, dvp, "..", 462 *vpp, 0, 0); |
463 if (tsp != NULL) 464 *tsp = ncp->nc_time; 465 if (ticksp != NULL) 466 *ticksp = ncp->nc_ticks; |
467 goto success; 468 } 469 } 470 471 hash = fnv_32_buf(cnp->cn_nameptr, cnp->cn_namelen, FNV1_32_INIT); 472 hash = fnv_32_buf(&dvp, sizeof(dvp), hash); 473 LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { 474 numchecks++; --- 30 unchanged lines hidden (view full) --- 505 if (ncp->nc_vp) { 506 numposhits++; 507 nchstats.ncs_goodhits++; 508 *vpp = ncp->nc_vp; 509 CTR4(KTR_VFS, "cache_lookup(%p, %s) found %p via ncp %p", 510 dvp, cnp->cn_nameptr, *vpp, ncp); 511 SDT_PROBE(vfs, namecache, lookup, hit, dvp, ncp->nc_name, 512 *vpp, 0, 0); |
513 if (tsp != NULL) 514 *tsp = ncp->nc_time; 515 if (ticksp != NULL) 516 *ticksp = ncp->nc_ticks; |
517 goto success; 518 } 519 520negative_success: 521 /* We found a negative match, and want to create it, so purge */ 522 if (cnp->cn_nameiop == CREATE) { 523 numnegzaps++; 524 nchstats.ncs_badhits++; --- 15 unchanged lines hidden (view full) --- 540 */ 541 TAILQ_REMOVE(&ncneg, ncp, nc_dst); 542 TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst); 543 nchstats.ncs_neghits++; 544 if (ncp->nc_flag & NCF_WHITE) 545 cnp->cn_flags |= ISWHITEOUT; 546 SDT_PROBE(vfs, namecache, lookup, hit_negative, dvp, ncp->nc_name, 547 0, 0, 0); |
548 if (tsp != NULL) 549 *tsp = ncp->nc_time; 550 if (ticksp != NULL) 551 *ticksp = ncp->nc_ticks; |
552 CACHE_WUNLOCK(); 553 return (ENOENT); 554 555wlock: 556 /* 557 * We need to update the cache after our lookup, so upgrade to 558 * a write lock and retry the operation. 559 */ --- 70 unchanged lines hidden (view full) --- 630 CACHE_RUNLOCK(); 631 return (0); 632} 633 634/* 635 * Add an entry to the cache. 636 */ 637void |
638cache_enter_time(dvp, vp, cnp, tsp) |
639 struct vnode *dvp; 640 struct vnode *vp; 641 struct componentname *cnp; |
642 struct timespec *tsp; |
643{ 644 struct namecache *ncp, *n2; 645 struct nchashhead *ncpp; 646 uint32_t hash; 647 int flag; 648 int hold; 649 int zap; 650 int len; --- 56 unchanged lines hidden (view full) --- 707 /* 708 * Calculate the hash key and setup as much of the new 709 * namecache entry as possible before acquiring the lock. 710 */ 711 ncp = cache_alloc(cnp->cn_namelen); 712 ncp->nc_vp = vp; 713 ncp->nc_dvp = dvp; 714 ncp->nc_flag = flag; |
715 if (tsp != NULL) 716 ncp->nc_time = *tsp; 717 else 718 timespecclear(&ncp->nc_time); 719 ncp->nc_ticks = ticks; |
720 len = ncp->nc_nlen = cnp->cn_namelen; 721 hash = fnv_32_buf(cnp->cn_nameptr, len, FNV1_32_INIT); 722 strlcpy(ncp->nc_name, cnp->cn_nameptr, len + 1); 723 hash = fnv_32_buf(&dvp, sizeof(dvp), hash); 724 CACHE_WLOCK(); 725 726 /* 727 * See if this vnode or negative entry is already in the cache 728 * with this name. This can happen with concurrent lookups of 729 * the same path name. 730 */ 731 ncpp = NCHHASH(hash); 732 LIST_FOREACH(n2, ncpp, nc_hash) { 733 if (n2->nc_dvp == dvp && 734 n2->nc_nlen == cnp->cn_namelen && 735 !bcmp(n2->nc_name, cnp->cn_nameptr, n2->nc_nlen)) { |
736 n2->nc_time = ncp->nc_time; 737 n2->nc_ticks = ncp->nc_ticks; |
738 CACHE_WUNLOCK(); 739 cache_free(ncp); 740 return; 741 } 742 } 743 744 if (flag == NCF_ISDOTDOT) { 745 /* --- 556 unchanged lines hidden (view full) --- 1302 } 1303 l = min(ncp->nc_nlen, buflen - 1); 1304 memcpy(buf, ncp->nc_name, l); 1305 CACHE_RUNLOCK(); 1306 buf[l] = '\0'; 1307 return (0); 1308} 1309 |
1310/* ABI compat shims for old kernel modules. */ 1311#undef cache_enter 1312#undef cache_lookup 1313 1314void cache_enter(struct vnode *dvp, struct vnode *vp, 1315 struct componentname *cnp); 1316int cache_lookup(struct vnode *dvp, struct vnode **vpp, 1317 struct componentname *cnp); 1318 1319void 1320cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) 1321{ 1322 1323 cache_enter_time(dvp, vp, cnp, NULL); 1324} 1325 1326int 1327cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) 1328{ 1329 1330 return (cache_lookup_times(dvp, vpp, cnp, NULL, NULL)); 1331} 1332 |
1333/* 1334 * This function updates path string to vnode's full global path 1335 * and checks the size of the new path string against the pathlen argument. 1336 * 1337 * Requires a locked, referenced vnode and GIANT lock held. 1338 * Vnode is re-locked on success or ENODEV, otherwise unlocked. 1339 * 1340 * If sysctl debug.disablefullpath is set, ENODEV is returned, --- 64 unchanged lines hidden --- |