Fri Jan 2 12:57:30 2009 UTC ()
- Don't vput() a vnode that we do not hold locked.
- Eliminate one of the few remaining uses of LK_CANRECURSE.


(ad)
diff -r1.107 -r1.108 src/sys/nfs/nfs_node.c
diff -r1.68 -r1.69 src/sys/nfs/nfsnode.h

cvs diff -r1.107 -r1.108 src/sys/nfs/nfs_node.c (expand / switch to context diff)
--- src/sys/nfs/nfs_node.c 2008/11/19 18:36:09 1.107
+++ src/sys/nfs/nfs_node.c 2009/01/02 12:57:29 1.108
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_node.c,v 1.107 2008/11/19 18:36:09 ad Exp $	*/
+/*	$NetBSD: nfs_node.c,v 1.108 2009/01/02 12:57:29 ad Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_node.c,v 1.107 2008/11/19 18:36:09 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_node.c,v 1.108 2009/01/02 12:57:29 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_nfs.h"
@@ -62,14 +62,14 @@
 
 struct pool nfs_node_pool;
 struct pool nfs_vattr_pool;
+static struct workqueue *nfs_sillyworkq;
 
-MALLOC_JUSTDEFINE(M_NFSNODE, "NFS node", "NFS vnode private part");
-
 extern int prtactive;
 
-void nfs_gop_size(struct vnode *, off_t, off_t *, int);
-int nfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
-int nfs_gop_write(struct vnode *, struct vm_page **, int, int);
+static void nfs_gop_size(struct vnode *, off_t, off_t *, int);
+static int nfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
+static int nfs_gop_write(struct vnode *, struct vm_page **, int, int);
+static void nfs_sillyworker(struct work *, void *);
 
 static const struct genfs_ops nfs_genfsops = {
 	.gop_size = nfs_gop_size,
@@ -83,11 +83,15 @@
 void
 nfs_node_init()
 {
-	malloc_type_attach(M_NFSNODE);
+
 	pool_init(&nfs_node_pool, sizeof(struct nfsnode), 0, 0, 0, "nfsnodepl",
 	    &pool_allocator_nointr, IPL_NONE);
 	pool_init(&nfs_vattr_pool, sizeof(struct vattr), 0, 0, 0, "nfsvapl",
 	    &pool_allocator_nointr, IPL_NONE);
+	if (workqueue_create(&nfs_sillyworkq, "nfssilly", nfs_sillyworker,
+	    NULL, PRI_NONE, IPL_NONE, 0) != 0) {
+	    	panic("nfs_node_init");
+	}
 }
 
 /*
@@ -96,9 +100,10 @@
 void
 nfs_node_done()
 {
+
 	pool_destroy(&nfs_node_pool);
 	pool_destroy(&nfs_vattr_pool);
-	malloc_type_detach(M_NFSNODE);
+	workqueue_destroy(nfs_sillyworkq);
 }
 
 #define	RBTONFSNODE(node) \
@@ -272,26 +277,7 @@
 	VOP_UNLOCK(vp, 0);
 
 	if (sp != NULL) {
-		int error;
-
-		/*
-		 * Remove the silly file that was rename'd earlier
-		 *
-		 * Just in case our thread also has the parent node locked,
-		 * we use LK_CANRECURSE.
-		 */
-
-		error = vn_lock(sp->s_dvp, LK_EXCLUSIVE | LK_CANRECURSE);
-		if (error || sp->s_dvp->v_data == NULL) {
-			/* XXX should recover */
-			printf("%s: vp=%p error=%d\n",
-			    __func__, sp->s_dvp, error);
-		} else {
-			nfs_removeit(sp);
-		}
-		kauth_cred_free(sp->s_cred);
-		vput(sp->s_dvp);
-		kmem_free(sp, sizeof(*sp));
+		workqueue_enqueue(nfs_sillyworkq, &sp->s_work, NULL);
 	}
 
 	return (0);
@@ -373,4 +359,31 @@
 		pmap_page_protect(pgs[i], VM_PROT_READ);
 	}
 	return genfs_gop_write(vp, pgs, npages, flags);
+}
+
+/*
+ * Remove a silly file that was rename'd earlier
+ */
+static void
+nfs_sillyworker(struct work *work, void *arg)
+{
+	struct sillyrename *sp;
+	int error;
+
+	sp = (struct sillyrename *)work;
+	error = vn_lock(sp->s_dvp, LK_EXCLUSIVE);
+	if (error || sp->s_dvp->v_data == NULL) {
+		/* XXX should recover */
+		printf("%s: vp=%p error=%d\n", __func__, sp->s_dvp, error);
+		if (error == 0) {
+			vput(sp->s_dvp);
+		} else {
+			vrele(sp->s_dvp);
+		}
+	} else {
+		nfs_removeit(sp);
+		vput(sp->s_dvp);
+	}
+	kauth_cred_free(sp->s_cred);
+	kmem_free(sp, sizeof(*sp));
 }

cvs diff -r1.68 -r1.69 src/sys/nfs/nfsnode.h (expand / switch to context diff)
--- src/sys/nfs/nfsnode.h 2008/10/22 11:36:06 1.68
+++ src/sys/nfs/nfsnode.h 2009/01/02 12:57:29 1.69
@@ -1,4 +1,4 @@
-/*	 $NetBSD: nfsnode.h,v 1.68 2008/10/22 11:36:06 matt Exp $	*/
+/*	 $NetBSD: nfsnode.h,v 1.69 2009/01/02 12:57:29 ad Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -41,6 +41,7 @@
 #include <sys/condvar.h>
 #include <sys/mutex.h>
 #include <sys/rb.h>
+#include <sys/workqueue.h>
 
 #ifndef _NFS_NFS_H_
 #include <nfs/nfs.h>
@@ -53,6 +54,7 @@
  * can be removed by nfs_inactive()
  */
 struct sillyrename {
+	struct work	s_work;
 	kauth_cred_t	s_cred;
 	struct	vnode *s_dvp;
 	long	s_namlen;
@@ -281,7 +283,6 @@
 int	nfs_advlock	__P((void *));
 int	nfs_getpages	__P((void *));
 int	nfs_putpages	__P((void *));
-int	nfs_gop_write(struct vnode *, struct vm_page **, int, int);
 int	nfs_kqfilter	__P((void *));
 
 extern int (**nfsv2_vnodeop_p) __P((void *));