diff options
author | Nick Piggin <nickpiggin@yahoo.com.au> | 2006-03-25 06:07:09 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-25 11:22:53 -0500 |
commit | c32ccd87bfd1414b0aabfcd8dbc7539ad23bcbaa (patch) | |
tree | 612dc637976cbe36e8b72924a1f7bd76e75463fd /fs/dcache.c | |
parent | bf36b9011e3c5b2739f9da2f6de8a6fa3edded32 (diff) |
[PATCH] inotify: lock avoidance with parent watch status in dentry
Previous inotify work avoidance is good when inotify is completely unused,
but it breaks down if even a single watch is in place anywhere in the
system. Robin Holt notices that udev is one such culprit - it slows down a
512-thread application on a 512 CPU system from 6 seconds to 22 minutes.
Solve this by adding a flag in the dentry that tells inotify whether or not
its parent inode has a watch on it. Event queueing to parent will skip
taking locks if this flag is cleared. Setting and clearing of this flag on
all child dentries versus event delivery: this is no in terms of race
cases, and that was shown to be equivalent to always performing the check.
The essential behaviour is that activity occuring _after_ a watch has been
added and _before_ it has been removed, will generate events.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Robert Love <rml@novell.com>
Cc: John McCutchan <ttb@tentacle.dhs.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 139e5fd22fa6..0f7ec12d65ff 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -802,6 +802,7 @@ void d_instantiate(struct dentry *entry, struct inode * inode) | |||
802 | if (inode) | 802 | if (inode) |
803 | list_add(&entry->d_alias, &inode->i_dentry); | 803 | list_add(&entry->d_alias, &inode->i_dentry); |
804 | entry->d_inode = inode; | 804 | entry->d_inode = inode; |
805 | fsnotify_d_instantiate(entry, inode); | ||
805 | spin_unlock(&dcache_lock); | 806 | spin_unlock(&dcache_lock); |
806 | security_d_instantiate(entry, inode); | 807 | security_d_instantiate(entry, inode); |
807 | } | 808 | } |
@@ -853,6 +854,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | |||
853 | list_add(&entry->d_alias, &inode->i_dentry); | 854 | list_add(&entry->d_alias, &inode->i_dentry); |
854 | do_negative: | 855 | do_negative: |
855 | entry->d_inode = inode; | 856 | entry->d_inode = inode; |
857 | fsnotify_d_instantiate(entry, inode); | ||
856 | spin_unlock(&dcache_lock); | 858 | spin_unlock(&dcache_lock); |
857 | security_d_instantiate(entry, inode); | 859 | security_d_instantiate(entry, inode); |
858 | return NULL; | 860 | return NULL; |
@@ -983,6 +985,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) | |||
983 | new = __d_find_alias(inode, 1); | 985 | new = __d_find_alias(inode, 1); |
984 | if (new) { | 986 | if (new) { |
985 | BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); | 987 | BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); |
988 | fsnotify_d_instantiate(new, inode); | ||
986 | spin_unlock(&dcache_lock); | 989 | spin_unlock(&dcache_lock); |
987 | security_d_instantiate(new, inode); | 990 | security_d_instantiate(new, inode); |
988 | d_rehash(dentry); | 991 | d_rehash(dentry); |
@@ -992,6 +995,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) | |||
992 | /* d_instantiate takes dcache_lock, so we do it by hand */ | 995 | /* d_instantiate takes dcache_lock, so we do it by hand */ |
993 | list_add(&dentry->d_alias, &inode->i_dentry); | 996 | list_add(&dentry->d_alias, &inode->i_dentry); |
994 | dentry->d_inode = inode; | 997 | dentry->d_inode = inode; |
998 | fsnotify_d_instantiate(dentry, inode); | ||
995 | spin_unlock(&dcache_lock); | 999 | spin_unlock(&dcache_lock); |
996 | security_d_instantiate(dentry, inode); | 1000 | security_d_instantiate(dentry, inode); |
997 | d_rehash(dentry); | 1001 | d_rehash(dentry); |
@@ -1176,6 +1180,9 @@ void d_delete(struct dentry * dentry) | |||
1176 | spin_lock(&dentry->d_lock); | 1180 | spin_lock(&dentry->d_lock); |
1177 | isdir = S_ISDIR(dentry->d_inode->i_mode); | 1181 | isdir = S_ISDIR(dentry->d_inode->i_mode); |
1178 | if (atomic_read(&dentry->d_count) == 1) { | 1182 | if (atomic_read(&dentry->d_count) == 1) { |
1183 | /* remove this and other inotify debug checks after 2.6.18 */ | ||
1184 | dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED; | ||
1185 | |||
1179 | dentry_iput(dentry); | 1186 | dentry_iput(dentry); |
1180 | fsnotify_nameremove(dentry, isdir); | 1187 | fsnotify_nameremove(dentry, isdir); |
1181 | return; | 1188 | return; |
@@ -1342,6 +1349,7 @@ already_unhashed: | |||
1342 | 1349 | ||
1343 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); | 1350 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); |
1344 | spin_unlock(&target->d_lock); | 1351 | spin_unlock(&target->d_lock); |
1352 | fsnotify_d_move(dentry); | ||
1345 | spin_unlock(&dentry->d_lock); | 1353 | spin_unlock(&dentry->d_lock); |
1346 | write_sequnlock(&rename_lock); | 1354 | write_sequnlock(&rename_lock); |
1347 | spin_unlock(&dcache_lock); | 1355 | spin_unlock(&dcache_lock); |