[PATCH] - Loop through the whole buffer that we read() from Inotify. Previously, only the first inotify_event entry was used, and propagated as much time as there was entry in the buffer. Further entry in the buffer were ignored. This lead to bug where important event were not propagated.

Yoann Vandoorselaere yoann.v at prelude-ids.com
Wed Jan 27 15:37:19 CET 2010


- Do not call infy_wd() in case we're getting IN_IGNORED. This flags indicate
  that the Inotify WD was deleted, either explicitly (inotify_rm_watch), or
  automatically (unmount, deletion). In any of theses case, we already have
  handled the deletion event ourselve.

  Avoid an useless wd table scan.

- Rather than removing the watch, and adding it again on every notification,
  only do it when necessary. Handle rename and create explicitly. Avoid a lot
  of inotify_add_watch() and inotify_rm_watch call.

  This additionally fixes a race were the currently read inotify_event buffer
  in infy_cb() got others events that we didn't propagate yet, and the WD is
  changed from the stat_timer_cb() function. Other events would then never
  propagate since infy_wd() wouldn't find the corresponding WD.
---
 ev.c |   37 ++++++++++++++++++++++++-------------
 1 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/ev.c b/ev.c
index ccd202b..94b2264 100644
--- a/ev.c
+++ b/ev.c
@@ -2957,11 +2957,27 @@ infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev)
 
           if (w->wd == wd || wd == -1)
             {
-              if (ev->mask & (IN_IGNORED | IN_UNMOUNT | IN_DELETE_SELF))
+              if ( ev->mask & IN_CREATE )
+                {
+                  char *ptr = strrchr(w->path, '/');
+                  if ( ptr && strcmp(ptr + 1, ev->name) == 0 )
+                    {
+                      /* remove the existing directory watcher, and create a watcher for the file */
+                      infy_del(EV_A_ w);
+                      infy_add(EV_A_ w);
+                    }
+                }
+              else if (ev->mask & (IN_UNMOUNT | IN_DELETE_SELF))
                 {
                   wlist_del (&fs_hash [slot & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w);
                   w->wd = -1;
-                  infy_add (EV_A_ w); /* re-add, no matter what */
+                  infy_add(EV_A_ w);
+                }
+              else if (ev->mask & IN_MOVE_SELF )
+                {
+                  /* make sure we continue monitoring the old filename */
+                  infy_del(EV_A_ w);
+                  infy_add(EV_A_ w);
                 }
 
               stat_timer_cb (EV_A_ &w->timer, 0);
@@ -2974,12 +2990,16 @@ static void
 infy_cb (EV_P_ ev_io *w, int revents)
 {
   char buf [EV_INOTIFY_BUFSIZE];
-  struct inotify_event *ev = (struct inotify_event *)buf;
   int ofs;
+  struct inotify_event *ev;
   int len = read (fs_fd, buf, sizeof (buf));
 
   for (ofs = 0; ofs < len; ofs += sizeof (struct inotify_event) + ev->len)
-    infy_wd (EV_A_ ev->wd, ev->wd, ev);
+  {
+    ev = (struct inotify_event *) (buf + ofs);
+    if ( !(ev->mask & IN_IGNORED) )
+      infy_wd (EV_A_ ev->wd, ev->wd, ev);
+  }
 }
 
 inline_size void
@@ -3128,15 +3148,6 @@ stat_timer_cb (EV_P_ ev_timer *w_, int revents)
       /* to ensure that prev is always different to attr */
       w->prev = prev;
 
-      #if EV_USE_INOTIFY
-        if (fs_fd >= 0)
-          {
-            infy_del (EV_A_ w);
-            infy_add (EV_A_ w);
-            ev_stat_stat (EV_A_ w); /* avoid race... */
-          }
-      #endif
-
       ev_feed_event (EV_A_ w, EV_STAT);
     }
 }
-- 
1.6.6


--=-MmETNoSx1xs/9u35zU63--




More information about the libev mailing list