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/linux | |
| 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/linux')
| -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 __ */ |
