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 /include | |
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 'include')
-rw-r--r-- | include/linux/dcache.h | 2 | ||||
-rw-r--r-- | include/linux/fsnotify.h | 19 | ||||
-rw-r--r-- | include/linux/inotify.h | 11 |
3 files changed, 32 insertions, 0 deletions
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 4361f3789975..d10bd30c337e 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -162,6 +162,8 @@ d_iput: no no no yes | |||
162 | #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ | 162 | #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ |
163 | #define DCACHE_UNHASHED 0x0010 | 163 | #define DCACHE_UNHASHED 0x0010 |
164 | 164 | ||
165 | #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */ | ||
166 | |||
165 | extern spinlock_t dcache_lock; | 167 | extern spinlock_t dcache_lock; |
166 | 168 | ||
167 | /** | 169 | /** |
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 03b8e7932b83..f7e517c1f1bd 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h | |||
@@ -17,6 +17,25 @@ | |||
17 | #include <linux/inotify.h> | 17 | #include <linux/inotify.h> |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * fsnotify_d_instantiate - instantiate a dentry for inode | ||
21 | * Called with dcache_lock held. | ||
22 | */ | ||
23 | static inline void fsnotify_d_instantiate(struct dentry *entry, | ||
24 | struct inode *inode) | ||
25 | { | ||
26 | inotify_d_instantiate(entry, inode); | ||
27 | } | ||
28 | |||
29 | /* | ||
30 | * fsnotify_d_move - entry has been moved | ||
31 | * Called with dcache_lock and entry->d_lock held. | ||
32 | */ | ||
33 | static inline void fsnotify_d_move(struct dentry *entry) | ||
34 | { | ||
35 | inotify_d_move(entry); | ||
36 | } | ||
37 | |||
38 | /* | ||
20 | * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir | 39 | * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir |
21 | */ | 40 | */ |
22 | static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, | 41 | static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, |
diff --git a/include/linux/inotify.h b/include/linux/inotify.h index 267c88b5f742..09e00433c78e 100644 --- a/include/linux/inotify.h +++ b/include/linux/inotify.h | |||
@@ -71,6 +71,8 @@ struct inotify_event { | |||
71 | 71 | ||
72 | #ifdef CONFIG_INOTIFY | 72 | #ifdef CONFIG_INOTIFY |
73 | 73 | ||
74 | extern void inotify_d_instantiate(struct dentry *, struct inode *); | ||
75 | extern void inotify_d_move(struct dentry *); | ||
74 | extern void inotify_inode_queue_event(struct inode *, __u32, __u32, | 76 | extern void inotify_inode_queue_event(struct inode *, __u32, __u32, |
75 | const char *); | 77 | const char *); |
76 | extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32, | 78 | extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32, |
@@ -81,6 +83,15 @@ extern u32 inotify_get_cookie(void); | |||
81 | 83 | ||
82 | #else | 84 | #else |
83 | 85 | ||
86 | static inline void inotify_d_instantiate(struct dentry *dentry, | ||
87 | struct inode *inode) | ||
88 | { | ||
89 | } | ||
90 | |||
91 | static inline void inotify_d_move(struct dentry *dentry) | ||
92 | { | ||
93 | } | ||
94 | |||
84 | static inline void inotify_inode_queue_event(struct inode *inode, | 95 | static inline void inotify_inode_queue_event(struct inode *inode, |
85 | __u32 mask, __u32 cookie, | 96 | __u32 mask, __u32 cookie, |
86 | const char *filename) | 97 | const char *filename) |