diff options
Diffstat (limited to 'fs/notify')
-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 c5adf83..6682686 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) } } -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 unsigned char *file_name, - struct fsnotify_event **event) +static int send_to_group(struct fsnotify_group *group, struct inode *to_tell, + struct vfsmount *mnt, __u32 mask, void *data, + int data_is, u32 cookie, const unsigned char *file_name, + struct fsnotify_event **event) { if (!group->ops->should_send_event(group, to_tell, mnt, mask, data, data_is)) - return; + return 0; if (!*event) { *event = fsnotify_create_event(to_tell, mask, data, data_is, file_name, cookie, GFP_KERNEL); - /* - * shit, we OOM'd and now we can't tell, maybe - * someday someone else will want to do something - * here - */ if (!*event) - return; + return -ENOMEM; } - group->ops->handle_event(group, *event); + return group->ops->handle_event(group, *event); } 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) * out to all of the registered fsnotify_group. Those groups can then use the * notification event in whatever means they feel necessary. */ -void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, - const unsigned char *file_name, u32 cookie) +int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, + const unsigned char *file_name, u32 cookie) { struct fsnotify_group *group; struct fsnotify_event *event = NULL; struct vfsmount *mnt = NULL; - int idx; + int idx, ret = 0; /* global tests shouldn't care about events on child only the specific event */ __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); /* if no fsnotify listeners, nothing to do */ if (list_empty(&fsnotify_inode_groups) && list_empty(&fsnotify_vfsmount_groups)) - return; + return 0; if (mask & FS_MODIFY) __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, /* if none of the directed listeners or vfsmount listeners care */ if (!(test_mask & fsnotify_inode_mask) && !(test_mask & fsnotify_vfsmount_mask)) - return; + return 0; if (data_is == FSNOTIFY_EVENT_PATH) mnt = ((struct path *)data)->mnt; @@ -236,7 +231,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, * listeners list cares, nothing to do */ if (!(test_mask & to_tell->i_fsnotify_mask) && !needed_by_vfsmount(test_mask, mnt)) - return; + return 0; /* * 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, 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(group, to_tell, NULL, mask, data, data_is, - cookie, file_name, &event); + ret = send_to_group(group, to_tell, NULL, mask, data, data_is, + cookie, file_name, &event); + if (ret) + goto out; } } } 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(group, to_tell, mnt, mask, data, data_is, - cookie, file_name, &event); + ret = send_to_group(group, to_tell, mnt, mask, data, data_is, + cookie, file_name, &event); + if (ret) + goto out; } } } - +out: srcu_read_unlock(&fsnotify_grp_srcu, idx); /* * 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, */ if (event) fsnotify_put_event(event); + + return 0; } EXPORT_SYMBOL_GPL(fsnotify); |