Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 9 Jul 2010 10:27:42 GMT
From:      Ilya Putsikau <ilya@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 180684 for review
Message-ID:  <201007091027.o69ARgtw024679@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@180684?ac=10

Change 180684 by ilya@ilya_triton on 2010/07/09 10:27:38

	Use kernel process instead of taskqueue to process events
	Set root and current firectories for fsnotify process
	Lookup and check global path only (not chroot)
	Hold vnode reference to prevent vnode reuse
	Return inode number in lookupex if node already exists

Affected files ...

.. //depot/projects/soc2010/ilya_fsnotify/src/sys/kern/vfs_notify.c#6 edit

Differences ...

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

@@ -39,6 +39,7 @@
 #include <sys/filio.h>
 #include <sys/hash.h>
 #include <sys/kernel.h>
+#include <sys/kthread.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
@@ -50,7 +51,7 @@
 #include <sys/queue.h>
 #include <sys/refcount.h>
 #include <sys/systm.h>
-#include <sys/taskqueue.h>
+#include <sys/unistd.h>
 #include <sys/vnode.h>
 
 #include <sys/fsnotify.h>
@@ -120,8 +121,7 @@
 static TAILQ_HEAD(, fnevent) fsnotify_queue =
     TAILQ_HEAD_INITIALIZER(fsnotify_queue);
 static struct mtx fsnotify_queue_mtx;
-static struct task fsnotify_task;
-static struct taskqueue *fsnotify_tq;
+static struct proc *fsnotify_proc;
 
 static struct fnnode_hashhead *fnnode_inohashtbl;
 static struct mtx fnnode_hashmtx;
@@ -150,7 +150,7 @@
 static vop_rmdir_t hook_rmdir;
 static vop_symlink_t hook_symlink;
 
-static void process_queue(void *context, int pending);
+static void process_queue(void *context);
 static void enqueue_direvent(struct fnnode *dirnode, struct componentname *cnp,
     int cookie, int mask);
 static void enqueue_fileevent(struct fnnode *dirnode, int cookie, int mask);
@@ -181,6 +181,7 @@
 {
 	struct fnnode_hashhead *hashhead;
 	struct fnnode *node;
+	struct proc *p;
 	int i;
 	int error = 0;
 
@@ -201,16 +202,19 @@
 		mtx_init(&fsnotify_queue_mtx, "fsnotify_queue", NULL, MTX_DEF);
 		mtx_init(&fnnode_hashmtx, "fsnotify_hash", NULL, MTX_DEF);
 
+		error = kproc_create(process_queue, NULL, &fsnotify_proc,
+		    RFHIGHPID, 0, "fsnotify");
+		if (error != 0) {
+			mtx_destroy(&fsnotify_queue_mtx);
+			mtx_destroy(&fnnode_hashmtx);
+			printf("cannot create fsnotify process\n");
+			return (error);
+		}
+
 		i = MAX(desiredvnodes / 32, 16);
 		fnnode_inohashtbl = hashinit(i, M_FSNOTIFYHASH,
 		    &fnnode_hashmask);
 
-		TASK_INIT(&fsnotify_task, 0, process_queue, NULL);
-		fsnotify_tq = taskqueue_create("fsnotify", M_WAITOK,
-		    taskqueue_thread_enqueue, &fsnotify_tq);
-		taskqueue_start_threads(&fsnotify_tq, 1, PWAIT,
-		    "fsnotify taskq");
-
 		/* FIXME: correct device permissions */
 		fsnotify_dev = make_dev(&fsnotify_cdevsw, 0, UID_ROOT,
 		    GID_WHEEL, 0666, "fsnotify");
@@ -234,19 +238,29 @@
 		fsnotify_hook_rmdir = NULL;
 		fsnotify_hook_symlink = NULL;
 		destroy_dev(fsnotify_dev);
-		taskqueue_drain(fsnotify_tq, &fsnotify_task);
-		taskqueue_free(fsnotify_tq);
+
+		mtx_lock(&fsnotify_queue_mtx);
+		if ((p = fsnotify_proc) != NULL) {
+			fsnotify_proc = NULL;
+			wakeup_one(&fsnotify_queue);
+			PROC_LOCK(p);
+			mtx_unlock(&fsnotify_queue_mtx);
+			msleep(p, &p->p_mtx, PWAIT, "fsnotify_destroy", 0);
+			PROC_UNLOCK(p);
+		} else
+			mtx_unlock(&fsnotify_queue_mtx);
+
 		for (i = 0; i <= fnnode_hashmask; i++) {
 			hashhead = &fnnode_inohashtbl[i];
 			while (!LIST_EMPTY(hashhead)) {
 				node = LIST_FIRST(hashhead);
 				mtx_lock(&node->nd_mtx);
-				if (node->nd_vnode != NULL) {
+				if (NODE_ISVALID(node->nd_vnode)) {
 					VI_LOCK(node->nd_vnode);
 					node->nd_vnode->v_fnnode = NULL;
 					printf("fsnotify unload: deref vp: node %p  vp %p\n",
 					    node, node->nd_vnode);
-					VI_UNLOCK(node->nd_vnode);
+					vdropl(node->nd_vnode);
 					node->nd_vnode = NULL;
 					mtx_unlock(&node->nd_mtx);
 					node_drop(node);
@@ -432,13 +446,14 @@
 		if (vp == NULL)
 			return (EBADF);
 		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+		ino = 0;
 		node = node_lookupex(vp, &ino, LOOKUP_IGNINVAL);
 		if (node != NULL) {
 			node_watchhold(node);
 			mtx_unlock(&node->nd_mtx);
 			VFS_UNLOCK_GIANT(vfslocked);
 		} else {
-			error = vn_fullpath(td, vp, &path, &pathfree);
+			error = vn_fullpath_global(td, vp, &path, &pathfree);
 			VFS_UNLOCK_GIANT(vfslocked);
 			if (error != 0)
 				return (error);
@@ -511,16 +526,17 @@
 	VI_LOCK(vp);
 	node = vp->v_fnnode;
 	vp->v_fnnode = NULL;
-	VI_UNLOCK(vp);
 
 	if (NODE_ISVALID(node)) {
+		vdropl(vp);
 		printf("node reclaim: deref vnode: node %p  vp %p\n",
 		    node, node->nd_vnode);
 		mtx_lock(&node->nd_mtx);
 		node->nd_vnode = NULL;
 		mtx_unlock(&node->nd_mtx);
 		node_drop(node);
-	}
+	} else
+		VI_UNLOCK(vp);
 }
 
 static __inline int
@@ -762,7 +778,7 @@
 	MPASS(ino != 0);
 
 	node = malloc(sizeof(struct fnnode), M_FSNOTIFY, M_WAITOK | M_ZERO);
-	printf("node alloc: node %p  vp %p\n", node, vp);
+	printf("node alloc: node %p  vp %p  ino %d\n", node, vp, ino);
 
 	refcount_init(&node->nd_refcnt, 2);
 	mtx_init(&node->nd_mtx, "fsnotify_node", NULL, MTX_DEF);
@@ -778,6 +794,7 @@
 	mtx_unlock(&fnnode_hashmtx);
 
 	VI_LOCK(vp);
+	vholdl(vp);
 	node->nd_vnode = vp;
 	vp->v_fnnode = node;
 	VI_UNLOCK(vp);
@@ -873,6 +890,7 @@
 			MPASS(node->nd_vnode == NULL);
 			node_hold(node);
 			printf("node lookup: ref vnode: node %p  vp %p\n", node, vp);
+			vholdl(vp);
 			vp->v_fnnode = node;
 			node->nd_vnode = vp;
 		} else
@@ -892,8 +910,9 @@
 	VI_UNLOCK(vp);
 
 done:
-	if (node != NULL)
-		mtx_assert(&node->nd_mtx, MA_OWNED);
+	if (node != NULL && inop != NULL)
+		*inop = node->nd_ino;
+
 	return (node);
 }
 
@@ -914,10 +933,7 @@
 	char *npath, *npathfree;
 	int vfslocked, error;
 
-	/*
-	 * TODO: has races. should be executed only in *single* process_queue
-	 * thread
-	 */
+	/* Should be executed in *single* process_queue thread */
 	vp = node->nd_vnode;
 	printf("node_updatepath: node %p  vp %p  %s\n",
 	    node, vp, node->nd_path);
@@ -930,7 +946,8 @@
 	vhold(vp);
 	mtx_unlock(&node->nd_mtx);
 
-	NDINIT(&ni, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE, path, curthread);
+	NDINIT_ATVP(&ni, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE, path, rootvnode,
+	    curthread);
 	error = namei(&ni);
 	vfslocked = NDHASGIANT(&ni);
 	if (error == 0) {
@@ -941,9 +958,8 @@
 		}
 		NDFREE(&ni, 0);
 	}
-	if (error != 0) {
-		error = vn_fullpath(curthread, vp, &npath, &npathfree);
-	}
+	if (error != 0)
+		error = vn_fullpath_global(curthread, vp, &npath, &npathfree);
 
 	VFS_UNLOCK_GIANT(vfslocked);
 	if ((vp->v_iflag & VI_DOOMED) != 0) {
@@ -1149,7 +1165,7 @@
 }
 
 static void
-process_queue(void *context, int pending)
+process_queue(void *context)
 {
 	struct fnnode *node;
 	struct fnwatch *watch;
@@ -1157,11 +1173,27 @@
 	struct fneventhandle *eh;
 	int i, handle_count;
 
+	MPASS(fsnotify_proc != NULL && fsnotify_proc == curthread->td_proc);
+
+	FILEDESC_XLOCK(fsnotify_proc->p_fd);
+	if (fsnotify_proc->p_fd->fd_cdir == NULL) {
+		fsnotify_proc->p_fd->fd_cdir = rootvnode;
+		vref(rootvnode);
+	}
+	if (fsnotify_proc->p_fd->fd_rdir == NULL) {
+		fsnotify_proc->p_fd->fd_rdir = rootvnode;
+		vref(rootvnode);
+	}
+	FILEDESC_XUNLOCK(fsnotify_proc->p_fd);
+
+	mtx_lock(&fsnotify_queue_mtx);
 	while (1) {
-		mtx_lock(&fsnotify_queue_mtx);
+		if (fsnotify_proc == NULL)
+			break;
 		if (TAILQ_EMPTY(&fsnotify_queue)) {
-			mtx_unlock(&fsnotify_queue_mtx);
-			break;
+			msleep(&fsnotify_queue, &fsnotify_queue_mtx, PWAIT,
+			    "wait", 0);
+			continue;
 		}
 		event = TAILQ_FIRST(&fsnotify_queue);
 		TAILQ_REMOVE(&fsnotify_queue, event, ev_queueentry);
@@ -1191,8 +1223,7 @@
 			event_free(event);
 			continue;
 		}
-		/* FIXME */
-		if (0 && node->nd_vnode != NULL)
+		if (node->nd_vnode != NULL)
 			node_updatepath(node);
 		else
 			printf("fsnotify: vnode not found, reusing cached path: %s\n",
@@ -1206,7 +1237,14 @@
 
 		for (i = 0; i < handle_count; i++)
 			session_enqueue(&event->ev_handlebuf[i]);
+
+		mtx_lock(&fsnotify_queue_mtx);
 	}
+
+	wakeup_one(&fsnotify_queue);
+	mtx_unlock(&fsnotify_queue_mtx);
+
+	kproc_exit(0);
 }
 
 static void
@@ -1237,7 +1275,7 @@
 	TAILQ_INSERT_TAIL(&fsnotify_queue, event, ev_queueentry);
 	mtx_unlock(&fsnotify_queue_mtx);
 
-	taskqueue_enqueue(fsnotify_tq, &fsnotify_task);
+	wakeup(&fsnotify_queue);
 }
 
 static void



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007091027.o69ARgtw024679>