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