]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/notify/inotify/inotify_fsnotify.c
fsnotify: cleanup should_send_event
[net-next-2.6.git] / fs / notify / inotify / inotify_fsnotify.c
index 388a150c3d4a4fbda541b4667bc1af106b88b3a2..7cf518b25daacf64694977d5b785e4a8149965a8 100644 (file)
@@ -22,6 +22,7 @@
  * General Public License for more details.
  */
 
+#include <linux/dcache.h> /* d_unlinked */
 #include <linux/fs.h> /* struct inode */
 #include <linux/fsnotify_backend.h>
 #include <linux/inotify.h>
@@ -51,9 +52,9 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new
                            !strcmp(old->file_name, new->file_name))
                                return true;
                        break;
-               case (FSNOTIFY_EVENT_PATH):
-                       if ((old->path.mnt == new->path.mnt) &&
-                           (old->path.dentry == new->path.dentry))
+               case (FSNOTIFY_EVENT_FILE):
+                       if ((old->file->f_path.mnt == new->file->f_path.mnt) &&
+                           (old->file->f_path.dentry == new->file->f_path.dentry))
                                return true;
                        break;
                case (FSNOTIFY_EVENT_NONE):
@@ -67,13 +68,11 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new
        return false;
 }
 
-static int inotify_merge(struct list_head *list,
-                        struct fsnotify_event *event,
-                        void **arg)
+static struct fsnotify_event *inotify_merge(struct list_head *list,
+                                           struct fsnotify_event *event)
 {
        struct fsnotify_event_holder *last_holder;
        struct fsnotify_event *last_event;
-       int ret = 0;
 
        /* and the list better be locked by something too */
        spin_lock(&event->lock);
@@ -81,29 +80,32 @@ static int inotify_merge(struct list_head *list,
        last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
        last_event = last_holder->event;
        if (event_compare(last_event, event))
-               ret = -EEXIST;
+               fsnotify_get_event(last_event);
+       else
+               last_event = NULL;
 
        spin_unlock(&event->lock);
 
-       return ret;
+       return last_event;
 }
 
-static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
+static int inotify_handle_event(struct fsnotify_group *group,
+                               struct fsnotify_mark *mark,
+                               struct fsnotify_event *event)
 {
-       struct fsnotify_mark *fsn_mark;
        struct inotify_inode_mark *i_mark;
        struct inode *to_tell;
        struct inotify_event_private_data *event_priv;
        struct fsnotify_event_private_data *fsn_event_priv;
-       int wd, ret;
+       struct fsnotify_event *added_event;
+       int wd, ret = 0;
+
+       pr_debug("%s: group=%p event=%p to_tell=%p mask=%x\n", __func__, group,
+                event, event->to_tell, event->mask);
 
        to_tell = event->to_tell;
 
-       fsn_mark = fsnotify_find_inode_mark(group, to_tell);
-       /* race with watch removal?  We already passes should_send */
-       if (unlikely(!fsn_mark))
-               return 0;
-       i_mark = container_of(fsn_mark, struct inotify_inode_mark,
+       i_mark = container_of(mark, struct inotify_inode_mark,
                              fsn_mark);
        wd = i_mark->wd;
 
@@ -116,24 +118,17 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
        fsn_event_priv->group = group;
        event_priv->wd = wd;
 
-       ret = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge, NULL);
-       if (ret) {
+       added_event = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge);
+       if (added_event) {
                inotify_free_event_priv(fsn_event_priv);
-               /* EEXIST says we tail matched, EOVERFLOW isn't something
-                * to report up the stack. */
-               if ((ret == -EEXIST) ||
-                   (ret == -EOVERFLOW))
-                       ret = 0;
+               if (!IS_ERR(added_event))
+                       fsnotify_put_event(added_event);
+               else
+                       ret = PTR_ERR(added_event);
        }
 
-       if (fsn_mark->mask & IN_ONESHOT)
-               fsnotify_destroy_mark(fsn_mark);
-
-       /*
-        * If we hold the fsn_mark until after the event is on the queue
-        * IN_IGNORED won't be able to pass this event in the queue
-        */
-       fsnotify_put_mark(fsn_mark);
+       if (mark->mask & IN_ONESHOT)
+               fsnotify_destroy_mark(mark);
 
        return ret;
 }
@@ -144,23 +139,18 @@ static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify
 }
 
 static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
-                                     struct vfsmount *mnt, __u32 mask, void *data,
-                                     int data_type)
+                                     struct vfsmount *mnt, struct fsnotify_mark *mark,
+                                     __u32 mask, void *data, int data_type)
 {
-       struct fsnotify_mark *fsn_mark;
-       bool send;
-
-       fsn_mark = fsnotify_find_inode_mark(group, inode);
-       if (!fsn_mark)
-               return false;
+       if ((mark->mask & FS_EXCL_UNLINK) &&
+           (data_type == FSNOTIFY_EVENT_FILE)) {
+               struct file *file  = data;
 
-       mask = (mask & ~FS_EVENT_ON_CHILD);
-       send = (fsn_mark->mask & mask);
-
-       /* find took a reference */
-       fsnotify_put_mark(fsn_mark);
+               if (d_unlinked(file->f_path.dentry))
+                       return false;
+       }
 
-       return send;
+       return true;
 }
 
 /*