summaryrefslogtreecommitdiffstats
path: root/sys/nwfs/nwfs_node.c
diff options
context:
space:
mode:
authorbp <bp@FreeBSD.org>2000-10-02 09:49:04 +0000
committerbp <bp@FreeBSD.org>2000-10-02 09:49:04 +0000
commitaf5c59dc4ff3f56184587c5798871262a8a7a217 (patch)
treef561b87c9c02b46312db8fbd1949d05303c8e94d /sys/nwfs/nwfs_node.c
parent72e68d3b765994ed27cdd33c3f725fcc3328cac3 (diff)
downloadFreeBSD-src-af5c59dc4ff3f56184587c5798871262a8a7a217.zip
FreeBSD-src-af5c59dc4ff3f56184587c5798871262a8a7a217.tar.gz
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.
Diffstat (limited to 'sys/nwfs/nwfs_node.c')
-rw-r--r--sys/nwfs/nwfs_node.c130
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);
}
/*
OpenPOWER on IntegriCloud