aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 21:24:23 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:58:52 -0400
commit3a9fb89f4cd04c23e16397befba92efb5d989b74 (patch)
treef60b48c8cf488ad8952601ccbc6192b5f86ec900
parent7131485a93679ff9a543b74df280cfd119eb03ca (diff)
fsnotify: include vfsmount in should_send_event when appropriate
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>
-rw-r--r--fs/notify/dnotify/dnotify.c4
-rw-r--r--fs/notify/fsnotify.c39
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c3
-rw-r--r--include/linux/fsnotify_backend.h3
-rw-r--r--kernel/audit_tree.c3
-rw-r--r--kernel/audit_watch.c3
6 files changed, 29 insertions, 26 deletions
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index e0a847bd53b..9eddafa4c7b 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -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;
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index a61aaa71082..78c440c343a 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -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);
}
}
}
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index 0a0f5d0f0d0..8075ae708ed 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -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;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index dea48bee057..c2a04b7e4fc 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -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);
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 04f16887406..ecf0bf260d0 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -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;
}
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 83d5f9674ce..6304ee5d764 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -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;