diff options
author | Eric Paris <eparis@redhat.com> | 2009-05-21 17:01:29 -0400 |
---|---|---|
committer | Eric Paris <eparis@redhat.com> | 2009-06-11 14:57:53 -0400 |
commit | c28f7e56e9d95fb531dc3be8df2e7f52bee76d21 (patch) | |
tree | efce13ed8c4f5b312ef0b77950489d52ef5a039a /include | |
parent | 3be25f49b9d6a97eae9bcb96d3292072b7658bd8 (diff) |
fsnotify: parent event notification
inotify and dnotify both use a similar parent notification mechanism. We
add a generic parent notification mechanism to fsnotify for both of these
to use. This new machanism also adds the dentry flag optimization which
exists for inotify to dnotify.
Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/dcache.h | 4 | ||||
-rw-r--r-- | include/linux/fsnotify.h | 34 | ||||
-rw-r--r-- | include/linux/fsnotify_backend.h | 64 |
3 files changed, 92 insertions, 10 deletions
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 15156364d196..97978004338d 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -180,10 +180,12 @@ d_iput: no no no yes | |||
180 | #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ | 180 | #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ |
181 | #define DCACHE_UNHASHED 0x0010 | 181 | #define DCACHE_UNHASHED 0x0010 |
182 | 182 | ||
183 | #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */ | 183 | #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched by inotify */ |
184 | 184 | ||
185 | #define DCACHE_COOKIE 0x0040 /* For use by dcookie subsystem */ | 185 | #define DCACHE_COOKIE 0x0040 /* For use by dcookie subsystem */ |
186 | 186 | ||
187 | #define DCACHE_FSNOTIFY_PARENT_WATCHED 0x0080 /* Parent inode is watched by some fsnotify listener */ | ||
188 | |||
187 | extern spinlock_t dcache_lock; | 189 | extern spinlock_t dcache_lock; |
188 | extern seqlock_t rename_lock; | 190 | extern seqlock_t rename_lock; |
189 | 191 | ||
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 3856eb6e5973..6a662ed0bc8a 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h | |||
@@ -23,15 +23,31 @@ | |||
23 | static inline void fsnotify_d_instantiate(struct dentry *entry, | 23 | static inline void fsnotify_d_instantiate(struct dentry *entry, |
24 | struct inode *inode) | 24 | struct inode *inode) |
25 | { | 25 | { |
26 | __fsnotify_d_instantiate(entry, inode); | ||
27 | |||
26 | inotify_d_instantiate(entry, inode); | 28 | inotify_d_instantiate(entry, inode); |
27 | } | 29 | } |
28 | 30 | ||
31 | /* Notify this dentry's parent about a child's events. */ | ||
32 | static inline void fsnotify_parent(struct dentry *dentry, __u32 mask) | ||
33 | { | ||
34 | __fsnotify_parent(dentry, mask); | ||
35 | |||
36 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | ||
37 | } | ||
38 | |||
29 | /* | 39 | /* |
30 | * fsnotify_d_move - entry has been moved | 40 | * fsnotify_d_move - entry has been moved |
31 | * Called with dcache_lock and entry->d_lock held. | 41 | * Called with dcache_lock and entry->d_lock held. |
32 | */ | 42 | */ |
33 | static inline void fsnotify_d_move(struct dentry *entry) | 43 | static inline void fsnotify_d_move(struct dentry *entry) |
34 | { | 44 | { |
45 | /* | ||
46 | * On move we need to update entry->d_flags to indicate if the new parent | ||
47 | * cares about events from this entry. | ||
48 | */ | ||
49 | __fsnotify_update_dcache_flags(entry); | ||
50 | |||
35 | inotify_d_move(entry); | 51 | inotify_d_move(entry); |
36 | } | 52 | } |
37 | 53 | ||
@@ -117,7 +133,8 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) | |||
117 | if (isdir) | 133 | if (isdir) |
118 | mask |= FS_IN_ISDIR; | 134 | mask |= FS_IN_ISDIR; |
119 | dnotify_parent(dentry, DN_DELETE); | 135 | dnotify_parent(dentry, DN_DELETE); |
120 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | 136 | |
137 | fsnotify_parent(dentry, mask); | ||
121 | } | 138 | } |
122 | 139 | ||
123 | /* | 140 | /* |
@@ -188,9 +205,9 @@ static inline void fsnotify_access(struct dentry *dentry) | |||
188 | mask |= FS_IN_ISDIR; | 205 | mask |= FS_IN_ISDIR; |
189 | 206 | ||
190 | dnotify_parent(dentry, DN_ACCESS); | 207 | dnotify_parent(dentry, DN_ACCESS); |
191 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | ||
192 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 208 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); |
193 | 209 | ||
210 | fsnotify_parent(dentry, mask); | ||
194 | fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE); | 211 | fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE); |
195 | } | 212 | } |
196 | 213 | ||
@@ -206,9 +223,9 @@ static inline void fsnotify_modify(struct dentry *dentry) | |||
206 | mask |= FS_IN_ISDIR; | 223 | mask |= FS_IN_ISDIR; |
207 | 224 | ||
208 | dnotify_parent(dentry, DN_MODIFY); | 225 | dnotify_parent(dentry, DN_MODIFY); |
209 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | ||
210 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 226 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); |
211 | 227 | ||
228 | fsnotify_parent(dentry, mask); | ||
212 | fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE); | 229 | fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE); |
213 | } | 230 | } |
214 | 231 | ||
@@ -223,9 +240,9 @@ static inline void fsnotify_open(struct dentry *dentry) | |||
223 | if (S_ISDIR(inode->i_mode)) | 240 | if (S_ISDIR(inode->i_mode)) |
224 | mask |= FS_IN_ISDIR; | 241 | mask |= FS_IN_ISDIR; |
225 | 242 | ||
226 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | ||
227 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 243 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); |
228 | 244 | ||
245 | fsnotify_parent(dentry, mask); | ||
229 | fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE); | 246 | fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE); |
230 | } | 247 | } |
231 | 248 | ||
@@ -236,16 +253,15 @@ static inline void fsnotify_close(struct file *file) | |||
236 | { | 253 | { |
237 | struct dentry *dentry = file->f_path.dentry; | 254 | struct dentry *dentry = file->f_path.dentry; |
238 | struct inode *inode = dentry->d_inode; | 255 | struct inode *inode = dentry->d_inode; |
239 | const char *name = dentry->d_name.name; | ||
240 | fmode_t mode = file->f_mode; | 256 | fmode_t mode = file->f_mode; |
241 | __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE; | 257 | __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE; |
242 | 258 | ||
243 | if (S_ISDIR(inode->i_mode)) | 259 | if (S_ISDIR(inode->i_mode)) |
244 | mask |= FS_IN_ISDIR; | 260 | mask |= FS_IN_ISDIR; |
245 | 261 | ||
246 | inotify_dentry_parent_queue_event(dentry, mask, 0, name); | ||
247 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 262 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); |
248 | 263 | ||
264 | fsnotify_parent(dentry, mask); | ||
249 | fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE); | 265 | fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE); |
250 | } | 266 | } |
251 | 267 | ||
@@ -260,9 +276,9 @@ static inline void fsnotify_xattr(struct dentry *dentry) | |||
260 | if (S_ISDIR(inode->i_mode)) | 276 | if (S_ISDIR(inode->i_mode)) |
261 | mask |= FS_IN_ISDIR; | 277 | mask |= FS_IN_ISDIR; |
262 | 278 | ||
263 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | ||
264 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 279 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); |
265 | 280 | ||
281 | fsnotify_parent(dentry, mask); | ||
266 | fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE); | 282 | fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE); |
267 | } | 283 | } |
268 | 284 | ||
@@ -311,8 +327,8 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) | |||
311 | if (S_ISDIR(inode->i_mode)) | 327 | if (S_ISDIR(inode->i_mode)) |
312 | in_mask |= FS_IN_ISDIR; | 328 | in_mask |= FS_IN_ISDIR; |
313 | inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL); | 329 | inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL); |
314 | inotify_dentry_parent_queue_event(dentry, in_mask, 0, | 330 | |
315 | dentry->d_name.name); | 331 | fsnotify_parent(dentry, in_mask); |
316 | fsnotify(inode, in_mask, inode, FSNOTIFY_EVENT_INODE); | 332 | fsnotify(inode, in_mask, inode, FSNOTIFY_EVENT_INODE); |
317 | } | 333 | } |
318 | } | 334 | } |
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index cad5c4d75c1d..13d2dd570049 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h | |||
@@ -46,6 +46,17 @@ | |||
46 | #define FS_DN_RENAME 0x10000000 /* file renamed */ | 46 | #define FS_DN_RENAME 0x10000000 /* file renamed */ |
47 | #define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */ | 47 | #define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */ |
48 | 48 | ||
49 | /* This inode cares about things that happen to its children. Always set for | ||
50 | * dnotify and inotify. */ | ||
51 | #define FS_EVENT_ON_CHILD 0x08000000 | ||
52 | |||
53 | /* This is a list of all events that may get sent to a parernt based on fs event | ||
54 | * happening to inodes inside that directory */ | ||
55 | #define FS_EVENTS_POSS_ON_CHILD (FS_ACCESS | FS_MODIFY | FS_ATTRIB |\ | ||
56 | FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN |\ | ||
57 | FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE |\ | ||
58 | FS_DELETE) | ||
59 | |||
49 | struct fsnotify_group; | 60 | struct fsnotify_group; |
50 | struct fsnotify_event; | 61 | struct fsnotify_event; |
51 | struct fsnotify_mark_entry; | 62 | struct fsnotify_mark_entry; |
@@ -183,8 +194,52 @@ struct fsnotify_mark_entry { | |||
183 | 194 | ||
184 | /* main fsnotify call to send events */ | 195 | /* main fsnotify call to send events */ |
185 | extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is); | 196 | extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is); |
197 | extern void __fsnotify_parent(struct dentry *dentry, __u32 mask); | ||
186 | extern void __fsnotify_inode_delete(struct inode *inode); | 198 | extern void __fsnotify_inode_delete(struct inode *inode); |
187 | 199 | ||
200 | static inline int fsnotify_inode_watches_children(struct inode *inode) | ||
201 | { | ||
202 | /* FS_EVENT_ON_CHILD is set if the inode may care */ | ||
203 | if (!(inode->i_fsnotify_mask & FS_EVENT_ON_CHILD)) | ||
204 | return 0; | ||
205 | /* this inode might care about child events, does it care about the | ||
206 | * specific set of events that can happen on a child? */ | ||
207 | return inode->i_fsnotify_mask & FS_EVENTS_POSS_ON_CHILD; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * Update the dentry with a flag indicating the interest of its parent to receive | ||
212 | * filesystem events when those events happens to this dentry->d_inode. | ||
213 | */ | ||
214 | static inline void __fsnotify_update_dcache_flags(struct dentry *dentry) | ||
215 | { | ||
216 | struct dentry *parent; | ||
217 | |||
218 | assert_spin_locked(&dcache_lock); | ||
219 | assert_spin_locked(&dentry->d_lock); | ||
220 | |||
221 | parent = dentry->d_parent; | ||
222 | if (fsnotify_inode_watches_children(parent->d_inode)) | ||
223 | dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; | ||
224 | else | ||
225 | dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * fsnotify_d_instantiate - instantiate a dentry for inode | ||
230 | * Called with dcache_lock held. | ||
231 | */ | ||
232 | static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode *inode) | ||
233 | { | ||
234 | if (!inode) | ||
235 | return; | ||
236 | |||
237 | assert_spin_locked(&dcache_lock); | ||
238 | |||
239 | spin_lock(&dentry->d_lock); | ||
240 | __fsnotify_update_dcache_flags(dentry); | ||
241 | spin_unlock(&dentry->d_lock); | ||
242 | } | ||
188 | 243 | ||
189 | /* called from fsnotify listeners, such as fanotify or dnotify */ | 244 | /* called from fsnotify listeners, such as fanotify or dnotify */ |
190 | 245 | ||
@@ -230,9 +285,18 @@ extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 | |||
230 | static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is) | 285 | static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is) |
231 | {} | 286 | {} |
232 | 287 | ||
288 | static inline void __fsnotify_parent(struct dentry *dentry, __u32 mask) | ||
289 | {} | ||
290 | |||
233 | static inline void __fsnotify_inode_delete(struct inode *inode) | 291 | static inline void __fsnotify_inode_delete(struct inode *inode) |
234 | {} | 292 | {} |
235 | 293 | ||
294 | static inline void __fsnotify_update_dcache_flags(struct dentry *dentry) | ||
295 | {} | ||
296 | |||
297 | static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode *inode) | ||
298 | {} | ||
299 | |||
236 | #endif /* CONFIG_FSNOTIFY */ | 300 | #endif /* CONFIG_FSNOTIFY */ |
237 | 301 | ||
238 | #endif /* __KERNEL __ */ | 302 | #endif /* __KERNEL __ */ |