diff options
Diffstat (limited to 'sys/nwfs/nwfs_node.c')
-rw-r--r-- | sys/nwfs/nwfs_node.c | 130 |
1 files changed, 73 insertions, 57 deletions
diff --git a/sys/nwfs/nwfs_node.c b/sys/nwfs/nwfs_node.c index 4232e9b..2d34600 100644 --- a/sys/nwfs/nwfs_node.c +++ b/sys/nwfs/nwfs_node.c @@ -61,7 +61,7 @@ extern vop_t **nwfs_vnodeop_p; static LIST_HEAD(nwnode_hash_head,nwnode) *nwhashtbl; static u_long nwnodehash; -static int nwhashlock = 0; +static struct lock nwhashlock; MALLOC_DEFINE(M_NWNODE, "NWFS node", "NWFS vnode private part"); MALLOC_DEFINE(M_NWFSHASH, "NWFS hash", "NWFS has table"); @@ -76,20 +76,18 @@ SYSCTL_PROC(_vfs_nwfs, OID_AUTO, vnprint, CTLFLAG_WR|CTLTYPE_OPAQUE, NULL, 0, nwfs_sysctl_vnprint, "S,vnlist", "vnode hash"); void -nwfs_hash_init(void) -{ +nwfs_hash_init(void) { nwhashtbl = hashinit(desiredvnodes, M_NWFSHASH, &nwnodehash); + lockinit(&nwhashlock, PVFS, "nwfshl", 0, 0); } void -nwfs_hash_free(void) -{ +nwfs_hash_free(void) { free(nwhashtbl, M_NWFSHASH); } int -nwfs_sysctl_vnprint(SYSCTL_HANDLER_ARGS) -{ +nwfs_sysctl_vnprint(SYSCTL_HANDLER_ARGS) { struct nwnode *np; struct nwnode_hash_head *nhpp; struct vnode *vp; @@ -102,6 +100,7 @@ nwfs_sysctl_vnprint(SYSCTL_HANDLER_ARGS) nhpp = &nwhashtbl[i]; for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) { vp = NWTOV(np); + vprint(NULL, vp); printf("%s:%d:%d:%d:%d\n",np->n_name,vp->v_usecount,vp->v_holdcnt, np->n_fid.f_id, np->n_fid.f_parent); } @@ -110,6 +109,27 @@ nwfs_sysctl_vnprint(SYSCTL_HANDLER_ARGS) } /* + * Search nwnode with given fid. + * Hash list should be locked by caller. + */ +static int +nwfs_hashlookup(struct nwmount *nmp, ncpfid fid, struct nwnode **npp) +{ + struct nwnode *np; + struct nwnode_hash_head *nhpp; + + nhpp = NWNOHASH(fid); + LIST_FOREACH(np, nhpp, n_hash) { + if (nmp != np->n_mount || !NWCMPF(&fid, &np->n_fid)) + continue; + if (npp) + *npp = np; + return 0; + } + return ENOENT; +} + +/* * Allocate new nwfsnode/vnode from given nwnode. * Vnode referenced and not locked. */ @@ -117,33 +137,26 @@ int nwfs_allocvp(struct mount *mp, ncpfid fid, struct vnode **vpp) { struct proc *p = curproc; /* XXX */ - struct nwnode *np, *np2; + struct nwnode *np; struct nwnode_hash_head *nhpp; + struct nwmount *nmp = VFSTONWFS(mp); struct vnode *vp; int error; -retry: - nhpp = NWNOHASH(fid); loop: - for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) { + lockmgr(&nwhashlock, LK_EXCLUSIVE, NULL, p); +rescan: + if (nwfs_hashlookup(nmp, fid, &np) == 0) { vp = NWTOV(np); - if (mp != vp->v_mount || !NWCMPF(&fid, &np->n_fid)) - continue; - if (vget(vp, LK_EXCLUSIVE, p)) + simple_lock(&vp->v_interlock); + lockmgr(&nwhashlock, LK_RELEASE, NULL, p); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) goto loop; *vpp = vp; return(0); } + lockmgr(&nwhashlock, LK_RELEASE, NULL, p); - /* lock list, or waiting in malloc can cause problems */ - if (nwhashlock) { - while(nwhashlock) { - nwhashlock = -1; - tsleep((caddr_t) &nwhashlock, PVM, "nwfsvp", 0); - } - goto loop; - } - nwhashlock = 1; /* * Do the MALLOC before the getnewvnode since doing so afterward * might cause a bogus v_data pointer to get dereferenced @@ -152,52 +165,47 @@ loop: MALLOC(np, struct nwnode *, sizeof *np, M_NWNODE, M_WAITOK); error = getnewvnode(VT_NWFS, mp, nwfs_vnodeop_p, &vp); if (error) { - if (nwhashlock < 0) - wakeup(&nwhashlock); - nwhashlock = 0; - *vpp = 0; + *vpp = NULL; FREE(np, M_NWNODE); return (error); } - *vpp = vp; - bzero(np,sizeof(*np)); + bzero(np, sizeof(*np)); vp->v_data = np; np->n_vnode = vp; - np->n_mount = VFSTONWFS(mp); - np->n_fid = fid; - for (np2 = nhpp->lh_first; np2 != 0; np2 = np->n_hash.le_next) { - if (mp != NWTOV(np2)->v_mount || !NWCMPF(&fid, &np2->n_fid)) - continue; + np->n_mount = nmp; + lockmgr(&nwhashlock, LK_EXCLUSIVE, NULL, p); + /* + * Another process can create vnode while we blocked in malloc() or + * getnewvnode(). Rescan list again. + */ + if (nwfs_hashlookup(nmp, fid, NULL) == 0) { + vp->v_data = NULL; + np->n_vnode = NULL; vrele(vp); FREE(np, M_NWNODE); - if (nwhashlock < 0) - wakeup(&nwhashlock); - nwhashlock = 0; - goto retry; + goto rescan; } + *vpp = vp; + np->n_fid = fid; + np->n_flag |= NNEW; + lockinit(&vp->v_lock, PINOD, "nwnode", 0, LK_CANRECURSE); + nhpp = NWNOHASH(fid); LIST_INSERT_HEAD(nhpp, np, n_hash); - if (nwhashlock < 0) - wakeup(&nwhashlock); - nwhashlock = 0; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - np->n_flag |= NNEW; - return (error); + lockmgr(&nwhashlock, LK_RELEASE, NULL, p); + return 0; } int -nwfs_lookupnp(struct nwmount *nmp, ncpfid fid, struct nwnode **npp) +nwfs_lookupnp(struct nwmount *nmp, ncpfid fid, struct proc *p, + struct nwnode **npp) { - struct nwnode *np; - struct nwnode_hash_head *nhpp; + int error; - nhpp = NWNOHASH(fid); - for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) { - if (nmp != np->n_mount || !NWCMPF(&fid, &np->n_fid)) - continue; - *npp = np; - return(0); - } - return ENOENT; + lockmgr(&nwhashlock, LK_EXCLUSIVE, NULL, p); + error = nwfs_hashlookup(nmp, fid, npp); + lockmgr(&nwhashlock, LK_RELEASE, NULL, p); + return error; } /* @@ -206,23 +214,27 @@ nwfs_lookupnp(struct nwmount *nmp, ncpfid fid, struct nwnode **npp) int nwfs_reclaim(ap) struct vop_reclaim_args /* { - struct vnode *a_vp; + struct vnode *a_vp; + struct proc *a_p; } */ *ap; { struct vnode *dvp = NULL, *vp = ap->a_vp; struct nwnode *dnp, *np = VTONW(vp); - struct nwmount *nmp=VTONWFS(vp); + struct nwmount *nmp = VTONWFS(vp); + struct proc *p = ap->a_p; NCPVNDEBUG("%s,%d\n", np->n_name, vp->v_usecount); if (np->n_refparent) { np->n_refparent = 0; - if (nwfs_lookupnp(nmp, np->n_parent, &dnp) == 0) { + if (nwfs_lookupnp(nmp, np->n_parent, p, &dnp) == 0) { dvp = dnp->n_vnode; } else { NCPVNDEBUG("%s: has no parent ?\n",np->n_name); } } + lockmgr(&nwhashlock, LK_EXCLUSIVE, NULL, p); LIST_REMOVE(np, n_hash); + lockmgr(&nwhashlock, LK_RELEASE, NULL, p); cache_purge(vp); if (nmp->n_root == np) { nmp->n_root = NULL; @@ -255,6 +267,10 @@ nwfs_inactive(ap) np->opened = 0; } VOP_UNLOCK(vp, 0, p); + if (np->n_flag & NSHOULDFREE) { + cache_purge(vp); + vgone(vp); + } return (0); } /* |