diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-19 20:46:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-19 20:46:44 -0400 |
commit | bee89ab228e6f51c4ddd3481b9bd491859a8ee7b (patch) | |
tree | 1810eef473172ab9e8ff52ded5e81f39eb8af748 /fs | |
parent | 5c6fb0059cec9a3c0f6d88a0ddf3d62ad323cd57 (diff) | |
parent | 528da3e9e237059a84a2625e942811cf824a6efd (diff) |
Merge branch 'for-linus' of git://git.infradead.org/users/eparis/notify
* 'for-linus' of git://git.infradead.org/users/eparis/notify:
inotify: inotify_destroy_mark_entry could get called twice
Diffstat (limited to 'fs')
-rw-r--r-- | fs/notify/inotify/inotify.h | 3 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 2 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 32 |
3 files changed, 8 insertions, 29 deletions
diff --git a/fs/notify/inotify/inotify.h b/fs/notify/inotify/inotify.h index ea2605a58b8a..f234f3a4c8ca 100644 --- a/fs/notify/inotify/inotify.h +++ b/fs/notify/inotify/inotify.h | |||
@@ -15,7 +15,8 @@ struct inotify_inode_mark_entry { | |||
15 | int wd; | 15 | int wd; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | extern void inotify_destroy_mark_entry(struct fsnotify_mark_entry *entry, struct fsnotify_group *group); | 18 | extern void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, |
19 | struct fsnotify_group *group); | ||
19 | extern void inotify_free_event_priv(struct fsnotify_event_private_data *event_priv); | 20 | extern void inotify_free_event_priv(struct fsnotify_event_private_data *event_priv); |
20 | 21 | ||
21 | extern const struct fsnotify_ops inotify_fsnotify_ops; | 22 | extern const struct fsnotify_ops inotify_fsnotify_ops; |
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 7ef75b83247e..47cd258fd24d 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
@@ -81,7 +81,7 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev | |||
81 | 81 | ||
82 | static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) | 82 | static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) |
83 | { | 83 | { |
84 | inotify_destroy_mark_entry(entry, group); | 84 | inotify_ignored_and_remove_idr(entry, group); |
85 | } | 85 | } |
86 | 86 | ||
87 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask) | 87 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask) |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 982a412ac5bc..ff231ad23895 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -363,39 +363,17 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns | |||
363 | } | 363 | } |
364 | 364 | ||
365 | /* | 365 | /* |
366 | * When, for whatever reason, inotify is done with a mark (or what used to be a | 366 | * Send IN_IGNORED for this wd, remove this wd from the idr, and drop the |
367 | * watch) we need to remove that watch from the idr and we need to send IN_IGNORED | 367 | * internal reference help on the mark because it is in the idr. |
368 | * for the given wd. | ||
369 | * | ||
370 | * There is a bit of recursion here. The loop looks like: | ||
371 | * inotify_destroy_mark_entry -> fsnotify_destroy_mark_by_entry -> | ||
372 | * inotify_freeing_mark -> inotify_destory_mark_entry -> restart | ||
373 | * But the loop is broken in 2 places. fsnotify_destroy_mark_by_entry sets | ||
374 | * entry->group = NULL before the call to inotify_freeing_mark, so the if (egroup) | ||
375 | * test below will not call back to fsnotify again. But even if that test wasn't | ||
376 | * there this would still be safe since fsnotify_destroy_mark_by_entry() is | ||
377 | * safe from recursion. | ||
378 | */ | 368 | */ |
379 | void inotify_destroy_mark_entry(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) | 369 | void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, |
370 | struct fsnotify_group *group) | ||
380 | { | 371 | { |
381 | struct inotify_inode_mark_entry *ientry; | 372 | struct inotify_inode_mark_entry *ientry; |
382 | struct inotify_event_private_data *event_priv; | 373 | struct inotify_event_private_data *event_priv; |
383 | struct fsnotify_event_private_data *fsn_event_priv; | 374 | struct fsnotify_event_private_data *fsn_event_priv; |
384 | struct fsnotify_group *egroup; | ||
385 | struct idr *idr; | 375 | struct idr *idr; |
386 | 376 | ||
387 | spin_lock(&entry->lock); | ||
388 | egroup = entry->group; | ||
389 | |||
390 | /* if egroup we aren't really done and something might still send events | ||
391 | * for this inode, on the callback we'll send the IN_IGNORED */ | ||
392 | if (egroup) { | ||
393 | spin_unlock(&entry->lock); | ||
394 | fsnotify_destroy_mark_by_entry(entry); | ||
395 | return; | ||
396 | } | ||
397 | spin_unlock(&entry->lock); | ||
398 | |||
399 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); | 377 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); |
400 | 378 | ||
401 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); | 379 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); |
@@ -699,7 +677,7 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) | |||
699 | fsnotify_get_mark(entry); | 677 | fsnotify_get_mark(entry); |
700 | spin_unlock(&group->inotify_data.idr_lock); | 678 | spin_unlock(&group->inotify_data.idr_lock); |
701 | 679 | ||
702 | inotify_destroy_mark_entry(entry, group); | 680 | fsnotify_destroy_mark_by_entry(entry); |
703 | fsnotify_put_mark(entry); | 681 | fsnotify_put_mark(entry); |
704 | 682 | ||
705 | out: | 683 | out: |