FreeBSD/sys/kern/vfs_cache.c
/*
 * Add an entry to the cache.
 */
Add an entry to the cache.
Add an entry to the cache .
void
cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
    struct timespec *tsp, struct timespec *dtsp)
{
	struct namecache *ncp, *n2;
	struct namecache_ts *n3;
	struct nchashhead *ncpp;
	uint32_t hash;
	int flag;
	int len;
	CTR3(KTR_VFS, "cache_enter(%p, %p, %s)", dvp, vp, cnp->cn_nameptr);
	VNASSERT(vp == NULL || (vp->v_iflag & VI_DOOMED) == 0, vp,
	    ("cache_enter: Adding a doomed vnode"));
	VNASSERT(dvp == NULL || (dvp->v_iflag & VI_DOOMED) == 0, dvp,
	    ("cache_enter: Doomed vnode used as src"));
	if (!doingcache)
		return;
	if (numcache >= desiredvnodes * ncsizefactor)
		return;
	flag = 0;
	if (cnp->cn_nameptr[0] == '.') {
		if (cnp->cn_namelen == 1)
			return;
		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
			CACHE_WLOCK();
			if ((ncp = dvp->v_cache_dd) != NULL &&
			    ncp->nc_flag & NCF_ISDOTDOT) {
				KASSERT(ncp->nc_dvp == dvp,
				    ("wrong isdotdot parent"));
				if (ncp->nc_vp != NULL) {
					TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst,
					    ncp, nc_dst);
				} else {
					TAILQ_REMOVE(&ncneg, ncp, nc_dst);
					numneg--;
				}
				if (vp != NULL) {
					TAILQ_INSERT_HEAD(&vp->v_cache_dst,
					    ncp, nc_dst);
				} else {
					TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
					numneg++;
				}
				ncp->nc_vp = vp;
				CACHE_WUNLOCK();
				return;
			}
			dvp->v_cache_dd = NULL;
			SDT_PROBE3(vfs, namecache, enter, done, dvp, "..", vp);
			CACHE_WUNLOCK();
			flag = NCF_ISDOTDOT;
		}
	}
	ncp = cache_alloc(cnp->cn_namelen, tsp != NULL);
	ncp->nc_vp = vp;
	ncp->nc_dvp = dvp;
	ncp->nc_flag = flag;
	if (tsp != NULL) {
		n3 = (struct namecache_ts *)ncp;
		n3->nc_time = *tsp;
		n3->nc_ticks = ticks;
		n3->nc_flag |= NCF_TS;
		if (dtsp != NULL) {
			n3->nc_dotdottime = *dtsp;
			n3->nc_flag |= NCF_DTS;
		}
	}
	len = ncp->nc_nlen = cnp->cn_namelen;
	hash = cache_get_hash(cnp->cn_nameptr, len, dvp);
	strlcpy(nc_get_name(ncp), cnp->cn_nameptr, len + 1);
	CACHE_WLOCK();
	ncpp = NCHHASH(hash);
	LIST_FOREACH(n2, ncpp, nc_hash) {
		if (n2->nc_dvp == dvp &&
		    n2->nc_nlen == cnp->cn_namelen &&
		    !bcmp(nc_get_name(n2), cnp->cn_nameptr, n2->nc_nlen)) {
			if (tsp != NULL) {
				KASSERT((n2->nc_flag & NCF_TS) != 0,
				    ("no NCF_TS"));
				n3 = (struct namecache_ts *)n2;
				n3->nc_time =
				    ((struct namecache_ts *)ncp)->nc_time;
				n3->nc_ticks =
				    ((struct namecache_ts *)ncp)->nc_ticks;
				if (dtsp != NULL) {
					n3->nc_dotdottime =
					    ((struct namecache_ts *)ncp)->
					    nc_dotdottime;
					n3->nc_flag |= NCF_DTS;
				}
			}
			CACHE_WUNLOCK();
			cache_free(ncp);
			return;
		}
	}
	if (flag == NCF_ISDOTDOT) {
		if (dvp->v_cache_dd != NULL) {
			CACHE_WUNLOCK();
			cache_free(ncp);
			return;
		}
		KASSERT(vp == NULL || vp->v_type == VDIR,
		    ("wrong vnode type %p", vp));
		dvp->v_cache_dd = ncp;
	}
	numcache++;
	if (vp != NULL) {
		if (vp->v_type == VDIR) {
			if (flag != NCF_ISDOTDOT) {
				if ((n2 = vp->v_cache_dd) != NULL &&
				    (n2->nc_flag & NCF_ISDOTDOT) != 0)
					cache_zap(n2);
				vp->v_cache_dd = ncp;
			}
		} else {
			vp->v_cache_dd = NULL;
		}
	}
	LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
	if (flag != NCF_ISDOTDOT) {
		if (LIST_EMPTY(&dvp->v_cache_src)) {
			vhold(dvp);
			numcachehv++;
		}
		LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src);
	}
	if (vp != NULL) {
		TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst);
		SDT_PROBE3(vfs, namecache, enter, done, dvp, nc_get_name(ncp),
		    vp);
	} else {
		if (cnp->cn_flags & ISWHITEOUT)
			ncp->nc_flag |= NCF_WHITE;
		TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
		numneg++;
		SDT_PROBE2(vfs, namecache, enter_negative, done, dvp,
		    nc_get_name(ncp));
	}
	if (numneg * ncnegfactor > numcache) {
		ncp = TAILQ_FIRST(&ncneg);
		KASSERT(ncp->nc_vp == NULL, ("ncp %p vp %p on ncneg",
		    ncp, ncp->nc_vp));
		cache_zap(ncp);
	}
	CACHE_WUNLOCK();
}
void cache_enter_time ( struct vnode * dvp , struct vnode * vp , struct componentname * cnp , struct timespec * tsp , struct timespec * dtsp ) { struct namecache * ncp , * n2 ; struct namecache_ts * n3 ; struct nchashhead * ncpp ; uint32_t hash ; int flag ; int len ; CTR3 ( KTR_VFS , " " , dvp , vp , cnp -> cn_nameptr ) ; VNASSERT ( vp == NULL || ( vp -> v_iflag & VI_DOOMED ) == 0 , vp , ( " " ) ) ; VNASSERT ( dvp == NULL || ( dvp -> v_iflag & VI_DOOMED ) == 0 , dvp , ( " " ) ) ; if ( ! doingcache ) return ; if ( numcache >= desiredvnodes * ncsizefactor ) return ; flag = 0 ; if ( cnp -> cn_nameptr [ 0 ] == ' ' ) { if ( cnp -> cn_namelen == 1 ) return ; if ( cnp -> cn_namelen == 2 && cnp -> cn_nameptr [ 1 ] == ' ' ) { CACHE_WLOCK ( ) ; if ( ( ncp = dvp -> v_cache_dd ) != NULL && ncp -> nc_flag & NCF_ISDOTDOT ) { KASSERT ( ncp -> nc_dvp == dvp , ( " " ) ) ; if ( ncp -> nc_vp != NULL ) { TAILQ_REMOVE ( & ncp -> nc_vp -> v_cache_dst , ncp , nc_dst ) ; } else { TAILQ_REMOVE ( & ncneg , ncp , nc_dst ) ; numneg -- ; } if ( vp != NULL ) { TAILQ_INSERT_HEAD ( & vp -> v_cache_dst , ncp , nc_dst ) ; } else { TAILQ_INSERT_TAIL ( & ncneg , ncp , nc_dst ) ; numneg ++ ; } ncp -> nc_vp = vp ; CACHE_WUNLOCK ( ) ; return ; } dvp -> v_cache_dd = NULL ; SDT_PROBE3 ( vfs , namecache , enter , done , dvp , " " , vp ) ; CACHE_WUNLOCK ( ) ; flag = NCF_ISDOTDOT ; } } ncp = cache_alloc ( cnp -> cn_namelen , tsp != NULL ) ; ncp -> nc_vp = vp ; ncp -> nc_dvp = dvp ; ncp -> nc_flag = flag ; if ( tsp != NULL ) { n3 = ( struct namecache_ts * ) ncp ; n3 -> nc_time = * tsp ; n3 -> nc_ticks = ticks ; n3 -> nc_flag |= NCF_TS ; if ( dtsp != NULL ) { n3 -> nc_dotdottime = * dtsp ; n3 -> nc_flag |= NCF_DTS ; } } len = ncp -> nc_nlen = cnp -> cn_namelen ; hash = cache_get_hash ( cnp -> cn_nameptr , len , dvp ) ; strlcpy ( nc_get_name ( ncp ) , cnp -> cn_nameptr , len + 1 ) ; CACHE_WLOCK ( ) ; ncpp = NCHHASH ( hash ) ; LIST_FOREACH ( n2 , ncpp , nc_hash ) { if ( n2 -> nc_dvp == dvp && n2 -> nc_nlen == cnp -> cn_namelen && ! bcmp ( nc_get_name ( n2 ) , cnp -> cn_nameptr , n2 -> nc_nlen ) ) { if ( tsp != NULL ) { KASSERT ( ( n2 -> nc_flag & NCF_TS ) != 0 , ( " " ) ) ; n3 = ( struct namecache_ts * ) n2 ; n3 -> nc_time = ( ( struct namecache_ts * ) ncp ) -> nc_time ; n3 -> nc_ticks = ( ( struct namecache_ts * ) ncp ) -> nc_ticks ; if ( dtsp != NULL ) { n3 -> nc_dotdottime = ( ( struct namecache_ts * ) ncp ) -> nc_dotdottime ; n3 -> nc_flag |= NCF_DTS ; } } CACHE_WUNLOCK ( ) ; cache_free ( ncp ) ; return ; } } if ( flag == NCF_ISDOTDOT ) { if ( dvp -> v_cache_dd != NULL ) { CACHE_WUNLOCK ( ) ; cache_free ( ncp ) ; return ; } KASSERT ( vp == NULL || vp -> v_type == VDIR , ( " " , vp ) ) ; dvp -> v_cache_dd = ncp ; } numcache ++ ; if ( vp != NULL ) { if ( vp -> v_type == VDIR ) { if ( flag != NCF_ISDOTDOT ) { if ( ( n2 = vp -> v_cache_dd ) != NULL && ( n2 -> nc_flag & NCF_ISDOTDOT ) != 0 ) cache_zap ( n2 ) ; vp -> v_cache_dd = ncp ; } } else { vp -> v_cache_dd = NULL ; } } LIST_INSERT_HEAD ( ncpp , ncp , nc_hash ) ; if ( flag != NCF_ISDOTDOT ) { if ( LIST_EMPTY ( & dvp -> v_cache_src ) ) { vhold ( dvp ) ; numcachehv ++ ; } LIST_INSERT_HEAD ( & dvp -> v_cache_src , ncp , nc_src ) ; } if ( vp != NULL ) { TAILQ_INSERT_HEAD ( & vp -> v_cache_dst , ncp , nc_dst ) ; SDT_PROBE3 ( vfs , namecache , enter , done , dvp , nc_get_name ( ncp ) , vp ) ; } else { if ( cnp -> cn_flags & ISWHITEOUT ) ncp -> nc_flag |= NCF_WHITE ; TAILQ_INSERT_TAIL ( & ncneg , ncp , nc_dst ) ; numneg ++ ; SDT_PROBE2 ( vfs , namecache , enter_negative , done , dvp , nc_get_name ( ncp ) ) ; } if ( numneg * ncnegfactor > numcache ) { ncp = TAILQ_FIRST ( & ncneg ) ; KASSERT ( ncp -> nc_vp == NULL , ( " " , ncp , ncp -> nc_vp ) ) ; cache_zap ( ncp ) ; } CACHE_WUNLOCK ( ) ; }
Add an entry to the cache.
Add an entry to the cache .
/*
	 * Avoid blowout in namecache entries.
	 */ /*
			 * If dotdot entry already exists, just retarget it
			 * to new parent vnode, otherwise continue with new
			 * namecache entry allocation.
			 */ /*
	 * Calculate the hash key and setup as much of the new
	 * namecache entry as possible before acquiring the lock.
	 */ /*
	 * See if this vnode or negative entry is already in the cache
	 * with this name.  This can happen with concurrent lookups of
	 * the same path name.
	 */ /*
		 * See if we are trying to add .. entry, but some other lookup
		 * has populated v_cache_dd pointer already.
		 */ /*
				 * For this case, the cache entry maps both the
				 * directory name in it and the name ".." for the
				 * directory's parent.
				 */ /*
	 * Insert the new namecache entry into the appropriate chain
	 * within the cache entries table.
	 */ /*
	 * If the entry is "negative", we place it into the
	 * "negative" cache queue, otherwise, we place it into the
	 * destination vnode's cache entries queue.
	 */