blob: 3856eb6e597313960ce409c25dd29b5193dca633 [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/*
Eric Paris3be25f42009-05-21 17:01:26 -0400103 * fsnotify_inode_delete - and inode is being evicted from cache, clean up is needed
104 */
105static inline void fsnotify_inode_delete(struct inode *inode)
106{
107 __fsnotify_inode_delete(inode);
108}
109
110/*
John McCutchan7a91bf72005-08-08 13:52:16 -0400111 * fsnotify_nameremove - a filename was removed from a directory
112 */
113static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
114{
Eric Paris90586522009-05-21 17:01:20 -0400115 __u32 mask = FS_DELETE;
116
John McCutchan7a91bf72005-08-08 13:52:16 -0400117 if (isdir)
Eric Paris90586522009-05-21 17:01:20 -0400118 mask |= FS_IN_ISDIR;
John McCutchan7a91bf72005-08-08 13:52:16 -0400119 dnotify_parent(dentry, DN_DELETE);
Eric Paris90586522009-05-21 17:01:20 -0400120 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
John McCutchan7a91bf72005-08-08 13:52:16 -0400121}
122
123/*
124 * fsnotify_inoderemove - an inode is going away
125 */
126static inline void fsnotify_inoderemove(struct inode *inode)
127{
Amy Griffis7c297722006-06-01 13:11:01 -0700128 inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
John McCutchan7a91bf72005-08-08 13:52:16 -0400129 inotify_inode_is_dead(inode);
John McCutchan7a91bf72005-08-08 13:52:16 -0400130
Eric Paris90586522009-05-21 17:01:20 -0400131 fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE);
Eric Paris3be25f42009-05-21 17:01:26 -0400132 __fsnotify_inode_delete(inode);
Jan Karaece95912008-02-06 01:37:13 -0800133}
134
135/*
Robert Love0eeca282005-07-12 17:06:03 -0400136 * fsnotify_create - 'name' was linked in
137 */
Amy Griffisf38aa942005-11-03 15:57:06 +0000138static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
Robert Love0eeca282005-07-12 17:06:03 -0400139{
140 inode_dir_notify(inode, DN_CREATE);
Amy Griffis7c297722006-06-01 13:11:01 -0700141 inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
142 dentry->d_inode);
Al Viro5a190ae2007-06-07 12:19:32 -0400143 audit_inode_child(dentry->d_name.name, dentry, inode);
Eric Paris90586522009-05-21 17:01:20 -0400144
145 fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400146}
147
148/*
Jan Karaece95912008-02-06 01:37:13 -0800149 * fsnotify_link - new hardlink in 'inode' directory
150 * Note: We have to pass also the linked inode ptr as some filesystems leave
151 * new_dentry->d_inode NULL and instantiate inode pointer later
152 */
153static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
154{
155 inode_dir_notify(dir, DN_CREATE);
156 inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name,
157 inode);
158 fsnotify_link_count(inode);
159 audit_inode_child(new_dentry->d_name.name, new_dentry, dir);
Eric Paris90586522009-05-21 17:01:20 -0400160
161 fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE);
Jan Karaece95912008-02-06 01:37:13 -0800162}
163
164/*
Robert Love0eeca282005-07-12 17:06:03 -0400165 * fsnotify_mkdir - directory 'name' was created
166 */
Amy Griffisf38aa942005-11-03 15:57:06 +0000167static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
Robert Love0eeca282005-07-12 17:06:03 -0400168{
Eric Paris90586522009-05-21 17:01:20 -0400169 __u32 mask = (FS_CREATE | FS_IN_ISDIR);
170 struct inode *d_inode = dentry->d_inode;
171
Robert Love0eeca282005-07-12 17:06:03 -0400172 inode_dir_notify(inode, DN_CREATE);
Eric Paris90586522009-05-21 17:01:20 -0400173 inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode);
Al Viro5a190ae2007-06-07 12:19:32 -0400174 audit_inode_child(dentry->d_name.name, dentry, inode);
Eric Paris90586522009-05-21 17:01:20 -0400175
176 fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400177}
178
179/*
180 * fsnotify_access - file was read
181 */
182static inline void fsnotify_access(struct dentry *dentry)
183{
184 struct inode *inode = dentry->d_inode;
Eric Paris90586522009-05-21 17:01:20 -0400185 __u32 mask = FS_ACCESS;
Robert Love0eeca282005-07-12 17:06:03 -0400186
187 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400188 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400189
190 dnotify_parent(dentry, DN_ACCESS);
191 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
Amy Griffis7c297722006-06-01 13:11:01 -0700192 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400193
194 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400195}
196
197/*
198 * fsnotify_modify - file was modified
199 */
200static inline void fsnotify_modify(struct dentry *dentry)
201{
202 struct inode *inode = dentry->d_inode;
Eric Paris90586522009-05-21 17:01:20 -0400203 __u32 mask = FS_MODIFY;
Robert Love0eeca282005-07-12 17:06:03 -0400204
205 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400206 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400207
208 dnotify_parent(dentry, DN_MODIFY);
209 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
Amy Griffis7c297722006-06-01 13:11:01 -0700210 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400211
212 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400213}
214
215/*
216 * fsnotify_open - file was opened
217 */
218static inline void fsnotify_open(struct dentry *dentry)
219{
220 struct inode *inode = dentry->d_inode;
Eric Paris90586522009-05-21 17:01:20 -0400221 __u32 mask = FS_OPEN;
Robert Love0eeca282005-07-12 17:06:03 -0400222
223 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400224 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400225
Robert Love0eeca282005-07-12 17:06:03 -0400226 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
Amy Griffis7c297722006-06-01 13:11:01 -0700227 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400228
229 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400230}
231
232/*
233 * fsnotify_close - file was closed
234 */
235static inline void fsnotify_close(struct file *file)
236{
Josef "Jeff" Sipek0f7fc9e2006-12-08 02:36:35 -0800237 struct dentry *dentry = file->f_path.dentry;
Robert Love0eeca282005-07-12 17:06:03 -0400238 struct inode *inode = dentry->d_inode;
239 const char *name = dentry->d_name.name;
Al Viroaeb5d722008-09-02 15:28:45 -0400240 fmode_t mode = file->f_mode;
Eric Paris90586522009-05-21 17:01:20 -0400241 __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
Robert Love0eeca282005-07-12 17:06:03 -0400242
243 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400244 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400245
246 inotify_dentry_parent_queue_event(dentry, mask, 0, name);
Amy Griffis7c297722006-06-01 13:11:01 -0700247 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400248
249 fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE);
Robert Love0eeca282005-07-12 17:06:03 -0400250}
251
252/*
253 * fsnotify_xattr - extended attributes were changed
254 */
255static inline void fsnotify_xattr(struct dentry *dentry)
256{
257 struct inode *inode = dentry->d_inode;
Eric Paris90586522009-05-21 17:01:20 -0400258 __u32 mask = FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400259
260 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400261 mask |= FS_IN_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400262
263 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
Amy Griffis7c297722006-06-01 13:11:01 -0700264 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
Eric Paris90586522009-05-21 17:01:20 -0400265
266 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400267}
268
269/*
270 * fsnotify_change - notify_change event. file was modified and/or metadata
271 * was changed.
272 */
273static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
274{
275 struct inode *inode = dentry->d_inode;
276 int dn_mask = 0;
Eric Paris90586522009-05-21 17:01:20 -0400277 __u32 in_mask = 0;
Robert Love0eeca282005-07-12 17:06:03 -0400278
279 if (ia_valid & ATTR_UID) {
Eric Paris90586522009-05-21 17:01:20 -0400280 in_mask |= FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400281 dn_mask |= DN_ATTRIB;
282 }
283 if (ia_valid & ATTR_GID) {
Eric Paris90586522009-05-21 17:01:20 -0400284 in_mask |= FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400285 dn_mask |= DN_ATTRIB;
286 }
287 if (ia_valid & ATTR_SIZE) {
Eric Paris90586522009-05-21 17:01:20 -0400288 in_mask |= FS_MODIFY;
Robert Love0eeca282005-07-12 17:06:03 -0400289 dn_mask |= DN_MODIFY;
290 }
291 /* both times implies a utime(s) call */
292 if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME))
293 {
Eric Paris90586522009-05-21 17:01:20 -0400294 in_mask |= FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400295 dn_mask |= DN_ATTRIB;
296 } else if (ia_valid & ATTR_ATIME) {
Eric Paris90586522009-05-21 17:01:20 -0400297 in_mask |= FS_ACCESS;
Robert Love0eeca282005-07-12 17:06:03 -0400298 dn_mask |= DN_ACCESS;
299 } else if (ia_valid & ATTR_MTIME) {
Eric Paris90586522009-05-21 17:01:20 -0400300 in_mask |= FS_MODIFY;
Robert Love0eeca282005-07-12 17:06:03 -0400301 dn_mask |= DN_MODIFY;
302 }
303 if (ia_valid & ATTR_MODE) {
Eric Paris90586522009-05-21 17:01:20 -0400304 in_mask |= FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400305 dn_mask |= DN_ATTRIB;
306 }
307
308 if (dn_mask)
309 dnotify_parent(dentry, dn_mask);
310 if (in_mask) {
311 if (S_ISDIR(inode->i_mode))
Eric Paris90586522009-05-21 17:01:20 -0400312 in_mask |= FS_IN_ISDIR;
Amy Griffis7c297722006-06-01 13:11:01 -0700313 inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL);
Robert Love0eeca282005-07-12 17:06:03 -0400314 inotify_dentry_parent_queue_event(dentry, in_mask, 0,
315 dentry->d_name.name);
Eric Paris90586522009-05-21 17:01:20 -0400316 fsnotify(inode, in_mask, inode, FSNOTIFY_EVENT_INODE);
Robert Love0eeca282005-07-12 17:06:03 -0400317 }
318}
319
Eric Paris90586522009-05-21 17:01:20 -0400320#if defined(CONFIG_INOTIFY) || defined(CONFIG_FSNOTIFY) /* notify helpers */
Robert Love0eeca282005-07-12 17:06:03 -0400321
322/*
323 * fsnotify_oldname_init - save off the old filename before we change it
324 */
325static inline const char *fsnotify_oldname_init(const char *name)
326{
327 return kstrdup(name, GFP_KERNEL);
328}
329
330/*
331 * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init
332 */
333static inline void fsnotify_oldname_free(const char *old_name)
334{
335 kfree(old_name);
336}
337
Eric Paris90586522009-05-21 17:01:20 -0400338#else /* CONFIG_INOTIFY || CONFIG_FSNOTIFY */
Robert Love0eeca282005-07-12 17:06:03 -0400339
340static inline const char *fsnotify_oldname_init(const char *name)
341{
342 return NULL;
343}
344
345static inline void fsnotify_oldname_free(const char *old_name)
346{
347}
348
349#endif /* ! CONFIG_INOTIFY */
350
Robert Love0eeca282005-07-12 17:06:03 -0400351#endif /* _LINUX_FS_NOTIFY_H */