xref: /openbmc/linux/include/linux/fsnotify.h (revision 24ce659d)
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 */
323