Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
0eeca283 RL |
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 | ||
90586523 | 15 | #include <linux/fsnotify_backend.h> |
73241ccc | 16 | #include <linux/audit.h> |
5a0e3ad6 | 17 | #include <linux/slab.h> |
187f1882 | 18 | #include <linux/bug.h> |
0eeca283 | 19 | |
a5e57b4d AG |
20 | /* Are there any inode/mount/sb objects watched with priority prio or above? */ |
21 | static inline bool fsnotify_sb_has_priority_watchers(struct super_block *sb, | |
22 | int prio) | |
b7dbaace | 23 | { |
cb5d4f48 AG |
24 | struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb); |
25 | ||
26 | /* Were any marks ever added to any object on this sb? */ | |
27 | if (!sbinfo) | |
28 | return false; | |
29 | ||
a5e57b4d AG |
30 | return atomic_long_read(&sbinfo->watched_objects[prio]); |
31 | } | |
32 | ||
33 | /* Are there any inode/mount/sb objects that are being watched at all? */ | |
34 | static inline bool fsnotify_sb_has_watchers(struct super_block *sb) | |
35 | { | |
36 | return fsnotify_sb_has_priority_watchers(sb, 0); | |
b7dbaace AG |
37 | } |
38 | ||
5f02a877 | 39 | /* |
a1aae057 AG |
40 | * Notify this @dir inode about a change in a child directory entry. |
41 | * The directory entry may have turned positive or negative or its inode may | |
42 | * have changed (i.e. renamed over). | |
5f02a877 AG |
43 | * |
44 | * Unlike fsnotify_parent(), the event will be reported regardless of the | |
40a100d3 AG |
45 | * FS_EVENT_ON_CHILD mask on the parent inode and will not be reported if only |
46 | * the child is interested and not the parent. | |
5f02a877 | 47 | */ |
9baf93d6 AG |
48 | static inline int fsnotify_name(__u32 mask, const void *data, int data_type, |
49 | struct inode *dir, const struct qstr *name, | |
50 | u32 cookie) | |
5f02a877 | 51 | { |
b7dbaace | 52 | if (!fsnotify_sb_has_watchers(dir->i_sb)) |
9baf93d6 | 53 | return 0; |
e43de7f0 | 54 | |
9baf93d6 | 55 | return fsnotify(mask, data, data_type, dir, name, NULL, cookie); |
a1aae057 AG |
56 | } |
57 | ||
58 | static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry, | |
59 | __u32 mask) | |
60 | { | |
fd5a3ff4 | 61 | fsnotify_name(mask, dentry, FSNOTIFY_EVENT_DENTRY, dir, &dentry->d_name, 0); |
5f02a877 AG |
62 | } |
63 | ||
82ace1ef AG |
64 | static inline void fsnotify_inode(struct inode *inode, __u32 mask) |
65 | { | |
b7dbaace | 66 | if (!fsnotify_sb_has_watchers(inode->i_sb)) |
e43de7f0 AG |
67 | return; |
68 | ||
82ace1ef AG |
69 | if (S_ISDIR(inode->i_mode)) |
70 | mask |= FS_ISDIR; | |
71 | ||
40a100d3 | 72 | fsnotify(mask, inode, FSNOTIFY_EVENT_INODE, NULL, NULL, inode, 0); |
82ace1ef AG |
73 | } |
74 | ||
71d73410 MG |
75 | /* Notify this dentry's parent about a child's events. */ |
76 | static inline int fsnotify_parent(struct dentry *dentry, __u32 mask, | |
77 | const void *data, int data_type) | |
78 | { | |
c738fbab AG |
79 | struct inode *inode = d_inode(dentry); |
80 | ||
b7dbaace | 81 | if (!fsnotify_sb_has_watchers(inode->i_sb)) |
e43de7f0 AG |
82 | return 0; |
83 | ||
9b93f331 | 84 | if (S_ISDIR(inode->i_mode)) { |
c738fbab AG |
85 | mask |= FS_ISDIR; |
86 | ||
9b93f331 AG |
87 | /* sb/mount marks are not interested in name of directory */ |
88 | if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED)) | |
89 | goto notify_child; | |
90 | } | |
91 | ||
92 | /* disconnected dentry cannot notify parent */ | |
93 | if (IS_ROOT(dentry)) | |
c738fbab | 94 | goto notify_child; |
71d73410 MG |
95 | |
96 | return __fsnotify_parent(dentry, mask, data, data_type); | |
c738fbab AG |
97 | |
98 | notify_child: | |
40a100d3 | 99 | return fsnotify(mask, data, data_type, NULL, NULL, inode, 0); |
71d73410 MG |
100 | } |
101 | ||
a704bba5 | 102 | /* |
c738fbab AG |
103 | * Simple wrappers to consolidate calls to fsnotify_parent() when an event |
104 | * is on a file/dentry. | |
a704bba5 | 105 | */ |
eae36a2b | 106 | static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask) |
a704bba5 | 107 | { |
fd5a3ff4 | 108 | fsnotify_parent(dentry, mask, dentry, FSNOTIFY_EVENT_DENTRY); |
eae36a2b AG |
109 | } |
110 | ||
a94204f4 | 111 | static inline int fsnotify_path(const struct path *path, __u32 mask) |
eae36a2b | 112 | { |
a94204f4 AG |
113 | return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH); |
114 | } | |
eae36a2b | 115 | |
a94204f4 AG |
116 | static inline int fsnotify_file(struct file *file, __u32 mask) |
117 | { | |
702eb71f JK |
118 | /* |
119 | * FMODE_NONOTIFY are fds generated by fanotify itself which should not | |
120 | * generate new events. We also don't want to generate events for | |
121 | * FMODE_PATH fds (involves open & close events) as they are just | |
122 | * handle creation / destruction events and not "real" file events. | |
123 | */ | |
a94204f4 | 124 | if (FMODE_FSNOTIFY_NONE(file->f_mode)) |
eae36a2b AG |
125 | return 0; |
126 | ||
a94204f4 | 127 | return fsnotify_path(&file->f_path, mask); |
a704bba5 MB |
128 | } |
129 | ||
7ea26f94 | 130 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS |
a94204f4 | 131 | |
95101401 | 132 | void file_set_fsnotify_mode_from_watchers(struct file *file); |
a94204f4 | 133 | |
36e28c42 | 134 | /* |
d9e5d310 | 135 | * fsnotify_file_area_perm - permission hook before access to file range |
36e28c42 | 136 | */ |
d9e5d310 AG |
137 | static inline int fsnotify_file_area_perm(struct file *file, int perm_mask, |
138 | const loff_t *ppos, size_t count) | |
c4ec54b4 | 139 | { |
cb383f06 AG |
140 | /* |
141 | * filesystem may be modified in the context of permission events | |
142 | * (e.g. by HSM filling a file on access), so sb freeze protection | |
143 | * must not be held. | |
144 | */ | |
145 | lockdep_assert_once(file_write_not_started(file)); | |
146 | ||
f156524e | 147 | if (!(perm_mask & (MAY_READ | MAY_WRITE | MAY_ACCESS))) |
c4ec54b4 | 148 | return 0; |
eae36a2b | 149 | |
a94204f4 AG |
150 | if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode))) |
151 | return 0; | |
152 | ||
f156524e AG |
153 | /* |
154 | * read()/write() and other types of access generate pre-content events. | |
155 | */ | |
156 | if (unlikely(FMODE_FSNOTIFY_HSM(file->f_mode))) { | |
9740d171 | 157 | int ret = fsnotify_pre_content(&file->f_path, ppos, count); |
f156524e AG |
158 | |
159 | if (ret) | |
160 | return ret; | |
161 | } | |
162 | ||
163 | if (!(perm_mask & MAY_READ)) | |
164 | return 0; | |
165 | ||
166 | /* | |
167 | * read() also generates the legacy FS_ACCESS_PERM event, so content | |
168 | * scanners can inspect the content filled by pre-content event. | |
169 | */ | |
a94204f4 | 170 | return fsnotify_path(&file->f_path, FS_ACCESS_PERM); |
36e28c42 | 171 | } |
66917a31 | 172 | |
066e053f AG |
173 | /* |
174 | * fsnotify_mmap_perm - permission hook before mmap of file range | |
175 | */ | |
176 | static inline int fsnotify_mmap_perm(struct file *file, int prot, | |
177 | const loff_t off, size_t len) | |
178 | { | |
179 | /* | |
180 | * mmap() generates only pre-content events. | |
181 | */ | |
182 | if (!file || likely(!FMODE_FSNOTIFY_HSM(file->f_mode))) | |
183 | return 0; | |
184 | ||
185 | return fsnotify_pre_content(&file->f_path, &off, len); | |
186 | } | |
187 | ||
4acf3bc7 AG |
188 | /* |
189 | * fsnotify_truncate_perm - permission hook before file truncate | |
190 | */ | |
191 | static inline int fsnotify_truncate_perm(const struct path *path, loff_t length) | |
192 | { | |
193 | struct inode *inode = d_inode(path->dentry); | |
194 | ||
195 | if (!(inode->i_sb->s_iflags & SB_I_ALLOW_HSM) || | |
196 | !fsnotify_sb_has_priority_watchers(inode->i_sb, | |
197 | FSNOTIFY_PRIO_PRE_CONTENT)) | |
198 | return 0; | |
199 | ||
200 | return fsnotify_pre_content(path, &length, 0); | |
201 | } | |
202 | ||
d9e5d310 | 203 | /* |
9740d171 | 204 | * fsnotify_file_perm - permission hook before file access (unknown range) |
d9e5d310 AG |
205 | */ |
206 | static inline int fsnotify_file_perm(struct file *file, int perm_mask) | |
207 | { | |
208 | return fsnotify_file_area_perm(file, perm_mask, NULL, 0); | |
209 | } | |
210 | ||
36e28c42 AG |
211 | /* |
212 | * fsnotify_open_perm - permission hook before file open | |
213 | */ | |
214 | static inline int fsnotify_open_perm(struct file *file) | |
215 | { | |
216 | int ret; | |
66917a31 | 217 | |
a94204f4 AG |
218 | if (likely(!FMODE_FSNOTIFY_PERM(file->f_mode))) |
219 | return 0; | |
220 | ||
36e28c42 | 221 | if (file->f_flags & __FMODE_EXEC) { |
a94204f4 | 222 | ret = fsnotify_path(&file->f_path, FS_OPEN_EXEC_PERM); |
36e28c42 AG |
223 | if (ret) |
224 | return ret; | |
66917a31 | 225 | } |
c4ec54b4 | 226 | |
a94204f4 | 227 | return fsnotify_path(&file->f_path, FS_OPEN_PERM); |
c4ec54b4 EP |
228 | } |
229 | ||
7ea26f94 | 230 | #else |
95101401 | 231 | static inline void file_set_fsnotify_mode_from_watchers(struct file *file) |
a94204f4 AG |
232 | { |
233 | } | |
234 | ||
7ea26f94 AG |
235 | static inline int fsnotify_file_area_perm(struct file *file, int perm_mask, |
236 | const loff_t *ppos, size_t count) | |
237 | { | |
238 | return 0; | |
239 | } | |
240 | ||
066e053f AG |
241 | static inline int fsnotify_mmap_perm(struct file *file, int prot, |
242 | const loff_t off, size_t len) | |
243 | { | |
244 | return 0; | |
245 | } | |
246 | ||
4acf3bc7 AG |
247 | static inline int fsnotify_truncate_perm(const struct path *path, loff_t length) |
248 | { | |
249 | return 0; | |
250 | } | |
251 | ||
7ea26f94 AG |
252 | static inline int fsnotify_file_perm(struct file *file, int perm_mask) |
253 | { | |
254 | return 0; | |
255 | } | |
256 | ||
257 | static inline int fsnotify_open_perm(struct file *file) | |
258 | { | |
259 | return 0; | |
260 | } | |
261 | #endif | |
262 | ||
90586523 EP |
263 | /* |
264 | * fsnotify_link_count - inode's link count changed | |
265 | */ | |
266 | static inline void fsnotify_link_count(struct inode *inode) | |
267 | { | |
82ace1ef | 268 | fsnotify_inode(inode, FS_ATTRIB); |
90586523 EP |
269 | } |
270 | ||
0eeca283 RL |
271 | /* |
272 | * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir | |
273 | */ | |
274 | static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, | |
f4ec3a3d | 275 | const struct qstr *old_name, |
0a20df7e AG |
276 | int isdir, struct inode *target, |
277 | struct dentry *moved) | |
0eeca283 | 278 | { |
5a190ae6 | 279 | struct inode *source = moved->d_inode; |
47882c6f | 280 | u32 fs_cookie = fsnotify_get_cookie(); |
5f02a877 AG |
281 | __u32 old_dir_mask = FS_MOVED_FROM; |
282 | __u32 new_dir_mask = FS_MOVED_TO; | |
e54183fa | 283 | __u32 rename_mask = FS_RENAME; |
25b229df | 284 | const struct qstr *new_name = &moved->d_name; |
0eeca283 | 285 | |
90586523 | 286 | if (isdir) { |
b29866aa EP |
287 | old_dir_mask |= FS_ISDIR; |
288 | new_dir_mask |= FS_ISDIR; | |
e54183fa | 289 | rename_mask |= FS_ISDIR; |
90586523 EP |
290 | } |
291 | ||
e54183fa AG |
292 | /* Event with information about both old and new parent+name */ |
293 | fsnotify_name(rename_mask, moved, FSNOTIFY_EVENT_DENTRY, | |
294 | old_dir, old_name, 0); | |
295 | ||
9baf93d6 AG |
296 | fsnotify_name(old_dir_mask, source, FSNOTIFY_EVENT_INODE, |
297 | old_dir, old_name, fs_cookie); | |
298 | fsnotify_name(new_dir_mask, source, FSNOTIFY_EVENT_INODE, | |
299 | new_dir, new_name, fs_cookie); | |
90586523 | 300 | |
2dfc1cae | 301 | if (target) |
90586523 | 302 | fsnotify_link_count(target); |
79cb299c | 303 | fsnotify_inode(source, FS_MOVE_SELF); |
4fa6b5ec | 304 | audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE); |
0eeca283 RL |
305 | } |
306 | ||
3be25f49 EP |
307 | /* |
308 | * fsnotify_inode_delete - and inode is being evicted from cache, clean up is needed | |
309 | */ | |
310 | static inline void fsnotify_inode_delete(struct inode *inode) | |
311 | { | |
312 | __fsnotify_inode_delete(inode); | |
313 | } | |
314 | ||
ca9c726e AG |
315 | /* |
316 | * fsnotify_vfsmount_delete - a vfsmount is being destroyed, clean up is needed | |
317 | */ | |
318 | static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt) | |
319 | { | |
320 | __fsnotify_vfsmount_delete(mnt); | |
321 | } | |
322 | ||
b944249b MS |
323 | static inline void fsnotify_mntns_delete(struct mnt_namespace *mntns) |
324 | { | |
325 | __fsnotify_mntns_delete(mntns); | |
326 | } | |
327 | ||
7a91bf7f JM |
328 | /* |
329 | * fsnotify_inoderemove - an inode is going away | |
330 | */ | |
331 | static inline void fsnotify_inoderemove(struct inode *inode) | |
332 | { | |
82ace1ef | 333 | fsnotify_inode(inode, FS_DELETE_SELF); |
3be25f49 | 334 | __fsnotify_inode_delete(inode); |
ece95912 JK |
335 | } |
336 | ||
0eeca283 RL |
337 | /* |
338 | * fsnotify_create - 'name' was linked in | |
dabe729d AG |
339 | * |
340 | * Caller must make sure that dentry->d_name is stable. | |
341 | * Note: some filesystems (e.g. kernfs) leave @dentry negative and instantiate | |
342 | * ->d_inode later | |
0eeca283 | 343 | */ |
dabe729d | 344 | static inline void fsnotify_create(struct inode *dir, struct dentry *dentry) |
0eeca283 | 345 | { |
dabe729d | 346 | audit_inode_child(dir, dentry, AUDIT_TYPE_CHILD_CREATE); |
90586523 | 347 | |
dabe729d | 348 | fsnotify_dirent(dir, dentry, FS_CREATE); |
0eeca283 RL |
349 | } |
350 | ||
ece95912 JK |
351 | /* |
352 | * fsnotify_link - new hardlink in 'inode' directory | |
dabe729d AG |
353 | * |
354 | * Caller must make sure that new_dentry->d_name is stable. | |
ece95912 JK |
355 | * Note: We have to pass also the linked inode ptr as some filesystems leave |
356 | * new_dentry->d_inode NULL and instantiate inode pointer later | |
357 | */ | |
a1aae057 AG |
358 | static inline void fsnotify_link(struct inode *dir, struct inode *inode, |
359 | struct dentry *new_dentry) | |
ece95912 | 360 | { |
ece95912 | 361 | fsnotify_link_count(inode); |
4fa6b5ec | 362 | audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE); |
90586523 | 363 | |
9baf93d6 AG |
364 | fsnotify_name(FS_CREATE, inode, FSNOTIFY_EVENT_INODE, |
365 | dir, &new_dentry->d_name, 0); | |
ece95912 JK |
366 | } |
367 | ||
a37d9a17 AG |
368 | /* |
369 | * fsnotify_delete - @dentry was unlinked and unhashed | |
370 | * | |
371 | * Caller must make sure that dentry->d_name is stable. | |
372 | * | |
373 | * Note: unlike fsnotify_unlink(), we have to pass also the unlinked inode | |
374 | * as this may be called after d_delete() and old_dentry may be negative. | |
375 | */ | |
376 | static inline void fsnotify_delete(struct inode *dir, struct inode *inode, | |
377 | struct dentry *dentry) | |
378 | { | |
379 | __u32 mask = FS_DELETE; | |
380 | ||
381 | if (S_ISDIR(inode->i_mode)) | |
382 | mask |= FS_ISDIR; | |
383 | ||
384 | fsnotify_name(mask, inode, FSNOTIFY_EVENT_INODE, dir, &dentry->d_name, | |
385 | 0); | |
386 | } | |
387 | ||
388 | /** | |
389 | * d_delete_notify - delete a dentry and call fsnotify_delete() | |
390 | * @dentry: The dentry to delete | |
391 | * | |
392 | * This helper is used to guaranty that the unlinked inode cannot be found | |
393 | * by lookup of this name after fsnotify_delete() event has been delivered. | |
394 | */ | |
395 | static inline void d_delete_notify(struct inode *dir, struct dentry *dentry) | |
396 | { | |
397 | struct inode *inode = d_inode(dentry); | |
398 | ||
399 | ihold(inode); | |
400 | d_delete(dentry); | |
401 | fsnotify_delete(dir, inode, dentry); | |
402 | iput(inode); | |
403 | } | |
404 | ||
116b9731 AG |
405 | /* |
406 | * fsnotify_unlink - 'name' was unlinked | |
407 | * | |
408 | * Caller must make sure that dentry->d_name is stable. | |
409 | */ | |
410 | static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry) | |
411 | { | |
a37d9a17 AG |
412 | if (WARN_ON_ONCE(d_is_negative(dentry))) |
413 | return; | |
116b9731 | 414 | |
a37d9a17 | 415 | fsnotify_delete(dir, d_inode(dentry), dentry); |
116b9731 AG |
416 | } |
417 | ||
0eeca283 RL |
418 | /* |
419 | * fsnotify_mkdir - directory 'name' was created | |
dabe729d AG |
420 | * |
421 | * Caller must make sure that dentry->d_name is stable. | |
422 | * Note: some filesystems (e.g. kernfs) leave @dentry negative and instantiate | |
423 | * ->d_inode later | |
0eeca283 | 424 | */ |
dabe729d | 425 | static inline void fsnotify_mkdir(struct inode *dir, struct dentry *dentry) |
0eeca283 | 426 | { |
dabe729d | 427 | audit_inode_child(dir, dentry, AUDIT_TYPE_CHILD_CREATE); |
90586523 | 428 | |
dabe729d | 429 | fsnotify_dirent(dir, dentry, FS_CREATE | FS_ISDIR); |
0eeca283 RL |
430 | } |
431 | ||
116b9731 AG |
432 | /* |
433 | * fsnotify_rmdir - directory 'name' was removed | |
434 | * | |
435 | * Caller must make sure that dentry->d_name is stable. | |
436 | */ | |
437 | static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry) | |
438 | { | |
a37d9a17 AG |
439 | if (WARN_ON_ONCE(d_is_negative(dentry))) |
440 | return; | |
116b9731 | 441 | |
a37d9a17 | 442 | fsnotify_delete(dir, d_inode(dentry), dentry); |
116b9731 AG |
443 | } |
444 | ||
0eeca283 RL |
445 | /* |
446 | * fsnotify_access - file was read | |
447 | */ | |
2a12a9d7 | 448 | static inline void fsnotify_access(struct file *file) |
0eeca283 | 449 | { |
eae36a2b | 450 | fsnotify_file(file, FS_ACCESS); |
0eeca283 RL |
451 | } |
452 | ||
453 | /* | |
454 | * fsnotify_modify - file was modified | |
455 | */ | |
2a12a9d7 | 456 | static inline void fsnotify_modify(struct file *file) |
0eeca283 | 457 | { |
eae36a2b | 458 | fsnotify_file(file, FS_MODIFY); |
0eeca283 RL |
459 | } |
460 | ||
461 | /* | |
462 | * fsnotify_open - file was opened | |
463 | */ | |
2a12a9d7 | 464 | static inline void fsnotify_open(struct file *file) |
0eeca283 | 465 | { |
90586523 | 466 | __u32 mask = FS_OPEN; |
0eeca283 | 467 | |
9b076f1c MB |
468 | if (file->f_flags & __FMODE_EXEC) |
469 | mask |= FS_OPEN_EXEC; | |
0eeca283 | 470 | |
eae36a2b | 471 | fsnotify_file(file, mask); |
0eeca283 RL |
472 | } |
473 | ||
474 | /* | |
475 | * fsnotify_close - file was closed | |
476 | */ | |
477 | static inline void fsnotify_close(struct file *file) | |
478 | { | |
eae36a2b AG |
479 | __u32 mask = (file->f_mode & FMODE_WRITE) ? FS_CLOSE_WRITE : |
480 | FS_CLOSE_NOWRITE; | |
0eeca283 | 481 | |
eae36a2b | 482 | fsnotify_file(file, mask); |
0eeca283 RL |
483 | } |
484 | ||
485 | /* | |
486 | * fsnotify_xattr - extended attributes were changed | |
487 | */ | |
488 | static inline void fsnotify_xattr(struct dentry *dentry) | |
489 | { | |
eae36a2b | 490 | fsnotify_dentry(dentry, FS_ATTRIB); |
0eeca283 RL |
491 | } |
492 | ||
493 | /* | |
494 | * fsnotify_change - notify_change event. file was modified and/or metadata | |
495 | * was changed. | |
496 | */ | |
497 | static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) | |
498 | { | |
3c5119c0 EP |
499 | __u32 mask = 0; |
500 | ||
501 | if (ia_valid & ATTR_UID) | |
502 | mask |= FS_ATTRIB; | |
503 | if (ia_valid & ATTR_GID) | |
504 | mask |= FS_ATTRIB; | |
505 | if (ia_valid & ATTR_SIZE) | |
506 | mask |= FS_MODIFY; | |
0eeca283 | 507 | |
0eeca283 RL |
508 | /* both times implies a utime(s) call */ |
509 | if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) | |
3c5119c0 EP |
510 | mask |= FS_ATTRIB; |
511 | else if (ia_valid & ATTR_ATIME) | |
512 | mask |= FS_ACCESS; | |
513 | else if (ia_valid & ATTR_MTIME) | |
514 | mask |= FS_MODIFY; | |
515 | ||
516 | if (ia_valid & ATTR_MODE) | |
517 | mask |= FS_ATTRIB; | |
0eeca283 | 518 | |
eae36a2b AG |
519 | if (mask) |
520 | fsnotify_dentry(dentry, mask); | |
0eeca283 RL |
521 | } |
522 | ||
9daa8110 GKB |
523 | static inline int fsnotify_sb_error(struct super_block *sb, struct inode *inode, |
524 | int error) | |
525 | { | |
526 | struct fs_error_report report = { | |
527 | .error = error, | |
528 | .inode = inode, | |
529 | .sb = sb, | |
530 | }; | |
531 | ||
532 | return fsnotify(FS_ERROR, &report, FSNOTIFY_EVENT_ERROR, | |
533 | NULL, NULL, NULL, 0); | |
534 | } | |
535 | ||
b944249b MS |
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 | ||
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 | ||
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 | ||
0eeca283 | 551 | #endif /* _LINUX_FS_NOTIFY_H */ |