From c32ccd87bfd1414b0aabfcd8dbc7539ad23bcbaa Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sat, 25 Mar 2006 03:07:09 -0800 Subject: [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 Cc: Robert Love Cc: John McCutchan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/dcache.h | 2 ++ include/linux/fsnotify.h | 19 +++++++++++++++++++ include/linux/inotify.h | 11 +++++++++++ 3 files changed, 32 insertions(+) (limited to 'include') diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 4361f378997..d10bd30c337 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -162,6 +162,8 @@ d_iput: no no no yes #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ #define DCACHE_UNHASHED 0x0010 +#define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */ + extern spinlock_t dcache_lock; /** diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 03b8e7932b8..f7e517c1f1b 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -16,6 +16,25 @@ #include #include +/* + * fsnotify_d_instantiate - instantiate a dentry for inode + * Called with dcache_lock held. + */ +static inline void fsnotify_d_instantiate(struct dentry *entry, + struct inode *inode) +{ + inotify_d_instantiate(entry, inode); +} + +/* + * fsnotify_d_move - entry has been moved + * Called with dcache_lock and entry->d_lock held. + */ +static inline void fsnotify_d_move(struct dentry *entry) +{ + inotify_d_move(entry); +} + /* * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir */ diff --git a/include/linux/inotify.h b/include/linux/inotify.h index 267c88b5f74..09e00433c78 100644 --- a/include/linux/inotify.h +++ b/include/linux/inotify.h @@ -71,6 +71,8 @@ struct inotify_event { #ifdef CONFIG_INOTIFY +extern void inotify_d_instantiate(struct dentry *, struct inode *); +extern void inotify_d_move(struct dentry *); extern void inotify_inode_queue_event(struct inode *, __u32, __u32, const char *); extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32, @@ -81,6 +83,15 @@ extern u32 inotify_get_cookie(void); #else +static inline void inotify_d_instantiate(struct dentry *dentry, + struct inode *inode) +{ +} + +static inline void inotify_d_move(struct dentry *dentry) +{ +} + static inline void inotify_inode_queue_event(struct inode *inode, __u32 mask, __u32 cookie, const char *filename) -- cgit v1.2.3