aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/fsnotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/fsnotify.c')
-rw-r--r--fs/notify/fsnotify.c47
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
172static void send_to_group(struct fsnotify_group *group, struct inode *to_tell, 172static 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
195static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt) 190static 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 */
209void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, 204int 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 263out:
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}
273EXPORT_SYMBOL_GPL(fsnotify); 274EXPORT_SYMBOL_GPL(fsnotify);
274 275