PERFORCE change 179260 for review
Ilya Putsikau
ilya at FreeBSD.org
Sun Jun 6 17:12:31 UTC 2010
http://p4web.freebsd.org/@@179260?ac=10
Change 179260 by ilya at 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 <sys/condvar.h>
#include <sys/fcntl.h>
#include <sys/filio.h>
+#include <sys/hash.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
@@ -44,70 +45,86 @@
#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/queue.h>
+#include <sys/refcount.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <sys/vnode.h>
#include <sys/fsnotify.h>
-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;
More information about the p4-projects
mailing list