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