Commit 3a9fb89f authored by Eric Paris's avatar Eric Paris

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: default avatarEric Paris <eparis@redhat.com>
parent 7131485a
...@@ -133,8 +133,8 @@ static int dnotify_handle_event(struct fsnotify_group *group, ...@@ -133,8 +133,8 @@ static int dnotify_handle_event(struct fsnotify_group *group,
* userspace notification for that pair. * userspace notification for that pair.
*/ */
static bool dnotify_should_send_event(struct fsnotify_group *group, static bool dnotify_should_send_event(struct fsnotify_group *group,
struct inode *inode, __u32 mask, struct inode *inode, struct vfsmount *mnt,
void *data, int data_type) __u32 mask, void *data, int data_type)
{ {
struct fsnotify_mark_entry *entry; struct fsnotify_mark_entry *entry;
bool send; bool send;
......
...@@ -135,13 +135,12 @@ void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask) ...@@ -135,13 +135,12 @@ void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
} }
EXPORT_SYMBOL_GPL(__fsnotify_parent); EXPORT_SYMBOL_GPL(__fsnotify_parent);
static void send_to_group(__u32 mask, static void send_to_group(struct fsnotify_group *group, struct inode *to_tell,
struct fsnotify_group *group, struct vfsmount *mnt, __u32 mask, void *data,
void *data, int data_is, const char *file_name, int data_is, u32 cookie, const char *file_name,
u32 cookie, struct fsnotify_event **event, struct fsnotify_event **event)
struct inode *to_tell)
{ {
if (!group->ops->should_send_event(group, to_tell, mask, if (!group->ops->should_send_event(group, to_tell, mnt, mask,
data, data_is)) data, data_is))
return; return;
if (!*event) { if (!*event) {
...@@ -159,15 +158,9 @@ static void send_to_group(__u32 mask, ...@@ -159,15 +158,9 @@ static void send_to_group(__u32 mask,
group->ops->handle_event(group, *event); 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 (!mnt)
if (data_is == FSNOTIFY_EVENT_PATH)
path = (struct path *)data;
else if (data_is == FSNOTIFY_EVENT_FILE)
path = &((struct file *)data)->f_path;
else
return false; return false;
/* hook in this when mnt->mnt_fsnotify_mask is defined */ /* 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 ...@@ -184,6 +177,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
{ {
struct fsnotify_group *group; struct fsnotify_group *group;
struct fsnotify_event *event = NULL; struct fsnotify_event *event = NULL;
struct vfsmount *mnt = NULL;
int idx; int idx;
/* global tests shouldn't care about events on child only the specific event */ /* global tests shouldn't care about events on child only the specific event */
__u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); __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 ...@@ -198,10 +192,15 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
!(test_mask & fsnotify_vfsmount_mask)) !(test_mask & fsnotify_vfsmount_mask))
return; 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 /* if this inode's directed listeners don't care and nothing on the vfsmount
* listeners list cares, nothing to do */ * listeners list cares, nothing to do */
if (!(test_mask & to_tell->i_fsnotify_mask) && if (!(test_mask & to_tell->i_fsnotify_mask) &&
!needed_by_vfsmount(test_mask, data, data_is)) !needed_by_vfsmount(test_mask, mnt))
return; return;
/* /*
...@@ -214,16 +213,16 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const ...@@ -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) { if (test_mask & to_tell->i_fsnotify_mask) {
list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) { list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) {
if (test_mask & group->mask) { if (test_mask & group->mask) {
send_to_group(mask, group, data, data_is, send_to_group(group, to_tell, NULL, mask, data, data_is,
file_name, cookie, &event, to_tell); 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) { list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) {
if (test_mask & group->mask) { if (test_mask & group->mask) {
send_to_group(mask, group, data, data_is, send_to_group(group, to_tell, mnt, mask, data, data_is,
file_name, cookie, &event, to_tell); cookie, file_name, &event);
} }
} }
} }
......
...@@ -141,7 +141,8 @@ static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnot ...@@ -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, 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; struct fsnotify_mark_entry *entry;
bool send; bool send;
......
...@@ -79,7 +79,8 @@ struct fsnotify_event_private_data; ...@@ -79,7 +79,8 @@ struct fsnotify_event_private_data;
*/ */
struct fsnotify_ops { struct fsnotify_ops {
bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, 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); int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event);
void (*free_group_priv)(struct fsnotify_group *group); void (*free_group_priv)(struct fsnotify_group *group);
void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group); void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group);
......
...@@ -920,7 +920,8 @@ static void audit_tree_freeing_mark(struct fsnotify_mark_entry *entry, struct fs ...@@ -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, 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; return 0;
} }
......
...@@ -514,7 +514,8 @@ void audit_remove_watch_rule(struct audit_krule *krule) ...@@ -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, 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; struct fsnotify_mark_entry *entry;
bool send; bool send;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment