fsnotify: include vfsmount in should_send_event when appropriate
authorEric Paris <eparis@redhat.com>
Fri, 18 Dec 2009 02:24:23 +0000 (21:24 -0500)
committerEric Paris <eparis@redhat.com>
Wed, 28 Jul 2010 13:58:52 +0000 (09:58 -0400)
To ensure that a group will not duplicate events when it receives it based
on the vfsmount and the inode should_send_event test we should distinguish
those two cases.  We pass a vfsmount to this function so groups can make
their own determinations.

Signed-off-by: Eric Paris <eparis@redhat.com>
fs/notify/dnotify/dnotify.c
fs/notify/fsnotify.c
fs/notify/inotify/inotify_fsnotify.c
include/linux/fsnotify_backend.h
kernel/audit_tree.c
kernel/audit_watch.c

index e0a847bd53bea7cbeb5111a2b812bbe612573184..9eddafa4c7ba878c05f7cd42d6bd769d3b81bf0f 100644 (file)
@@ -133,8 +133,8 @@ static int dnotify_handle_event(struct fsnotify_group *group,
  * userspace notification for that pair.
  */
 static bool dnotify_should_send_event(struct fsnotify_group *group,
-                                     struct inode *inode, __u32 mask,
-                                     void *data, int data_type)
+                                     struct inode *inode, struct vfsmount *mnt,
+                                     __u32 mask, void *data, int data_type)
 {
        struct fsnotify_mark_entry *entry;
        bool send;
index a61aaa71082566818dabd7d2d25fc9a53120ad23..78c440c343a8a3738425e86c67d4c7079cfe325f 100644 (file)
@@ -135,13 +135,12 @@ void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
 }
 EXPORT_SYMBOL_GPL(__fsnotify_parent);
 
-static void send_to_group(__u32 mask,
-                         struct fsnotify_group *group,
-                         void *data, int data_is, const char *file_name,
-                         u32 cookie, struct fsnotify_event **event,
-                         struct inode *to_tell)
+static void send_to_group(struct fsnotify_group *group, struct inode *to_tell,
+                         struct vfsmount *mnt, __u32 mask, void *data,
+                         int data_is, u32 cookie, const char *file_name,
+                         struct fsnotify_event **event)
 {
-       if (!group->ops->should_send_event(group, to_tell, mask,
+       if (!group->ops->should_send_event(group, to_tell, mnt, mask,
                                           data, data_is))
                return;
        if (!*event) {
@@ -159,15 +158,9 @@ static void send_to_group(__u32 mask,
        group->ops->handle_event(group, *event);
 }
 
-static bool needed_by_vfsmount(__u32 test_mask, void *data, int data_is)
+static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt)
 {
-       struct path *path;
-
-       if (data_is == FSNOTIFY_EVENT_PATH)
-               path = (struct path *)data;
-       else if (data_is == FSNOTIFY_EVENT_FILE)
-               path = &((struct file *)data)->f_path;
-       else
+       if (!mnt)
                return false;
 
        /* hook in this when mnt->mnt_fsnotify_mask is defined */
@@ -184,6 +177,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
 {
        struct fsnotify_group *group;
        struct fsnotify_event *event = NULL;
+       struct vfsmount *mnt = NULL;
        int idx;
        /* global tests shouldn't care about events on child only the specific event */
        __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
@@ -198,10 +192,15 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
            !(test_mask & fsnotify_vfsmount_mask))
                 return;
  
+       if (data_is == FSNOTIFY_EVENT_PATH)
+               mnt = ((struct path *)data)->mnt;
+       else if (data_is == FSNOTIFY_EVENT_FILE)
+               mnt = ((struct file *)data)->f_path.mnt;
+
        /* if this inode's directed listeners don't care and nothing on the vfsmount
         * listeners list cares, nothing to do */
        if (!(test_mask & to_tell->i_fsnotify_mask) &&
-           !needed_by_vfsmount(test_mask, data, data_is))
+           !needed_by_vfsmount(test_mask, mnt))
                 return;
 
        /*
@@ -214,16 +213,16 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
        if (test_mask & to_tell->i_fsnotify_mask) {
                list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) {
                        if (test_mask & group->mask) {
-                               send_to_group(mask, group, data, data_is,
-                                             file_name, cookie, &event, to_tell);
+                               send_to_group(group, to_tell, NULL, mask, data, data_is,
+                                             cookie, file_name, &event);
                        }
                }
        }
-       if (needed_by_vfsmount(test_mask, data, data_is)) {
+       if (needed_by_vfsmount(test_mask, mnt)) {
                list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) {
                        if (test_mask & group->mask) {
-                               send_to_group(mask, group, data, data_is,
-                                             file_name, cookie, &event, to_tell);
+                               send_to_group(group, to_tell, mnt, mask, data, data_is,
+                                             cookie, file_name, &event);
                        }
                }
        }
index 0a0f5d0f0d0af6995c21973fd40be6c8191eba9b..8075ae708ed46e3ead63b8b4197bdc6a0c19a22a 100644 (file)
@@ -141,7 +141,8 @@ static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnot
 }
 
 static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
-                                     __u32 mask, void *data, int data_type)
+                                     struct vfsmount *mnt, __u32 mask, void *data,
+                                     int data_type)
 {
        struct fsnotify_mark_entry *entry;
        bool send;
index dea48bee057d1213eef82563d06ebae10de10b67..c2a04b7e4fcadf01b5b8d458949001f83c56f2dc 100644 (file)
@@ -79,7 +79,8 @@ struct fsnotify_event_private_data;
  */
 struct fsnotify_ops {
        bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode,
-                                 __u32 mask, void *data, int data_type);
+                                 struct vfsmount *mnt, __u32 mask, void *data,
+                                 int data_type);
        int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event);
        void (*free_group_priv)(struct fsnotify_group *group);
        void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group);
index 04f16887406bbe7bf9bc3fe5a2ee3261660a8300..ecf0bf260d0930e9c203e80527aaf6fa2692d4c0 100644 (file)
@@ -920,7 +920,8 @@ static void audit_tree_freeing_mark(struct fsnotify_mark_entry *entry, struct fs
 }
 
 static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode,
-                                 __u32 mask, void *data, int data_type)
+                                 struct vfsmount *mnt, __u32 mask, void *data,
+                                 int data_type)
 {
        return 0;
 }
index 83d5f9674ceca0eb612db20e9cfe9876269c1677..6304ee5d76427752b3ecedf48675fff6c7575561 100644 (file)
@@ -514,7 +514,8 @@ void audit_remove_watch_rule(struct audit_krule *krule)
 }
 
 static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode,
-                                         __u32 mask, void *data, int data_type)
+                                         struct vfsmount *mnt, __u32 mask, void *data,
+                                         int data_type)
 {
        struct fsnotify_mark_entry *entry;
        bool send;