blob: 6c9ebefdac8e4f24b680beaf0215b3d09808d2fd [file] [log] [blame]
Robert Love0eeca282005-07-12 17:06:03 -04001#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 Love0eeca282005-07-12 17:06:03 -040014#include <linux/dnotify.h>
15#include <linux/inotify.h>
Eric Paris90586522009-05-21 17:01:20 -040016#include <linux/fsnotify_backend.h>
Amy Griffis73241cc2005-11-03 16:00:25 +000017#include <linux/audit.h>
Robert Love0eeca282005-07-12 17:06:03 -040018
19/*
Nick Pigginc32ccd82006-03-25 03:07:09 -080020 * fsnotify_d_instantiate - instantiate a dentry for inode
21 * Called with dcache_lock held.
22 */
23static 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 */
33static inline void fsnotify_d_move(struct dentry *entry)
34{
35 inotify_d_move(entry);
36}
37
38/*
Eric Paris90586522009-05-21 17:01:20 -040039 * fsnotify_link_count - inode's link count changed
40 */
41static 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/*
Robert Love0eeca282005-07-12 17:06:03 -040049 * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
50 */
51static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
52 const char *old_name, const char *new_name,
Al Viro5a190ae2007-06-07 12:19:32 -040053 int isdir, struct inode *target, struct dentry *moved)
Robert Love0eeca282005-07-12 17:06:03 -040054{
Al Viro5a190ae2007-06-07 12:19:32 -040055 struct inode *source = moved->d_inode;
Robert Love0eeca282005-07-12 17:06:03 -040056 u32 cookie = inotify_get_cookie();
Eric Paris90586522009-05-21 17:01:20 -040057 __u32 old_dir_mask = 0;
58 __u32 new_dir_mask = 0;
Robert Love0eeca282005-07-12 17:06:03 -040059
Eric Paris90586522009-05-21 17:01:20 -040060 if (old_dir == new_dir) {
Robert Love0eeca282005-07-12 17:06:03 -040061 inode_dir_notify(old_dir, DN_RENAME);
Eric Paris90586522009-05-21 17:01:20 -040062 old_dir_mask = FS_DN_RENAME;
63 } else {
Robert Love0eeca282005-07-12 17:06:03 -040064 inode_dir_notify(old_dir, DN_DELETE);
Eric Paris90586522009-05-21 17:01:20 -040065 old_dir_mask = FS_DELETE;
Robert Love0eeca282005-07-12 17:06:03 -040066 inode_dir_notify(new_dir, DN_CREATE);
Eric Paris90586522009-05-21 17:01:20 -040067 new_dir_mask = FS_CREATE;
Robert Love0eeca282005-07-12 17:06:03 -040068 }
69
Eric Paris90586522009-05-21 17:01:20 -040070 if (isdir) {
Robert Love0eeca282005-07-12 17:06:03 -040071 isdir = IN_ISDIR;
Eric Paris90586522009-05-21 17:01:20 -040072 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
Amy Griffis7c297722006-06-01 13:11:01 -070079 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);
John McCutchan75449532005-08-01 11:00:45 -040083
Eric Paris90586522009-05-21 17:01:20 -040084 fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE);
85 fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE);
86
John McCutchan75449532005-08-01 11:00:45 -040087 if (target) {
Amy Griffis7c297722006-06-01 13:11:01 -070088 inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL);
John McCutchan75449532005-08-01 11:00:45 -040089 inotify_inode_is_dead(target);
Eric Paris90586522009-05-21 17:01:20 -040090
91 /* this is really a link_count change not a removal */
92 fsnotify_link_count(target);
John McCutchan75449532005-08-01 11:00:45 -040093 }
John McCutchan89204c42005-08-15 12:13:28 -040094
95 if (source) {
Amy Griffis7c297722006-06-01 13:11:01 -070096 inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -040097 fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE);
John McCutchan89204c42005-08-15 12:13:28 -040098 }
Al Viro5a190ae2007-06-07 12:19:32 -040099 audit_inode_child(new_name, moved, new_dir);
Robert Love0eeca282005-07-12 17:06:03 -0400100}
101
102/*
John McCutchan7a91bf72005-08-08 13:52:16 -0400103 * fsnotify_nameremove - a filename was removed from a directory
104 */
105static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
106{
Eric Paris90586522009-05-21 17:01:20 -0400107 __u32 mask = FS_DELETE;
108
John McCutchan7a91bf72005-08-08 13:52:16 -0400109 if (isdir)
Eric Paris90586522009-05-21 17:01:20 -0400110 mask |= FS_IN_ISDIR;
John McCutchan7a91bf72005-08-08 13:52:16 -0400111 dnotify_parent(dentry, DN_DELETE);
Eric Paris90586522009-05-21 17:01:20 -0400112 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
John McCutchan7a91bf72005-08-08 13:52:16 -0400113}
114
115/*
116 * fsnotify_inoderemove - an inode is going away
117 */
118static inline void fsnotify_inoderemove(struct inode *inode)
119{
Amy Griffis7c297722006-06-01 13:11:01 -0700120 inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
John McCutchan7a91bf72005-08-08 13:52:16 -0400121 inotify_inode_is_dead(inode);
John McCutchan7a91bf72005-08-08 13:52:16 -0400122
Eric Paris90586522009-05-21 17:01:20 -0400123 fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE);
Jan Karaece95912008-02-06 01:37:13 -0800124}
125
126/*
Robert Love0eeca282005-07-12 17:06:03 -0400127 * fsnotify_create - 'name' was linked in
128 */
Amy Griffisf38aa942005-11-03 15:57:06 +0000129static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
Robert Love0eeca282005-07-12 17:06:03 -0400130{
131 inode_dir_notify(inode, DN_CREATE);
Amy Griffis7c297722006-06-01 13:11:01 -0700132 inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
133 dentry->d_inode);
Al Viro5a190ae2007-06-07 12:19:32 -0400134 audit_inode_child(dentry->d_name.name, dentry, inode);
Eric Paris90586522009-05-21 17:01:20 -0400135
136 fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400137}
138
139/*
Jan Karaece95912008-02-06 01:37:13 -0800140 * 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 */
144static 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);
Eric Paris90586522009-05-21 17:01:20 -0400151
152 fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE);
Jan Karaece95912008-02-06 01:37:13 -0800153}
154
155/*
Robert Love0eeca282005-07-12 17:06:03 -0400156 * fsnotify_mkdir - directory 'name' was created
157 */
Amy Griffisf38aa942005-11-03 15:57:06 +0000158static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
Robert Love0eeca282005-07-12 17:06:03 -0400159{
Eric Paris90586522009-05-21 17:01:20 -0400160 __u32 mask = (FS_CREATE | FS_IN_ISDIR);
161 struct inode *d_inode = dentry->d_inode;
162
Robert Love0eeca282005-07-12 17:06:03 -0400163 inode_dir_notify(inode, DN_CREATE);
Eric Paris90586522009-05-21 17:01:20 -0400164 inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode);
Al Viro5a190ae2007-06-07 12:19:32 -0400165 audit_inode_child(dentry->d_name.name, dentry, inode);
Eric Paris90586522009-05-21 17:01:20 -0400166
167 fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400168}
169
170/*
171 * fsnotify_access - file was read
172 */
173static inline void fsnotify_access(struct dentry *dentry)
174{
175 struct inode *inode = dentry->d_inode;
Eric Paris90586522009-05-21 17:01:20 -0400176 __u32 mask = FS_ACCESS;
Robert Love0eeca282005-07-12 17:06:03 -0400177
178 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400179 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400180
181 dnotify_parent(dentry, DN_ACCESS);
182 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
Amy Griffis7c297722006-06-01 13:11:01 -0700183 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400184
185 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400186}
187
188/*
189 * fsnotify_modify - file was modified
190 */
191static inline void fsnotify_modify(struct dentry *dentry)
192{
193 struct inode *inode = dentry->d_inode;
Eric Paris90586522009-05-21 17:01:20 -0400194 __u32 mask = FS_MODIFY;
Robert Love0eeca282005-07-12 17:06:03 -0400195
196 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400197 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400198
199 dnotify_parent(dentry, DN_MODIFY);
200 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
Amy Griffis7c297722006-06-01 13:11:01 -0700201 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400202
203 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400204}
205
206/*
207 * fsnotify_open - file was opened
208 */
209static inline void fsnotify_open(struct dentry *dentry)
210{
211 struct inode *inode = dentry->d_inode;
Eric Paris90586522009-05-21 17:01:20 -0400212 __u32 mask = FS_OPEN;
Robert Love0eeca282005-07-12 17:06:03 -0400213
214 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400215 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400216
Robert Love0eeca282005-07-12 17:06:03 -0400217 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
Amy Griffis7c297722006-06-01 13:11:01 -0700218 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400219
220 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400221}
222
223/*
224 * fsnotify_close - file was closed
225 */
226static inline void fsnotify_close(struct file *file)
227{
Josef "Jeff" Sipek0f7fc9e2006-12-08 02:36:35 -0800228 struct dentry *dentry = file->f_path.dentry;
Robert Love0eeca282005-07-12 17:06:03 -0400229 struct inode *inode = dentry->d_inode;
230 const char *name = dentry->d_name.name;
Al Viroaeb5d722008-09-02 15:28:45 -0400231 fmode_t mode = file->f_mode;
Eric Paris90586522009-05-21 17:01:20 -0400232 __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
Robert Love0eeca282005-07-12 17:06:03 -0400233
234 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400235 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400236
237 inotify_dentry_parent_queue_event(dentry, mask, 0, name);
Amy Griffis7c297722006-06-01 13:11:01 -0700238 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400239
240 fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE);
Robert Love0eeca282005-07-12 17:06:03 -0400241}
242
243/*
244 * fsnotify_xattr - extended attributes were changed
245 */
246static inline void fsnotify_xattr(struct dentry *dentry)
247{
248 struct inode *inode = dentry->d_inode;
Eric Paris90586522009-05-21 17:01:20 -0400249 __u32 mask = FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400250
251 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400252 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400253
254 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
Amy Griffis7c297722006-06-01 13:11:01 -0700255 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400256
257 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400258}
259
260/*
261 * fsnotify_change - notify_change event. file was modified and/or metadata
262 * was changed.
263 */
264static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
265{
266 struct inode *inode = dentry->d_inode;
267 int dn_mask = 0;
Eric Paris90586522009-05-21 17:01:20 -0400268 __u32 in_mask = 0;
Robert Love0eeca282005-07-12 17:06:03 -0400269
270 if (ia_valid & ATTR_UID) {
Eric Paris90586522009-05-21 17:01:20 -0400271 in_mask |= FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400272 dn_mask |= DN_ATTRIB;
273 }
274 if (ia_valid & ATTR_GID) {
Eric Paris90586522009-05-21 17:01:20 -0400275 in_mask |= FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400276 dn_mask |= DN_ATTRIB;
277 }
278 if (ia_valid & ATTR_SIZE) {
Eric Paris90586522009-05-21 17:01:20 -0400279 in_mask |= FS_MODIFY;
Robert Love0eeca282005-07-12 17:06:03 -0400280 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 {
Eric Paris90586522009-05-21 17:01:20 -0400285 in_mask |= FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400286 dn_mask |= DN_ATTRIB;
287 } else if (ia_valid & ATTR_ATIME) {
Eric Paris90586522009-05-21 17:01:20 -0400288 in_mask |= FS_ACCESS;
Robert Love0eeca282005-07-12 17:06:03 -0400289 dn_mask |= DN_ACCESS;
290 } else if (ia_valid & ATTR_MTIME) {
Eric Paris90586522009-05-21 17:01:20 -0400291 in_mask |= FS_MODIFY;
Robert Love0eeca282005-07-12 17:06:03 -0400292 dn_mask |= DN_MODIFY;
293 }
294 if (ia_valid & ATTR_MODE) {
Eric Paris90586522009-05-21 17:01:20 -0400295 in_mask |= FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400296 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))
Eric Paris90586522009-05-21 17:01:20 -0400303 in_mask |= FS_IN_ISDIR;
Amy Griffis7c297722006-06-01 13:11:01 -0700304 inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL);
Robert Love0eeca282005-07-12 17:06:03 -0400305 inotify_dentry_parent_queue_event(dentry, in_mask, 0,
306 dentry->d_name.name);
Eric Paris90586522009-05-21 17:01:20 -0400307 fsnotify(inode, in_mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400308 }
309}
310
Eric Paris90586522009-05-21 17:01:20 -0400311#if defined(CONFIG_INOTIFY) || defined(CONFIG_FSNOTIFY) /* notify helpers */
Robert Love0eeca282005-07-12 17:06:03 -0400312
313/*
314 * fsnotify_oldname_init - save off the old filename before we change it
315 */
316static 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 */
324static inline void fsnotify_oldname_free(const char *old_name)
325{
326 kfree(old_name);
327}
328
Eric Paris90586522009-05-21 17:01:20 -0400329#else /* CONFIG_INOTIFY || CONFIG_FSNOTIFY */
Robert Love0eeca282005-07-12 17:06:03 -0400330
331static inline const char *fsnotify_oldname_init(const char *name)
332{
333 return NULL;
334}
335
336static inline void fsnotify_oldname_free(const char *old_name)
337{
338}
339
340#endif /* ! CONFIG_INOTIFY */
341
Robert Love0eeca282005-07-12 17:06:03 -0400342#endif /* _LINUX_FS_NOTIFY_H */