diff options
Diffstat (limited to 'sys/fs/pseudofs/pseudofs_vncache.c')
-rw-r--r-- | sys/fs/pseudofs/pseudofs_vncache.c | 96 |
1 files changed, 68 insertions, 28 deletions
diff --git a/sys/fs/pseudofs/pseudofs_vncache.c b/sys/fs/pseudofs/pseudofs_vncache.c index 3ff33d7..191f85c 100644 --- a/sys/fs/pseudofs/pseudofs_vncache.c +++ b/sys/fs/pseudofs/pseudofs_vncache.c @@ -35,6 +35,7 @@ #include <sys/malloc.h> #include <sys/mount.h> #include <sys/mutex.h> +#include <sys/proc.h> #include <sys/sbuf.h> #include <sys/sysctl.h> #include <sys/vnode.h> @@ -45,21 +46,30 @@ static MALLOC_DEFINE(M_PFSVNCACHE, "pfs_vncache", "pseudofs vnode cache"); static struct mtx pfs_vncache_mutex; - -struct pfs_vnode { - struct vnode *pv_vnode; - struct pfs_vnode *pv_next; -} *pfs_vncache; +struct pfs_vdata *pfs_vncache; +static void pfs_exit(struct proc *p); SYSCTL_NODE(_vfs_pfs, OID_AUTO, vncache, CTLFLAG_RW, 0, "pseudofs vnode cache"); +static int pfs_vncache_entries; +SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, entries, CTLFLAG_RD, + &pfs_vncache_entries, 0, + "number of entries in the vnode cache"); + +static int pfs_vncache_maxentries; +SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, maxentries, CTLFLAG_RD, + &pfs_vncache_maxentries, 0, + "highest number of entries in the vnode cache"); + static int pfs_vncache_hits; -SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, hits, CTLFLAG_RD, &pfs_vncache_hits, 0, +SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, hits, CTLFLAG_RD, + &pfs_vncache_hits, 0, "number of cache hits since initialization"); static int pfs_vncache_misses; -SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, misses, CTLFLAG_RD, &pfs_vncache_misses, 0, +SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, misses, CTLFLAG_RD, + &pfs_vncache_misses, 0, "number of cache misses since initialization"); extern vop_t **pfs_vnodeop_p; @@ -70,7 +80,9 @@ extern vop_t **pfs_vnodeop_p; void pfs_vncache_load(void) { - mtx_init(&pfs_vncache_mutex, "pseudofs_vncache", MTX_DEF); + mtx_init(&pfs_vncache_mutex, "pseudofs_vncache", MTX_DEF|MTX_RECURSE); + /* XXX at_exit() can fail with ENOMEN */ + at_exit(pfs_exit); } /* @@ -79,6 +91,7 @@ pfs_vncache_load(void) void pfs_vncache_unload(void) { + rm_at_exit(pfs_exit); mtx_destroy(&pfs_vncache_mutex); } @@ -89,18 +102,17 @@ int pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, struct pfs_node *pn, pid_t pid) { - struct pfs_vnode *pv; struct pfs_vdata *pvd; int error; /* see if the vnode is in the cache */ + /* XXX linear search... not very efficient */ mtx_lock(&pfs_vncache_mutex); - for (pv = pfs_vncache; pv; pv = pv->pv_next) { - pvd = (struct pfs_vdata *)pv->pv_vnode->v_data; + for (pvd = pfs_vncache; pvd; pvd = pvd->pvd_next) { if (pvd->pvd_pn == pn && pvd->pvd_pid == pid) { - if (vget(pv->pv_vnode, 0, curthread) == 0) { + if (vget(pvd->pvd_vnode, 0, curthread) == 0) { ++pfs_vncache_hits; - *vpp = pv->pv_vnode; + *vpp = pvd->pvd_vnode; mtx_unlock(&pfs_vncache_mutex); return (0); } @@ -112,8 +124,9 @@ pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, ++pfs_vncache_misses; /* nope, get a new one */ - MALLOC(pv, struct pfs_vnode *, sizeof *pv, M_PFSVNCACHE, M_WAITOK); MALLOC(pvd, struct pfs_vdata *, sizeof *pvd, M_PFSVNCACHE, M_WAITOK); + if (++pfs_vncache_entries > pfs_vncache_maxentries) + pfs_vncache_maxentries = pfs_vncache_entries; error = getnewvnode(VT_PSEUDOFS, mp, pfs_vnodeop_p, vpp); if (error) return (error); @@ -126,6 +139,7 @@ pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, #if 0 printf("root vnode allocated\n"); #endif + /* fall through */ case pfstype_dir: case pfstype_this: case pfstype_parent: @@ -143,10 +157,13 @@ pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, default: panic("%s has unexpected type: %d", pn->pn_name, pn->pn_type); } - pv->pv_vnode = *vpp; + pvd->pvd_vnode = *vpp; mtx_lock(&pfs_vncache_mutex); - pv->pv_next = pfs_vncache; - pfs_vncache = pv; + pvd->pvd_prev = NULL; + pvd->pvd_next = pfs_vncache; + if (pvd->pvd_next) + pvd->pvd_next->pvd_prev = pvd; + pfs_vncache = pvd; mtx_unlock(&pfs_vncache_mutex); return (0); } @@ -157,23 +174,46 @@ pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, int pfs_vncache_free(struct vnode *vp) { - struct pfs_vnode *prev, *pv; struct pfs_vdata *pvd; mtx_lock(&pfs_vncache_mutex); - for (prev = NULL, pv = pfs_vncache; pv; prev = pv, pv = pv->pv_next) - if (pv->pv_vnode == vp) - break; - KASSERT(pv != NULL, ("pfs_vncache_free(): not in cache\n")); - if (prev) - prev->pv_next = pv->pv_next; + pvd = (struct pfs_vdata *)vp->v_data; + KASSERT(pvd != NULL, ("pfs_vncache_free(): no vnode data\n")); + if (pvd->pvd_next) + pvd->pvd_next->pvd_prev = pvd->pvd_prev; + if (pvd->pvd_prev) + pvd->pvd_prev->pvd_next = pvd->pvd_next; else - pfs_vncache = pv->pv_next; + pfs_vncache = pvd->pvd_next; mtx_unlock(&pfs_vncache_mutex); - - pvd = (struct pfs_vdata *)vp->v_data; + + --pfs_vncache_entries; FREE(pvd, M_PFSVNCACHE); vp->v_data = NULL; - FREE(pv, M_PFSVNCACHE); return (0); } + +/* + * Free all vnodes associated with a defunct process + */ +static void +pfs_exit(struct proc *p) +{ + struct pfs_vdata *pvd, *prev; + + mtx_lock(&pfs_vncache_mutex); + /* + * The double loop is necessary because vgone() indirectly + * calls pfs_vncache_free() which frees pvd, so we have to + * backtrace one step every time we free a vnode. + */ + /* XXX linear search... not very efficient */ + for (pvd = pfs_vncache; pvd != NULL; pvd = pvd->pvd_next) { + while (pvd != NULL && pvd->pvd_pid == p->p_pid) { + prev = pvd->pvd_prev; + vgone(pvd->pvd_vnode); + pvd = prev ? prev->pvd_next : pfs_vncache; + } + } + mtx_unlock(&pfs_vncache_mutex); +} |