| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 1 | #ifndef _LINUX_FS_NOTIFY_H | 
|  | 2 | #define _LINUX_FS_NOTIFY_H | 
|  | 3 |  | 
|  | 4 | /* | 
|  | 5 | * include/linux/fsnotify.h - generic hooks for filesystem notification, to | 
|  | 6 | * reduce in-source duplication from both dnotify and inotify. | 
|  | 7 | * | 
|  | 8 | * We don't compile any of this away in some complicated menagerie of ifdefs. | 
|  | 9 | * Instead, we rely on the code inside to optimize away as needed. | 
|  | 10 | * | 
|  | 11 | * (C) Copyright 2005 Robert Love | 
|  | 12 | */ | 
|  | 13 |  | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 14 | #include <linux/dnotify.h> | 
|  | 15 | #include <linux/inotify.h> | 
| Amy Griffis | 73241cc | 2005-11-03 16:00:25 +0000 | [diff] [blame] | 16 | #include <linux/audit.h> | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 17 |  | 
|  | 18 | /* | 
| Nick Piggin | c32ccd8 | 2006-03-25 03:07:09 -0800 | [diff] [blame] | 19 | * fsnotify_d_instantiate - instantiate a dentry for inode | 
|  | 20 | * Called with dcache_lock held. | 
|  | 21 | */ | 
|  | 22 | static inline void fsnotify_d_instantiate(struct dentry *entry, | 
|  | 23 | struct inode *inode) | 
|  | 24 | { | 
|  | 25 | inotify_d_instantiate(entry, inode); | 
|  | 26 | } | 
|  | 27 |  | 
|  | 28 | /* | 
|  | 29 | * fsnotify_d_move - entry has been moved | 
|  | 30 | * Called with dcache_lock and entry->d_lock held. | 
|  | 31 | */ | 
|  | 32 | static inline void fsnotify_d_move(struct dentry *entry) | 
|  | 33 | { | 
|  | 34 | inotify_d_move(entry); | 
|  | 35 | } | 
|  | 36 |  | 
|  | 37 | /* | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 38 | * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir | 
|  | 39 | */ | 
|  | 40 | static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, | 
|  | 41 | const char *old_name, const char *new_name, | 
| Al Viro | 5a190ae | 2007-06-07 12:19:32 -0400 | [diff] [blame] | 42 | int isdir, struct inode *target, struct dentry *moved) | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 43 | { | 
| Al Viro | 5a190ae | 2007-06-07 12:19:32 -0400 | [diff] [blame] | 44 | struct inode *source = moved->d_inode; | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 45 | u32 cookie = inotify_get_cookie(); | 
|  | 46 |  | 
|  | 47 | if (old_dir == new_dir) | 
|  | 48 | inode_dir_notify(old_dir, DN_RENAME); | 
|  | 49 | else { | 
|  | 50 | inode_dir_notify(old_dir, DN_DELETE); | 
|  | 51 | inode_dir_notify(new_dir, DN_CREATE); | 
|  | 52 | } | 
|  | 53 |  | 
|  | 54 | if (isdir) | 
|  | 55 | isdir = IN_ISDIR; | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 56 | inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name, | 
|  | 57 | source); | 
|  | 58 | inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name, | 
|  | 59 | source); | 
| John McCutchan | 7544953 | 2005-08-01 11:00:45 -0400 | [diff] [blame] | 60 |  | 
|  | 61 | if (target) { | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 62 | inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL); | 
| John McCutchan | 7544953 | 2005-08-01 11:00:45 -0400 | [diff] [blame] | 63 | inotify_inode_is_dead(target); | 
|  | 64 | } | 
| John McCutchan | 89204c4 | 2005-08-15 12:13:28 -0400 | [diff] [blame] | 65 |  | 
|  | 66 | if (source) { | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 67 | inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL); | 
| John McCutchan | 89204c4 | 2005-08-15 12:13:28 -0400 | [diff] [blame] | 68 | } | 
| Al Viro | 5a190ae | 2007-06-07 12:19:32 -0400 | [diff] [blame] | 69 | audit_inode_child(new_name, moved, new_dir); | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 70 | } | 
|  | 71 |  | 
|  | 72 | /* | 
| John McCutchan | 7a91bf7 | 2005-08-08 13:52:16 -0400 | [diff] [blame] | 73 | * fsnotify_nameremove - a filename was removed from a directory | 
|  | 74 | */ | 
|  | 75 | static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) | 
|  | 76 | { | 
|  | 77 | if (isdir) | 
|  | 78 | isdir = IN_ISDIR; | 
|  | 79 | dnotify_parent(dentry, DN_DELETE); | 
|  | 80 | inotify_dentry_parent_queue_event(dentry, IN_DELETE|isdir, 0, dentry->d_name.name); | 
|  | 81 | } | 
|  | 82 |  | 
|  | 83 | /* | 
|  | 84 | * fsnotify_inoderemove - an inode is going away | 
|  | 85 | */ | 
|  | 86 | static inline void fsnotify_inoderemove(struct inode *inode) | 
|  | 87 | { | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 88 | inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL); | 
| John McCutchan | 7a91bf7 | 2005-08-08 13:52:16 -0400 | [diff] [blame] | 89 | inotify_inode_is_dead(inode); | 
|  | 90 | } | 
|  | 91 |  | 
|  | 92 | /* | 
| Jan Kara | ece9591 | 2008-02-06 01:37:13 -0800 | [diff] [blame] | 93 | * fsnotify_link_count - inode's link count changed | 
|  | 94 | */ | 
|  | 95 | static inline void fsnotify_link_count(struct inode *inode) | 
|  | 96 | { | 
|  | 97 | inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL); | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | /* | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 101 | * fsnotify_create - 'name' was linked in | 
|  | 102 | */ | 
| Amy Griffis | f38aa94 | 2005-11-03 15:57:06 +0000 | [diff] [blame] | 103 | static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 104 | { | 
|  | 105 | inode_dir_notify(inode, DN_CREATE); | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 106 | inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name, | 
|  | 107 | dentry->d_inode); | 
| Al Viro | 5a190ae | 2007-06-07 12:19:32 -0400 | [diff] [blame] | 108 | audit_inode_child(dentry->d_name.name, dentry, inode); | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 109 | } | 
|  | 110 |  | 
|  | 111 | /* | 
| Jan Kara | ece9591 | 2008-02-06 01:37:13 -0800 | [diff] [blame] | 112 | * fsnotify_link - new hardlink in 'inode' directory | 
|  | 113 | * Note: We have to pass also the linked inode ptr as some filesystems leave | 
|  | 114 | *   new_dentry->d_inode NULL and instantiate inode pointer later | 
|  | 115 | */ | 
|  | 116 | static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry) | 
|  | 117 | { | 
|  | 118 | inode_dir_notify(dir, DN_CREATE); | 
|  | 119 | inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name, | 
|  | 120 | inode); | 
|  | 121 | fsnotify_link_count(inode); | 
|  | 122 | audit_inode_child(new_dentry->d_name.name, new_dentry, dir); | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | /* | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 126 | * fsnotify_mkdir - directory 'name' was created | 
|  | 127 | */ | 
| Amy Griffis | f38aa94 | 2005-11-03 15:57:06 +0000 | [diff] [blame] | 128 | static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 129 | { | 
|  | 130 | inode_dir_notify(inode, DN_CREATE); | 
| Amy Griffis | f38aa94 | 2005-11-03 15:57:06 +0000 | [diff] [blame] | 131 | inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 132 | dentry->d_name.name, dentry->d_inode); | 
| Al Viro | 5a190ae | 2007-06-07 12:19:32 -0400 | [diff] [blame] | 133 | audit_inode_child(dentry->d_name.name, dentry, inode); | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 134 | } | 
|  | 135 |  | 
|  | 136 | /* | 
|  | 137 | * fsnotify_access - file was read | 
|  | 138 | */ | 
|  | 139 | static inline void fsnotify_access(struct dentry *dentry) | 
|  | 140 | { | 
|  | 141 | struct inode *inode = dentry->d_inode; | 
|  | 142 | u32 mask = IN_ACCESS; | 
|  | 143 |  | 
|  | 144 | if (S_ISDIR(inode->i_mode)) | 
|  | 145 | mask |= IN_ISDIR; | 
|  | 146 |  | 
|  | 147 | dnotify_parent(dentry, DN_ACCESS); | 
|  | 148 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 149 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 150 | } | 
|  | 151 |  | 
|  | 152 | /* | 
|  | 153 | * fsnotify_modify - file was modified | 
|  | 154 | */ | 
|  | 155 | static inline void fsnotify_modify(struct dentry *dentry) | 
|  | 156 | { | 
|  | 157 | struct inode *inode = dentry->d_inode; | 
|  | 158 | u32 mask = IN_MODIFY; | 
|  | 159 |  | 
|  | 160 | if (S_ISDIR(inode->i_mode)) | 
|  | 161 | mask |= IN_ISDIR; | 
|  | 162 |  | 
|  | 163 | dnotify_parent(dentry, DN_MODIFY); | 
|  | 164 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 165 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 166 | } | 
|  | 167 |  | 
|  | 168 | /* | 
|  | 169 | * fsnotify_open - file was opened | 
|  | 170 | */ | 
|  | 171 | static inline void fsnotify_open(struct dentry *dentry) | 
|  | 172 | { | 
|  | 173 | struct inode *inode = dentry->d_inode; | 
|  | 174 | u32 mask = IN_OPEN; | 
|  | 175 |  | 
|  | 176 | if (S_ISDIR(inode->i_mode)) | 
|  | 177 | mask |= IN_ISDIR; | 
|  | 178 |  | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 179 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 180 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 181 | } | 
|  | 182 |  | 
|  | 183 | /* | 
|  | 184 | * fsnotify_close - file was closed | 
|  | 185 | */ | 
|  | 186 | static inline void fsnotify_close(struct file *file) | 
|  | 187 | { | 
| Josef "Jeff" Sipek | 0f7fc9e | 2006-12-08 02:36:35 -0800 | [diff] [blame] | 188 | struct dentry *dentry = file->f_path.dentry; | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 189 | struct inode *inode = dentry->d_inode; | 
|  | 190 | const char *name = dentry->d_name.name; | 
| Al Viro | aeb5d72 | 2008-09-02 15:28:45 -0400 | [diff] [blame] | 191 | fmode_t mode = file->f_mode; | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 192 | u32 mask = (mode & FMODE_WRITE) ? IN_CLOSE_WRITE : IN_CLOSE_NOWRITE; | 
|  | 193 |  | 
|  | 194 | if (S_ISDIR(inode->i_mode)) | 
|  | 195 | mask |= IN_ISDIR; | 
|  | 196 |  | 
|  | 197 | inotify_dentry_parent_queue_event(dentry, mask, 0, name); | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 198 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 199 | } | 
|  | 200 |  | 
|  | 201 | /* | 
|  | 202 | * fsnotify_xattr - extended attributes were changed | 
|  | 203 | */ | 
|  | 204 | static inline void fsnotify_xattr(struct dentry *dentry) | 
|  | 205 | { | 
|  | 206 | struct inode *inode = dentry->d_inode; | 
|  | 207 | u32 mask = IN_ATTRIB; | 
|  | 208 |  | 
|  | 209 | if (S_ISDIR(inode->i_mode)) | 
|  | 210 | mask |= IN_ISDIR; | 
|  | 211 |  | 
|  | 212 | inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 213 | inotify_inode_queue_event(inode, mask, 0, NULL, NULL); | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 214 | } | 
|  | 215 |  | 
|  | 216 | /* | 
|  | 217 | * fsnotify_change - notify_change event.  file was modified and/or metadata | 
|  | 218 | * was changed. | 
|  | 219 | */ | 
|  | 220 | static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) | 
|  | 221 | { | 
|  | 222 | struct inode *inode = dentry->d_inode; | 
|  | 223 | int dn_mask = 0; | 
|  | 224 | u32 in_mask = 0; | 
|  | 225 |  | 
|  | 226 | if (ia_valid & ATTR_UID) { | 
|  | 227 | in_mask |= IN_ATTRIB; | 
|  | 228 | dn_mask |= DN_ATTRIB; | 
|  | 229 | } | 
|  | 230 | if (ia_valid & ATTR_GID) { | 
|  | 231 | in_mask |= IN_ATTRIB; | 
|  | 232 | dn_mask |= DN_ATTRIB; | 
|  | 233 | } | 
|  | 234 | if (ia_valid & ATTR_SIZE) { | 
|  | 235 | in_mask |= IN_MODIFY; | 
|  | 236 | dn_mask |= DN_MODIFY; | 
|  | 237 | } | 
|  | 238 | /* both times implies a utime(s) call */ | 
|  | 239 | if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) | 
|  | 240 | { | 
|  | 241 | in_mask |= IN_ATTRIB; | 
|  | 242 | dn_mask |= DN_ATTRIB; | 
|  | 243 | } else if (ia_valid & ATTR_ATIME) { | 
|  | 244 | in_mask |= IN_ACCESS; | 
|  | 245 | dn_mask |= DN_ACCESS; | 
|  | 246 | } else if (ia_valid & ATTR_MTIME) { | 
|  | 247 | in_mask |= IN_MODIFY; | 
|  | 248 | dn_mask |= DN_MODIFY; | 
|  | 249 | } | 
|  | 250 | if (ia_valid & ATTR_MODE) { | 
|  | 251 | in_mask |= IN_ATTRIB; | 
|  | 252 | dn_mask |= DN_ATTRIB; | 
|  | 253 | } | 
|  | 254 |  | 
|  | 255 | if (dn_mask) | 
|  | 256 | dnotify_parent(dentry, dn_mask); | 
|  | 257 | if (in_mask) { | 
|  | 258 | if (S_ISDIR(inode->i_mode)) | 
|  | 259 | in_mask |= IN_ISDIR; | 
| Amy Griffis | 7c29772 | 2006-06-01 13:11:01 -0700 | [diff] [blame] | 260 | inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL); | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 261 | inotify_dentry_parent_queue_event(dentry, in_mask, 0, | 
|  | 262 | dentry->d_name.name); | 
|  | 263 | } | 
|  | 264 | } | 
|  | 265 |  | 
|  | 266 | #ifdef CONFIG_INOTIFY	/* inotify helpers */ | 
|  | 267 |  | 
|  | 268 | /* | 
|  | 269 | * fsnotify_oldname_init - save off the old filename before we change it | 
|  | 270 | */ | 
|  | 271 | static inline const char *fsnotify_oldname_init(const char *name) | 
|  | 272 | { | 
|  | 273 | return kstrdup(name, GFP_KERNEL); | 
|  | 274 | } | 
|  | 275 |  | 
|  | 276 | /* | 
|  | 277 | * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init | 
|  | 278 | */ | 
|  | 279 | static inline void fsnotify_oldname_free(const char *old_name) | 
|  | 280 | { | 
|  | 281 | kfree(old_name); | 
|  | 282 | } | 
|  | 283 |  | 
|  | 284 | #else	/* CONFIG_INOTIFY */ | 
|  | 285 |  | 
|  | 286 | static inline const char *fsnotify_oldname_init(const char *name) | 
|  | 287 | { | 
|  | 288 | return NULL; | 
|  | 289 | } | 
|  | 290 |  | 
|  | 291 | static inline void fsnotify_oldname_free(const char *old_name) | 
|  | 292 | { | 
|  | 293 | } | 
|  | 294 |  | 
|  | 295 | #endif	/* ! CONFIG_INOTIFY */ | 
|  | 296 |  | 
| Robert Love | 0eeca28 | 2005-07-12 17:06:03 -0400 | [diff] [blame] | 297 | #endif	/* _LINUX_FS_NOTIFY_H */ |