[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>
This commit is contained in:
committed by
Linus Torvalds
parent
bf36b9011e
commit
c32ccd87bf
@ -802,6 +802,7 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
|
||||
if (inode)
|
||||
list_add(&entry->d_alias, &inode->i_dentry);
|
||||
entry->d_inode = inode;
|
||||
fsnotify_d_instantiate(entry, inode);
|
||||
spin_unlock(&dcache_lock);
|
||||
security_d_instantiate(entry, inode);
|
||||
}
|
||||
@ -853,6 +854,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
|
||||
list_add(&entry->d_alias, &inode->i_dentry);
|
||||
do_negative:
|
||||
entry->d_inode = inode;
|
||||
fsnotify_d_instantiate(entry, inode);
|
||||
spin_unlock(&dcache_lock);
|
||||
security_d_instantiate(entry, inode);
|
||||
return NULL;
|
||||
@ -983,6 +985,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
|
||||
new = __d_find_alias(inode, 1);
|
||||
if (new) {
|
||||
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
|
||||
fsnotify_d_instantiate(new, inode);
|
||||
spin_unlock(&dcache_lock);
|
||||
security_d_instantiate(new, inode);
|
||||
d_rehash(dentry);
|
||||
@ -992,6 +995,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
|
||||
/* d_instantiate takes dcache_lock, so we do it by hand */
|
||||
list_add(&dentry->d_alias, &inode->i_dentry);
|
||||
dentry->d_inode = inode;
|
||||
fsnotify_d_instantiate(dentry, inode);
|
||||
spin_unlock(&dcache_lock);
|
||||
security_d_instantiate(dentry, inode);
|
||||
d_rehash(dentry);
|
||||
@ -1176,6 +1180,9 @@ void d_delete(struct dentry * dentry)
|
||||
spin_lock(&dentry->d_lock);
|
||||
isdir = S_ISDIR(dentry->d_inode->i_mode);
|
||||
if (atomic_read(&dentry->d_count) == 1) {
|
||||
/* remove this and other inotify debug checks after 2.6.18 */
|
||||
dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;
|
||||
|
||||
dentry_iput(dentry);
|
||||
fsnotify_nameremove(dentry, isdir);
|
||||
return;
|
||||
@ -1342,6 +1349,7 @@ already_unhashed:
|
||||
|
||||
list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
|
||||
spin_unlock(&target->d_lock);
|
||||
fsnotify_d_move(dentry);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
write_sequnlock(&rename_lock);
|
||||
spin_unlock(&dcache_lock);
|
||||
|
Reference in New Issue
Block a user