blob: fd1ce10553bfad43fbbfdc1faa367f9fd0fd93c8 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001/* SPDX-License-Identifier: GPL-2.0 */
Robert Love0eeca282005-07-12 17:06:03 -04002#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
Eric Paris90586522009-05-21 17:01:20 -040015#include <linux/fsnotify_backend.h>
Amy Griffis73241cc2005-11-03 16:00:25 +000016#include <linux/audit.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Paul Gortmaker187f1882011-11-23 20:12:59 -050018#include <linux/bug.h>
Robert Love0eeca282005-07-12 17:06:03 -040019
Eric Parisc28f7e52009-05-21 17:01:29 -040020/* Notify this dentry's parent about a child's events. */
Al Viro12c7f9d2016-11-20 20:23:04 -050021static inline int fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask)
Eric Parisc28f7e52009-05-21 17:01:29 -040022{
Andreas Gruenbacher72acc852009-12-17 21:24:24 -050023 if (!dentry)
Linus Torvalds20696012010-08-12 14:23:04 -070024 dentry = path->dentry;
Eric Paris28c60e32009-12-17 21:24:21 -050025
Eric Paris52420392010-10-28 17:21:56 -040026 return __fsnotify_parent(path, dentry, mask);
Eric Parisc28f7e52009-05-21 17:01:29 -040027}
28
Eric Parisc4ec54b2009-12-17 21:24:34 -050029/* simple call site for access decisions */
30static inline int fsnotify_perm(struct file *file, int mask)
31{
Al Viro40212d52016-11-20 20:24:41 -050032 const struct path *path = &file->f_path;
Miklos Szeredi573e1782018-07-18 15:44:44 +020033 struct inode *inode = file_inode(file);
Eric Parisfb1cfb82010-05-12 11:42:29 -040034 __u32 fsnotify_mask = 0;
Eric Paris52420392010-10-28 17:21:56 -040035 int ret;
Eric Parisc4ec54b2009-12-17 21:24:34 -050036
37 if (file->f_mode & FMODE_NONOTIFY)
38 return 0;
39 if (!(mask & (MAY_READ | MAY_OPEN)))
40 return 0;
Eric Parisc4ec54b2009-12-17 21:24:34 -050041 if (mask & MAY_OPEN)
42 fsnotify_mask = FS_OPEN_PERM;
Eric Parisfb1cfb82010-05-12 11:42:29 -040043 else if (mask & MAY_READ)
44 fsnotify_mask = FS_ACCESS_PERM;
45 else
46 BUG();
Eric Parisc4ec54b2009-12-17 21:24:34 -050047
Eric Paris52420392010-10-28 17:21:56 -040048 ret = fsnotify_parent(path, NULL, fsnotify_mask);
49 if (ret)
50 return ret;
51
Linus Torvalds20696012010-08-12 14:23:04 -070052 return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
Eric Parisc4ec54b2009-12-17 21:24:34 -050053}
54
Nick Pigginc32ccd82006-03-25 03:07:09 -080055/*
Eric Paris90586522009-05-21 17:01:20 -040056 * fsnotify_link_count - inode's link count changed
57 */
58static inline void fsnotify_link_count(struct inode *inode)
59{
Eric Paris47882c62009-05-21 17:01:47 -040060 fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
Eric Paris90586522009-05-21 17:01:20 -040061}
62
63/*
Robert Love0eeca282005-07-12 17:06:03 -040064 * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
65 */
66static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
Eric Paris59b0df22010-02-08 12:53:52 -050067 const unsigned char *old_name,
Al Viro5a190ae2007-06-07 12:19:32 -040068 int isdir, struct inode *target, struct dentry *moved)
Robert Love0eeca282005-07-12 17:06:03 -040069{
Al Viro5a190ae2007-06-07 12:19:32 -040070 struct inode *source = moved->d_inode;
Eric Paris47882c62009-05-21 17:01:47 -040071 u32 fs_cookie = fsnotify_get_cookie();
Eric Parisff52cc22009-06-11 11:09:47 -040072 __u32 old_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_FROM);
73 __u32 new_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_TO);
Eric Paris59b0df22010-02-08 12:53:52 -050074 const unsigned char *new_name = moved->d_name.name;
Robert Love0eeca282005-07-12 17:06:03 -040075
Eric Parisff52cc22009-06-11 11:09:47 -040076 if (old_dir == new_dir)
77 old_dir_mask |= FS_DN_RENAME;
Robert Love0eeca282005-07-12 17:06:03 -040078
Eric Paris90586522009-05-21 17:01:20 -040079 if (isdir) {
Eric Parisb29866a2010-10-28 17:21:58 -040080 old_dir_mask |= FS_ISDIR;
81 new_dir_mask |= FS_ISDIR;
Eric Paris90586522009-05-21 17:01:20 -040082 }
83
Jan Kara6ee8e252015-02-10 14:08:32 -080084 fsnotify(old_dir, old_dir_mask, source, FSNOTIFY_EVENT_INODE, old_name,
85 fs_cookie);
86 fsnotify(new_dir, new_dir_mask, source, FSNOTIFY_EVENT_INODE, new_name,
87 fs_cookie);
Eric Paris90586522009-05-21 17:01:20 -040088
Eric Paris2dfc1ca2009-12-17 20:30:52 -050089 if (target)
Eric Paris90586522009-05-21 17:01:20 -040090 fsnotify_link_count(target);
John McCutchan89204c42005-08-15 12:13:28 -040091
Eric Paris2dfc1ca2009-12-17 20:30:52 -050092 if (source)
Eric Paris47882c62009-05-21 17:01:47 -040093 fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0);
Jeff Layton4fa6b5e2012-10-10 15:25:25 -040094 audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE);
Robert Love0eeca282005-07-12 17:06:03 -040095}
96
97/*
Eric Paris3be25f42009-05-21 17:01:26 -040098 * fsnotify_inode_delete - and inode is being evicted from cache, clean up is needed
99 */
100static inline void fsnotify_inode_delete(struct inode *inode)
101{
102 __fsnotify_inode_delete(inode);
103}
104
105/*
Andreas Gruenbacherca9c7262009-12-17 21:24:27 -0500106 * fsnotify_vfsmount_delete - a vfsmount is being destroyed, clean up is needed
107 */
108static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt)
109{
110 __fsnotify_vfsmount_delete(mnt);
111}
112
113/*
John McCutchan7a91bf72005-08-08 13:52:16 -0400114 * fsnotify_nameremove - a filename was removed from a directory
115 */
116static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
117{
Eric Paris90586522009-05-21 17:01:20 -0400118 __u32 mask = FS_DELETE;
119
John McCutchan7a91bf72005-08-08 13:52:16 -0400120 if (isdir)
Eric Parisb29866a2010-10-28 17:21:58 -0400121 mask |= FS_ISDIR;
Eric Parisc28f7e52009-05-21 17:01:29 -0400122
Eric Paris28c60e32009-12-17 21:24:21 -0500123 fsnotify_parent(NULL, dentry, mask);
John McCutchan7a91bf72005-08-08 13:52:16 -0400124}
125
126/*
127 * fsnotify_inoderemove - an inode is going away
128 */
129static inline void fsnotify_inoderemove(struct inode *inode)
130{
Eric Paris47882c62009-05-21 17:01:47 -0400131 fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
Eric Paris3be25f42009-05-21 17:01:26 -0400132 __fsnotify_inode_delete(inode);
Jan Karaece95912008-02-06 01:37:13 -0800133}
134
135/*
Robert Love0eeca282005-07-12 17:06:03 -0400136 * fsnotify_create - 'name' was linked in
137 */
Amy Griffisf38aa942005-11-03 15:57:06 +0000138static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
Robert Love0eeca282005-07-12 17:06:03 -0400139{
Jeff Layton4fa6b5e2012-10-10 15:25:25 -0400140 audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
Eric Paris90586522009-05-21 17:01:20 -0400141
Eric Paris47882c62009-05-21 17:01:47 -0400142 fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
Robert Love0eeca282005-07-12 17:06:03 -0400143}
144
145/*
Jan Karaece95912008-02-06 01:37:13 -0800146 * fsnotify_link - new hardlink in 'inode' directory
147 * Note: We have to pass also the linked inode ptr as some filesystems leave
148 * new_dentry->d_inode NULL and instantiate inode pointer later
149 */
150static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
151{
Jan Karaece95912008-02-06 01:37:13 -0800152 fsnotify_link_count(inode);
Jeff Layton4fa6b5e2012-10-10 15:25:25 -0400153 audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE);
Eric Paris90586522009-05-21 17:01:20 -0400154
Eric Paris47882c62009-05-21 17:01:47 -0400155 fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0);
Jan Karaece95912008-02-06 01:37:13 -0800156}
157
158/*
Robert Love0eeca282005-07-12 17:06:03 -0400159 * fsnotify_mkdir - directory 'name' was created
160 */
Amy Griffisf38aa942005-11-03 15:57:06 +0000161static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
Robert Love0eeca282005-07-12 17:06:03 -0400162{
Eric Parisb29866a2010-10-28 17:21:58 -0400163 __u32 mask = (FS_CREATE | FS_ISDIR);
Eric Paris90586522009-05-21 17:01:20 -0400164 struct inode *d_inode = dentry->d_inode;
165
Jeff Layton4fa6b5e2012-10-10 15:25:25 -0400166 audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
Eric Paris90586522009-05-21 17:01:20 -0400167
Eric Paris47882c62009-05-21 17:01:47 -0400168 fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
Robert Love0eeca282005-07-12 17:06:03 -0400169}
170
171/*
172 * fsnotify_access - file was read
173 */
Eric Paris2a12a9d2009-12-17 21:24:21 -0500174static inline void fsnotify_access(struct file *file)
Robert Love0eeca282005-07-12 17:06:03 -0400175{
Al Viro40212d52016-11-20 20:24:41 -0500176 const struct path *path = &file->f_path;
Miklos Szeredi573e1782018-07-18 15:44:44 +0200177 struct inode *inode = file_inode(file);
Eric Paris90586522009-05-21 17:01:20 -0400178 __u32 mask = FS_ACCESS;
Robert Love0eeca282005-07-12 17:06:03 -0400179
180 if (S_ISDIR(inode->i_mode))
Eric Parisb29866a2010-10-28 17:21:58 -0400181 mask |= FS_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400182
Eric Parisecf081d2009-12-17 21:24:25 -0500183 if (!(file->f_mode & FMODE_NONOTIFY)) {
Linus Torvalds20696012010-08-12 14:23:04 -0700184 fsnotify_parent(path, NULL, mask);
185 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
Eric Parisecf081d2009-12-17 21:24:25 -0500186 }
Robert Love0eeca282005-07-12 17:06:03 -0400187}
188
189/*
190 * fsnotify_modify - file was modified
191 */
Eric Paris2a12a9d2009-12-17 21:24:21 -0500192static inline void fsnotify_modify(struct file *file)
Robert Love0eeca282005-07-12 17:06:03 -0400193{
Al Viro40212d52016-11-20 20:24:41 -0500194 const struct path *path = &file->f_path;
Miklos Szeredi573e1782018-07-18 15:44:44 +0200195 struct inode *inode = file_inode(file);
Eric Paris90586522009-05-21 17:01:20 -0400196 __u32 mask = FS_MODIFY;
Robert Love0eeca282005-07-12 17:06:03 -0400197
198 if (S_ISDIR(inode->i_mode))
Eric Parisb29866a2010-10-28 17:21:58 -0400199 mask |= FS_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400200
Eric Parisecf081d2009-12-17 21:24:25 -0500201 if (!(file->f_mode & FMODE_NONOTIFY)) {
Linus Torvalds20696012010-08-12 14:23:04 -0700202 fsnotify_parent(path, NULL, mask);
203 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
Eric Parisecf081d2009-12-17 21:24:25 -0500204 }
Robert Love0eeca282005-07-12 17:06:03 -0400205}
206
207/*
208 * fsnotify_open - file was opened
209 */
Eric Paris2a12a9d2009-12-17 21:24:21 -0500210static inline void fsnotify_open(struct file *file)
Robert Love0eeca282005-07-12 17:06:03 -0400211{
Al Viro40212d52016-11-20 20:24:41 -0500212 const struct path *path = &file->f_path;
Miklos Szeredi573e1782018-07-18 15:44:44 +0200213 struct inode *inode = file_inode(file);
Eric Paris90586522009-05-21 17:01:20 -0400214 __u32 mask = FS_OPEN;
Robert Love0eeca282005-07-12 17:06:03 -0400215
216 if (S_ISDIR(inode->i_mode))
Eric Parisb29866a2010-10-28 17:21:58 -0400217 mask |= FS_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400218
Lino Sanfilippo6bff7ec2010-10-29 12:02:17 +0200219 fsnotify_parent(path, NULL, mask);
220 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
Robert Love0eeca282005-07-12 17:06:03 -0400221}
222
223/*
224 * fsnotify_close - file was closed
225 */
226static inline void fsnotify_close(struct file *file)
227{
Al Viro40212d52016-11-20 20:24:41 -0500228 const struct path *path = &file->f_path;
Miklos Szeredi573e1782018-07-18 15:44:44 +0200229 struct inode *inode = file_inode(file);
Al Viroaeb5d722008-09-02 15:28:45 -0400230 fmode_t mode = file->f_mode;
Eric Paris90586522009-05-21 17:01:20 -0400231 __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
Robert Love0eeca282005-07-12 17:06:03 -0400232
233 if (S_ISDIR(inode->i_mode))
Eric Parisb29866a2010-10-28 17:21:58 -0400234 mask |= FS_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400235
Eric Parisecf081d2009-12-17 21:24:25 -0500236 if (!(file->f_mode & FMODE_NONOTIFY)) {
Linus Torvalds20696012010-08-12 14:23:04 -0700237 fsnotify_parent(path, NULL, mask);
238 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
Eric Parisecf081d2009-12-17 21:24:25 -0500239 }
Robert Love0eeca282005-07-12 17:06:03 -0400240}
241
242/*
243 * fsnotify_xattr - extended attributes were changed
244 */
245static inline void fsnotify_xattr(struct dentry *dentry)
246{
247 struct inode *inode = dentry->d_inode;
Eric Paris90586522009-05-21 17:01:20 -0400248 __u32 mask = FS_ATTRIB;
Robert Love0eeca282005-07-12 17:06:03 -0400249
250 if (S_ISDIR(inode->i_mode))
Eric Parisb29866a2010-10-28 17:21:58 -0400251 mask |= FS_ISDIR;
Robert Love0eeca282005-07-12 17:06:03 -0400252
Eric Paris28c60e32009-12-17 21:24:21 -0500253 fsnotify_parent(NULL, dentry, mask);
Eric Paris47882c62009-05-21 17:01:47 -0400254 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
Robert Love0eeca282005-07-12 17:06:03 -0400255}
256
257/*
258 * fsnotify_change - notify_change event. file was modified and/or metadata
259 * was changed.
260 */
261static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
262{
263 struct inode *inode = dentry->d_inode;
Eric Paris3c5119c2009-05-21 17:01:33 -0400264 __u32 mask = 0;
Robert Love0eeca282005-07-12 17:06:03 -0400265
Eric Paris3c5119c2009-05-21 17:01:33 -0400266 if (ia_valid & ATTR_UID)
267 mask |= FS_ATTRIB;
268 if (ia_valid & ATTR_GID)
269 mask |= FS_ATTRIB;
270 if (ia_valid & ATTR_SIZE)
271 mask |= FS_MODIFY;
272
Robert Love0eeca282005-07-12 17:06:03 -0400273 /* both times implies a utime(s) call */
274 if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME))
Eric Paris3c5119c2009-05-21 17:01:33 -0400275 mask |= FS_ATTRIB;
276 else if (ia_valid & ATTR_ATIME)
277 mask |= FS_ACCESS;
278 else if (ia_valid & ATTR_MTIME)
279 mask |= FS_MODIFY;
Robert Love0eeca282005-07-12 17:06:03 -0400280
Eric Paris3c5119c2009-05-21 17:01:33 -0400281 if (ia_valid & ATTR_MODE)
282 mask |= FS_ATTRIB;
283
284 if (mask) {
Robert Love0eeca282005-07-12 17:06:03 -0400285 if (S_ISDIR(inode->i_mode))
Eric Parisb29866a2010-10-28 17:21:58 -0400286 mask |= FS_ISDIR;
Eric Paris28c60e32009-12-17 21:24:21 -0500287
288 fsnotify_parent(NULL, dentry, mask);
Eric Paris47882c62009-05-21 17:01:47 -0400289 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
Robert Love0eeca282005-07-12 17:06:03 -0400290 }
291}
292
Robert Love0eeca282005-07-12 17:06:03 -0400293#endif /* _LINUX_FS_NOTIFY_H */