cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fsnotify.h (9987B)


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