diff options
Diffstat (limited to 'fs/inotify.c')
-rw-r--r-- | fs/inotify.c | 30 |
1 files changed, 15 insertions, 15 deletions
diff --git a/fs/inotify.c b/fs/inotify.c index 2c5b92152876..690e72595e6e 100644 --- a/fs/inotify.c +++ b/fs/inotify.c | |||
@@ -168,20 +168,14 @@ static void set_dentry_child_flags(struct inode *inode, int watched) | |||
168 | struct dentry *child; | 168 | struct dentry *child; |
169 | 169 | ||
170 | list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { | 170 | list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { |
171 | if (!child->d_inode) { | 171 | if (!child->d_inode) |
172 | WARN_ON(child->d_flags & DCACHE_INOTIFY_PARENT_WATCHED); | ||
173 | continue; | 172 | continue; |
174 | } | 173 | |
175 | spin_lock(&child->d_lock); | 174 | spin_lock(&child->d_lock); |
176 | if (watched) { | 175 | if (watched) |
177 | WARN_ON(child->d_flags & | ||
178 | DCACHE_INOTIFY_PARENT_WATCHED); | ||
179 | child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED; | 176 | child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED; |
180 | } else { | 177 | else |
181 | WARN_ON(!(child->d_flags & | 178 | child->d_flags &=~DCACHE_INOTIFY_PARENT_WATCHED; |
182 | DCACHE_INOTIFY_PARENT_WATCHED)); | ||
183 | child->d_flags&=~DCACHE_INOTIFY_PARENT_WATCHED; | ||
184 | } | ||
185 | spin_unlock(&child->d_lock); | 179 | spin_unlock(&child->d_lock); |
186 | } | 180 | } |
187 | } | 181 | } |
@@ -253,7 +247,6 @@ void inotify_d_instantiate(struct dentry *entry, struct inode *inode) | |||
253 | if (!inode) | 247 | if (!inode) |
254 | return; | 248 | return; |
255 | 249 | ||
256 | WARN_ON(entry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED); | ||
257 | spin_lock(&entry->d_lock); | 250 | spin_lock(&entry->d_lock); |
258 | parent = entry->d_parent; | 251 | parent = entry->d_parent; |
259 | if (parent->d_inode && inotify_inode_watched(parent->d_inode)) | 252 | if (parent->d_inode && inotify_inode_watched(parent->d_inode)) |
@@ -627,6 +620,7 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, | |||
627 | struct inode *inode, u32 mask) | 620 | struct inode *inode, u32 mask) |
628 | { | 621 | { |
629 | int ret = 0; | 622 | int ret = 0; |
623 | int newly_watched; | ||
630 | 624 | ||
631 | /* don't allow invalid bits: we don't want flags set */ | 625 | /* don't allow invalid bits: we don't want flags set */ |
632 | mask &= IN_ALL_EVENTS | IN_ONESHOT; | 626 | mask &= IN_ALL_EVENTS | IN_ONESHOT; |
@@ -653,12 +647,18 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, | |||
653 | */ | 647 | */ |
654 | watch->inode = igrab(inode); | 648 | watch->inode = igrab(inode); |
655 | 649 | ||
656 | if (!inotify_inode_watched(inode)) | ||
657 | set_dentry_child_flags(inode, 1); | ||
658 | |||
659 | /* Add the watch to the handle's and the inode's list */ | 650 | /* Add the watch to the handle's and the inode's list */ |
651 | newly_watched = !inotify_inode_watched(inode); | ||
660 | list_add(&watch->h_list, &ih->watches); | 652 | list_add(&watch->h_list, &ih->watches); |
661 | list_add(&watch->i_list, &inode->inotify_watches); | 653 | list_add(&watch->i_list, &inode->inotify_watches); |
654 | /* | ||
655 | * Set child flags _after_ adding the watch, so there is no race | ||
656 | * windows where newly instantiated children could miss their parent's | ||
657 | * watched flag. | ||
658 | */ | ||
659 | if (newly_watched) | ||
660 | set_dentry_child_flags(inode, 1); | ||
661 | |||
662 | out: | 662 | out: |
663 | mutex_unlock(&ih->mutex); | 663 | mutex_unlock(&ih->mutex); |
664 | mutex_unlock(&inode->inotify_mutex); | 664 | mutex_unlock(&inode->inotify_mutex); |