fanotify: should_send_event needs to handle vfsmounts
authorEric Paris <eparis@redhat.com>
Fri, 18 Dec 2009 02:24:28 +0000 (21:24 -0500)
committerEric Paris <eparis@redhat.com>
Wed, 28 Jul 2010 13:58:57 +0000 (09:58 -0400)
currently should_send_event in fanotify only cares about marks on inodes.
This patch extends that interface to indicate that it cares about events
that happened on vfsmounts.

Signed-off-by: Eric Paris <eparis@redhat.com>
fs/notify/fanotify/fanotify.c
include/linux/fsnotify_backend.h

index aa5e92661142f6e21b1cb2be6695c7683a732853..202be8adb2ec6e3f6f5950e4c57b4ac32382e55f 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/fsnotify_backend.h>
 #include <linux/init.h>
 #include <linux/kernel.h> /* UINT_MAX */
+#include <linux/mount.h>
 #include <linux/types.h>
 
 #include "fanotify.h"
@@ -99,24 +100,35 @@ static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_e
        return ret;
 }
 
-static bool fanotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
-                                      struct vfsmount *mnt, __u32 mask, void *data,
-                                      int data_type)
+static bool should_send_vfsmount_event(struct fsnotify_group *group, struct vfsmount *mnt,
+                                      __u32 mask)
 {
        struct fsnotify_mark *fsn_mark;
        bool send;
 
-       pr_debug("%s: group=%p inode=%p mask=%x data=%p data_type=%d\n",
-                __func__, group, inode, mask, data, data_type);
+       pr_debug("%s: group=%p vfsmount=%p mask=%x\n",
+                __func__, group, mnt, mask);
 
-       /* sorry, fanotify only gives a damn about files and dirs */
-       if (!S_ISREG(inode->i_mode) &&
-           !S_ISDIR(inode->i_mode))
+       fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
+       if (!fsn_mark)
                return false;
 
-       /* if we don't have enough info to send an event to userspace say no */
-       if (data_type != FSNOTIFY_EVENT_PATH)
-               return false;
+       send = (mask & fsn_mark->mask);
+
+       /* find took a reference */
+       fsnotify_put_mark(fsn_mark);
+
+       return send;
+}
+
+static bool should_send_inode_event(struct fsnotify_group *group, struct inode *inode,
+                                   __u32 mask)
+{
+       struct fsnotify_mark *fsn_mark;
+       bool send;
+
+       pr_debug("%s: group=%p inode=%p mask=%x\n",
+                __func__, group, inode, mask);
 
        fsn_mark = fsnotify_find_inode_mark(group, inode);
        if (!fsn_mark)
@@ -142,6 +154,28 @@ static bool fanotify_should_send_event(struct fsnotify_group *group, struct inod
        return send;
 }
 
+static bool fanotify_should_send_event(struct fsnotify_group *group, struct inode *to_tell,
+                                      struct vfsmount *mnt, __u32 mask, void *data,
+                                      int data_type)
+{
+       pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x data=%p data_type=%d\n",
+                __func__, group, to_tell, mnt, mask, data, data_type);
+
+       /* sorry, fanotify only gives a damn about files and dirs */
+       if (!S_ISREG(to_tell->i_mode) &&
+           !S_ISDIR(to_tell->i_mode))
+               return false;
+
+       /* if we don't have enough info to send an event to userspace say no */
+       if (data_type != FSNOTIFY_EVENT_PATH)
+               return false;
+
+       if (mnt)
+               return should_send_vfsmount_event(group, mnt, mask);
+       else
+               return should_send_inode_event(group, to_tell, mask);
+}
+
 const struct fsnotify_ops fanotify_fsnotify_ops = {
        .handle_event = fanotify_handle_event,
        .should_send_event = fanotify_should_send_event,
index 1af42cbfc4294edda82e3f785a17b7dc3c776c71..2d2f015fb7002270c5fb85fc871491e28501ff27 100644 (file)
@@ -368,6 +368,8 @@ extern void fsnotify_recalc_inode_mask(struct inode *inode);
 extern void fsnotify_init_mark(struct fsnotify_mark *mark, void (*free_mark)(struct fsnotify_mark *mark));
 /* find (and take a reference) to a mark associated with group and inode */
 extern struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, struct inode *inode);
+/* find (and take a reference) to a mark associated with group and vfsmount */
+extern struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, struct vfsmount *mnt);
 /* copy the values from old into new */
 extern void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old);
 /* attach the mark to both the group and the inode */