aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/nwfs/nwfs_node.c
diff options
context:
space:
mode:
authorBoris Popov <bp@FreeBSD.org>2000-10-02 09:49:04 +0000
committerBoris Popov <bp@FreeBSD.org>2000-10-02 09:49:04 +0000
commit5c4db877e4d58d1c6752626c0e2bf45746b97618 (patch)
treeef5107a1af37ea0f3ae8c7c2539b893a8ecfd68d /sys/fs/nwfs/nwfs_node.c
parent7f66accf0272b30ef257cc4c195c38fd17e0c446 (diff)
downloadsrc-5c4db877e4d58d1c6752626c0e2bf45746b97618.tar.gz
src-5c4db877e4d58d1c6752626c0e2bf45746b97618.zip
Protect hash data with lock manager instead of home grown one.
Replace shared lock on vnode with exclusive one. It shouldn't impact perfomance as NCP protocol doesn't support outstanding requests. Do not hold simple lock on vnode for long period of time. Add functionality to the nwfs_print() routine.
Notes
Notes: svn path=/head/; revision=66540
Diffstat (limited to 'sys/fs/nwfs/nwfs_node.c')
-rw-r--r--sys/fs/nwfs/nwfs_node.c130
1 files changed, 73 insertions, 57 deletions
diff --git a/sys/fs/nwfs/nwfs_node.c b/sys/fs/nwfs/nwfs_node.c
index 4232e9b369da..2d3460093bc7 100644
--- a/sys/fs/nwfs/nwfs_node.c
+++ b/sys/fs/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);
}
/*