fsnotify: unified filesystem notification backend
[linux-2.6] / include / linux / fsnotify.h
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
14 #include <linux/dnotify.h>
15 #include <linux/inotify.h>
16 #include <linux/fsnotify_backend.h>
17 #include <linux/audit.h>
18
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 /*
39  * fsnotify_link_count - inode's link count changed
40  */
41 static inline void fsnotify_link_count(struct inode *inode)
42 {
43         inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
44
45         fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE);
46 }
47
48 /*
49  * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
50  */
51 static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
52                                  const char *old_name, const char *new_name,
53                                  int isdir, struct inode *target, struct dentry *moved)
54 {
55         struct inode *source = moved->d_inode;
56         u32 cookie = inotify_get_cookie();
57         __u32 old_dir_mask = 0;
58         __u32 new_dir_mask = 0;
59
60         if (old_dir == new_dir) {
61                 inode_dir_notify(old_dir, DN_RENAME);
62                 old_dir_mask = FS_DN_RENAME;
63         } else {
64                 inode_dir_notify(old_dir, DN_DELETE);
65                 old_dir_mask = FS_DELETE;
66                 inode_dir_notify(new_dir, DN_CREATE);
67                 new_dir_mask = FS_CREATE;
68         }
69
70         if (isdir) {
71                 isdir = IN_ISDIR;
72                 old_dir_mask |= FS_IN_ISDIR;
73                 new_dir_mask |= FS_IN_ISDIR;
74         }
75
76         old_dir_mask |= FS_MOVED_FROM;
77         new_dir_mask |= FS_MOVED_TO;
78
79         inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name,
80                                   source);
81         inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name,
82                                   source);
83
84         fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE);
85         fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE);
86
87         if (target) {
88                 inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL);
89                 inotify_inode_is_dead(target);
90
91                 /* this is really a link_count change not a removal */
92                 fsnotify_link_count(target);
93         }
94
95         if (source) {
96                 inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
97                 fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE);
98         }
99         audit_inode_child(new_name, moved, new_dir);
100 }
101
102 /*
103  * fsnotify_nameremove - a filename was removed from a directory
104  */
105 static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
106 {
107         __u32 mask = FS_DELETE;
108
109         if (isdir)
110                 mask |= FS_IN_ISDIR;
111         dnotify_parent(dentry, DN_DELETE);
112         inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
113 }
114
115 /*
116  * fsnotify_inoderemove - an inode is going away
117  */
118 static inline void fsnotify_inoderemove(struct inode *inode)
119 {
120         inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
121         inotify_inode_is_dead(inode);
122
123         fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE);
124 }
125
126 /*
127  * fsnotify_create - 'name' was linked in
128  */
129 static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
130 {
131         inode_dir_notify(inode, DN_CREATE);
132         inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
133                                   dentry->d_inode);
134         audit_inode_child(dentry->d_name.name, dentry, inode);
135
136         fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE);
137 }
138
139 /*
140  * fsnotify_link - new hardlink in 'inode' directory
141  * Note: We have to pass also the linked inode ptr as some filesystems leave
142  *   new_dentry->d_inode NULL and instantiate inode pointer later
143  */
144 static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
145 {
146         inode_dir_notify(dir, DN_CREATE);
147         inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name,
148                                   inode);
149         fsnotify_link_count(inode);
150         audit_inode_child(new_dentry->d_name.name, new_dentry, dir);
151
152         fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE);
153 }
154
155 /*
156  * fsnotify_mkdir - directory 'name' was created
157  */
158 static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
159 {
160         __u32 mask = (FS_CREATE | FS_IN_ISDIR);
161         struct inode *d_inode = dentry->d_inode;
162
163         inode_dir_notify(inode, DN_CREATE);
164         inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode);
165         audit_inode_child(dentry->d_name.name, dentry, inode);
166
167         fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE);
168 }
169
170 /*
171  * fsnotify_access - file was read
172  */
173 static inline void fsnotify_access(struct dentry *dentry)
174 {
175         struct inode *inode = dentry->d_inode;
176         __u32 mask = FS_ACCESS;
177
178         if (S_ISDIR(inode->i_mode))
179                 mask |= FS_IN_ISDIR;
180
181         dnotify_parent(dentry, DN_ACCESS);
182         inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
183         inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
184
185         fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
186 }
187
188 /*
189  * fsnotify_modify - file was modified
190  */
191 static inline void fsnotify_modify(struct dentry *dentry)
192 {
193         struct inode *inode = dentry->d_inode;
194         __u32 mask = FS_MODIFY;
195
196         if (S_ISDIR(inode->i_mode))
197                 mask |= FS_IN_ISDIR;
198
199         dnotify_parent(dentry, DN_MODIFY);
200         inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
201         inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
202
203         fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
204 }
205
206 /*
207  * fsnotify_open - file was opened
208  */
209 static inline void fsnotify_open(struct dentry *dentry)
210 {
211         struct inode *inode = dentry->d_inode;
212         __u32 mask = FS_OPEN;
213
214         if (S_ISDIR(inode->i_mode))
215                 mask |= FS_IN_ISDIR;
216
217         inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
218         inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
219
220         fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
221 }
222
223 /*
224  * fsnotify_close - file was closed
225  */
226 static inline void fsnotify_close(struct file *file)
227 {
228         struct dentry *dentry = file->f_path.dentry;
229         struct inode *inode = dentry->d_inode;
230         const char *name = dentry->d_name.name;
231         fmode_t mode = file->f_mode;
232         __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
233
234         if (S_ISDIR(inode->i_mode))
235                 mask |= FS_IN_ISDIR;
236
237         inotify_dentry_parent_queue_event(dentry, mask, 0, name);
238         inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
239
240         fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE);
241 }
242
243 /*
244  * fsnotify_xattr - extended attributes were changed
245  */
246 static inline void fsnotify_xattr(struct dentry *dentry)
247 {
248         struct inode *inode = dentry->d_inode;
249         __u32 mask = FS_ATTRIB;
250
251         if (S_ISDIR(inode->i_mode))
252                 mask |= FS_IN_ISDIR;
253
254         inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
255         inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
256
257         fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
258 }
259
260 /*
261  * fsnotify_change - notify_change event.  file was modified and/or metadata
262  * was changed.
263  */
264 static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
265 {
266         struct inode *inode = dentry->d_inode;
267         int dn_mask = 0;
268         __u32 in_mask = 0;
269
270         if (ia_valid & ATTR_UID) {
271                 in_mask |= FS_ATTRIB;
272                 dn_mask |= DN_ATTRIB;
273         }
274         if (ia_valid & ATTR_GID) {
275                 in_mask |= FS_ATTRIB;
276                 dn_mask |= DN_ATTRIB;
277         }
278         if (ia_valid & ATTR_SIZE) {
279                 in_mask |= FS_MODIFY;
280                 dn_mask |= DN_MODIFY;
281         }
282         /* both times implies a utime(s) call */
283         if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME))
284         {
285                 in_mask |= FS_ATTRIB;
286                 dn_mask |= DN_ATTRIB;
287         } else if (ia_valid & ATTR_ATIME) {
288                 in_mask |= FS_ACCESS;
289                 dn_mask |= DN_ACCESS;
290         } else if (ia_valid & ATTR_MTIME) {
291                 in_mask |= FS_MODIFY;
292                 dn_mask |= DN_MODIFY;
293         }
294         if (ia_valid & ATTR_MODE) {
295                 in_mask |= FS_ATTRIB;
296                 dn_mask |= DN_ATTRIB;
297         }
298
299         if (dn_mask)
300                 dnotify_parent(dentry, dn_mask);
301         if (in_mask) {
302                 if (S_ISDIR(inode->i_mode))
303                         in_mask |= FS_IN_ISDIR;
304                 inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL);
305                 inotify_dentry_parent_queue_event(dentry, in_mask, 0,
306                                                   dentry->d_name.name);
307                 fsnotify(inode, in_mask, inode, FSNOTIFY_EVENT_INODE);
308         }
309 }
310
311 #if defined(CONFIG_INOTIFY) || defined(CONFIG_FSNOTIFY) /* notify helpers */
312
313 /*
314  * fsnotify_oldname_init - save off the old filename before we change it
315  */
316 static inline const char *fsnotify_oldname_init(const char *name)
317 {
318         return kstrdup(name, GFP_KERNEL);
319 }
320
321 /*
322  * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init
323  */
324 static inline void fsnotify_oldname_free(const char *old_name)
325 {
326         kfree(old_name);
327 }
328
329 #else   /* CONFIG_INOTIFY || CONFIG_FSNOTIFY */
330
331 static inline const char *fsnotify_oldname_init(const char *name)
332 {
333         return NULL;
334 }
335
336 static inline void fsnotify_oldname_free(const char *old_name)
337 {
338 }
339
340 #endif  /* ! CONFIG_INOTIFY */
341
342 #endif  /* _LINUX_FS_NOTIFY_H */