From owner-p4-projects@FreeBSD.ORG Sun Jun 6 17:12:31 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id EB5701065672; Sun, 6 Jun 2010 17:12:30 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id AF58C1065678 for ; Sun, 6 Jun 2010 17:12:30 +0000 (UTC) (envelope-from ilya@FreeBSD.org) Received: from repoman.freebsd.org (unknown [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 9C66C8FC0A for ; Sun, 6 Jun 2010 17:12:30 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id o56HCUPc013202 for ; Sun, 6 Jun 2010 17:12:30 GMT (envelope-from ilya@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id o56HCUqn013200 for perforce@freebsd.org; Sun, 6 Jun 2010 17:12:30 GMT (envelope-from ilya@FreeBSD.org) Date: Sun, 6 Jun 2010 17:12:30 GMT Message-Id: <201006061712.o56HCUqn013200@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to ilya@FreeBSD.org using -f From: Ilya Putsikau To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 179260 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 06 Jun 2010 17:12:31 -0000 http://p4web.freebsd.org/@@179260?ac=10 Change 179260 by ilya@ilya_triton on 2010/06/06 17:11:32 Add device read, poll and ioctl calls. Ioctls: add watch, remove watch, FIONREAD Inital support for creating and searching for nodes Affected files ... .. //depot/projects/soc2010/ilya_fsnotify/src/sys/kern/vfs_notify.c#2 edit .. //depot/projects/soc2010/ilya_fsnotify/src/sys/sys/fsnotify.h#2 edit Differences ... ==== //depot/projects/soc2010/ilya_fsnotify/src/sys/kern/vfs_notify.c#2 (text+ko) ==== @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -44,70 +45,86 @@ #include #include #include +#include #include #include #include #include -struct fn_eventhandle; +struct fneventhandle; +struct fnwatch; -struct fn_session { - TAILQ_HEAD(, fn_eventhandle) queue; - struct mtx queue_mtx; - struct cv queue_ready_cv; - struct selinfo queue_poll; - int queue_size; +struct fnsession { + struct mtx ss_mtx; + TAILQ_HEAD(, fneventhandle) ss_queue; + TAILQ_HEAD(, fnwatch) ss_watchlist; + struct cv ss_queuecv; + struct selinfo ss_queuepoll; + int ss_queuesize; }; -struct fn_watch { - TAILQ_ENTRY(fn_watch) node_entry; - struct fn_node *node; - struct fn_session *session; - int wd; - int mask; +struct fnnode { + LIST_ENTRY(fnnode) nd_hashentry; + TAILQ_HEAD(, fnwatch) nd_watchlist; + struct mtx nd_mtx; + struct vnode *nd_vnode; + char *nd_path; + int nd_pathlen; + uint32_t nd_pathhash; + int nd_watchcount; + u_int nd_supermask; + volatile u_int nd_refcnt; }; -struct fn_node { - TAILQ_HEAD(, fn_watch) watch_list; - struct mtx node_mtx; - struct vnode *vnode; - char *path; - char *path_buf; - int path_len; - int watch_count; - u_int supermask; - volatile u_int refcnt; +struct fneventhandle { + TAILQ_ENTRY(fneventhandle) eh_queueentry; + struct fnevent *eh_event; + struct fnwatch *eh_watch; }; -struct fn_eventhandle { - TAILQ_ENTRY(fn_eventhandle) sessionqueue_entry; - struct fn_event *event; - struct fn_watch *watch; +struct fnevent { + TAILQ_ENTRY(fnevent) ev_queueentry; + struct fnnode *ev_node; + char *ev_path; + int ev_pathlen; + int ev_mask; + int ev_cookie; + int ev_handlecount; + int ev_handlemaxsize; + struct fneventhandle ev_handlebuf[0]; }; -struct fn_event { - TAILQ_ENTRY(fn_event) queue_entry; - struct fn_node *node; - int flags; - int mask; - int cookie; - int handle_count; - int handle_maxsize; - int path_pos; - char path_buf[PATH_MAX]; - struct fn_eventhandle handle_buf[0]; +struct fnwatch { + TAILQ_ENTRY(fnwatch) wt_nodeentry; + TAILQ_ENTRY(fnwatch) wt_sessionentry; + struct fnnode *wt_node; + struct fnsession *wt_session; + int wt_mask; + int wt_wd; + volatile u_int wt_refcnt; }; +LIST_HEAD(fnnode_hashhead, fnnode); + +static MALLOC_DEFINE(M_FSNOTIFY, "fsnotify", "fsnotify"); +static MALLOC_DEFINE(M_FSNOTIFYHASH, "fsnotify_hash", "fsnotify hash tables"); +static MALLOC_DEFINE(M_FSNOTIFYPATH, "fsnotify_path", "fsnotify path buffers"); + static struct cdev *fsnotify_dev; -static MALLOC_DEFINE(M_FSNOTIFY, "fsnotify", "fsnotify"); -static TAILQ_HEAD(, fn_event) fsnotify_queue = + +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 fnnode_hashhead **fnnode_vphashtbl; +static struct fnnode_hashhead **fnnode_pathhashtbl; +static struct mtx fnnode_hashmtx; +static u_long fnnode_hashmask; + static d_open_t fsnotify_open; static d_read_t fsnotify_read; static d_ioctl_t fsnotify_ioctl; @@ -131,14 +148,22 @@ static vop_symlink_t hook_symlink; static void process_queue(void *context, int pending); -static void enqueue_direvent(struct fn_node *pn, struct componentname *cnp, +static void enqueue_direvent(struct fnnode *dirnode, struct componentname *cnp, int mask); -static void enqueue_fileevent(struct fn_node *pn, int mask); -static struct fn_node* node_lookup(struct vnode *vp); +static void enqueue_fileevent(struct fnnode *dirnode, int mask); +static void session_drophandle(struct fnsession *ss, struct fneventhandle *eh); +static int session_addwatch(struct fnsession *ss, struct fnnode *node, int mask, + struct fnwatch **watchpp); +static int session_rmwatch(struct fnsession *ss, int wd); +static struct fnnode* node_lookup(struct vnode *vp); +static struct fnnode* node_alloc(char *path, int pathlen); +static void node_create(struct fnnode *node, struct vnode *vp); +static void node_destroy(struct fnnode *node); static int fsnotify_modevent(struct module *module, int cmd, void *arg) { + int hashsize; int error = 0; switch (cmd) { @@ -155,9 +180,16 @@ } mtx_init(&fsnotify_queue_mtx, "fsnotify_queue", NULL, MTX_DEF); + mtx_init(&fnnode_hashmtx, "fsnotify_hash", NULL, MTX_DEF); + + hashsize = MAX(desiredvnodes / 32, 16); + fnnode_vphashtbl = hashinit(hashsize, M_FSNOTIFYHASH, + &fnnode_hashmask); + fnnode_pathhashtbl = hashinit(hashsize, M_FSNOTIFYHASH, + &fnnode_hashmask); TASK_INIT(&fsnotify_task, 0, process_queue, NULL); - fsnotify_tq = taskqueue_create_fast("fsnotify", M_WAITOK, + fsnotify_tq = taskqueue_create("fsnotify", M_WAITOK, taskqueue_thread_enqueue, &fsnotify_tq); taskqueue_start_threads(&fsnotify_tq, 1, PWAIT, "fsnotify taskq"); @@ -185,7 +217,10 @@ destroy_dev(fsnotify_dev); taskqueue_drain(fsnotify_tq, &fsnotify_task); taskqueue_free(fsnotify_tq); + free(fnnode_vphashtbl, M_FSNOTIFYHASH); + free(fnnode_pathhashtbl, M_FSNOTIFYHASH); mtx_destroy(&fsnotify_queue_mtx); + mtx_destroy(&fnnode_hashmtx); break; case MOD_SHUTDOWN: break; @@ -214,12 +249,16 @@ static void fsnotify_session_dtor(void *data) { - struct fn_session *ss = data; + struct fnsession *ss = data; + struct fneventhandle *eh; - /* TODO drop all elements in queue */ + while (!TAILQ_EMPTY(&ss->ss_queue)) { + eh = TAILQ_FIRST(&ss->ss_queue); + session_drophandle(ss, eh); + } - cv_destroy(&ss->queue_ready_cv); - mtx_destroy(&ss->queue_mtx); + cv_destroy(&ss->ss_queuecv); + mtx_destroy(&ss->ss_mtx); free(ss, M_FSNOTIFY); } @@ -227,12 +266,12 @@ static int fsnotify_open(struct cdev *dev, int flag, int mode, struct thread *td) { - struct fn_session *ss; + struct fnsession *ss; - ss = malloc(sizeof(struct fn_session), M_FSNOTIFY, M_WAITOK | M_ZERO); + ss = malloc(sizeof(struct fnsession), M_FSNOTIFY, M_WAITOK | M_ZERO); - mtx_init(&ss->queue_mtx, "fn_session_queue", NULL, MTX_DEF); - cv_init(&ss->queue_ready_cv, "fn_session_queue_ready"); + mtx_init(&ss->ss_mtx, "fnsession_queue", NULL, MTX_DEF); + cv_init(&ss->ss_queuecv, "fnsession_queuecv"); devfs_set_cdevpriv(ss, fsnotify_session_dtor); @@ -242,8 +281,11 @@ static int fsnotify_read(struct cdev *dev, struct uio *uio, int flag) { - struct fn_session *ss; - int error; + struct fsnotify_event *ue; + struct fnsession *ss; + struct fneventhandle *eh; + int len, error; + char user_buf[sizeof(struct fsnotify_event) + PATH_MAX]; if (uio->uio_resid == 0) return (0); @@ -251,8 +293,44 @@ error = devfs_get_cdevpriv((void **)&ss); if (error != 0) return (error); + + printf("fsnotify_read: offset %jd\n", uio->uio_offset); - /* TODO */ + mtx_lock(&ss->ss_mtx); + + if (TAILQ_EMPTY(&ss->ss_queue)) { + if (flag & O_NONBLOCK) + error = EWOULDBLOCK; + else + error = cv_wait_sig(&ss->ss_queuecv, + &ss->ss_mtx); + } + + if (error != 0) { + mtx_unlock(&ss->ss_mtx); + return (error); + } + + eh = TAILQ_FIRST(&ss->ss_queue); + ue = (struct fsnotify_event *) user_buf; + ue->wd = eh->eh_watch->wt_wd; + ue->mask = eh->eh_watch->wt_mask & eh->eh_event->ev_mask; + ue->cookie = eh->eh_event->ev_cookie; + ue->len = eh->eh_event->ev_pathlen + 1; + memcpy(ue->name, eh->eh_event->ev_path, ue->len); + len = ue->len + sizeof(struct fsnotify_event); + + mtx_unlock(&ss->ss_mtx); + + error = uiomove(user_buf, MIN(len, uio->uio_resid), uio); + printf("fsnotify_read: uiomove: error %d, offset %jd, len %d\n", error, + uio->uio_offset, len); + if (error == 0 && uio->uio_offset >= len) { + uio->uio_offset = 0; + mtx_lock(&ss->ss_mtx); + session_drophandle(ss, eh); + mtx_unlock(&ss->ss_mtx); + } return (error); } @@ -261,7 +339,11 @@ fsnotify_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { - struct fn_session *ss; + struct fnsession *ss; + struct fnnode *node; + struct fnwatch *watch; + struct fsnotify_addwatch_args *add_args; + struct vnode *vp; int error; error = devfs_get_cdevpriv((void **)&ss); @@ -270,11 +352,31 @@ switch (cmd) { case FSNOTIFY_ADDWATCH: - return (0); + add_args = (struct fsnotify_addwatch_args *)data; + /* TODO: get vnode for fd */ + vp = NULL; + node = node_lookup(vp); + if (node == NULL) { + /* TODO: get full path for vp */ + node_alloc(NULL, 0); + node_create(node, vp); + mtx_lock(&node->nd_mtx); + } + error = session_addwatch(ss, node, add_args->mask, &watch); + if (error == 0) + add_args->wd = watch->wt_wd; + return (error); case FSNOTIFY_RMWATCH: - return (0); + error = session_rmwatch(ss, *(int *)data); + return (error); case FIONREAD: - *(int *)data = 0; + mtx_lock(&ss->ss_mtx); + if (!TAILQ_EMPTY(&ss->ss_queue)) + *(int *)data = sizeof(struct fsnotify_event) + + TAILQ_FIRST(&ss->ss_queue)->eh_event->ev_pathlen + 1; + else + *(int *)data = 0; + mtx_unlock(&ss->ss_mtx); return (0); default: return (ENOIOCTL); @@ -284,21 +386,24 @@ static int fsnotify_poll(struct cdev *dev, int events, struct thread *td) { - struct fn_session *ss; + struct fnsession *ss; int revents; if (devfs_get_cdevpriv((void **)&ss) != 0) return (events & - (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM)); + (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)); revents = 0; if (events & (POLLIN | POLLRDNORM)) { - /* TODO */ + mtx_lock(&ss->ss_mtx); + if (!TAILQ_EMPTY(&ss->ss_queue)) + revents = (events & (POLLIN | POLLRDNORM)); + mtx_unlock(&ss->ss_mtx); } if (revents == 0) - selrecord(td, &ss->queue_poll); + selrecord(td, &ss->ss_queuepoll); return (revents); } @@ -310,10 +415,10 @@ hook_generic_create(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) { - struct fn_node *pn; + struct fnnode *dirnode; - pn = node_lookup(dvp); - if (pn != NULL) + dirnode = node_lookup(dvp); + if (dirnode != NULL) enqueue_direvent(NULL, cnp, FE_CREATE); return (0); } @@ -322,7 +427,7 @@ hook_generic_remove(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) { - struct fn_node *pn, *n; + struct fnnode *dirnode, *n; n = node_lookup(vp); if (n != NULL) { @@ -333,36 +438,36 @@ enqueue_fileevent(NULL, FE_DESTROY); } - pn = node_lookup(dvp); - if (pn != NULL) + dirnode = node_lookup(dvp); + if (dirnode != NULL) enqueue_direvent(NULL, cnp, FE_REMOVE); } static int hook_create(struct vop_create_args *ap) { - hook_generic_remove(ap->a_dvp, *ap->a_vpp, ap->a_cnp); + hook_generic_create(ap->a_dvp, *ap->a_vpp, ap->a_cnp); return (0); } static int hook_mkdir(struct vop_mkdir_args *ap) { - hook_generic_remove(ap->a_dvp, *ap->a_vpp, ap->a_cnp); + hook_generic_create(ap->a_dvp, *ap->a_vpp, ap->a_cnp); return (0); } static int hook_link(struct vop_link_args *ap) { - hook_generic_remove(ap->a_tdvp, ap->a_vp, ap->a_cnp); + hook_generic_create(ap->a_tdvp, ap->a_vp, ap->a_cnp); return (0); } static int hook_symlink(struct vop_symlink_args *ap) { - hook_generic_remove(ap->a_dvp, *ap->a_vpp, ap->a_cnp); + hook_generic_create(ap->a_dvp, *ap->a_vpp, ap->a_cnp); return (0); } @@ -386,65 +491,208 @@ return (0); } -#if 0 -static struct fn_node* -node_alloc(char *name, int namelen) +static __inline void +watch_hold(struct fnwatch *watch) +{ + refcount_acquire(&watch->wt_refcnt); +} + +static void +watch_drop(struct fnwatch *watch) { - struct fn_node *n; + if (refcount_release(&watch->wt_refcnt) != 0) { + free(watch, M_FSNOTIFY); + } +} - n = malloc(sizeof(struct fn_node) + namelen + 1, M_FSNOTIFY, - M_WAITOK | M_ZERO); +static int +watch_nextwd(void) +{ + static volatile int wd = 1; + int nwd; - n->refcnt = 1; +again: + nwd = atomic_fetchadd_int(&wd, 1); - /* FIXME - memcpy(n->name, name, namelen); - n->namelen = namelen; - */ + if (nwd <= 0) { + if (atomic_cmpset_int(&wd, nwd, 1) == 0) + goto again; + } - return n; + return (nwd); } -#endif -static __inline struct fn_node * -node_hold(struct fn_node *node) +static struct fnnode* +node_alloc(char *path, int pathlen) { - return node; + struct fnnode *node; + + node = malloc(sizeof(struct fnnode), M_FSNOTIFY, M_WAITOK | M_ZERO); + node->nd_path = malloc(pathlen + 1, M_FSNOTIFYPATH, M_WAITOK); + + refcount_init(&node->nd_refcnt, 1); + + memcpy(node->nd_path, path, pathlen); + node->nd_path[pathlen] = '\0'; + node->nd_pathlen = pathlen; + node->nd_pathhash = hash32_buf(node->nd_path, pathlen, HASHINIT); + + return (node); } static __inline void -node_drop(struct fn_node *node) +node_hold(struct fnnode *node) +{ + refcount_acquire(&node->nd_refcnt); +} + +static void +node_drop(struct fnnode *node) +{ + if (refcount_release(&node->nd_refcnt) != 0) { + KASSERT(node->nd_watchcount == 0 && node->nd_supermask == 0 && + TAILQ_EMPTY(&node->nd_watchlist), ("Invalid reference count")); + mtx_destroy(&node->nd_mtx); + free(node->nd_path, M_FSNOTIFYPATH); + free(node, M_FSNOTIFY); + } +} + +static __inline struct fnnode_hashhead * +node_vphashhead(struct vnode *vp) +{ + uint32_t h; + + h = hash32_buf(vp, sizeof(vp), HASHINIT); + return fnnode_vphashtbl[h & fnnode_hashmask]; +} + +static __inline struct fnnode_hashhead * +node_pathhashhead(char *path, int pathlen) +{ + uint32_t h; + + h = hash32_buf(path, pathlen, HASHINIT); + return fnnode_vphashtbl[h & fnnode_hashmask]; +} + +static void +node_create(struct fnnode *node, struct vnode *vp) +{ + struct fnnode *ni; + + MPASS(vp != NULL); + mtx_lock(&fnnode_hashmtx); + /* DEBUG */ + LIST_FOREACH(ni, node_vphashhead(vp), nd_hashentry) { + if (ni->nd_vnode == vp) { + panic("Node already exists in vnode hash table: %s", + node->nd_path); + } + } + LIST_INSERT_HEAD(node_vphashhead(vp), node, nd_hashentry); + mtx_unlock(&fnnode_hashmtx); +} + +static void +node_destroy(struct fnnode *node) { + struct fnwatch *watch; + + mtx_lock(&node->nd_mtx); + while (!TAILQ_EMPTY(&node->nd_watchlist)) { + watch = TAILQ_FIRST(&node->nd_watchlist); + TAILQ_REMOVE(&node->nd_watchlist, watch, wt_nodeentry); + watch_drop(watch); + } + mtx_unlock(&node->nd_mtx); + mtx_lock(&fnnode_hashmtx); + LIST_REMOVE(node, nd_hashentry); + mtx_unlock(&fnnode_hashmtx); + node_drop(node); } -static struct fn_node* +static struct fnnode* node_lookup(struct vnode *vp) { - return (NULL); + struct fnnode *node, *rv; + int pathhash, pathlen; + char *path; + + rv = NULL; + path = NULL; + pathhash = pathlen = 0; /* FIXME */ + /* 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; + } + } + mtx_unlock(&fnnode_hashmtx); + + if (node == NULL) { + /* TODO: lookup full path */ + + mtx_lock(&fnnode_hashmtx); + LIST_FOREACH(node, node_vphashhead(vp), nd_hashentry) { + if (node->nd_pathhash != pathhash || + node->nd_pathlen != pathlen || + memcmp(node->nd_path, path, pathlen) != 0) + continue; + /* add to vphash */ + mtx_lock(&node->nd_mtx); + rv = (node->nd_watchcount == 0 ? NULL : node); + if (rv == NULL) + mtx_unlock(&node->nd_mtx); + break; + } + mtx_unlock(&fnnode_hashmtx); + } + + if (path != NULL) + free(path, M_FSNOTIFY); + + return (rv); } - -static struct fn_event * -event_alloc(struct fn_node *node, int handle_maxsize, int mask, int cookie) +static struct fnevent * +event_alloc(struct fnnode *node, char *path, int pathlen, int handle_maxsize, + int mask, int cookie) { - struct fn_event *event; + struct fnevent *event; + int addslash; MPASS(handle_maxsize > 0); MPASS(mask != 0); + MPASS(pathlen > 0); - event = malloc(sizeof(struct fn_event) + - (sizeof(struct fn_eventhandle) * handle_maxsize), + event = malloc(sizeof(struct fnevent) + + (sizeof(struct fneventhandle) * handle_maxsize), M_FSNOTIFY, M_WAITOK | M_ZERO); - event->path_pos = sizeof(event->path_buf) - 1; - event->handle_maxsize = handle_maxsize; - event->node = node; - event->mask = mask; - event->cookie = cookie; + event->ev_handlemaxsize = handle_maxsize; + event->ev_node = node; + event->ev_mask = mask; + event->ev_cookie = cookie; + addslash = (path[0] != '/' && node->nd_path[0] != '/' ? 1 : 0); + event->ev_pathlen = node->nd_pathlen + addslash + pathlen; + event->ev_path = malloc(event->ev_pathlen + 1, M_FSNOTIFYPATH, + M_WAITOK); + memcpy(event->ev_path, node->nd_path, node->nd_pathlen); + if (addslash != 0) + event->ev_path[node->nd_pathlen] = '/'; + memcpy(event->ev_path + node->nd_pathlen + addslash, path, + pathlen); + event->ev_path[event->ev_pathlen] = '\0'; return (event); } -static __inline int +static int event_nextcookie(void) { static volatile int cookie = 1; @@ -452,122 +700,183 @@ return atomic_fetchadd_int(&cookie, 1); } +static void +eventhandle_drop(struct fneventhandle *eh) +{ + struct fnnode *node; + + node = eh->eh_event->ev_node; + + mtx_lock(&node->nd_mtx); + eh->eh_event->ev_handlecount--; + if (eh->eh_event->ev_handlecount == 0) { + node_drop(node); + free(eh->eh_event, M_FSNOTIFY); + } + mtx_unlock(&node->nd_mtx); +} + static int -event_prependpath(struct fn_event *event, char *path, int pathlen, int addslash) +session_addwatch(struct fnsession *ss, struct fnnode *node, int mask, + struct fnwatch **watchpp) { - int pos; + struct fnwatch *watch; - MPASS(path[pathlen] != '/'); - MPASS(pathlen > 0); + watch = malloc(sizeof(struct fnwatch), M_FSNOTIFY, M_WAITOK | M_ZERO); - pos = event->path_pos; + refcount_init(&watch->wt_refcnt, 2); - if (addslash != 0) - addslash = 1; + watch->wt_wd = watch_nextwd(); + watch->wt_mask = mask; + watch->wt_session = ss; + node_hold(node); + watch->wt_node = node; - if (pathlen + addslash > pos) { - printf("fsnotify: path is too long: %.*s/%s\n", pathlen, path, - event->path_buf); - return (ENAMETOOLONG); - } + mtx_lock(&ss->ss_mtx); + TAILQ_INSERT_TAIL(&ss->ss_watchlist, watch, wt_sessionentry); + mtx_unlock(&ss->ss_mtx); + mtx_lock(&node->nd_mtx); + TAILQ_INSERT_TAIL(&node->nd_watchlist, watch, wt_nodeentry); + mtx_unlock(&node->nd_mtx); - if (addslash) - event->path_buf[pos--] = '/'; + if (watchpp != NULL) + *watchpp = watch; - pos -= pathlen; - memcpy(path, event->path_buf + pos, pathlen); + return (0); +} - event->path_pos = pos; +static int +session_rmwatch(struct fnsession *ss, int wd) +{ + struct fnwatch *watch, *tmp; + mtx_lock(&ss->ss_mtx); + TAILQ_FOREACH_SAFE(watch, &ss->ss_watchlist, wt_sessionentry, tmp) { + if (watch->wt_wd != wd) + continue; + TAILQ_REMOVE(&ss->ss_watchlist, watch, wt_sessionentry); + watch_drop(watch); + watch->wt_session = NULL; + break; + } + mtx_unlock(&ss->ss_mtx); + if (watch == NULL) + return (ENOENT); return (0); } static void -session_enqueue(struct fn_eventhandle *eh) +session_drophandle(struct fnsession *ss, struct fneventhandle *eh) +{ + TAILQ_REMOVE(&ss->ss_queue, eh, eh_queueentry); + ss->ss_queuesize--; + + eventhandle_drop(eh); +} + +static void +session_enqueue(struct fneventhandle *eh) { - struct fn_session *ss; + struct fnsession *ss; + + ss = eh->eh_watch->wt_session; - ss = eh->watch->session; - mtx_lock(&ss->queue_mtx); - TAILQ_INSERT_TAIL(&ss->queue, eh, sessionqueue_entry); - ss->queue_size++; - mtx_unlock(&ss->queue_mtx); - cv_broadcast(&ss->queue_ready_cv); - selwakeup(&ss->queue_poll); + if (ss == NULL) + return; + mtx_lock(&ss->ss_mtx); + if (eh->eh_watch->wt_session != NULL) { + mtx_unlock(&ss->ss_mtx); + eventhandle_drop(eh); + return; + } + TAILQ_INSERT_TAIL(&ss->ss_queue, eh, eh_queueentry); + ss->ss_queuesize++; + mtx_unlock(&ss->ss_mtx); + cv_broadcast(&ss->ss_queuecv); + selwakeup(&ss->ss_queuepoll); } static void process_queue(void *context, int pending) { - struct fn_node *node; - struct fn_watch *watch; - struct fn_event *event; - struct fn_eventhandle *eh; + struct fnnode *node; + struct fnwatch *watch; + struct fnevent *event; + struct fneventhandle *eh; int i, handle_count; while (1) { mtx_lock(&fsnotify_queue_mtx); - if (!TAILQ_EMPTY(&fsnotify_queue)) + if (TAILQ_EMPTY(&fsnotify_queue)) { + mtx_unlock(&fsnotify_queue_mtx); break; + } event = TAILQ_FIRST(&fsnotify_queue); - TAILQ_REMOVE(&fsnotify_queue, event, queue_entry); + TAILQ_REMOVE(&fsnotify_queue, event, ev_queueentry); mtx_unlock(&fsnotify_queue_mtx); - node = event->node; + node = event->ev_node; /* FIXME: lookup node full path */ - mtx_lock(&node->node_mtx); - TAILQ_FOREACH(watch, &node->watch_list, node_entry) { - if ((watch->mask & event->mask) == 0) + mtx_lock(&node->nd_mtx); + TAILQ_FOREACH(watch, &node->nd_watchlist, wt_nodeentry) { + if ((watch->wt_mask & event->ev_mask) == 0) continue; - if (event->handle_count >= event->handle_maxsize) { + if (event->ev_handlecount >= event->ev_handlemaxsize) { printf("fsnotify: event handle buffer is too small: %d\n", - event->handle_maxsize); + event->ev_handlemaxsize); break; } - eh = &event->handle_buf[event->handle_count++]; - eh->event = event; - eh->watch = watch; + eh = &event->ev_handlebuf[event->ev_handlecount++]; + eh->eh_event = event; + eh->eh_watch = watch; } - handle_count = event->handle_count; - mtx_unlock(&node->node_mtx); + handle_count = event->ev_handlecount; + mtx_unlock(&node->nd_mtx); MPASS(handle_count > 0); for (i = 0; i < handle_count; i++) { - session_enqueue(&event->handle_buf[i]); + session_enqueue(&event->ev_handlebuf[i]); } } } static void -enqueue_direvent(struct fn_node *pn, struct componentname *cnp, int mask) +enqueue_direvent(struct fnnode *dirnode, struct componentname *cnp, int mask) { - struct fn_event *event; - int error; + struct fnevent *event; + int supermask, watch_count; printf("enqueue_direvent: %s %x\n", cnp->cn_nameptr, mask); - if ((pn->supermask & mask) == 0) { - node_drop(pn); + mtx_assert(&dirnode->nd_mtx, MA_OWNED); + watch_count = dirnode->nd_watchcount; + supermask = dirnode->nd_supermask & mask; + node_hold(dirnode); + mtx_unlock(&dirnode->nd_mtx); + + if (supermask == 0) { + node_drop(dirnode); return; } - event = event_alloc(pn, pn->watch_count + 1, mask, event_nextcookie()); - error = event_prependpath(event, cnp->cn_nameptr, cnp->cn_namelen, 0); - if (error != 0) { - node_drop(pn); - free(event, M_FSNOTIFY); - return; - } + KASSERT(watch_count > 0, ("No watchers found")); + + event = event_alloc(dirnode, cnp->cn_nameptr, cnp->cn_namelen, + watch_count + 1, mask, event_nextcookie()); + + mtx_lock(&fsnotify_queue_mtx); + TAILQ_INSERT_TAIL(&fsnotify_queue, event, ev_queueentry); + mtx_unlock(&fsnotify_queue_mtx); taskqueue_enqueue(fsnotify_tq, &fsnotify_task); } static void -enqueue_fileevent(struct fn_node *pn, int mask) +enqueue_fileevent(struct fnnode *node, int mask) { printf("enqueue_fileevent: %x\n", mask); } ==== //depot/projects/soc2010/ilya_fsnotify/src/sys/sys/fsnotify.h#2 (text+ko) ==== @@ -30,14 +30,6 @@ #ifndef _SYS_FSNOTIFY_H_ #define _SYS_FSNOTIFY_H_ -struct fsnotify_event { - int32_t wd; - uint32_t mask; - uint32_t cookie; - uint32_t len; - char name[0]; -}; - #define FE_CREATE 0x0001 #define FE_REMOVE 0x0002 #define FE_RENAME_FROM 0x0004 @@ -49,9 +41,23 @@ #define FE_DESTROY 0x0080 -#define FSNOTIFY_ADDWATCH _IOW('F', 1, int) +#define FSNOTIFY_ADDWATCH _IOWR('F', 1, struct fsnotify_addwatch_args) #define FSNOTIFY_RMWATCH _IOW('F', 2, int) +struct fsnotify_event { + int32_t wd; + uint32_t mask; + uint32_t cookie; + uint32_t len; + char name[0]; +}; + +struct fsnotify_addwatch_args { + int fd; + int32_t wd; + uint32_t mask; +}; + #ifdef _KERNEL extern vop_create_t *fsnotify_hook_create;