diff options
author | Eric Paris <eparis@redhat.com> | 2009-12-17 21:24:23 -0500 |
---|---|---|
committer | Eric Paris <eparis@redhat.com> | 2010-07-28 09:58:52 -0400 |
commit | 3a9fb89f4cd04c23e16397befba92efb5d989b74 (patch) | |
tree | f60b48c8cf488ad8952601ccbc6192b5f86ec900 | |
parent | 7131485a93679ff9a543b74df280cfd119eb03ca (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.c | 4 | ||||
-rw-r--r-- | fs/notify/fsnotify.c | 39 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 3 | ||||
-rw-r--r-- | include/linux/fsnotify_backend.h | 3 | ||||
-rw-r--r-- | kernel/audit_tree.c | 3 | ||||
-rw-r--r-- | kernel/audit_watch.c | 3 |
6 files changed, 29 insertions, 26 deletions
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index e0a847bd53be..9eddafa4c7ba 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, | |||
133 | * userspace notification for that pair. | 133 | * userspace notification for that pair. |
134 | */ | 134 | */ |
135 | static bool dnotify_should_send_event(struct fsnotify_group *group, | 135 | static bool dnotify_should_send_event(struct fsnotify_group *group, |
136 | struct inode *inode, __u32 mask, | 136 | struct inode *inode, struct vfsmount *mnt, |
137 | void *data, int data_type) | 137 | __u32 mask, void *data, int data_type) |
138 | { | 138 | { |
139 | struct fsnotify_mark_entry *entry; | 139 | struct fsnotify_mark_entry *entry; |
140 | bool send; | 140 | bool send; |
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index a61aaa710825..78c440c343a8 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) | |||
135 | } | 135 | } |
136 | EXPORT_SYMBOL_GPL(__fsnotify_parent); | 136 | EXPORT_SYMBOL_GPL(__fsnotify_parent); |
137 | 137 | ||
138 | static void send_to_group(__u32 mask, | 138 | static void send_to_group(struct fsnotify_group *group, struct inode *to_tell, |
139 | struct fsnotify_group *group, | 139 | struct vfsmount *mnt, __u32 mask, void *data, |
140 | void *data, int data_is, const char *file_name, | 140 | int data_is, u32 cookie, const char *file_name, |
141 | u32 cookie, struct fsnotify_event **event, | 141 | struct fsnotify_event **event) |
142 | struct inode *to_tell) | ||
143 | { | 142 | { |
144 | if (!group->ops->should_send_event(group, to_tell, mask, | 143 | if (!group->ops->should_send_event(group, to_tell, mnt, mask, |
145 | data, data_is)) | 144 | data, data_is)) |
146 | return; | 145 | return; |
147 | if (!*event) { | 146 | if (!*event) { |
@@ -159,15 +158,9 @@ static void send_to_group(__u32 mask, | |||
159 | group->ops->handle_event(group, *event); | 158 | group->ops->handle_event(group, *event); |
160 | } | 159 | } |
161 | 160 | ||
162 | static bool needed_by_vfsmount(__u32 test_mask, void *data, int data_is) | 161 | static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt) |
163 | { | 162 | { |
164 | struct path *path; | 163 | if (!mnt) |
165 | |||
166 | if (data_is == FSNOTIFY_EVENT_PATH) | ||
167 | path = (struct path *)data; | ||
168 | else if (data_is == FSNOTIFY_EVENT_FILE) | ||
169 | path = &((struct file *)data)->f_path; | ||
170 | else | ||
171 | return false; | 164 | return false; |
172 | 165 | ||
173 | /* hook in this when mnt->mnt_fsnotify_mask is defined */ | 166 | /* 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 | { | 177 | { |
185 | struct fsnotify_group *group; | 178 | struct fsnotify_group *group; |
186 | struct fsnotify_event *event = NULL; | 179 | struct fsnotify_event *event = NULL; |
180 | struct vfsmount *mnt = NULL; | ||
187 | int idx; | 181 | int idx; |
188 | /* global tests shouldn't care about events on child only the specific event */ | 182 | /* global tests shouldn't care about events on child only the specific event */ |
189 | __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); | 183 | __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 | !(test_mask & fsnotify_vfsmount_mask)) | 192 | !(test_mask & fsnotify_vfsmount_mask)) |
199 | return; | 193 | return; |
200 | 194 | ||
195 | if (data_is == FSNOTIFY_EVENT_PATH) | ||
196 | mnt = ((struct path *)data)->mnt; | ||
197 | else if (data_is == FSNOTIFY_EVENT_FILE) | ||
198 | mnt = ((struct file *)data)->f_path.mnt; | ||
199 | |||
201 | /* if this inode's directed listeners don't care and nothing on the vfsmount | 200 | /* if this inode's directed listeners don't care and nothing on the vfsmount |
202 | * listeners list cares, nothing to do */ | 201 | * listeners list cares, nothing to do */ |
203 | if (!(test_mask & to_tell->i_fsnotify_mask) && | 202 | if (!(test_mask & to_tell->i_fsnotify_mask) && |
204 | !needed_by_vfsmount(test_mask, data, data_is)) | 203 | !needed_by_vfsmount(test_mask, mnt)) |
205 | return; | 204 | return; |
206 | 205 | ||
207 | /* | 206 | /* |
@@ -214,16 +213,16 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const | |||
214 | if (test_mask & to_tell->i_fsnotify_mask) { | 213 | if (test_mask & to_tell->i_fsnotify_mask) { |
215 | list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) { | 214 | list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) { |
216 | if (test_mask & group->mask) { | 215 | if (test_mask & group->mask) { |
217 | send_to_group(mask, group, data, data_is, | 216 | send_to_group(group, to_tell, NULL, mask, data, data_is, |
218 | file_name, cookie, &event, to_tell); | 217 | cookie, file_name, &event); |
219 | } | 218 | } |
220 | } | 219 | } |
221 | } | 220 | } |
222 | if (needed_by_vfsmount(test_mask, data, data_is)) { | 221 | if (needed_by_vfsmount(test_mask, mnt)) { |
223 | list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) { | 222 | list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) { |
224 | if (test_mask & group->mask) { | 223 | if (test_mask & group->mask) { |
225 | send_to_group(mask, group, data, data_is, | 224 | send_to_group(group, to_tell, mnt, mask, data, data_is, |
226 | file_name, cookie, &event, to_tell); | 225 | cookie, file_name, &event); |
227 | } | 226 | } |
228 | } | 227 | } |
229 | } | 228 | } |
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 0a0f5d0f0d0a..8075ae708ed4 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 | |||
141 | } | 141 | } |
142 | 142 | ||
143 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, | 143 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, |
144 | __u32 mask, void *data, int data_type) | 144 | struct vfsmount *mnt, __u32 mask, void *data, |
145 | int data_type) | ||
145 | { | 146 | { |
146 | struct fsnotify_mark_entry *entry; | 147 | struct fsnotify_mark_entry *entry; |
147 | bool send; | 148 | bool send; |
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index dea48bee057d..c2a04b7e4fca 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h | |||
@@ -79,7 +79,8 @@ struct fsnotify_event_private_data; | |||
79 | */ | 79 | */ |
80 | struct fsnotify_ops { | 80 | struct fsnotify_ops { |
81 | bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, | 81 | bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, |
82 | __u32 mask, void *data, int data_type); | 82 | struct vfsmount *mnt, __u32 mask, void *data, |
83 | int data_type); | ||
83 | int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event); | 84 | int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event); |
84 | void (*free_group_priv)(struct fsnotify_group *group); | 85 | void (*free_group_priv)(struct fsnotify_group *group); |
85 | void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group); | 86 | 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 04f16887406b..ecf0bf260d09 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 | |||
920 | } | 920 | } |
921 | 921 | ||
922 | static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode, | 922 | static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode, |
923 | __u32 mask, void *data, int data_type) | 923 | struct vfsmount *mnt, __u32 mask, void *data, |
924 | int data_type) | ||
924 | { | 925 | { |
925 | return 0; | 926 | return 0; |
926 | } | 927 | } |
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 83d5f9674cec..6304ee5d7642 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c | |||
@@ -514,7 +514,8 @@ void audit_remove_watch_rule(struct audit_krule *krule) | |||
514 | } | 514 | } |
515 | 515 | ||
516 | static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode, | 516 | static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode, |
517 | __u32 mask, void *data, int data_type) | 517 | struct vfsmount *mnt, __u32 mask, void *data, |
518 | int data_type) | ||
518 | { | 519 | { |
519 | struct fsnotify_mark_entry *entry; | 520 | struct fsnotify_mark_entry *entry; |
520 | bool send; | 521 | bool send; |