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