PERFORCE change 180031 for review

Ilya Putsikau ilya at FreeBSD.org
Mon Jun 21 08:27:16 UTC 2010


http://p4web.freebsd.org/@@180031?ac=10

Change 180031 by ilya at ilya_triton on 2010/06/21 08:26:19

	Embed fnnode reference to vnode
	Add reclaim hook
	Remove vp hash, use only inode hash table
	Extend node_lookupex to ignore invalid node reference and optionally lock vnode
	Fix vnode locking in hook_rename

Affected files ...

.. //depot/projects/soc2010/ilya_fsnotify/src/sys/kern/vfs_notify.c#4 edit
.. //depot/projects/soc2010/ilya_fsnotify/src/sys/kern/vfs_subr.c#3 edit
.. //depot/projects/soc2010/ilya_fsnotify/src/sys/sys/fsnotify.h#4 edit
.. //depot/projects/soc2010/ilya_fsnotify/src/sys/sys/vnode.h#2 edit

Differences ...

==== //depot/projects/soc2010/ilya_fsnotify/src/sys/kern/vfs_notify.c#4 (text+ko) ====

@@ -123,8 +123,7 @@
 static struct task fsnotify_task;
 static struct taskqueue *fsnotify_tq;
 
-static struct fnnode_hashhead **fnnode_vphashtbl;
-static struct fnnode_hashhead **fnnode_inohashtbl;
+static struct fnnode_hashhead *fnnode_inohashtbl;
 static struct mtx fnnode_hashmtx;
 static u_long fnnode_hashmask;
 
@@ -142,6 +141,7 @@
 	.d_name		= "fsnotify",
 };
 
+static void hook_reclaim(struct vnode *vp);
 static vop_create_t hook_create;
 static vop_link_t hook_link;
 static vop_mkdir_t hook_mkdir;
@@ -160,13 +160,18 @@
 static int session_rmwatch(struct fnsession *ss, int wd);
 static struct fnnode* node_lookup(struct vnode *vp);
 static struct fnnode* node_lookupex(struct vnode *vp, ino_t *inop,
-    int vplocked);
+    int flags);
 static struct fnnode* node_alloc(struct vnode *vp, ino_t ino);
-static void node_destroy(struct fnnode *node);
+static void node_drop(struct fnnode *node);
 static void event_copypath(struct fnevent *event, char *path, int *pathlen);
 static int event_pathlen(struct fnevent *event);
 static int event_nextcookie(void);
 
+#define	NODE_ISVALID(a)		((a) != NULL && (a) != FNNODE_INVAL)
+
+#define	LOOKUP_VPLOCKED		0x0001
+#define	LOOKUP_IGNINVAL		0x0002
+
 static int
 fsnotify_modevent(struct module *module, int cmd, void *arg)
 {
@@ -175,7 +180,8 @@
 
 	switch (cmd) {
 	case MOD_LOAD:
-		if (fsnotify_hook_create != NULL ||
+		if (fsnotify_hook_reclaim != NULL ||
+		    fsnotify_hook_create != NULL ||
 		    fsnotify_hook_link != NULL ||
 		    fsnotify_hook_mkdir != NULL ||
 		    fsnotify_hook_remove != NULL ||
@@ -190,8 +196,6 @@
 		mtx_init(&fnnode_hashmtx, "fsnotify_hash", NULL, MTX_DEF);
 
 		hashsize = MAX(desiredvnodes / 32, 16);
-		fnnode_vphashtbl = hashinit(hashsize, M_FSNOTIFYHASH,
-		    &fnnode_hashmask);
 		fnnode_inohashtbl = hashinit(hashsize, M_FSNOTIFYHASH,
 		    &fnnode_hashmask);
 
@@ -205,6 +209,7 @@
 		fsnotify_dev = make_dev(&fsnotify_cdevsw, 0, UID_ROOT,
 		    GID_WHEEL, 0666, "fsnotify");
 
+		fsnotify_hook_reclaim = hook_reclaim;
 		fsnotify_hook_create = hook_create;
 		fsnotify_hook_link = hook_link;
 		fsnotify_hook_mkdir = hook_mkdir;
@@ -214,6 +219,7 @@
 		fsnotify_hook_symlink = hook_symlink;
 		break;
 	case MOD_UNLOAD:
+		fsnotify_hook_reclaim = NULL;
 		fsnotify_hook_create = NULL;
 		fsnotify_hook_link = NULL;
 		fsnotify_hook_mkdir = NULL;
@@ -224,7 +230,6 @@
 		destroy_dev(fsnotify_dev);
 		taskqueue_drain(fsnotify_tq, &fsnotify_task);
 		taskqueue_free(fsnotify_tq);
-		free(fnnode_vphashtbl, M_FSNOTIFYHASH);
 		free(fnnode_inohashtbl, M_FSNOTIFYHASH);
 		mtx_destroy(&fsnotify_queue_mtx);
 		mtx_destroy(&fnnode_hashmtx);
@@ -279,6 +284,8 @@
 
 	mtx_init(&ss->ss_mtx, "fnsession_queue", NULL, MTX_DEF);
 	cv_init(&ss->ss_queuecv, "fnsession_queuecv");
+	TAILQ_INIT(&ss->ss_queue);
+	TAILQ_INIT(&ss->ss_watchlist);
 
 	devfs_set_cdevpriv(ss, fsnotify_session_dtor);
 
@@ -353,7 +360,6 @@
 {
 	struct fnsession *ss;
 	struct fnnode *node;
-	struct fnnode *freenode;
 	struct fnevent *event;
 	struct fnwatch *watch;
 	struct fsnotify_addwatch_args *add_args;
@@ -383,10 +389,9 @@
 		if (vp == NULL)
 			return (EBADF);
 		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
-		node = node_lookupex(vp, &ino, 0);
+		node = node_lookupex(vp, &ino, LOOKUP_IGNINVAL);
 		if (node != NULL) {
 			VFS_UNLOCK_GIANT(vfslocked);
-			freenode = NULL;
 		} else {
 			error = vn_fullpath(td, vp, &path, &pathfree);
 			VFS_UNLOCK_GIANT(vfslocked);
@@ -396,14 +401,11 @@
 			node->nd_path = path;
 			node->nd_pathlen = strlen(path);
 			node->nd_pathfree = pathfree;
-			freenode = node;
 		}
 		error = session_addwatch(ss, node, add_args->fa_mask, &watch);
-		if (error == 0) {
+		if (error == 0)
 			add_args->fa_wd = watch->wt_wd;
-		} else if (freenode != NULL) {
-			node_destroy(node);
-		}
+		/* If error != 0 node will be removed by hook_reclaim */
 		break;
 	case FSNOTIFY_RMWATCH:
 		error = session_rmwatch(ss, *(int *)data);
@@ -453,6 +455,20 @@
 /*
  * VFS hooks
  */
+static void
+hook_reclaim(struct vnode *vp)
+{
+	struct fnnode *node;
+
+	VI_LOCK(vp);
+	node = vp->v_fnnode;
+	vp->v_fnnode = NULL;
+	VI_UNLOCK(vp);
+
+	if (NODE_ISVALID(node))
+		node_drop(node);
+}
+
 static __inline int
 hook_generic_create(struct vnode *dvp, struct vnode *vp,
     struct componentname *cnp)
@@ -533,7 +549,7 @@
 
 	cookie = event_nextcookie();
 	if (ap->a_tvp != NULL) {
-		tnode = node_lookup(ap->a_tvp);
+		tnode = node_lookupex(ap->a_tvp, NULL, 0);
 		if (tnode != NULL) {
 			enqueue_fileevent(tnode, cookie,
 			    FE_DESTROY | FE_REMOVE);
@@ -548,7 +564,7 @@
 	fdirnode = node_lookupex(ap->a_fdvp, NULL, 0);
 	if (fdirnode != NULL)
 		enqueue_direvent(fdirnode, ap->a_fcnp, cookie, FE_RENAME_FROM);
-	tdirnode = node_lookup(ap->a_tdvp);
+	tdirnode = node_lookupex(ap->a_tdvp, NULL, 0);
 	if (tdirnode != NULL)
 		enqueue_direvent(tdirnode, ap->a_tcnp, cookie, FE_RENAME_TO);
 
@@ -591,6 +607,11 @@
 	if (refcount_release(&node->nd_refcnt) != 0) {
 		KASSERT(node->nd_watchcount == 0 && node->nd_supermask == 0 &&
 		    TAILQ_EMPTY(&node->nd_watchlist), ("Invalid reference count"));
+		if (node->nd_ino != 0) {
+			mtx_lock(&fnnode_hashmtx);
+			LIST_REMOVE(node, nd_hashentry);
+			mtx_unlock(&fnnode_hashmtx);
+		}
 		mtx_destroy(&node->nd_mtx);
 		free(node->nd_path, M_TEMP);
 		free(node, M_FSNOTIFY);
@@ -598,22 +619,12 @@
 }
 
 static __inline struct fnnode_hashhead *
-node_vphashhead(struct vnode *vp)
-{
-	uint32_t h;
-
-	h = hash32_buf(vp, sizeof(vp), HASHINIT);
-	h += vp->v_mount->mnt_hashseed;
-	return fnnode_vphashtbl[h & fnnode_hashmask];
-}
-
-static __inline struct fnnode_hashhead *
 node_inohashhead(struct mount *mnt, ino_t ino)
 {
 	uint32_t h;
 
 	h = ino + mnt->mnt_hashseed;
-	return fnnode_inohashtbl[h & fnnode_hashmask];
+	return &fnnode_inohashtbl[h & fnnode_hashmask];
 }
 
 static struct fnnode *
@@ -622,21 +633,19 @@
 	struct fnnode *node;
 
 	MPASS(vp != NULL);
+	MPASS(ino != 0);
 
 	node = malloc(sizeof(struct fnnode), M_FSNOTIFY, M_WAITOK | M_ZERO);
 
 	refcount_init(&node->nd_refcnt, 1);
+	mtx_init(&node->nd_mtx, "fsnotify_node", NULL, MTX_DEF);
+	TAILQ_INIT(&node->nd_watchlist);
+
+	node->nd_ino = ino;
 
-	mtx_lock(&fnnode_hashmtx);
-	/* DEBUG */
-	LIST_FOREACH(node, node_vphashhead(vp), nd_hashentry) {
-		if (node->nd_vnode == vp) {
-			panic("Node already exists in vnode hash table: %p",
-			    node->nd_vnode);
-		}
-	}
-	LIST_INSERT_HEAD(node_vphashhead(vp), node, nd_hashentry);
-	mtx_unlock(&fnnode_hashmtx);
+	VI_LOCK(vp);
+	vp->v_fnnode = node;
+	VI_UNLOCK(vp);
 
 	return (node);
 }
@@ -657,18 +666,6 @@
 	}
 }
 
-static void
-node_destroy(struct fnnode *node)
-{
-	mtx_lock(&node->nd_mtx);
-	node_detachwatches(node);
-	mtx_unlock(&node->nd_mtx);
-	mtx_lock(&fnnode_hashmtx);
-	LIST_REMOVE(node, nd_hashentry);
-	mtx_unlock(&fnnode_hashmtx);
-	node_drop(node);
-}
-
 static int
 node_getino(struct vnode *vp, ino_t *inop, int vplocked)
 {
@@ -681,7 +678,10 @@
 			return (error);
 	}
 
-	error = VOP_GETATTR(vp, &va, thread0.td_ucred);
+	if (vp->v_iflag & VI_DOOMED)
+		return (EINVAL);
+
+	error = VOP_GETATTR(vp, &va, NOCRED);
 	if (error == 0)
 		*inop = va.va_fileid;
 
@@ -692,51 +692,66 @@
 }
 
 static struct fnnode*
-node_lookupex(struct vnode *vp, ino_t *inop, int vplocked)
+node_lookupex(struct vnode *vp, ino_t *inop, int flags)
 {
 	struct fnnode *node, *rv;
 	ino_t ino;
-	int error;
+	int error, watchcount;
 
 	rv = NULL;
-	/* Node is always on one of the hash tables. */
-	mtx_lock(&fnnode_hashmtx);
-	LIST_FOREACH(node, node_vphashhead(vp), nd_hashentry) {
-		if (node->nd_vnode == vp) {
-			mtx_lock(&node->nd_mtx);
-			rv = (node->nd_watchcount == 0 ? NULL : node);
-			if (rv == NULL)
-				mtx_unlock(&node->nd_mtx);
-			break;
-		}
+	VI_LOCK(vp);
+	node = vp->v_fnnode;
+	VI_UNLOCK(vp);
+	if (node == FNNODE_INVAL) {
+		node = NULL;
+		if ((flags & LOOKUP_IGNINVAL) == 0)
+			goto done;
+	} else if (node != NULL) {
+		mtx_lock(&node->nd_mtx);
+		watchcount = node->nd_watchcount;
+		mtx_unlock(&node->nd_mtx);
+		if (watchcount == 0)
+			node = NULL;
+		goto done;
 	}
-	mtx_unlock(&fnnode_hashmtx);
 
-	if (node == NULL) {
-		if (inop == NULL)
-			inop = &ino;
-		error = node_getino(vp, inop, vplocked);
-		if (error != 0)
-			goto done;
+	node = NULL;
+	if (inop == NULL)
+		inop = &ino;
+	error = node_getino(vp, inop, flags & LOOKUP_VPLOCKED);
+	if (error != 0)
+		goto done;
 
-		mtx_lock(&fnnode_hashmtx);
-		LIST_FOREACH(node,
-		    node_inohashhead(vp->v_mount, *inop), nd_hashentry) {
-			if (node->nd_ino != *inop ||
-			    node->nd_mount != vp->v_mount)
-				continue;
-			/* add to inohash */
-			mtx_lock(&node->nd_mtx);
-			rv = (node->nd_watchcount == 0 ? NULL : node);
-			if (rv == NULL)
-				mtx_unlock(&node->nd_mtx);
-			break;
-		}
+	mtx_lock(&fnnode_hashmtx);
+	LIST_FOREACH(node,
+	    node_inohashhead(vp->v_mount, *inop), nd_hashentry) {
+		if (node->nd_ino != *inop ||
+		    node->nd_mount != vp->v_mount)
+			continue;
+		mtx_lock(&node->nd_mtx);
+		VI_LOCK(vp);
+		if (!NODE_ISVALID(vp->v_fnnode)) {
+			node_hold(node);
+			vp->v_fnnode = node;
+		} else
+			MPASS(vp->v_fnnode == node);
+		VI_UNLOCK(vp);
+		watchcount = node->nd_watchcount;
+		mtx_unlock(&node->nd_mtx);
+		if (watchcount == 0)
+			node = NULL;
 		mtx_unlock(&fnnode_hashmtx);
+		goto done;
 	}
+	mtx_unlock(&fnnode_hashmtx);
 
+	VI_LOCK(vp);
+	if (!NODE_ISVALID(vp->v_fnnode))
+		vp->v_fnnode = FNNODE_INVAL;
+	VI_UNLOCK(vp);
+
 done:
-	return (rv);
+	return (node);
 }
 
 static __inline struct fnnode*
@@ -744,7 +759,7 @@
 {
 	ASSERT_VOP_LOCKED(vp, "fsnotify node lookup");
 
-	return (node_lookupex(vp, NULL, 1));
+	return (node_lookupex(vp, NULL, LOOKUP_VPLOCKED));
 }
 
 static int

==== //depot/projects/soc2010/ilya_fsnotify/src/sys/kern/vfs_subr.c#3 (text+ko) ====

@@ -275,6 +275,8 @@
 /* 
  * fsnotify hooks
  */
+
+void (*fsnotify_hook_reclaim)(struct vnode *vp) = NULL;
 vop_create_t *fsnotify_hook_create = NULL;
 vop_link_t *fsnotify_hook_link = NULL;
 vop_mkdir_t *fsnotify_hook_mkdir = NULL;
@@ -2598,6 +2600,8 @@
 	 */
 	delmntque(vp);
 	cache_purge(vp);
+	if (fsnotify_hook_reclaim != NULL)
+		fsnotify_hook_reclaim(vp);
 	/*
 	 * Done with purge, reset to the standard lock and invalidate
 	 * the vnode.

==== //depot/projects/soc2010/ilya_fsnotify/src/sys/sys/fsnotify.h#4 (text+ko) ====

@@ -27,22 +27,22 @@
  * $FreeBSD$
  */
 
-#ifndef _SYS_FSNOTIFY_H_
+#ifndef	_SYS_FSNOTIFY_H_
 #define	_SYS_FSNOTIFY_H_
 
-#define FE_CREATE		0x0001
-#define FE_REMOVE		0x0002
-#define FE_RENAME_FROM		0x0004
-#define FE_RENAME_TO		0x0008
+#define	FE_CREATE		0x0001
+#define	FE_REMOVE		0x0002
+#define	FE_RENAME_FROM		0x0004
+#define	FE_RENAME_TO		0x0008
 
-#define FE_CLOSE		0x0010
-#define FE_INACTIVE		0x0020
-#define FE_INACTIVE_CHANGED	0x0040
+#define	FE_CLOSE		0x0010
+#define	FE_INACTIVE		0x0020
+#define	FE_INACTIVE_CHANGED	0x0040
 
-#define FE_DESTROY		0x0080
+#define	FE_DESTROY		0x0080
 
-#define FSNOTIFY_ADDWATCH	_IOWR('F', 1, struct fsnotify_addwatch_args)
-#define FSNOTIFY_RMWATCH	_IOW('F', 2, int)
+#define	FSNOTIFY_ADDWATCH	_IOWR('F', 1, struct fsnotify_addwatch_args)
+#define	FSNOTIFY_RMWATCH	_IOW('F', 2, int)
 
 struct fsnotify_event {
 	int32_t		fe_wd;
@@ -61,6 +61,10 @@
 
 #ifdef _KERNEL
 
+#define	FNNODE_INVAL		((void *)(uintptr_t)(-1))
+
+extern void (*fsnotify_hook_reclaim)(struct vnode *vp);
+
 extern vop_create_t *fsnotify_hook_create;
 extern vop_link_t *fsnotify_hook_link;
 extern vop_mkdir_t *fsnotify_hook_mkdir;
@@ -69,7 +73,7 @@
 extern vop_rmdir_t *fsnotify_hook_rmdir;
 extern vop_symlink_t *fsnotify_hook_symlink;
 
-#endif /* _KERNEL */
+#endif	/* _KERNEL */
 
-#endif /* !_SYS_FSNOTIFY_H_ */
+#endif	/* !_SYS_FSNOTIFY_H_ */
 

==== //depot/projects/soc2010/ilya_fsnotify/src/sys/sys/vnode.h#2 (text+ko) ====

@@ -60,6 +60,7 @@
  * it from v_data.  If non-null, this area is freed in getnewvnode().
  */
 
+struct fnnode;
 struct namecache;
 
 struct vpollinfo {
@@ -169,6 +170,7 @@
 	struct vpollinfo *v_pollinfo;		/* G Poll events, p for *v_pi */
 	struct label *v_label;			/* MAC label for vnode */
 	struct lockf *v_lockf;			/* Byte-level lock list */
+	struct fnnode *v_fnnode;		/* i fsnotify node */
 };
 
 #endif /* defined(_KERNEL) || defined(_KVM_VNODE) */


More information about the p4-projects mailing list