pseudofs_vncache.c revision 77998
175295Sdes/*-
275295Sdes * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav
375295Sdes * All rights reserved.
475295Sdes *
575295Sdes * Redistribution and use in source and binary forms, with or without
675295Sdes * modification, are permitted provided that the following conditions
775295Sdes * are met:
875295Sdes * 1. Redistributions of source code must retain the above copyright
975295Sdes *    notice, this list of conditions and the following disclaimer
1075295Sdes *    in this position and unchanged.
1175295Sdes * 2. Redistributions in binary form must reproduce the above copyright
1275295Sdes *    notice, this list of conditions and the following disclaimer in the
1375295Sdes *    documentation and/or other materials provided with the distribution.
1475295Sdes * 3. The name of the author may not be used to endorse or promote products
1575295Sdes *    derived from this software without specific prior written permission.
1675295Sdes *
1775295Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1875295Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1975295Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2075295Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2175295Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2275295Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2375295Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2475295Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2575295Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2675295Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2775295Sdes *
2875295Sdes *      $FreeBSD: head/sys/fs/pseudofs/pseudofs_vncache.c 77998 2001-06-10 18:39:21Z des $
2975295Sdes */
3075295Sdes
3175295Sdes#include <sys/param.h>
3275295Sdes#include <sys/kernel.h>
3375295Sdes#include <sys/systm.h>
3475295Sdes#include <sys/malloc.h>
3575295Sdes#include <sys/mount.h>
3677965Sdes#include <sys/mutex.h>
3775295Sdes#include <sys/sbuf.h>
3875295Sdes#include <sys/sysctl.h>
3975295Sdes#include <sys/vnode.h>
4075295Sdes
4175295Sdes#include <fs/pseudofs/pseudofs.h>
4275295Sdes#include <fs/pseudofs/pseudofs_internal.h>
4375295Sdes
4477998Sdesstatic MALLOC_DEFINE(M_PFSVNCACHE, "pfs_vncache", "pseudofs vnode cache");
4575295Sdes
4675295Sdesstatic struct mtx pfs_vncache_mutex;
4775295Sdes
4875295Sdesstruct pfs_vnode {
4975295Sdes	struct vnode		*pv_vnode;
5075295Sdes	struct pfs_vnode	*pv_next;
5175295Sdes} *pfs_vncache;
5275295Sdes
5375295SdesSYSCTL_NODE(_vfs_pfs, OID_AUTO, vncache, CTLFLAG_RW, 0,
5475295Sdes    "pseudofs vnode cache");
5575295Sdes
5675295Sdesstatic int pfs_vncache_hits;
5775295SdesSYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, hits, CTLFLAG_RD, &pfs_vncache_hits, 0,
5875295Sdes    "number of cache hits since initialization");
5975295Sdes
6075295Sdesstatic int pfs_vncache_misses;
6175295SdesSYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, misses, CTLFLAG_RD, &pfs_vncache_misses, 0,
6275295Sdes    "number of cache misses since initialization");
6375295Sdes
6475295Sdesextern vop_t **pfs_vnodeop_p;
6575295Sdes
6675295Sdes/*
6775295Sdes * Initialize vnode cache
6875295Sdes */
6975295Sdesvoid
7075295Sdespfs_vncache_load(void)
7175295Sdes{
7275295Sdes	mtx_init(&pfs_vncache_mutex, "pseudofs_vncache", MTX_DEF);
7375295Sdes}
7475295Sdes
7575295Sdes/*
7675295Sdes * Tear down vnode cache
7775295Sdes */
7875295Sdesvoid
7975295Sdespfs_vncache_unload(void)
8075295Sdes{
8175295Sdes	mtx_destroy(&pfs_vncache_mutex);
8275295Sdes}
8375295Sdes
8475295Sdes/*
8575295Sdes * Allocate a vnode
8675295Sdes */
8775295Sdesint
8877998Sdespfs_vncache_alloc(struct mount *mp, struct vnode **vpp,
8977998Sdes		  struct pfs_node *pn, pid_t pid)
9075295Sdes{
9175295Sdes	struct pfs_vnode *pv;
9277998Sdes	struct pfs_vdata *pvd;
9375295Sdes	int error;
9475295Sdes
9577998Sdes	/* see if the vnode is in the cache */
9675295Sdes	mtx_lock(&pfs_vncache_mutex);
9777998Sdes	for (pv = pfs_vncache; pv; pv = pv->pv_next) {
9877998Sdes		pvd = (struct pfs_vdata *)pv->pv_vnode->v_data;
9977998Sdes		if (pvd->pvd_pn == pn && pvd->pvd_pid == pid) {
10075295Sdes			if (vget(pv->pv_vnode, 0, curproc) == 0) {
10175295Sdes				++pfs_vncache_hits;
10275295Sdes				*vpp = pv->pv_vnode;
10375295Sdes				mtx_unlock(&pfs_vncache_mutex);
10475295Sdes				return (0);
10575295Sdes			}
10677998Sdes			/* XXX if this can happen, we're in trouble */
10777998Sdes			break;
10877998Sdes		}
10977998Sdes	}
11077998Sdes	mtx_unlock(&pfs_vncache_mutex);
11175295Sdes	++pfs_vncache_misses;
11275295Sdes
11375295Sdes	/* nope, get a new one */
11475295Sdes	MALLOC(pv, struct pfs_vnode *, sizeof *pv, M_PFSVNCACHE, M_WAITOK);
11577998Sdes	MALLOC(pvd, struct pfs_vdata *, sizeof *pvd, M_PFSVNCACHE, M_WAITOK);
11675295Sdes	error = getnewvnode(VT_PSEUDOFS, mp, pfs_vnodeop_p, vpp);
11777998Sdes	if (error)
11875295Sdes		return (error);
11977998Sdes	pvd->pvd_pn = pn;
12077998Sdes	pvd->pvd_pid = pid;
12177998Sdes	(*vpp)->v_data = pvd;
12275295Sdes	switch (pn->pn_type) {
12375295Sdes	case pfstype_root:
12475295Sdes		(*vpp)->v_flag = VROOT;
12575295Sdes#if 0
12675295Sdes		printf("root vnode allocated\n");
12775295Sdes#endif
12875295Sdes	case pfstype_dir:
12975295Sdes	case pfstype_this:
13075295Sdes	case pfstype_parent:
13177998Sdes	case pfstype_procdir:
13275295Sdes		(*vpp)->v_type = VDIR;
13375295Sdes		break;
13475295Sdes	case pfstype_file:
13575295Sdes		(*vpp)->v_type = VREG;
13675295Sdes		break;
13775295Sdes	case pfstype_symlink:
13875295Sdes		(*vpp)->v_type = VLNK;
13975295Sdes		break;
14077998Sdes	case pfstype_none:
14177998Sdes		KASSERT(0, ("pfs_vncache_alloc called for null node\n"));
14275295Sdes	default:
14375295Sdes		panic("%s has unexpected type: %d", pn->pn_name, pn->pn_type);
14475295Sdes	}
14575295Sdes	pv->pv_vnode = *vpp;
14677998Sdes	mtx_lock(&pfs_vncache_mutex);
14775295Sdes	pv->pv_next = pfs_vncache;
14875295Sdes	pfs_vncache = pv;
14975295Sdes	mtx_unlock(&pfs_vncache_mutex);
15075295Sdes	return (0);
15175295Sdes}
15275295Sdes
15375295Sdes/*
15475295Sdes * Free a vnode
15575295Sdes */
15675295Sdesint
15775295Sdespfs_vncache_free(struct vnode *vp)
15875295Sdes{
15975295Sdes	struct pfs_vnode *prev, *pv;
16077998Sdes	struct pfs_vdata *pvd;
16175295Sdes
16275295Sdes	mtx_lock(&pfs_vncache_mutex);
16375295Sdes	for (prev = NULL, pv = pfs_vncache; pv; prev = pv, pv = pv->pv_next)
16475295Sdes		if (pv->pv_vnode == vp)
16575295Sdes			break;
16677998Sdes	KASSERT(pv != NULL, ("pfs_vncache_free(): not in cache\n"));
16777998Sdes	if (prev)
16877998Sdes		prev->pv_next = pv->pv_next;
16977998Sdes	else
17077998Sdes		pfs_vncache = pv->pv_next;
17177998Sdes	mtx_unlock(&pfs_vncache_mutex);
17277998Sdes
17377998Sdes	pvd = (struct pfs_vdata *)vp->v_data;
17477998Sdes	FREE(pvd, M_PFSVNCACHE);
17575295Sdes	vp->v_data = NULL;
17677998Sdes	FREE(pv, M_PFSVNCACHE);
17775295Sdes	return (0);
17875295Sdes}
179