Branch data Line data Source code
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 the directory entry @dentry.
22 : : *
23 : : * Unlike fsnotify_parent(), the event will be reported regardless of the
24 : : * FS_EVENT_ON_CHILD mask on the parent inode.
25 : : */
26 : : static inline int fsnotify_dirent(struct inode *dir, struct dentry *dentry,
27 : : __u32 mask)
28 : : {
29 : 3 : return fsnotify(dir, mask, d_inode(dentry), FSNOTIFY_EVENT_INODE,
30 : 3 : &dentry->d_name, 0);
31 : : }
32 : :
33 : : /* Notify this dentry's parent about a child's events. */
34 : : static inline int fsnotify_parent(const struct path *path,
35 : : struct dentry *dentry, __u32 mask)
36 : : {
37 : 3 : if (!dentry)
38 : 3 : dentry = path->dentry;
39 : :
40 : 3 : return __fsnotify_parent(path, dentry, mask);
41 : : }
42 : :
43 : : /*
44 : : * Simple wrapper to consolidate calls fsnotify_parent()/fsnotify() when
45 : : * an event is on a path.
46 : : */
47 : 3 : static inline int fsnotify_path(struct inode *inode, const struct path *path,
48 : : __u32 mask)
49 : : {
50 : : int ret = fsnotify_parent(path, NULL, mask);
51 : :
52 : 3 : if (ret)
53 : : return ret;
54 : 3 : return fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
55 : : }
56 : :
57 : : /* Simple call site for access decisions */
58 : 3 : static inline int fsnotify_perm(struct file *file, int mask)
59 : : {
60 : : int ret;
61 : 3 : const struct path *path = &file->f_path;
62 : : struct inode *inode = file_inode(file);
63 : : __u32 fsnotify_mask = 0;
64 : :
65 : 3 : if (file->f_mode & FMODE_NONOTIFY)
66 : : return 0;
67 : 3 : if (!(mask & (MAY_READ | MAY_OPEN)))
68 : : return 0;
69 : 3 : if (mask & MAY_OPEN) {
70 : : fsnotify_mask = FS_OPEN_PERM;
71 : :
72 : 3 : if (file->f_flags & __FMODE_EXEC) {
73 : 3 : ret = fsnotify_path(inode, path, FS_OPEN_EXEC_PERM);
74 : :
75 : 3 : if (ret)
76 : : return ret;
77 : : }
78 : 3 : } else if (mask & MAY_READ) {
79 : : fsnotify_mask = FS_ACCESS_PERM;
80 : : }
81 : :
82 : 3 : if (S_ISDIR(inode->i_mode))
83 : 3 : fsnotify_mask |= FS_ISDIR;
84 : :
85 : 3 : return fsnotify_path(inode, path, fsnotify_mask);
86 : : }
87 : :
88 : : /*
89 : : * fsnotify_link_count - inode's link count changed
90 : : */
91 : 3 : static inline void fsnotify_link_count(struct inode *inode)
92 : : {
93 : : __u32 mask = FS_ATTRIB;
94 : :
95 : 3 : if (S_ISDIR(inode->i_mode))
96 : : mask |= FS_ISDIR;
97 : :
98 : 3 : fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
99 : 3 : }
100 : :
101 : : /*
102 : : * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
103 : : */
104 : 3 : static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
105 : : const struct qstr *old_name,
106 : : int isdir, struct inode *target,
107 : : struct dentry *moved)
108 : : {
109 : 3 : struct inode *source = moved->d_inode;
110 : 3 : u32 fs_cookie = fsnotify_get_cookie();
111 : : __u32 old_dir_mask = FS_MOVED_FROM;
112 : : __u32 new_dir_mask = FS_MOVED_TO;
113 : : __u32 mask = FS_MOVE_SELF;
114 : 3 : const struct qstr *new_name = &moved->d_name;
115 : :
116 : 3 : if (old_dir == new_dir)
117 : : old_dir_mask |= FS_DN_RENAME;
118 : :
119 : 3 : if (isdir) {
120 : 0 : old_dir_mask |= FS_ISDIR;
121 : : new_dir_mask |= FS_ISDIR;
122 : : mask |= FS_ISDIR;
123 : : }
124 : :
125 : 3 : fsnotify(old_dir, old_dir_mask, source, FSNOTIFY_EVENT_INODE, old_name,
126 : : fs_cookie);
127 : 3 : fsnotify(new_dir, new_dir_mask, source, FSNOTIFY_EVENT_INODE, new_name,
128 : : fs_cookie);
129 : :
130 : 3 : if (target)
131 : 3 : fsnotify_link_count(target);
132 : :
133 : 3 : if (source)
134 : 3 : fsnotify(source, mask, source, FSNOTIFY_EVENT_INODE, NULL, 0);
135 : 3 : audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE);
136 : 3 : }
137 : :
138 : : /*
139 : : * fsnotify_inode_delete - and inode is being evicted from cache, clean up is needed
140 : : */
141 : : static inline void fsnotify_inode_delete(struct inode *inode)
142 : : {
143 : 3 : __fsnotify_inode_delete(inode);
144 : : }
145 : :
146 : : /*
147 : : * fsnotify_vfsmount_delete - a vfsmount is being destroyed, clean up is needed
148 : : */
149 : : static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt)
150 : : {
151 : 3 : __fsnotify_vfsmount_delete(mnt);
152 : : }
153 : :
154 : : /*
155 : : * fsnotify_inoderemove - an inode is going away
156 : : */
157 : 3 : static inline void fsnotify_inoderemove(struct inode *inode)
158 : : {
159 : : __u32 mask = FS_DELETE_SELF;
160 : :
161 : 3 : if (S_ISDIR(inode->i_mode))
162 : : mask |= FS_ISDIR;
163 : :
164 : 3 : fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
165 : 3 : __fsnotify_inode_delete(inode);
166 : 3 : }
167 : :
168 : : /*
169 : : * fsnotify_create - 'name' was linked in
170 : : */
171 : 3 : static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
172 : : {
173 : 3 : audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
174 : :
175 : : fsnotify_dirent(inode, dentry, FS_CREATE);
176 : 3 : }
177 : :
178 : : /*
179 : : * fsnotify_link - new hardlink in 'inode' directory
180 : : * Note: We have to pass also the linked inode ptr as some filesystems leave
181 : : * new_dentry->d_inode NULL and instantiate inode pointer later
182 : : */
183 : 3 : static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
184 : : {
185 : 3 : fsnotify_link_count(inode);
186 : 3 : audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE);
187 : :
188 : 3 : fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, &new_dentry->d_name, 0);
189 : 3 : }
190 : :
191 : : /*
192 : : * fsnotify_unlink - 'name' was unlinked
193 : : *
194 : : * Caller must make sure that dentry->d_name is stable.
195 : : */
196 : 3 : static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
197 : : {
198 : : /* Expected to be called before d_delete() */
199 : 3 : WARN_ON_ONCE(d_is_negative(dentry));
200 : :
201 : : fsnotify_dirent(dir, dentry, FS_DELETE);
202 : 3 : }
203 : :
204 : : /*
205 : : * fsnotify_mkdir - directory 'name' was created
206 : : */
207 : 3 : static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
208 : : {
209 : 3 : audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
210 : :
211 : : fsnotify_dirent(inode, dentry, FS_CREATE | FS_ISDIR);
212 : 3 : }
213 : :
214 : : /*
215 : : * fsnotify_rmdir - directory 'name' was removed
216 : : *
217 : : * Caller must make sure that dentry->d_name is stable.
218 : : */
219 : 3 : static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry)
220 : : {
221 : : /* Expected to be called before d_delete() */
222 : 3 : WARN_ON_ONCE(d_is_negative(dentry));
223 : :
224 : : fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR);
225 : 3 : }
226 : :
227 : : /*
228 : : * fsnotify_access - file was read
229 : : */
230 : 3 : static inline void fsnotify_access(struct file *file)
231 : : {
232 : 3 : const struct path *path = &file->f_path;
233 : : struct inode *inode = file_inode(file);
234 : : __u32 mask = FS_ACCESS;
235 : :
236 : 3 : if (S_ISDIR(inode->i_mode))
237 : : mask |= FS_ISDIR;
238 : :
239 : 3 : if (!(file->f_mode & FMODE_NONOTIFY))
240 : 3 : fsnotify_path(inode, path, mask);
241 : 3 : }
242 : :
243 : : /*
244 : : * fsnotify_modify - file was modified
245 : : */
246 : 3 : static inline void fsnotify_modify(struct file *file)
247 : : {
248 : 3 : const struct path *path = &file->f_path;
249 : : struct inode *inode = file_inode(file);
250 : : __u32 mask = FS_MODIFY;
251 : :
252 : 3 : if (S_ISDIR(inode->i_mode))
253 : : mask |= FS_ISDIR;
254 : :
255 : 3 : if (!(file->f_mode & FMODE_NONOTIFY))
256 : 3 : fsnotify_path(inode, path, mask);
257 : 3 : }
258 : :
259 : : /*
260 : : * fsnotify_open - file was opened
261 : : */
262 : 3 : static inline void fsnotify_open(struct file *file)
263 : : {
264 : 3 : const struct path *path = &file->f_path;
265 : : struct inode *inode = file_inode(file);
266 : : __u32 mask = FS_OPEN;
267 : :
268 : 3 : if (S_ISDIR(inode->i_mode))
269 : : mask |= FS_ISDIR;
270 : 3 : if (file->f_flags & __FMODE_EXEC)
271 : 3 : mask |= FS_OPEN_EXEC;
272 : :
273 : 3 : fsnotify_path(inode, path, mask);
274 : 3 : }
275 : :
276 : : /*
277 : : * fsnotify_close - file was closed
278 : : */
279 : 3 : static inline void fsnotify_close(struct file *file)
280 : : {
281 : 3 : const struct path *path = &file->f_path;
282 : : struct inode *inode = file_inode(file);
283 : 3 : fmode_t mode = file->f_mode;
284 : 3 : __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
285 : :
286 : 3 : if (S_ISDIR(inode->i_mode))
287 : 3 : mask |= FS_ISDIR;
288 : :
289 : 3 : if (!(file->f_mode & FMODE_NONOTIFY))
290 : 3 : fsnotify_path(inode, path, mask);
291 : 3 : }
292 : :
293 : : /*
294 : : * fsnotify_xattr - extended attributes were changed
295 : : */
296 : 3 : static inline void fsnotify_xattr(struct dentry *dentry)
297 : : {
298 : 3 : struct inode *inode = dentry->d_inode;
299 : : __u32 mask = FS_ATTRIB;
300 : :
301 : 3 : if (S_ISDIR(inode->i_mode))
302 : : mask |= FS_ISDIR;
303 : :
304 : : fsnotify_parent(NULL, dentry, mask);
305 : 3 : fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
306 : 3 : }
307 : :
308 : : /*
309 : : * fsnotify_change - notify_change event. file was modified and/or metadata
310 : : * was changed.
311 : : */
312 : 3 : static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
313 : : {
314 : 3 : struct inode *inode = dentry->d_inode;
315 : : __u32 mask = 0;
316 : :
317 : 3 : if (ia_valid & ATTR_UID)
318 : : mask |= FS_ATTRIB;
319 : 3 : if (ia_valid & ATTR_GID)
320 : : mask |= FS_ATTRIB;
321 : 3 : if (ia_valid & ATTR_SIZE)
322 : 3 : mask |= FS_MODIFY;
323 : :
324 : : /* both times implies a utime(s) call */
325 : 3 : if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME))
326 : 3 : mask |= FS_ATTRIB;
327 : 3 : else if (ia_valid & ATTR_ATIME)
328 : 0 : mask |= FS_ACCESS;
329 : 3 : else if (ia_valid & ATTR_MTIME)
330 : 3 : mask |= FS_MODIFY;
331 : :
332 : 3 : if (ia_valid & ATTR_MODE)
333 : 3 : mask |= FS_ATTRIB;
334 : :
335 : 3 : if (mask) {
336 : 3 : if (S_ISDIR(inode->i_mode))
337 : 3 : mask |= FS_ISDIR;
338 : :
339 : : fsnotify_parent(NULL, dentry, mask);
340 : 3 : fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
341 : : }
342 : 3 : }
343 : :
344 : : #endif /* _LINUX_FS_NOTIFY_H */
|