PERFORCE change 179568 for review
Ilya Putsikau
ilya at FreeBSD.org
Sun Jun 13 10:58:02 UTC 2010
http://p4web.freebsd.org/@@179568?ac=10
Change 179568 by ilya at ilya_triton on 2010/06/13 10:57:15
- Update node path while processing event, first perform direct lookup for cached path and if it fails try to get full path
- Add rename hook
- Perform full path lookup for fd in addwatch
- Replace full path hash table with inode number hash table.
- Improve path handling in both fnnode and fnevent.
- Remove reference counting from fnwatch, there can be max 2 references
Affected files ...
.. //depot/projects/soc2010/ilya_fsnotify/src/sys/kern/vfs_notify.c#3 edit
.. //depot/projects/soc2010/ilya_fsnotify/src/sys/sys/fsnotify.h#3 edit
Differences ...
==== //depot/projects/soc2010/ilya_fsnotify/src/sys/kern/vfs_notify.c#3 (text+ko) ====
@@ -34,12 +34,15 @@
#include <sys/conf.h>
#include <sys/condvar.h>
#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
#include <sys/filio.h>
#include <sys/hash.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/mount.h>
#include <sys/mutex.h>
#include <sys/namei.h>
#include <sys/poll.h>
@@ -69,12 +72,14 @@
TAILQ_HEAD(, fnwatch) nd_watchlist;
struct mtx nd_mtx;
struct vnode *nd_vnode;
+ struct mount *nd_mount;
char *nd_path;
+ char *nd_pathfree;
+ ino_t nd_ino;
+ volatile u_int nd_refcnt;
int nd_pathlen;
- uint32_t nd_pathhash;
int nd_watchcount;
u_int nd_supermask;
- volatile u_int nd_refcnt;
};
struct fneventhandle {
@@ -86,8 +91,8 @@
struct fnevent {
TAILQ_ENTRY(fnevent) ev_queueentry;
struct fnnode *ev_node;
- char *ev_path;
- int ev_pathlen;
+ char *ev_pathfree;
+ int ev_pathpos;
int ev_mask;
int ev_cookie;
int ev_handlecount;
@@ -102,7 +107,6 @@
struct fnsession *wt_session;
int wt_mask;
int wt_wd;
- volatile u_int wt_refcnt;
};
@@ -110,7 +114,6 @@
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;
@@ -121,7 +124,7 @@
static struct taskqueue *fsnotify_tq;
static struct fnnode_hashhead **fnnode_vphashtbl;
-static struct fnnode_hashhead **fnnode_pathhashtbl;
+static struct fnnode_hashhead **fnnode_inohashtbl;
static struct mtx fnnode_hashmtx;
static u_long fnnode_hashmask;
@@ -149,16 +152,20 @@
static void process_queue(void *context, int pending);
static void enqueue_direvent(struct fnnode *dirnode, struct componentname *cnp,
- int mask);
-static void enqueue_fileevent(struct fnnode *dirnode, int mask);
+ int cookie, int mask);
+static void enqueue_fileevent(struct fnnode *dirnode, int cookie, 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 struct fnnode* node_lookupex(struct vnode *vp, ino_t *inop,
+ int vplocked);
+static struct fnnode* node_alloc(struct vnode *vp, ino_t ino);
static void node_destroy(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);
static int
fsnotify_modevent(struct module *module, int cmd, void *arg)
@@ -185,7 +192,7 @@
hashsize = MAX(desiredvnodes / 32, 16);
fnnode_vphashtbl = hashinit(hashsize, M_FSNOTIFYHASH,
&fnnode_hashmask);
- fnnode_pathhashtbl = hashinit(hashsize, M_FSNOTIFYHASH,
+ fnnode_inohashtbl = hashinit(hashsize, M_FSNOTIFYHASH,
&fnnode_hashmask);
TASK_INIT(&fsnotify_task, 0, process_queue, NULL);
@@ -218,7 +225,7 @@
taskqueue_drain(fsnotify_tq, &fsnotify_task);
taskqueue_free(fsnotify_tq);
free(fnnode_vphashtbl, M_FSNOTIFYHASH);
- free(fnnode_pathhashtbl, M_FSNOTIFYHASH);
+ free(fnnode_inohashtbl, M_FSNOTIFYHASH);
mtx_destroy(&fsnotify_queue_mtx);
mtx_destroy(&fnnode_hashmtx);
break;
@@ -281,11 +288,13 @@
static int
fsnotify_read(struct cdev *dev, struct uio *uio, int flag)
{
- struct fsnotify_event *ue;
+ struct fnevent *event;
+ struct fneventhandle *eh;
struct fnsession *ss;
- struct fneventhandle *eh;
+ struct fnwatch *watch;
+ struct fsnotify_event *fe;
int len, error;
- char user_buf[sizeof(struct fsnotify_event) + PATH_MAX];
+ char user_buf[sizeof(struct fsnotify_event) + MAXPATHLEN];
if (uio->uio_resid == 0)
return (0);
@@ -312,13 +321,16 @@
}
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);
+ event = eh->eh_event;
+ watch = eh->eh_watch;
+ fe = (struct fsnotify_event *) user_buf;
+ fe->fe_wd = watch->wt_wd;
+ fe->fe_mask = watch->wt_mask & event->ev_mask;
+ fe->fe_fileno = event->ev_node->nd_ino;
+ fe->fe_cookie = event->ev_cookie;
+ event_copypath(event, fe->fe_name, &fe->fe_namelen);
+ fe->fe_namelen += 1;
+ len = fe->fe_namelen + sizeof(struct fsnotify_event);
mtx_unlock(&ss->ss_mtx);
@@ -341,9 +353,16 @@
{
struct fnsession *ss;
struct fnnode *node;
+ struct fnnode *freenode;
+ struct fnevent *event;
struct fnwatch *watch;
struct fsnotify_addwatch_args *add_args;
+ struct file *fp;
+ struct filedesc *fdp;
struct vnode *vp;
+ ino_t ino;
+ char *path, *pathfree;
+ int vfslocked;
int error;
error = devfs_get_cdevpriv((void **)&ss);
@@ -353,34 +372,57 @@
switch (cmd) {
case FSNOTIFY_ADDWATCH:
add_args = (struct fsnotify_addwatch_args *)data;
- /* TODO: get vnode for fd */
+ fdp = td->td_proc->p_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);
+ FILEDESC_SLOCK(fdp);
+ fp = fget_locked(fdp, add_args->fa_fd);
+ if (fp != NULL && fp->f_type == DTYPE_VNODE) {
+ vp = fp->f_vnode;
+ }
+ FILEDESC_SUNLOCK(fdp);
+ if (vp == NULL)
+ return (EBADF);
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ node = node_lookupex(vp, &ino, 0);
+ if (node != NULL) {
+ VFS_UNLOCK_GIANT(vfslocked);
+ freenode = NULL;
+ } else {
+ error = vn_fullpath(td, vp, &path, &pathfree);
+ VFS_UNLOCK_GIANT(vfslocked);
+ if (error != 0)
+ return (error);
+ node = node_alloc(vp, ino);
+ 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) {
+ add_args->fa_wd = watch->wt_wd;
+ } else if (freenode != NULL) {
+ node_destroy(node);
}
- error = session_addwatch(ss, node, add_args->mask, &watch);
- if (error == 0)
- add_args->wd = watch->wt_wd;
- return (error);
+ break;
case FSNOTIFY_RMWATCH:
error = session_rmwatch(ss, *(int *)data);
- return (error);
+ break;
case FIONREAD:
mtx_lock(&ss->ss_mtx);
- if (!TAILQ_EMPTY(&ss->ss_queue))
+ if (!TAILQ_EMPTY(&ss->ss_queue)) {
+ event = TAILQ_FIRST(&ss->ss_queue)->eh_event;
*(int *)data = sizeof(struct fsnotify_event) +
- TAILQ_FIRST(&ss->ss_queue)->eh_event->ev_pathlen + 1;
- else
+ event_pathlen(event) + 1;
+ } else
*(int *)data = 0;
mtx_unlock(&ss->ss_mtx);
- return (0);
+ break;
default:
- return (ENOIOCTL);
+ error = ENOENT;
}
+
+ return (error);
}
static int
@@ -419,7 +461,7 @@
dirnode = node_lookup(dvp);
if (dirnode != NULL)
- enqueue_direvent(NULL, cnp, FE_CREATE);
+ enqueue_direvent(dirnode, cnp, event_nextcookie(), FE_CREATE);
return (0);
}
@@ -427,20 +469,18 @@
hook_generic_remove(struct vnode *dvp, struct vnode *vp,
struct componentname *cnp)
{
- struct fnnode *dirnode, *n;
+ struct fnnode *dirnode, *node;
+ int cookie;
+
+ cookie = event_nextcookie();
- n = node_lookup(vp);
- if (n != NULL) {
- /* TODO */
- /*
- node_remove(n);
- */
- enqueue_fileevent(NULL, FE_DESTROY);
- }
+ node = node_lookup(vp);
+ if (node != NULL)
+ enqueue_fileevent(node, cookie, FE_DESTROY | FE_REMOVE);
dirnode = node_lookup(dvp);
if (dirnode != NULL)
- enqueue_direvent(NULL, cnp, FE_REMOVE);
+ enqueue_direvent(dirnode, cnp, cookie, FE_REMOVE);
}
static int
@@ -488,21 +528,38 @@
static int
hook_rename(struct vop_rename_args *ap)
{
+ struct fnnode *fdirnode, *fnode, *tdirnode, *tnode;
+ int cookie;
+
+ cookie = event_nextcookie();
+ if (ap->a_tvp != NULL) {
+ tnode = node_lookup(ap->a_tvp);
+ if (tnode != NULL) {
+ enqueue_fileevent(tnode, cookie,
+ FE_DESTROY | FE_REMOVE);
+ }
+ }
+ fnode = node_lookupex(ap->a_fvp, NULL, 0);
+ if (fnode != NULL) {
+ /* TODO */
+ /* mark path stale */
+ }
+
+ 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);
+ if (tdirnode != NULL)
+ enqueue_direvent(tdirnode, ap->a_tcnp, cookie, FE_RENAME_TO);
+
return (0);
}
-static __inline void
-watch_hold(struct fnwatch *watch)
-{
- refcount_acquire(&watch->wt_refcnt);
-}
-
static void
-watch_drop(struct fnwatch *watch)
+watch_tryfree(struct fnwatch *watch)
{
- if (refcount_release(&watch->wt_refcnt) != 0) {
+ if (watch->wt_session == NULL && watch->wt_node == NULL)
free(watch, M_FSNOTIFY);
- }
}
static int
@@ -522,24 +579,6 @@
return (nwd);
}
-static struct fnnode*
-node_alloc(char *path, int pathlen)
-{
- 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_hold(struct fnnode *node)
{
@@ -553,7 +592,7 @@
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->nd_path, M_TEMP);
free(node, M_FSNOTIFY);
}
}
@@ -564,47 +603,65 @@
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_pathhashhead(char *path, int pathlen)
+node_inohashhead(struct mount *mnt, ino_t ino)
{
uint32_t h;
- h = hash32_buf(path, pathlen, HASHINIT);
- return fnnode_vphashtbl[h & fnnode_hashmask];
+ h = ino + mnt->mnt_hashseed;
+ return fnnode_inohashtbl[h & fnnode_hashmask];
}
-static void
-node_create(struct fnnode *node, struct vnode *vp)
+static struct fnnode *
+node_alloc(struct vnode *vp, ino_t ino)
{
- struct fnnode *ni;
+ struct fnnode *node;
MPASS(vp != NULL);
+
+ node = malloc(sizeof(struct fnnode), M_FSNOTIFY, M_WAITOK | M_ZERO);
+
+ refcount_init(&node->nd_refcnt, 1);
+
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_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);
+
+ return (node);
}
static void
-node_destroy(struct fnnode *node)
+node_detachwatches(struct fnnode *node)
{
struct fnwatch *watch;
- mtx_lock(&node->nd_mtx);
+ mtx_assert(&node->nd_mtx, MA_OWNED);
+ node->nd_watchcount = 0;
+ node->nd_supermask = 0;
while (!TAILQ_EMPTY(&node->nd_watchlist)) {
watch = TAILQ_FIRST(&node->nd_watchlist);
TAILQ_REMOVE(&node->nd_watchlist, watch, wt_nodeentry);
- watch_drop(watch);
+ watch->wt_node = NULL;
+ watch_tryfree(watch);
}
+}
+
+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);
@@ -612,16 +669,36 @@
node_drop(node);
}
+static int
+node_getino(struct vnode *vp, ino_t *inop, int vplocked)
+{
+ struct vattr va;
+ int error;
+
+ if (vplocked == 0) {
+ error = vn_lock(vp, LK_SHARED);
+ if (error != 0)
+ return (error);
+ }
+
+ error = VOP_GETATTR(vp, &va, thread0.td_ucred);
+ if (error == 0)
+ *inop = va.va_fileid;
+
+ if (vplocked == 0)
+ VOP_UNLOCK(vp, 0);
+
+ return (error);
+}
+
static struct fnnode*
-node_lookup(struct vnode *vp)
+node_lookupex(struct vnode *vp, ino_t *inop, int vplocked)
{
struct fnnode *node, *rv;
- int pathhash, pathlen;
- char *path;
+ ino_t ino;
+ int error;
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) {
@@ -636,15 +713,19 @@
mtx_unlock(&fnnode_hashmtx);
if (node == NULL) {
- /* TODO: lookup full path */
+ if (inop == NULL)
+ inop = &ino;
+ error = node_getino(vp, inop, vplocked);
+ if (error != 0)
+ goto done;
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)
+ 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 vphash */
+ /* add to inohash */
mtx_lock(&node->nd_mtx);
rv = (node->nd_watchcount == 0 ? NULL : node);
if (rv == NULL)
@@ -654,22 +735,89 @@
mtx_unlock(&fnnode_hashmtx);
}
- if (path != NULL)
- free(path, M_FSNOTIFY);
+done:
+ return (rv);
+}
+
+static __inline struct fnnode*
+node_lookup(struct vnode *vp)
+{
+ ASSERT_VOP_LOCKED(vp, "fsnotify node lookup");
+
+ return (node_lookupex(vp, NULL, 1));
+}
+
+static int
+node_updatepath(struct fnnode *node)
+{
+ struct nameidata ni;
+ struct vnode *vp;
+ char *path, *pathfree;
+ char *npath, *npathfree;
+ int vfslocked, error;
+
+ /*
+ * TODO: has races. should be executed only in *single* process_queue
+ * thread
+ */
+ vp = node->nd_vnode;
+ if ((vp->v_iflag & VI_DOOMED) != 0)
+ return (ENOENT);
+
+ path = node->nd_path;
+ pathfree = node->nd_pathfree;
+ npath = npathfree = NULL;
+ vhold(vp);
+ mtx_unlock(&node->nd_mtx);
+
+ NDINIT(&ni, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE, path, curthread);
+ error = namei(&ni);
+ vfslocked = NDHASGIANT(&ni);
+ if (error == 0) {
+ if (vp != ni.ni_vp) {
+ printf("fsnotify: vnode was replaced between lookups: %s\n",
+ path);
+ error = ENOENT;
+ }
+ NDFREE(&ni, 0);
+ }
+ if (error != 0) {
+ error = vn_fullpath(curthread, vp, &npath, &npathfree);
+ }
- return (rv);
+ VFS_UNLOCK_GIANT(vfslocked);
+ if ((vp->v_iflag & VI_DOOMED) != 0) {
+ printf("fsnotify: vnode is doomed: %s\n", path);
+ error = ENOENT;
+ }
+ vdrop(vp);
+ mtx_lock(&node->nd_mtx);
+ if (path != node->nd_path) {
+ /* Lookup race */
+ free(pathfree, M_TEMP);
+ MPASS(node->nd_path != NULL);
+ error = 0;
+ } else if (error == 0 && npath != NULL) {
+ free(node->nd_pathfree, M_TEMP);
+ node->nd_path = npath;
+ node->nd_pathlen = strlen(npath);
+ node->nd_pathfree = npathfree;
+ npathfree = NULL;
+ }
+ if (npathfree != NULL)
+ free(npathfree, M_TEMP);
+ return (error);
}
static struct fnevent *
-event_alloc(struct fnnode *node, char *path, int pathlen, int handle_maxsize,
+event_alloc(struct fnnode *node, char *name, int namelen, int handle_maxsize,
int mask, int cookie)
{
struct fnevent *event;
- int addslash;
MPASS(handle_maxsize > 0);
MPASS(mask != 0);
- MPASS(pathlen > 0);
+ MPASS(namelen > 0);
event = malloc(sizeof(struct fnevent) +
(sizeof(struct fneventhandle) * handle_maxsize),
@@ -678,42 +826,78 @@
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';
+ event->ev_pathfree = uma_zalloc(namei_zone, M_WAITOK);
+ event->ev_pathpos = MAXPATHLEN - 1 - namelen;
+ memcpy(event->ev_pathfree + event->ev_pathpos, name, namelen);
+ event->ev_pathfree[MAXPATHLEN - 1] = '\0';
return (event);
}
-static int
-event_nextcookie(void)
+static void
+event_free(struct fnevent *event)
+{
+ node_drop(event->ev_node);
+ uma_zfree(namei_zone, event->ev_pathfree);
+ free(event, M_FSNOTIFY);
+}
+
+static __inline int
+event_pathlen(struct fnevent *event)
{
- static volatile int cookie = 1;
+ return (MAXPATHLEN - 1 - event->ev_pathpos);
+}
- return atomic_fetchadd_int(&cookie, 1);
+static __inline void
+event_copypath(struct fnevent *event, char *path, int *pathlen)
+{
+ *pathlen = event_pathlen(event);
+ memcpy(path, event->ev_pathfree + *pathlen, *pathlen);
}
static void
eventhandle_drop(struct fneventhandle *eh)
{
struct fnnode *node;
+ int handlecount;
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);
- }
+ handlecount = --eh->eh_event->ev_handlecount;
mtx_unlock(&node->nd_mtx);
+ MPASS(handlecount >= 0);
+ if (handlecount == 0)
+ event_free(eh->eh_event);
+}
+
+static void
+event_prependpath(struct fnevent *event, struct fnnode *node)
+{
+ int pos, len;
+
+ pos = event->ev_pathpos;
+ len = node->nd_pathlen;
+ MPASS(len > 0 && node->nd_path[len - 1] != '/');
+ MPASS(MAXPATHLEN - pos < len + 1);
+
+ event->ev_pathfree[--pos] = '/';
+ pos -= len;
+ memcpy(event->ev_pathfree + pos, node->nd_path, len);
+
+ event->ev_pathpos = pos;
+}
+
+static int
+event_nextcookie(void)
+{
+ static volatile int cookie = 1;
+ int r;
+
+ r = atomic_fetchadd_int(&cookie, 1);
+ if (r == 0)
+ r = atomic_fetchadd_int(&cookie, 1);
+ return (r);
}
static int
@@ -724,8 +908,6 @@
watch = malloc(sizeof(struct fnwatch), M_FSNOTIFY, M_WAITOK | M_ZERO);
- refcount_init(&watch->wt_refcnt, 2);
-
watch->wt_wd = watch_nextwd();
watch->wt_mask = mask;
watch->wt_session = ss;
@@ -738,6 +920,8 @@
mtx_lock(&node->nd_mtx);
TAILQ_INSERT_TAIL(&node->nd_watchlist, watch, wt_nodeentry);
+ node->nd_watchcount++;
+ node->nd_supermask |= watch->wt_mask;
mtx_unlock(&node->nd_mtx);
if (watchpp != NULL)
@@ -756,8 +940,8 @@
if (watch->wt_wd != wd)
continue;
TAILQ_REMOVE(&ss->ss_watchlist, watch, wt_sessionentry);
- watch_drop(watch);
watch->wt_session = NULL;
+ watch_tryfree(watch);
break;
}
mtx_unlock(&ss->ss_mtx);
@@ -805,6 +989,7 @@
struct fnwatch *watch;
struct fnevent *event;
struct fneventhandle *eh;
+ struct vnode *vp;
int i, handle_count;
while (1) {
@@ -819,8 +1004,6 @@
node = event->ev_node;
- /* FIXME: lookup node full path */
-
mtx_lock(&node->nd_mtx);
TAILQ_FOREACH(watch, &node->nd_watchlist, wt_nodeentry) {
if ((watch->wt_mask & event->ev_mask) == 0)
@@ -835,17 +1018,31 @@
eh->eh_watch = watch;
}
handle_count = event->ev_handlecount;
+ if (handle_count == 0) {
+ node->nd_supermask &= ~event->ev_mask;
+ mtx_unlock(&node->nd_mtx);
+ event_free(event);
+ continue;
+ }
+ vp = node->nd_vnode;
+ if (vp != NULL)
+ node_updatepath(node);
+ else
+ printf("fsnotify: vnode not found, reusing cached path: %s\n",
+ node->nd_path);
+ if (event->ev_mask & FE_DESTROY)
+ node_detachwatches(node);
+
+ event_prependpath(event, node);
mtx_unlock(&node->nd_mtx);
- MPASS(handle_count > 0);
- for (i = 0; i < handle_count; i++) {
+ for (i = 0; i < handle_count; i++)
session_enqueue(&event->ev_handlebuf[i]);
- }
}
}
static void
-enqueue_direvent(struct fnnode *dirnode, struct componentname *cnp, int mask)
+enqueue_direvent(struct fnnode *dirnode, struct componentname *cnp, int cookie, int mask)
{
struct fnevent *event;
int supermask, watch_count;
@@ -866,7 +1063,7 @@
KASSERT(watch_count > 0, ("No watchers found"));
event = event_alloc(dirnode, cnp->cn_nameptr, cnp->cn_namelen,
- watch_count + 1, mask, event_nextcookie());
+ watch_count + 1, mask, cookie);
mtx_lock(&fsnotify_queue_mtx);
TAILQ_INSERT_TAIL(&fsnotify_queue, event, ev_queueentry);
@@ -876,7 +1073,7 @@
}
static void
-enqueue_fileevent(struct fnnode *node, int mask)
+enqueue_fileevent(struct fnnode *node, int cookie, int mask)
{
printf("enqueue_fileevent: %x\n", mask);
}
==== //depot/projects/soc2010/ilya_fsnotify/src/sys/sys/fsnotify.h#3 (text+ko) ====
@@ -45,17 +45,18 @@
#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];
+ int32_t fe_wd;
+ uint32_t fe_mask;
+ uint32_t fe_cookie;
+ uint32_t fe_namelen;
+ ino_t fe_fileno;
+ char fe_name[0];
};
struct fsnotify_addwatch_args {
- int fd;
- int32_t wd;
- uint32_t mask;
+ int fa_fd;
+ uint32_t fa_mask;
+ int32_t fa_wd;
};
#ifdef _KERNEL
More information about the p4-projects
mailing list