diff options
Diffstat (limited to 'fs/notify/fsnotify.c')
-rw-r--r-- | fs/notify/fsnotify.c | 47 |
1 files changed, 24 insertions, 23 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index c5adf833bf6a..668268627894 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -169,27 +169,22 @@ void __fsnotify_flush_ignored_mask(struct inode *inode, void *data, int data_is) | |||
169 | } | 169 | } |
170 | } | 170 | } |
171 | 171 | ||
172 | static void send_to_group(struct fsnotify_group *group, struct inode *to_tell, | 172 | static int send_to_group(struct fsnotify_group *group, struct inode *to_tell, |
173 | struct vfsmount *mnt, __u32 mask, void *data, | 173 | struct vfsmount *mnt, __u32 mask, void *data, |
174 | int data_is, u32 cookie, const unsigned char *file_name, | 174 | int data_is, u32 cookie, const unsigned char *file_name, |
175 | struct fsnotify_event **event) | 175 | struct fsnotify_event **event) |
176 | { | 176 | { |
177 | if (!group->ops->should_send_event(group, to_tell, mnt, mask, | 177 | if (!group->ops->should_send_event(group, to_tell, mnt, mask, |
178 | data, data_is)) | 178 | data, data_is)) |
179 | return; | 179 | return 0; |
180 | if (!*event) { | 180 | if (!*event) { |
181 | *event = fsnotify_create_event(to_tell, mask, data, | 181 | *event = fsnotify_create_event(to_tell, mask, data, |
182 | data_is, file_name, | 182 | data_is, file_name, |
183 | cookie, GFP_KERNEL); | 183 | cookie, GFP_KERNEL); |
184 | /* | ||
185 | * shit, we OOM'd and now we can't tell, maybe | ||
186 | * someday someone else will want to do something | ||
187 | * here | ||
188 | */ | ||
189 | if (!*event) | 184 | if (!*event) |
190 | return; | 185 | return -ENOMEM; |
191 | } | 186 | } |
192 | group->ops->handle_event(group, *event); | 187 | return group->ops->handle_event(group, *event); |
193 | } | 188 | } |
194 | 189 | ||
195 | static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt) | 190 | static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt) |
@@ -206,20 +201,20 @@ static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt) | |||
206 | * out to all of the registered fsnotify_group. Those groups can then use the | 201 | * out to all of the registered fsnotify_group. Those groups can then use the |
207 | * notification event in whatever means they feel necessary. | 202 | * notification event in whatever means they feel necessary. |
208 | */ | 203 | */ |
209 | void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, | 204 | int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, |
210 | const unsigned char *file_name, u32 cookie) | 205 | const unsigned char *file_name, u32 cookie) |
211 | { | 206 | { |
212 | struct fsnotify_group *group; | 207 | struct fsnotify_group *group; |
213 | struct fsnotify_event *event = NULL; | 208 | struct fsnotify_event *event = NULL; |
214 | struct vfsmount *mnt = NULL; | 209 | struct vfsmount *mnt = NULL; |
215 | int idx; | 210 | int idx, ret = 0; |
216 | /* global tests shouldn't care about events on child only the specific event */ | 211 | /* global tests shouldn't care about events on child only the specific event */ |
217 | __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); | 212 | __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); |
218 | 213 | ||
219 | /* if no fsnotify listeners, nothing to do */ | 214 | /* if no fsnotify listeners, nothing to do */ |
220 | if (list_empty(&fsnotify_inode_groups) && | 215 | if (list_empty(&fsnotify_inode_groups) && |
221 | list_empty(&fsnotify_vfsmount_groups)) | 216 | list_empty(&fsnotify_vfsmount_groups)) |
222 | return; | 217 | return 0; |
223 | 218 | ||
224 | if (mask & FS_MODIFY) | 219 | if (mask & FS_MODIFY) |
225 | __fsnotify_flush_ignored_mask(to_tell, data, data_is); | 220 | __fsnotify_flush_ignored_mask(to_tell, data, data_is); |
@@ -227,7 +222,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, | |||
227 | /* if none of the directed listeners or vfsmount listeners care */ | 222 | /* if none of the directed listeners or vfsmount listeners care */ |
228 | if (!(test_mask & fsnotify_inode_mask) && | 223 | if (!(test_mask & fsnotify_inode_mask) && |
229 | !(test_mask & fsnotify_vfsmount_mask)) | 224 | !(test_mask & fsnotify_vfsmount_mask)) |
230 | return; | 225 | return 0; |
231 | 226 | ||
232 | if (data_is == FSNOTIFY_EVENT_PATH) | 227 | if (data_is == FSNOTIFY_EVENT_PATH) |
233 | mnt = ((struct path *)data)->mnt; | 228 | mnt = ((struct path *)data)->mnt; |
@@ -236,7 +231,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, | |||
236 | * listeners list cares, nothing to do */ | 231 | * listeners list cares, nothing to do */ |
237 | if (!(test_mask & to_tell->i_fsnotify_mask) && | 232 | if (!(test_mask & to_tell->i_fsnotify_mask) && |
238 | !needed_by_vfsmount(test_mask, mnt)) | 233 | !needed_by_vfsmount(test_mask, mnt)) |
239 | return; | 234 | return 0; |
240 | 235 | ||
241 | /* | 236 | /* |
242 | * SRCU!! the groups list is very very much read only and the path is | 237 | * SRCU!! the groups list is very very much read only and the path is |
@@ -248,20 +243,24 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, | |||
248 | if (test_mask & to_tell->i_fsnotify_mask) { | 243 | if (test_mask & to_tell->i_fsnotify_mask) { |
249 | list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) { | 244 | list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) { |
250 | if (test_mask & group->mask) { | 245 | if (test_mask & group->mask) { |
251 | send_to_group(group, to_tell, NULL, mask, data, data_is, | 246 | ret = send_to_group(group, to_tell, NULL, mask, data, data_is, |
252 | cookie, file_name, &event); | 247 | cookie, file_name, &event); |
248 | if (ret) | ||
249 | goto out; | ||
253 | } | 250 | } |
254 | } | 251 | } |
255 | } | 252 | } |
256 | if (needed_by_vfsmount(test_mask, mnt)) { | 253 | if (needed_by_vfsmount(test_mask, mnt)) { |
257 | list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) { | 254 | list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) { |
258 | if (test_mask & group->mask) { | 255 | if (test_mask & group->mask) { |
259 | send_to_group(group, to_tell, mnt, mask, data, data_is, | 256 | ret = send_to_group(group, to_tell, mnt, mask, data, data_is, |
260 | cookie, file_name, &event); | 257 | cookie, file_name, &event); |
258 | if (ret) | ||
259 | goto out; | ||
261 | } | 260 | } |
262 | } | 261 | } |
263 | } | 262 | } |
264 | 263 | out: | |
265 | srcu_read_unlock(&fsnotify_grp_srcu, idx); | 264 | srcu_read_unlock(&fsnotify_grp_srcu, idx); |
266 | /* | 265 | /* |
267 | * fsnotify_create_event() took a reference so the event can't be cleaned | 266 | * fsnotify_create_event() took a reference so the event can't be cleaned |
@@ -269,6 +268,8 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, | |||
269 | */ | 268 | */ |
270 | if (event) | 269 | if (event) |
271 | fsnotify_put_event(event); | 270 | fsnotify_put_event(event); |
271 | |||
272 | return 0; | ||
272 | } | 273 | } |
273 | EXPORT_SYMBOL_GPL(fsnotify); | 274 | EXPORT_SYMBOL_GPL(fsnotify); |
274 | 275 | ||