Merge tag 'topic/phy-compliance-2020-04-08' of git://anongit.freedesktop.org/drm...
[linux-2.6-microblaze.git] / include / linux / fsnotify.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _LINUX_FS_NOTIFY_H
3 #define _LINUX_FS_NOTIFY_H
4
5 /*
6  * include/linux/fsnotify.h - generic hooks for filesystem notification, to
7  * reduce in-source duplication from both dnotify and inotify.
8  *
9  * We don't compile any of this away in some complicated menagerie of ifdefs.
10  * Instead, we rely on the code inside to optimize away as needed.
11  *
12  * (C) Copyright 2005 Robert Love
13  */
14
15 #include <linux/fsnotify_backend.h>
16 #include <linux/audit.h>
17 #include <linux/slab.h>
18 #include <linux/bug.h>
19
20 /*
21  * Notify this @dir inode about a change in a child directory entry.
22  * The directory entry may have turned positive or negative or its inode may
23  * have changed (i.e. renamed over).
24  *
25  * Unlike fsnotify_parent(), the event will be reported regardless of the
26  * FS_EVENT_ON_CHILD mask on the parent inode.
27  */
28 static inline void fsnotify_name(struct inode *dir, __u32 mask,
29                                  struct inode *child,
30                                  const struct qstr *name, u32 cookie)
31 {
32         fsnotify(dir, mask, child, FSNOTIFY_EVENT_INODE, name, cookie);
33         /*
34          * Send another flavor of the event without child inode data and
35          * without the specific event type (e.g. FS_CREATE|FS_IS_DIR).
36          * The name is relative to the dir inode the event is reported to.
37          */
38         fsnotify(dir, FS_DIR_MODIFY, dir, FSNOTIFY_EVENT_INODE, name, 0);
39 }
40
41 static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry,
42                                    __u32 mask)
43 {
44         fsnotify_name(dir, mask, d_inode(dentry), &dentry->d_name, 0);
45 }
46
47 /*
48  * Simple wrappers to consolidate calls fsnotify_parent()/fsnotify() when
49  * an event is on a file/dentry.
50  */
51 static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask)
52 {
53         struct inode *inode = d_inode(dentry);
54
55         if (S_ISDIR(inode->i_mode))
56                 mask |= FS_ISDIR;
57
58         fsnotify_parent(dentry, mask, inode, FSNOTIFY_EVENT_INODE);
59         fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
60 }
61
62 static inline int fsnotify_file(struct file *file, __u32 mask)
63 {
64         const struct path *path = &file->f_path;
65         struct inode *inode = file_inode(file);
66         int ret;
67
68         if (file->f_mode & FMODE_NONOTIFY)
69                 return 0;
70
71         if (S_ISDIR(inode->i_mode))
72                 mask |= FS_ISDIR;
73
74         ret = fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH);
75         if (ret)
76                 return ret;
77
78         return fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
79 }
80
81 /* Simple call site for access decisions */
82 static inline int fsnotify_perm(struct file *file, int mask)
83 {
84         int ret;
85         __u32 fsnotify_mask = 0;
86
87         if (!(mask & (MAY_READ | MAY_OPEN)))
88                 return 0;
89
90         if (mask & MAY_OPEN) {
91                 fsnotify_mask = FS_OPEN_PERM;
92
93                 if (file->f_flags & __FMODE_EXEC) {
94                         ret = fsnotify_file(file, FS_OPEN_EXEC_PERM);
95
96                         if (ret)
97                                 return ret;
98                 }
99         } else if (mask & MAY_READ) {
100                 fsnotify_mask = FS_ACCESS_PERM;
101         }
102
103         return fsnotify_file(file, fsnotify_mask);
104 }
105
106 /*
107  * fsnotify_link_count - inode's link count changed
108  */
109 static inline void fsnotify_link_count(struct inode *inode)
110 {
111         __u32 mask = FS_ATTRIB;
112
113         if (S_ISDIR(inode->i_mode))
114                 mask |= FS_ISDIR;
115
116         fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
117 }
118
119 /*
120  * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
121  */
122 static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
123                                  const struct qstr *old_name,
124                                  int isdir, struct inode *target,
125                                  struct dentry *moved)
126 {
127         struct inode *source = moved->d_inode;
128         u32 fs_cookie = fsnotify_get_cookie();
129         __u32 old_dir_mask = FS_MOVED_FROM;
130         __u32 new_dir_mask = FS_MOVED_TO;
131         __u32 mask = FS_MOVE_SELF;
132         const struct qstr *new_name = &moved->d_name;
133
134         if (old_dir == new_dir)
135                 old_dir_mask |= FS_DN_RENAME;
136
137         if (isdir) {
138                 old_dir_mask |= FS_ISDIR;
139                 new_dir_mask |= FS_ISDIR;
140                 mask |= FS_ISDIR;
141         }
142
143         fsnotify_name(old_dir, old_dir_mask, source, old_name, fs_cookie);
144         fsnotify_name(new_dir, new_dir_mask, source, new_name, fs_cookie);
145
146         if (target)
147                 fsnotify_link_count(target);
148
149         if (source)
150                 fsnotify(source, mask, source, FSNOTIFY_EVENT_INODE, NULL, 0);
151         audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE);
152 }
153
154 /*
155  * fsnotify_inode_delete - and inode is being evicted from cache, clean up is needed
156  */
157 static inline void fsnotify_inode_delete(struct inode *inode)
158 {
159         __fsnotify_inode_delete(inode);
160 }
161
162 /*
163  * fsnotify_vfsmount_delete - a vfsmount is being destroyed, clean up is needed
164  */
165 static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt)
166 {
167         __fsnotify_vfsmount_delete(mnt);
168 }
169
170 /*
171  * fsnotify_inoderemove - an inode is going away
172  */
173 static inline void fsnotify_inoderemove(struct inode *inode)
174 {
175         __u32 mask = FS_DELETE_SELF;
176
177         if (S_ISDIR(inode->i_mode))
178                 mask |= FS_ISDIR;
179
180         fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
181         __fsnotify_inode_delete(inode);
182 }
183
184 /*
185  * fsnotify_create - 'name' was linked in
186  */
187 static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
188 {
189         audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
190
191         fsnotify_dirent(inode, dentry, FS_CREATE);
192 }
193
194 /*
195  * fsnotify_link - new hardlink in 'inode' directory
196  * Note: We have to pass also the linked inode ptr as some filesystems leave
197  *   new_dentry->d_inode NULL and instantiate inode pointer later
198  */
199 static inline void fsnotify_link(struct inode *dir, struct inode *inode,
200                                  struct dentry *new_dentry)
201 {
202         fsnotify_link_count(inode);
203         audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE);
204
205         fsnotify_name(dir, FS_CREATE, inode, &new_dentry->d_name, 0);
206 }
207
208 /*
209  * fsnotify_unlink - 'name' was unlinked
210  *
211  * Caller must make sure that dentry->d_name is stable.
212  */
213 static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
214 {
215         /* Expected to be called before d_delete() */
216         WARN_ON_ONCE(d_is_negative(dentry));
217
218         fsnotify_dirent(dir, dentry, FS_DELETE);
219 }
220
221 /*
222  * fsnotify_mkdir - directory 'name' was created
223  */
224 static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
225 {
226         audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
227
228         fsnotify_dirent(inode, dentry, FS_CREATE | FS_ISDIR);
229 }
230
231 /*
232  * fsnotify_rmdir - directory 'name' was removed
233  *
234  * Caller must make sure that dentry->d_name is stable.
235  */
236 static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry)
237 {
238         /* Expected to be called before d_delete() */
239         WARN_ON_ONCE(d_is_negative(dentry));
240
241         fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR);
242 }
243
244 /*
245  * fsnotify_access - file was read
246  */
247 static inline void fsnotify_access(struct file *file)
248 {
249         fsnotify_file(file, FS_ACCESS);
250 }
251
252 /*
253  * fsnotify_modify - file was modified
254  */
255 static inline void fsnotify_modify(struct file *file)
256 {
257         fsnotify_file(file, FS_MODIFY);
258 }
259
260 /*
261  * fsnotify_open - file was opened
262  */
263 static inline void fsnotify_open(struct file *file)
264 {
265         __u32 mask = FS_OPEN;
266
267         if (file->f_flags & __FMODE_EXEC)
268                 mask |= FS_OPEN_EXEC;
269
270         fsnotify_file(file, mask);
271 }
272
273 /*
274  * fsnotify_close - file was closed
275  */
276 static inline void fsnotify_close(struct file *file)
277 {
278         __u32 mask = (file->f_mode & FMODE_WRITE) ? FS_CLOSE_WRITE :
279                                                     FS_CLOSE_NOWRITE;
280
281         fsnotify_file(file, mask);
282 }
283
284 /*
285  * fsnotify_xattr - extended attributes were changed
286  */
287 static inline void fsnotify_xattr(struct dentry *dentry)
288 {
289         fsnotify_dentry(dentry, FS_ATTRIB);
290 }
291
292 /*
293  * fsnotify_change - notify_change event.  file was modified and/or metadata
294  * was changed.
295  */
296 static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
297 {
298         __u32 mask = 0;
299
300         if (ia_valid & ATTR_UID)
301                 mask |= FS_ATTRIB;
302         if (ia_valid & ATTR_GID)
303                 mask |= FS_ATTRIB;
304         if (ia_valid & ATTR_SIZE)
305                 mask |= FS_MODIFY;
306
307         /* both times implies a utime(s) call */
308         if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME))
309                 mask |= FS_ATTRIB;
310         else if (ia_valid & ATTR_ATIME)
311                 mask |= FS_ACCESS;
312         else if (ia_valid & ATTR_MTIME)
313                 mask |= FS_MODIFY;
314
315         if (ia_valid & ATTR_MODE)
316                 mask |= FS_ATTRIB;
317
318         if (mask)
319                 fsnotify_dentry(dentry, mask);
320 }
321
322 #endif  /* _LINUX_FS_NOTIFY_H */