summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/dnlc.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/fs/dnlc.c')
-rw-r--r--usr/src/uts/common/fs/dnlc.c92
1 files changed, 57 insertions, 35 deletions
diff --git a/usr/src/uts/common/fs/dnlc.c b/usr/src/uts/common/fs/dnlc.c
index c8ba22e012..ef44a25622 100644
--- a/usr/src/uts/common/fs/dnlc.c
+++ b/usr/src/uts/common/fs/dnlc.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -67,6 +67,28 @@
*/
/*
+ * We want to be able to identify files that are referenced only by the DNLC.
+ * When adding a reference from the DNLC, call VN_HOLD_DNLC instead of VN_HOLD,
+ * since multiple DNLC references should only be counted once in v_count. This
+ * file contains only two(2) calls to VN_HOLD, renamed VN_HOLD_CALLER in the
+ * hope that no one will mistakenly add a VN_HOLD to this file. (Unfortunately
+ * it is not possible to #undef VN_HOLD and retain VN_HOLD_CALLER. Ideally a
+ * Makefile rule would grep uncommented C tokens to check that VN_HOLD is
+ * referenced only once in this file, to define VN_HOLD_CALLER.)
+ */
+#define VN_HOLD_CALLER VN_HOLD
+#define VN_HOLD_DNLC(vp) { \
+ mutex_enter(&(vp)->v_lock); \
+ if ((vp)->v_count_dnlc == 0) \
+ (vp)->v_count++; \
+ (vp)->v_count_dnlc++; \
+ mutex_exit(&(vp)->v_lock); \
+}
+#define VN_RELE_DNLC(vp) { \
+ vn_rele_dnlc(vp); \
+}
+
+/*
* Tunable nc_hashavelen is the average length desired for this chain, from
* which the size of the nc_hash table is derived at create time.
*/
@@ -387,13 +409,14 @@ dnlc_init()
* so that it never goes away (VOP_INACTIVE isn't called on it).
*/
negative_cache_vnode.v_count = 1;
+ negative_cache_vnode.v_count_dnlc = 0;
/*
* Initialise kstats - both the old compatability raw kind and
* the more extensive named stats.
*/
ksp = kstat_create("unix", 0, "ncstats", "misc", KSTAT_TYPE_RAW,
- sizeof (struct ncstats), KSTAT_FLAG_VIRTUAL);
+ sizeof (struct ncstats), KSTAT_FLAG_VIRTUAL);
if (ksp) {
ksp->ks_data = (void *) &ncstats;
kstat_install(ksp);
@@ -433,9 +456,9 @@ dnlc_enter(vnode_t *dp, char *name, vnode_t *vp)
if ((ncp = dnlc_get(namlen)) == NULL)
return;
ncp->dp = dp;
- VN_HOLD(dp);
+ VN_HOLD_DNLC(dp);
ncp->vp = vp;
- VN_HOLD(vp);
+ VN_HOLD_DNLC(vp);
bcopy(name, ncp->name, namlen + 1); /* name and null */
ncp->hash = hash;
hp = &nc_hash[hash & nc_hashmask];
@@ -445,12 +468,11 @@ dnlc_enter(vnode_t *dp, char *name, vnode_t *vp)
mutex_exit(&hp->hash_lock);
ncstats.dbl_enters++;
ncs.ncs_dbl_enters.value.ui64++;
- VN_RELE(dp);
- VN_RELE(vp);
+ VN_RELE_DNLC(dp);
+ VN_RELE_DNLC(vp);
dnlc_free(ncp); /* crfree done here */
TRACE_2(TR_FAC_NFS, TR_DNLC_ENTER_END,
- "dnlc_enter_end:(%S) %d",
- "dbl enter", ncstats.dbl_enters);
+ "dnlc_enter_end:(%S) %d", "dbl enter", ncstats.dbl_enters);
return;
}
/*
@@ -508,9 +530,9 @@ dnlc_update(vnode_t *dp, char *name, vnode_t *vp)
return;
}
ncp->dp = dp;
- VN_HOLD(dp);
+ VN_HOLD_DNLC(dp);
ncp->vp = vp;
- VN_HOLD(vp);
+ VN_HOLD_DNLC(vp);
bcopy(name, ncp->name, namlen + 1); /* name and null */
ncp->hash = hash;
hp = &nc_hash[hash & nc_hashmask];
@@ -521,21 +543,21 @@ dnlc_update(vnode_t *dp, char *name, vnode_t *vp)
tvp = tcp->vp;
tcp->vp = vp;
mutex_exit(&hp->hash_lock);
- VN_RELE(tvp);
+ VN_RELE_DNLC(tvp);
ncstats.enters++;
ncs.ncs_enters.value.ui64++;
TRACE_2(TR_FAC_NFS, TR_DNLC_ENTER_END,
"dnlc_update_end:(%S) %d", "done", ncstats.enters);
} else {
mutex_exit(&hp->hash_lock);
- VN_RELE(vp);
+ VN_RELE_DNLC(vp);
ncstats.dbl_enters++;
ncs.ncs_dbl_enters.value.ui64++;
TRACE_2(TR_FAC_NFS, TR_DNLC_ENTER_END,
"dnlc_update_end:(%S) %d",
"dbl enter", ncstats.dbl_enters);
}
- VN_RELE(dp);
+ VN_RELE_DNLC(dp);
dnlc_free(ncp); /* crfree done here */
return;
}
@@ -612,7 +634,7 @@ dnlc_lookup(vnode_t *dp, char *name)
* put a hold on it.
*/
vp = ncp->vp;
- VN_HOLD(vp);
+ VN_HOLD_CALLER(vp); /* VN_HOLD 1 of 2 in this file */
mutex_exit(&hp->hash_lock);
ncstats.hits++;
ncs.ncs_hits.value.ui64++;
@@ -620,8 +642,8 @@ dnlc_lookup(vnode_t *dp, char *name)
ncs.ncs_neg_hits.value.ui64++;
}
TRACE_4(TR_FAC_NFS, TR_DNLC_LOOKUP_END,
- "dnlc_lookup_end:%S %d vp %x name %s",
- "hit", ncstats.hits, vp, name);
+ "dnlc_lookup_end:%S %d vp %x name %s", "hit",
+ ncstats.hits, vp, name);
return (vp);
}
depth++;
@@ -631,7 +653,7 @@ dnlc_lookup(vnode_t *dp, char *name)
ncstats.misses++;
ncs.ncs_misses.value.ui64++;
TRACE_4(TR_FAC_NFS, TR_DNLC_LOOKUP_END,
- "dnlc_lookup_end:%S %d vp %x name %s", "miss", ncstats.misses,
+ "dnlc_lookup_end:%S %d vp %x name %s", "miss", ncstats.misses,
NULL, name);
return (NULL);
}
@@ -659,8 +681,8 @@ dnlc_remove(vnode_t *dp, char *name)
*/
nc_rmhash(ncp);
mutex_exit(&hp->hash_lock);
- VN_RELE(ncp->vp);
- VN_RELE(ncp->dp);
+ VN_RELE_DNLC(ncp->vp);
+ VN_RELE_DNLC(ncp->dp);
dnlc_free(ncp);
return;
}
@@ -707,7 +729,7 @@ dnlc_purge()
/* Release holds on all the vnodes now that we have no locks */
for (i = 0; i < index; i++) {
- VN_RELE(nc_rele[i]);
+ VN_RELE_DNLC(nc_rele[i]);
}
if (ncp != (ncache_t *)nch) {
nch--; /* Do current hash chain again */
@@ -716,9 +738,8 @@ dnlc_purge()
}
/*
- * Purge any cache entries referencing a vnode.
- * Exit as soon as the vnode reference count goes to 1, as the caller
- * must hold a reference, and the dnlc can therefore have no more.
+ * Purge any cache entries referencing a vnode. Exit as soon as the dnlc
+ * reference count goes to zero (the caller still holds a reference).
*/
void
dnlc_purge_vp(vnode_t *vp)
@@ -729,7 +750,7 @@ dnlc_purge_vp(vnode_t *vp)
vnode_t *nc_rele[DNLC_MAX_RELE];
ASSERT(vp->v_count > 0);
- if (vp->v_count == 1) {
+ if (vp->v_count_dnlc == 0) {
return;
}
@@ -764,11 +785,11 @@ dnlc_purge_vp(vnode_t *vp)
/* Release holds on all the vnodes now that we have no locks */
while (index) {
- VN_RELE(nc_rele[--index]);
+ VN_RELE_DNLC(nc_rele[--index]);
}
- if (vp->v_count == 1) {
- return; /* no more dnlc references */
+ if (vp->v_count_dnlc == 0) {
+ return;
}
if (ncp != (ncache_t *)nch) {
@@ -830,7 +851,7 @@ dnlc_purge_vfsp(vfs_t *vfsp, int count)
mutex_exit(&nch->hash_lock);
/* Release holds on all the vnodes now that we have no locks */
for (i = 0; i < index; i++) {
- VN_RELE(nc_rele[i]);
+ VN_RELE_DNLC(nc_rele[i]);
}
if (count != 0 && n >= count) {
return (n);
@@ -889,8 +910,8 @@ dnlc_fs_purge1(vnodeops_t *vop)
if (ncp != (ncache_t *)hp) {
nc_rmhash(ncp);
mutex_exit(&hp->hash_lock);
- VN_RELE(ncp->dp);
- VN_RELE(vp)
+ VN_RELE_DNLC(ncp->dp);
+ VN_RELE_DNLC(vp)
dnlc_free(ncp);
ncs.ncs_purge_total.value.ui64++;
return (1);
@@ -932,7 +953,8 @@ dnlc_reverse_lookup(vnode_t *vp, char *buf, size_t buflen)
bcopy(ncp->name, buf, ncp->namlen);
buf[ncp->namlen] = '\0';
pvp = ncp->dp;
- VN_HOLD(pvp);
+ /* VN_HOLD 2 of 2 in this file */
+ VN_HOLD_CALLER(pvp);
mutex_exit(&nch->hash_lock);
return (pvp);
}
@@ -1101,8 +1123,8 @@ found:
*/
nc_rmhash(ncp);
mutex_exit(&hp->hash_lock);
- VN_RELE(vp);
- VN_RELE(ncp->dp);
+ VN_RELE_DNLC(vp);
+ VN_RELE_DNLC(ncp->dp);
dnlc_free(ncp);
} while (dnlc_nentries > low_water);
@@ -1329,7 +1351,7 @@ ok:
* then free this cache
*/
if ((dcp->dc_num_entries + dcp->dc_num_free) >
- dnlc_dir_max_size) {
+ dnlc_dir_max_size) {
mutex_exit(&dcap->dca_lock);
dnlc_dir_purge(dcap);
kmem_free(dep, sizeof (dcentry_t) - 1 + namlen);
@@ -1434,7 +1456,7 @@ ok:
dcp = (dircache_t *)dcap->dca_dircache;
if (VALID_DIR_CACHE(dcp)) {
if ((dcp->dc_num_entries + dcp->dc_num_free) >
- dnlc_dir_max_size) {
+ dnlc_dir_max_size) {
mutex_exit(&dcap->dca_lock);
dnlc_dir_purge(dcap);
kmem_cache_free(dnlc_dir_space_cache, dfp);