xref: /linux-6.15/include/linux/fsnotify.h (revision 066e053f)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
20eeca283SRobert Love #ifndef _LINUX_FS_NOTIFY_H
30eeca283SRobert Love #define _LINUX_FS_NOTIFY_H
40eeca283SRobert Love 
50eeca283SRobert Love /*
60eeca283SRobert Love  * include/linux/fsnotify.h - generic hooks for filesystem notification, to
70eeca283SRobert Love  * reduce in-source duplication from both dnotify and inotify.
80eeca283SRobert Love  *
90eeca283SRobert Love  * We don't compile any of this away in some complicated menagerie of ifdefs.
100eeca283SRobert Love  * Instead, we rely on the code inside to optimize away as needed.
110eeca283SRobert Love  *
120eeca283SRobert Love  * (C) Copyright 2005 Robert Love
130eeca283SRobert Love  */
140eeca283SRobert Love 
1590586523SEric Paris #include <linux/fsnotify_backend.h>
1673241cccSAmy Griffis #include <linux/audit.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
18187f1882SPaul Gortmaker #include <linux/bug.h>
190eeca283SRobert Love 
20a5e57b4dSAmir Goldstein /* Are there any inode/mount/sb objects watched with priority prio or above? */
fsnotify_sb_has_priority_watchers(struct super_block * sb,int prio)21a5e57b4dSAmir Goldstein static inline bool fsnotify_sb_has_priority_watchers(struct super_block *sb,
22a5e57b4dSAmir Goldstein 						     int prio)
23b7dbaaceSAmir Goldstein {
24cb5d4f48SAmir Goldstein 	struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);
25cb5d4f48SAmir Goldstein 
26cb5d4f48SAmir Goldstein 	/* Were any marks ever added to any object on this sb? */
27cb5d4f48SAmir Goldstein 	if (!sbinfo)
28cb5d4f48SAmir Goldstein 		return false;
29cb5d4f48SAmir Goldstein 
30a5e57b4dSAmir Goldstein 	return atomic_long_read(&sbinfo->watched_objects[prio]);
31a5e57b4dSAmir Goldstein }
32a5e57b4dSAmir Goldstein 
33a5e57b4dSAmir Goldstein /* Are there any inode/mount/sb objects that are being watched at all? */
fsnotify_sb_has_watchers(struct super_block * sb)34a5e57b4dSAmir Goldstein static inline bool fsnotify_sb_has_watchers(struct super_block *sb)
35a5e57b4dSAmir Goldstein {
36a5e57b4dSAmir Goldstein 	return fsnotify_sb_has_priority_watchers(sb, 0);
37b7dbaaceSAmir Goldstein }
38b7dbaaceSAmir Goldstein 
395f02a877SAmir Goldstein /*
40a1aae057SAmir Goldstein  * Notify this @dir inode about a change in a child directory entry.
41a1aae057SAmir Goldstein  * The directory entry may have turned positive or negative or its inode may
42a1aae057SAmir Goldstein  * have changed (i.e. renamed over).
435f02a877SAmir Goldstein  *
445f02a877SAmir Goldstein  * Unlike fsnotify_parent(), the event will be reported regardless of the
4540a100d3SAmir Goldstein  * FS_EVENT_ON_CHILD mask on the parent inode and will not be reported if only
4640a100d3SAmir Goldstein  * the child is interested and not the parent.
475f02a877SAmir Goldstein  */
fsnotify_name(__u32 mask,const void * data,int data_type,struct inode * dir,const struct qstr * name,u32 cookie)489baf93d6SAmir Goldstein static inline int fsnotify_name(__u32 mask, const void *data, int data_type,
499baf93d6SAmir Goldstein 				struct inode *dir, const struct qstr *name,
509baf93d6SAmir Goldstein 				u32 cookie)
51a1aae057SAmir Goldstein {
52b7dbaaceSAmir Goldstein 	if (!fsnotify_sb_has_watchers(dir->i_sb))
539baf93d6SAmir Goldstein 		return 0;
54e43de7f0SAmir Goldstein 
559baf93d6SAmir Goldstein 	return fsnotify(mask, data, data_type, dir, name, NULL, cookie);
56a1aae057SAmir Goldstein }
57a1aae057SAmir Goldstein 
fsnotify_dirent(struct inode * dir,struct dentry * dentry,__u32 mask)58a1aae057SAmir Goldstein static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry,
595f02a877SAmir Goldstein 				   __u32 mask)
605f02a877SAmir Goldstein {
61fd5a3ff4SAmir Goldstein 	fsnotify_name(mask, dentry, FSNOTIFY_EVENT_DENTRY, dir, &dentry->d_name, 0);
625f02a877SAmir Goldstein }
635f02a877SAmir Goldstein 
fsnotify_inode(struct inode * inode,__u32 mask)6482ace1efSAmir Goldstein static inline void fsnotify_inode(struct inode *inode, __u32 mask)
6582ace1efSAmir Goldstein {
66b7dbaaceSAmir Goldstein 	if (!fsnotify_sb_has_watchers(inode->i_sb))
67e43de7f0SAmir Goldstein 		return;
68e43de7f0SAmir Goldstein 
6982ace1efSAmir Goldstein 	if (S_ISDIR(inode->i_mode))
7082ace1efSAmir Goldstein 		mask |= FS_ISDIR;
7182ace1efSAmir Goldstein 
7240a100d3SAmir Goldstein 	fsnotify(mask, inode, FSNOTIFY_EVENT_INODE, NULL, NULL, inode, 0);
7382ace1efSAmir Goldstein }
7482ace1efSAmir Goldstein 
7571d73410SMel Gorman /* Notify this dentry's parent about a child's events. */
fsnotify_parent(struct dentry * dentry,__u32 mask,const void * data,int data_type)7671d73410SMel Gorman static inline int fsnotify_parent(struct dentry *dentry, __u32 mask,
7771d73410SMel Gorman 				  const void *data, int data_type)
7871d73410SMel Gorman {
79eae36a2bSAmir Goldstein 	struct inode *inode = d_inode(dentry);
80a704bba5SMatthew Bobrowski 
81b7dbaaceSAmir Goldstein 	if (!fsnotify_sb_has_watchers(inode->i_sb))
82e43de7f0SAmir Goldstein 		return 0;
83e43de7f0SAmir Goldstein 
849b93f331SAmir Goldstein 	if (S_ISDIR(inode->i_mode)) {
85eae36a2bSAmir Goldstein 		mask |= FS_ISDIR;
86eae36a2bSAmir Goldstein 
879b93f331SAmir Goldstein 		/* sb/mount marks are not interested in name of directory */
88c738fbabSAmir Goldstein 		if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
89c738fbabSAmir Goldstein 			goto notify_child;
909b93f331SAmir Goldstein 	}
919b93f331SAmir Goldstein 
929b93f331SAmir Goldstein 	/* disconnected dentry cannot notify parent */
939b93f331SAmir Goldstein 	if (IS_ROOT(dentry))
949b93f331SAmir Goldstein 		goto notify_child;
95c738fbabSAmir Goldstein 
96c738fbabSAmir Goldstein 	return __fsnotify_parent(dentry, mask, data, data_type);
97c738fbabSAmir Goldstein 
98c738fbabSAmir Goldstein notify_child:
9940a100d3SAmir Goldstein 	return fsnotify(mask, data, data_type, NULL, NULL, inode, 0);
100c738fbabSAmir Goldstein }
101c738fbabSAmir Goldstein 
102c738fbabSAmir Goldstein /*
103c738fbabSAmir Goldstein  * Simple wrappers to consolidate calls to fsnotify_parent() when an event
104c738fbabSAmir Goldstein  * is on a file/dentry.
105c738fbabSAmir Goldstein  */
fsnotify_dentry(struct dentry * dentry,__u32 mask)106c738fbabSAmir Goldstein static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask)
107c738fbabSAmir Goldstein {
108fd5a3ff4SAmir Goldstein 	fsnotify_parent(dentry, mask, dentry, FSNOTIFY_EVENT_DENTRY);
109eae36a2bSAmir Goldstein }
110eae36a2bSAmir Goldstein 
fsnotify_path(const struct path * path,__u32 mask)111a94204f4SAmir Goldstein static inline int fsnotify_path(const struct path *path, __u32 mask)
112a94204f4SAmir Goldstein {
113a94204f4SAmir Goldstein 	return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH);
114a94204f4SAmir Goldstein }
115a94204f4SAmir Goldstein 
fsnotify_file(struct file * file,__u32 mask)116eae36a2bSAmir Goldstein static inline int fsnotify_file(struct file *file, __u32 mask)
117eae36a2bSAmir Goldstein {
118702eb71fSJan Kara 	/*
119702eb71fSJan Kara 	 * FMODE_NONOTIFY are fds generated by fanotify itself which should not
120702eb71fSJan Kara 	 * generate new events. We also don't want to generate events for
121702eb71fSJan Kara 	 * FMODE_PATH fds (involves open & close events) as they are just
122702eb71fSJan Kara 	 * handle creation / destruction events and not "real" file events.
123702eb71fSJan Kara 	 */
124a94204f4SAmir Goldstein 	if (FMODE_FSNOTIFY_NONE(file->f_mode))
125eae36a2bSAmir Goldstein 		return 0;
126eae36a2bSAmir Goldstein 
127a94204f4SAmir Goldstein 	return fsnotify_path(&file->f_path, mask);
128a704bba5SMatthew Bobrowski }
129a704bba5SMatthew Bobrowski 
1307ea26f94SAmir Goldstein #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
131a94204f4SAmir Goldstein 
13295101401SAmir Goldstein void file_set_fsnotify_mode_from_watchers(struct file *file);
133a94204f4SAmir Goldstein 
13436e28c42SAmir Goldstein /*
135d9e5d310SAmir Goldstein  * fsnotify_file_area_perm - permission hook before access to file range
13636e28c42SAmir Goldstein  */
fsnotify_file_area_perm(struct file * file,int perm_mask,const loff_t * ppos,size_t count)137d9e5d310SAmir Goldstein static inline int fsnotify_file_area_perm(struct file *file, int perm_mask,
138d9e5d310SAmir Goldstein 					  const loff_t *ppos, size_t count)
139c4ec54b4SEric Paris {
140cb383f06SAmir Goldstein 	/*
141cb383f06SAmir Goldstein 	 * filesystem may be modified in the context of permission events
142cb383f06SAmir Goldstein 	 * (e.g. by HSM filling a file on access), so sb freeze protection
143cb383f06SAmir Goldstein 	 * must not be held.
144cb383f06SAmir Goldstein 	 */
145cb383f06SAmir Goldstein 	lockdep_assert_once(file_write_not_started(file));
146cb383f06SAmir Goldstein 
147f156524eSAmir Goldstein 	if (!(perm_mask & (MAY_READ | MAY_WRITE | MAY_ACCESS)))
148c4ec54b4SEric Paris 		return 0;
149eae36a2bSAmir Goldstein 
150a94204f4SAmir Goldstein 	if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode)))
151a94204f4SAmir Goldstein 		return 0;
152a94204f4SAmir Goldstein 
153f156524eSAmir Goldstein 	/*
154f156524eSAmir Goldstein 	 * read()/write() and other types of access generate pre-content events.
155f156524eSAmir Goldstein 	 */
156f156524eSAmir Goldstein 	if (unlikely(FMODE_FSNOTIFY_HSM(file->f_mode))) {
1579740d171SAmir Goldstein 		int ret = fsnotify_pre_content(&file->f_path, ppos, count);
158f156524eSAmir Goldstein 
159f156524eSAmir Goldstein 		if (ret)
160f156524eSAmir Goldstein 			return ret;
161f156524eSAmir Goldstein 	}
162f156524eSAmir Goldstein 
163f156524eSAmir Goldstein 	if (!(perm_mask & MAY_READ))
164f156524eSAmir Goldstein 		return 0;
165f156524eSAmir Goldstein 
166f156524eSAmir Goldstein 	/*
167f156524eSAmir Goldstein 	 * read() also generates the legacy FS_ACCESS_PERM event, so content
168f156524eSAmir Goldstein 	 * scanners can inspect the content filled by pre-content event.
169f156524eSAmir Goldstein 	 */
170a94204f4SAmir Goldstein 	return fsnotify_path(&file->f_path, FS_ACCESS_PERM);
17136e28c42SAmir Goldstein }
17236e28c42SAmir Goldstein 
17336e28c42SAmir Goldstein /*
174*066e053fSAmir Goldstein  * fsnotify_mmap_perm - permission hook before mmap of file range
175*066e053fSAmir Goldstein  */
fsnotify_mmap_perm(struct file * file,int prot,const loff_t off,size_t len)176*066e053fSAmir Goldstein static inline int fsnotify_mmap_perm(struct file *file, int prot,
177*066e053fSAmir Goldstein 				     const loff_t off, size_t len)
178*066e053fSAmir Goldstein {
179*066e053fSAmir Goldstein 	/*
180*066e053fSAmir Goldstein 	 * mmap() generates only pre-content events.
181*066e053fSAmir Goldstein 	 */
182*066e053fSAmir Goldstein 	if (!file || likely(!FMODE_FSNOTIFY_HSM(file->f_mode)))
183*066e053fSAmir Goldstein 		return 0;
184*066e053fSAmir Goldstein 
185*066e053fSAmir Goldstein 	return fsnotify_pre_content(&file->f_path, &off, len);
186*066e053fSAmir Goldstein }
187*066e053fSAmir Goldstein 
188*066e053fSAmir Goldstein /*
1894acf3bc7SAmir Goldstein  * fsnotify_truncate_perm - permission hook before file truncate
1904acf3bc7SAmir Goldstein  */
fsnotify_truncate_perm(const struct path * path,loff_t length)1914acf3bc7SAmir Goldstein static inline int fsnotify_truncate_perm(const struct path *path, loff_t length)
1924acf3bc7SAmir Goldstein {
1934acf3bc7SAmir Goldstein 	struct inode *inode = d_inode(path->dentry);
1944acf3bc7SAmir Goldstein 
1954acf3bc7SAmir Goldstein 	if (!(inode->i_sb->s_iflags & SB_I_ALLOW_HSM) ||
1964acf3bc7SAmir Goldstein 	    !fsnotify_sb_has_priority_watchers(inode->i_sb,
1974acf3bc7SAmir Goldstein 					       FSNOTIFY_PRIO_PRE_CONTENT))
1984acf3bc7SAmir Goldstein 		return 0;
1994acf3bc7SAmir Goldstein 
2004acf3bc7SAmir Goldstein 	return fsnotify_pre_content(path, &length, 0);
2014acf3bc7SAmir Goldstein }
2024acf3bc7SAmir Goldstein 
2034acf3bc7SAmir Goldstein /*
2049740d171SAmir Goldstein  * fsnotify_file_perm - permission hook before file access (unknown range)
205d9e5d310SAmir Goldstein  */
fsnotify_file_perm(struct file * file,int perm_mask)206d9e5d310SAmir Goldstein static inline int fsnotify_file_perm(struct file *file, int perm_mask)
207d9e5d310SAmir Goldstein {
208d9e5d310SAmir Goldstein 	return fsnotify_file_area_perm(file, perm_mask, NULL, 0);
209d9e5d310SAmir Goldstein }
210d9e5d310SAmir Goldstein 
211d9e5d310SAmir Goldstein /*
21236e28c42SAmir Goldstein  * fsnotify_open_perm - permission hook before file open
21336e28c42SAmir Goldstein  */
fsnotify_open_perm(struct file * file)21436e28c42SAmir Goldstein static inline int fsnotify_open_perm(struct file *file)
21536e28c42SAmir Goldstein {
21636e28c42SAmir Goldstein 	int ret;
21766917a31SMatthew Bobrowski 
218a94204f4SAmir Goldstein 	if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode)))
219a94204f4SAmir Goldstein 		return 0;
220a94204f4SAmir Goldstein 
22166917a31SMatthew Bobrowski 	if (file->f_flags & __FMODE_EXEC) {
222a94204f4SAmir Goldstein 		ret = fsnotify_path(&file->f_path, FS_OPEN_EXEC_PERM);
22366917a31SMatthew Bobrowski 		if (ret)
22466917a31SMatthew Bobrowski 			return ret;
22566917a31SMatthew Bobrowski 	}
226c4ec54b4SEric Paris 
227a94204f4SAmir Goldstein 	return fsnotify_path(&file->f_path, FS_OPEN_PERM);
228c4ec54b4SEric Paris }
229c4ec54b4SEric Paris 
2307ea26f94SAmir Goldstein #else
file_set_fsnotify_mode_from_watchers(struct file * file)23195101401SAmir Goldstein static inline void file_set_fsnotify_mode_from_watchers(struct file *file)
232a94204f4SAmir Goldstein {
233a94204f4SAmir Goldstein }
234a94204f4SAmir Goldstein 
fsnotify_file_area_perm(struct file * file,int perm_mask,const loff_t * ppos,size_t count)2357ea26f94SAmir Goldstein static inline int fsnotify_file_area_perm(struct file *file, int perm_mask,
2367ea26f94SAmir Goldstein 					  const loff_t *ppos, size_t count)
2377ea26f94SAmir Goldstein {
2387ea26f94SAmir Goldstein 	return 0;
2397ea26f94SAmir Goldstein }
2407ea26f94SAmir Goldstein 
fsnotify_mmap_perm(struct file * file,int prot,const loff_t off,size_t len)241*066e053fSAmir Goldstein static inline int fsnotify_mmap_perm(struct file *file, int prot,
242*066e053fSAmir Goldstein 				     const loff_t off, size_t len)
243*066e053fSAmir Goldstein {
244*066e053fSAmir Goldstein 	return 0;
245*066e053fSAmir Goldstein }
246*066e053fSAmir Goldstein 
fsnotify_truncate_perm(const struct path * path,loff_t length)2474acf3bc7SAmir Goldstein static inline int fsnotify_truncate_perm(const struct path *path, loff_t length)
2484acf3bc7SAmir Goldstein {
2494acf3bc7SAmir Goldstein 	return 0;
2504acf3bc7SAmir Goldstein }
2514acf3bc7SAmir Goldstein 
fsnotify_file_perm(struct file * file,int perm_mask)2527ea26f94SAmir Goldstein static inline int fsnotify_file_perm(struct file *file, int perm_mask)
2537ea26f94SAmir Goldstein {
2547ea26f94SAmir Goldstein 	return 0;
2557ea26f94SAmir Goldstein }
2567ea26f94SAmir Goldstein 
fsnotify_open_perm(struct file * file)2577ea26f94SAmir Goldstein static inline int fsnotify_open_perm(struct file *file)
2587ea26f94SAmir Goldstein {
2597ea26f94SAmir Goldstein 	return 0;
2607ea26f94SAmir Goldstein }
2617ea26f94SAmir Goldstein #endif
2627ea26f94SAmir Goldstein 
263c32ccd87SNick Piggin /*
26490586523SEric Paris  * fsnotify_link_count - inode's link count changed
26590586523SEric Paris  */
fsnotify_link_count(struct inode * inode)26690586523SEric Paris static inline void fsnotify_link_count(struct inode *inode)
26790586523SEric Paris {
26882ace1efSAmir Goldstein 	fsnotify_inode(inode, FS_ATTRIB);
26990586523SEric Paris }
27090586523SEric Paris 
27190586523SEric Paris /*
2720eeca283SRobert Love  * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
2730eeca283SRobert Love  */
fsnotify_move(struct inode * old_dir,struct inode * new_dir,const struct qstr * old_name,int isdir,struct inode * target,struct dentry * moved)2740eeca283SRobert Love static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
275f4ec3a3dSAl Viro 				 const struct qstr *old_name,
2760a20df7eSAmir Goldstein 				 int isdir, struct inode *target,
2770a20df7eSAmir Goldstein 				 struct dentry *moved)
2780eeca283SRobert Love {
2795a190ae6SAl Viro 	struct inode *source = moved->d_inode;
28047882c6fSEric Paris 	u32 fs_cookie = fsnotify_get_cookie();
2815f02a877SAmir Goldstein 	__u32 old_dir_mask = FS_MOVED_FROM;
2825f02a877SAmir Goldstein 	__u32 new_dir_mask = FS_MOVED_TO;
283e54183faSAmir Goldstein 	__u32 rename_mask = FS_RENAME;
28425b229dfSAl Viro 	const struct qstr *new_name = &moved->d_name;
2850eeca283SRobert Love 
28690586523SEric Paris 	if (isdir) {
287b29866aaSEric Paris 		old_dir_mask |= FS_ISDIR;
288b29866aaSEric Paris 		new_dir_mask |= FS_ISDIR;
289e54183faSAmir Goldstein 		rename_mask |= FS_ISDIR;
29090586523SEric Paris 	}
29190586523SEric Paris 
292e54183faSAmir Goldstein 	/* Event with information about both old and new parent+name */
293e54183faSAmir Goldstein 	fsnotify_name(rename_mask, moved, FSNOTIFY_EVENT_DENTRY,
294e54183faSAmir Goldstein 		      old_dir, old_name, 0);
295e54183faSAmir Goldstein 
2969baf93d6SAmir Goldstein 	fsnotify_name(old_dir_mask, source, FSNOTIFY_EVENT_INODE,
2979baf93d6SAmir Goldstein 		      old_dir, old_name, fs_cookie);
2989baf93d6SAmir Goldstein 	fsnotify_name(new_dir_mask, source, FSNOTIFY_EVENT_INODE,
2999baf93d6SAmir Goldstein 		      new_dir, new_name, fs_cookie);
30090586523SEric Paris 
3012dfc1caeSEric Paris 	if (target)
30290586523SEric Paris 		fsnotify_link_count(target);
30382ace1efSAmir Goldstein 	fsnotify_inode(source, FS_MOVE_SELF);
3044fa6b5ecSJeff Layton 	audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE);
3050eeca283SRobert Love }
3060eeca283SRobert Love 
3070eeca283SRobert Love /*
3083be25f49SEric Paris  * fsnotify_inode_delete - and inode is being evicted from cache, clean up is needed
3093be25f49SEric Paris  */
fsnotify_inode_delete(struct inode * inode)3103be25f49SEric Paris static inline void fsnotify_inode_delete(struct inode *inode)
3113be25f49SEric Paris {
3123be25f49SEric Paris 	__fsnotify_inode_delete(inode);
3133be25f49SEric Paris }
3143be25f49SEric Paris 
3153be25f49SEric Paris /*
316ca9c726eSAndreas Gruenbacher  * fsnotify_vfsmount_delete - a vfsmount is being destroyed, clean up is needed
317ca9c726eSAndreas Gruenbacher  */
fsnotify_vfsmount_delete(struct vfsmount * mnt)318ca9c726eSAndreas Gruenbacher static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt)
319ca9c726eSAndreas Gruenbacher {
320ca9c726eSAndreas Gruenbacher 	__fsnotify_vfsmount_delete(mnt);
321ca9c726eSAndreas Gruenbacher }
322ca9c726eSAndreas Gruenbacher 
fsnotify_mntns_delete(struct mnt_namespace * mntns)323ca9c726eSAndreas Gruenbacher static inline void fsnotify_mntns_delete(struct mnt_namespace *mntns)
3247a91bf7fSJohn McCutchan {
3257a91bf7fSJohn McCutchan 	__fsnotify_mntns_delete(mntns);
3267a91bf7fSJohn McCutchan }
3277a91bf7fSJohn McCutchan 
32882ace1efSAmir Goldstein /*
3293be25f49SEric Paris  * fsnotify_inoderemove - an inode is going away
330ece95912SJan Kara  */
fsnotify_inoderemove(struct inode * inode)331ece95912SJan Kara static inline void fsnotify_inoderemove(struct inode *inode)
332ece95912SJan Kara {
3330eeca283SRobert Love 	fsnotify_inode(inode, FS_DELETE_SELF);
334dabe729dSAmir Goldstein 	__fsnotify_inode_delete(inode);
335dabe729dSAmir Goldstein }
336dabe729dSAmir Goldstein 
337dabe729dSAmir Goldstein /*
3380eeca283SRobert Love  * fsnotify_create - 'name' was linked in
339dabe729dSAmir Goldstein  *
3400eeca283SRobert Love  * Caller must make sure that dentry->d_name is stable.
341dabe729dSAmir Goldstein  * Note: some filesystems (e.g. kernfs) leave @dentry negative and instantiate
34290586523SEric Paris  * ->d_inode later
343dabe729dSAmir Goldstein  */
fsnotify_create(struct inode * dir,struct dentry * dentry)3440eeca283SRobert Love static inline void fsnotify_create(struct inode *dir, struct dentry *dentry)
3450eeca283SRobert Love {
3460eeca283SRobert Love 	audit_inode_child(dir, dentry, AUDIT_TYPE_CHILD_CREATE);
347ece95912SJan Kara 
348dabe729dSAmir Goldstein 	fsnotify_dirent(dir, dentry, FS_CREATE);
349dabe729dSAmir Goldstein }
350ece95912SJan Kara 
351ece95912SJan Kara /*
352ece95912SJan Kara  * fsnotify_link - new hardlink in 'inode' directory
353a1aae057SAmir Goldstein  *
354a1aae057SAmir Goldstein  * Caller must make sure that new_dentry->d_name is stable.
355ece95912SJan Kara  * Note: We have to pass also the linked inode ptr as some filesystems leave
356ece95912SJan Kara  *   new_dentry->d_inode NULL and instantiate inode pointer later
3574fa6b5ecSJeff Layton  */
fsnotify_link(struct inode * dir,struct inode * inode,struct dentry * new_dentry)35890586523SEric Paris static inline void fsnotify_link(struct inode *dir, struct inode *inode,
3599baf93d6SAmir Goldstein 				 struct dentry *new_dentry)
3609baf93d6SAmir Goldstein {
361ece95912SJan Kara 	fsnotify_link_count(inode);
362ece95912SJan Kara 	audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE);
363ece95912SJan Kara 
364a37d9a17SAmir Goldstein 	fsnotify_name(FS_CREATE, inode, FSNOTIFY_EVENT_INODE,
365a37d9a17SAmir Goldstein 		      dir, &new_dentry->d_name, 0);
366a37d9a17SAmir Goldstein }
367a37d9a17SAmir Goldstein 
368a37d9a17SAmir Goldstein /*
369a37d9a17SAmir Goldstein  * fsnotify_delete - @dentry was unlinked and unhashed
370a37d9a17SAmir Goldstein  *
371a37d9a17SAmir Goldstein  * Caller must make sure that dentry->d_name is stable.
372a37d9a17SAmir Goldstein  *
373a37d9a17SAmir Goldstein  * Note: unlike fsnotify_unlink(), we have to pass also the unlinked inode
374a37d9a17SAmir Goldstein  * as this may be called after d_delete() and old_dentry may be negative.
375a37d9a17SAmir Goldstein  */
fsnotify_delete(struct inode * dir,struct inode * inode,struct dentry * dentry)376a37d9a17SAmir Goldstein static inline void fsnotify_delete(struct inode *dir, struct inode *inode,
377a37d9a17SAmir Goldstein 				   struct dentry *dentry)
378a37d9a17SAmir Goldstein {
379a37d9a17SAmir Goldstein 	__u32 mask = FS_DELETE;
380a37d9a17SAmir Goldstein 
381a37d9a17SAmir Goldstein 	if (S_ISDIR(inode->i_mode))
382a37d9a17SAmir Goldstein 		mask |= FS_ISDIR;
383a37d9a17SAmir Goldstein 
384a37d9a17SAmir Goldstein 	fsnotify_name(mask, inode, FSNOTIFY_EVENT_INODE, dir, &dentry->d_name,
385a37d9a17SAmir Goldstein 		      0);
386a37d9a17SAmir Goldstein }
387a37d9a17SAmir Goldstein 
388a37d9a17SAmir Goldstein /**
389a37d9a17SAmir Goldstein  * d_delete_notify - delete a dentry and call fsnotify_delete()
390a37d9a17SAmir Goldstein  * @dentry: The dentry to delete
391a37d9a17SAmir Goldstein  *
392a37d9a17SAmir Goldstein  * This helper is used to guaranty that the unlinked inode cannot be found
393a37d9a17SAmir Goldstein  * by lookup of this name after fsnotify_delete() event has been delivered.
394a37d9a17SAmir Goldstein  */
d_delete_notify(struct inode * dir,struct dentry * dentry)395a37d9a17SAmir Goldstein static inline void d_delete_notify(struct inode *dir, struct dentry *dentry)
396a37d9a17SAmir Goldstein {
397a37d9a17SAmir Goldstein 	struct inode *inode = d_inode(dentry);
398a37d9a17SAmir Goldstein 
399a37d9a17SAmir Goldstein 	ihold(inode);
400a37d9a17SAmir Goldstein 	d_delete(dentry);
401116b9731SAmir Goldstein 	fsnotify_delete(dir, inode, dentry);
402116b9731SAmir Goldstein 	iput(inode);
403116b9731SAmir Goldstein }
404116b9731SAmir Goldstein 
405116b9731SAmir Goldstein /*
406116b9731SAmir Goldstein  * fsnotify_unlink - 'name' was unlinked
407a37d9a17SAmir Goldstein  *
408a37d9a17SAmir Goldstein  * Caller must make sure that dentry->d_name is stable.
409116b9731SAmir Goldstein  */
fsnotify_unlink(struct inode * dir,struct dentry * dentry)410a37d9a17SAmir Goldstein static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
411116b9731SAmir Goldstein {
412116b9731SAmir Goldstein 	if (WARN_ON_ONCE(d_is_negative(dentry)))
413116b9731SAmir Goldstein 		return;
4140eeca283SRobert Love 
415dabe729dSAmir Goldstein 	fsnotify_delete(dir, d_inode(dentry), dentry);
416dabe729dSAmir Goldstein }
417dabe729dSAmir Goldstein 
418dabe729dSAmir Goldstein /*
4190eeca283SRobert Love  * fsnotify_mkdir - directory 'name' was created
420dabe729dSAmir Goldstein  *
4210eeca283SRobert Love  * Caller must make sure that dentry->d_name is stable.
422dabe729dSAmir Goldstein  * Note: some filesystems (e.g. kernfs) leave @dentry negative and instantiate
42390586523SEric Paris  * ->d_inode later
424dabe729dSAmir Goldstein  */
fsnotify_mkdir(struct inode * dir,struct dentry * dentry)4250eeca283SRobert Love static inline void fsnotify_mkdir(struct inode *dir, struct dentry *dentry)
4260eeca283SRobert Love {
4270eeca283SRobert Love 	audit_inode_child(dir, dentry, AUDIT_TYPE_CHILD_CREATE);
428116b9731SAmir Goldstein 
429116b9731SAmir Goldstein 	fsnotify_dirent(dir, dentry, FS_CREATE | FS_ISDIR);
430116b9731SAmir Goldstein }
431116b9731SAmir Goldstein 
432116b9731SAmir Goldstein /*
433116b9731SAmir Goldstein  * fsnotify_rmdir - directory 'name' was removed
434a37d9a17SAmir Goldstein  *
435a37d9a17SAmir Goldstein  * Caller must make sure that dentry->d_name is stable.
436116b9731SAmir Goldstein  */
fsnotify_rmdir(struct inode * dir,struct dentry * dentry)437a37d9a17SAmir Goldstein static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry)
438116b9731SAmir Goldstein {
439116b9731SAmir Goldstein 	if (WARN_ON_ONCE(d_is_negative(dentry)))
440116b9731SAmir Goldstein 		return;
4410eeca283SRobert Love 
4420eeca283SRobert Love 	fsnotify_delete(dir, d_inode(dentry), dentry);
4432a12a9d7SEric Paris }
4440eeca283SRobert Love 
445eae36a2bSAmir Goldstein /*
446ecf081d1SEric Paris  * fsnotify_access - file was read
4470eeca283SRobert Love  */
fsnotify_access(struct file * file)4480eeca283SRobert Love static inline void fsnotify_access(struct file *file)
4490eeca283SRobert Love {
4500eeca283SRobert Love 	fsnotify_file(file, FS_ACCESS);
4512a12a9d7SEric Paris }
4520eeca283SRobert Love 
453eae36a2bSAmir Goldstein /*
454ecf081d1SEric Paris  * fsnotify_modify - file was modified
4550eeca283SRobert Love  */
fsnotify_modify(struct file * file)4560eeca283SRobert Love static inline void fsnotify_modify(struct file *file)
4570eeca283SRobert Love {
4580eeca283SRobert Love 	fsnotify_file(file, FS_MODIFY);
4592a12a9d7SEric Paris }
4600eeca283SRobert Love 
46190586523SEric Paris /*
4620eeca283SRobert Love  * fsnotify_open - file was opened
4639b076f1cSMatthew Bobrowski  */
fsnotify_open(struct file * file)4649b076f1cSMatthew Bobrowski static inline void fsnotify_open(struct file *file)
4650eeca283SRobert Love {
466eae36a2bSAmir Goldstein 	__u32 mask = FS_OPEN;
4670eeca283SRobert Love 
4680eeca283SRobert Love 	if (file->f_flags & __FMODE_EXEC)
4690eeca283SRobert Love 		mask |= FS_OPEN_EXEC;
4700eeca283SRobert Love 
4710eeca283SRobert Love 	fsnotify_file(file, mask);
4720eeca283SRobert Love }
4730eeca283SRobert Love 
474eae36a2bSAmir Goldstein /*
475eae36a2bSAmir Goldstein  * fsnotify_close - file was closed
4760eeca283SRobert Love  */
fsnotify_close(struct file * file)477eae36a2bSAmir Goldstein static inline void fsnotify_close(struct file *file)
478ecf081d1SEric Paris {
4790eeca283SRobert Love 	__u32 mask = (file->f_mode & FMODE_WRITE) ? FS_CLOSE_WRITE :
4800eeca283SRobert Love 						    FS_CLOSE_NOWRITE;
4810eeca283SRobert Love 
4820eeca283SRobert Love 	fsnotify_file(file, mask);
4830eeca283SRobert Love }
4840eeca283SRobert Love 
485eae36a2bSAmir Goldstein /*
4860eeca283SRobert Love  * fsnotify_xattr - extended attributes were changed
4870eeca283SRobert Love  */
fsnotify_xattr(struct dentry * dentry)4880eeca283SRobert Love static inline void fsnotify_xattr(struct dentry *dentry)
4890eeca283SRobert Love {
4900eeca283SRobert Love 	fsnotify_dentry(dentry, FS_ATTRIB);
4910eeca283SRobert Love }
4920eeca283SRobert Love 
4930eeca283SRobert Love /*
4943c5119c0SEric Paris  * fsnotify_change - notify_change event.  file was modified and/or metadata
4950eeca283SRobert Love  * was changed.
4963c5119c0SEric Paris  */
fsnotify_change(struct dentry * dentry,unsigned int ia_valid)4973c5119c0SEric Paris static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
4983c5119c0SEric Paris {
4993c5119c0SEric Paris 	__u32 mask = 0;
5003c5119c0SEric Paris 
5013c5119c0SEric Paris 	if (ia_valid & ATTR_UID)
5023c5119c0SEric Paris 		mask |= FS_ATTRIB;
5030eeca283SRobert Love 	if (ia_valid & ATTR_GID)
5040eeca283SRobert Love 		mask |= FS_ATTRIB;
5053c5119c0SEric Paris 	if (ia_valid & ATTR_SIZE)
5063c5119c0SEric Paris 		mask |= FS_MODIFY;
5073c5119c0SEric Paris 
5083c5119c0SEric Paris 	/* both times implies a utime(s) call */
5093c5119c0SEric Paris 	if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME))
5100eeca283SRobert Love 		mask |= FS_ATTRIB;
5113c5119c0SEric Paris 	else if (ia_valid & ATTR_ATIME)
5123c5119c0SEric Paris 		mask |= FS_ACCESS;
5133c5119c0SEric Paris 	else if (ia_valid & ATTR_MTIME)
514eae36a2bSAmir Goldstein 		mask |= FS_MODIFY;
515eae36a2bSAmir Goldstein 
5160eeca283SRobert Love 	if (ia_valid & ATTR_MODE)
5170eeca283SRobert Love 		mask |= FS_ATTRIB;
5189daa8110SGabriel Krisman Bertazi 
5199daa8110SGabriel Krisman Bertazi 	if (mask)
5209daa8110SGabriel Krisman Bertazi 		fsnotify_dentry(dentry, mask);
5219daa8110SGabriel Krisman Bertazi }
5229daa8110SGabriel Krisman Bertazi 
fsnotify_sb_error(struct super_block * sb,struct inode * inode,int error)5239daa8110SGabriel Krisman Bertazi static inline int fsnotify_sb_error(struct super_block *sb, struct inode *inode,
5249daa8110SGabriel Krisman Bertazi 				    int error)
5259daa8110SGabriel Krisman Bertazi {
5269daa8110SGabriel Krisman Bertazi 	struct fs_error_report report = {
5279daa8110SGabriel Krisman Bertazi 		.error = error,
5289daa8110SGabriel Krisman Bertazi 		.inode = inode,
5299daa8110SGabriel Krisman Bertazi 		.sb = sb,
5309daa8110SGabriel Krisman Bertazi 	};
5310eeca283SRobert Love 
532 	return fsnotify(FS_ERROR, &report, FSNOTIFY_EVENT_ERROR,
533 			NULL, NULL, NULL, 0);
534 }
535 
fsnotify_mnt_attach(struct mnt_namespace * ns,struct vfsmount * mnt)536 static inline void fsnotify_mnt_attach(struct mnt_namespace *ns, struct vfsmount *mnt)
537 {
538 	fsnotify_mnt(FS_MNT_ATTACH, ns, mnt);
539 }
540 
fsnotify_mnt_detach(struct mnt_namespace * ns,struct vfsmount * mnt)541 static inline void fsnotify_mnt_detach(struct mnt_namespace *ns, struct vfsmount *mnt)
542 {
543 	fsnotify_mnt(FS_MNT_DETACH, ns, mnt);
544 }
545 
fsnotify_mnt_move(struct mnt_namespace * ns,struct vfsmount * mnt)546 static inline void fsnotify_mnt_move(struct mnt_namespace *ns, struct vfsmount *mnt)
547 {
548 	fsnotify_mnt(FS_MNT_MOVE, ns, mnt);
549 }
550 
551 #endif	/* _LINUX_FS_NOTIFY_H */
552