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>
This commit is contained in:
parent
7131485a93
commit
3a9fb89f4c
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user