Merge branch 'for-linus' of git://git.infradead.org/users/eparis/notify
* 'for-linus' of git://git.infradead.org/users/eparis/notify: (132 commits) fanotify: use both marks when possible fsnotify: pass both the vfsmount mark and inode mark fsnotify: walk the inode and vfsmount lists simultaneously fsnotify: rework ignored mark flushing fsnotify: remove global fsnotify groups lists fsnotify: remove group->mask fsnotify: remove the global masks fsnotify: cleanup should_send_event fanotify: use the mark in handler functions audit: use the mark in handler functions dnotify: use the mark in handler functions inotify: use the mark in handler functions fsnotify: send fsnotify_mark to groups in event handling functions fsnotify: Exchange list heads instead of moving elements fsnotify: srcu to protect read side of inode and vfsmount locks fsnotify: use an explicit flag to indicate fsnotify_destroy_mark has been called fsnotify: use _rcu functions for mark list traversal fsnotify: place marks on object in order of group memory address vfs/fsnotify: fsnotify_close can delay the final work in fput fsnotify: store struct file not struct path ... Fix up trivial delete/modify conflict in fs/notify/inotify/inotify.c.
This commit is contained in:
@@ -210,6 +210,7 @@ unifdef-y += ethtool.h
|
||||
unifdef-y += eventpoll.h
|
||||
unifdef-y += signalfd.h
|
||||
unifdef-y += ext2_fs.h
|
||||
unifdef-y += fanotify.h
|
||||
unifdef-y += fb.h
|
||||
unifdef-y += fcntl.h
|
||||
unifdef-y += filter.h
|
||||
|
@@ -28,6 +28,7 @@ struct dnotify_struct {
|
||||
FS_CREATE | FS_DN_RENAME |\
|
||||
FS_MOVED_FROM | FS_MOVED_TO)
|
||||
|
||||
extern int dir_notify_enable;
|
||||
extern void dnotify_flush(struct file *, fl_owner_t);
|
||||
extern int fcntl_dirnotify(int, struct file *, unsigned long);
|
||||
|
||||
|
105
include/linux/fanotify.h
Normal file
105
include/linux/fanotify.h
Normal file
@@ -0,0 +1,105 @@
|
||||
#ifndef _LINUX_FANOTIFY_H
|
||||
#define _LINUX_FANOTIFY_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* the following events that user-space can register for */
|
||||
#define FAN_ACCESS 0x00000001 /* File was accessed */
|
||||
#define FAN_MODIFY 0x00000002 /* File was modified */
|
||||
#define FAN_CLOSE_WRITE 0x00000008 /* Unwrittable file closed */
|
||||
#define FAN_CLOSE_NOWRITE 0x00000010 /* Writtable file closed */
|
||||
#define FAN_OPEN 0x00000020 /* File was opened */
|
||||
|
||||
#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */
|
||||
|
||||
/* FIXME currently Q's have no limit.... */
|
||||
#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
|
||||
|
||||
#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */
|
||||
#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */
|
||||
|
||||
/* helper events */
|
||||
#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
|
||||
|
||||
/* flags used for fanotify_init() */
|
||||
#define FAN_CLOEXEC 0x00000001
|
||||
#define FAN_NONBLOCK 0x00000002
|
||||
|
||||
#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK)
|
||||
|
||||
/* flags used for fanotify_modify_mark() */
|
||||
#define FAN_MARK_ADD 0x00000001
|
||||
#define FAN_MARK_REMOVE 0x00000002
|
||||
#define FAN_MARK_DONT_FOLLOW 0x00000004
|
||||
#define FAN_MARK_ONLYDIR 0x00000008
|
||||
#define FAN_MARK_MOUNT 0x00000010
|
||||
#define FAN_MARK_IGNORED_MASK 0x00000020
|
||||
#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040
|
||||
#define FAN_MARK_FLUSH 0x00000080
|
||||
|
||||
#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\
|
||||
FAN_MARK_REMOVE |\
|
||||
FAN_MARK_DONT_FOLLOW |\
|
||||
FAN_MARK_ONLYDIR |\
|
||||
FAN_MARK_MOUNT |\
|
||||
FAN_MARK_IGNORED_MASK |\
|
||||
FAN_MARK_IGNORED_SURV_MODIFY)
|
||||
|
||||
/*
|
||||
* All of the events - we build the list by hand so that we can add flags in
|
||||
* the future and not break backward compatibility. Apps will get only the
|
||||
* events that they originally wanted. Be sure to add new events here!
|
||||
*/
|
||||
#define FAN_ALL_EVENTS (FAN_ACCESS |\
|
||||
FAN_MODIFY |\
|
||||
FAN_CLOSE |\
|
||||
FAN_OPEN)
|
||||
|
||||
/*
|
||||
* All events which require a permission response from userspace
|
||||
*/
|
||||
#define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\
|
||||
FAN_ACCESS_PERM)
|
||||
|
||||
#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\
|
||||
FAN_ALL_PERM_EVENTS |\
|
||||
FAN_Q_OVERFLOW)
|
||||
|
||||
#define FANOTIFY_METADATA_VERSION 1
|
||||
|
||||
struct fanotify_event_metadata {
|
||||
__u32 event_len;
|
||||
__u32 vers;
|
||||
__s32 fd;
|
||||
__u64 mask;
|
||||
__s64 pid;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct fanotify_response {
|
||||
__s32 fd;
|
||||
__u32 response;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Legit userspace responses to a _PERM event */
|
||||
#define FAN_ALLOW 0x01
|
||||
#define FAN_DENY 0x02
|
||||
|
||||
/* Helper functions to deal with fanotify_event_metadata buffers */
|
||||
#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata))
|
||||
|
||||
#define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \
|
||||
(struct fanotify_event_metadata*)(((char *)(meta)) + \
|
||||
(meta)->event_len))
|
||||
|
||||
#define FAN_EVENT_OK(meta, len) ((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \
|
||||
(long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \
|
||||
(long)(meta)->event_len <= (long)(len))
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct fanotify_wait {
|
||||
struct fsnotify_event *event;
|
||||
__s32 fd;
|
||||
};
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_FANOTIFY_H */
|
@@ -91,6 +91,9 @@ struct inodes_stat_t {
|
||||
/* Expect random access pattern */
|
||||
#define FMODE_RANDOM ((__force fmode_t)0x1000)
|
||||
|
||||
/* File was opened by fanotify and shouldn't generate fanotify events */
|
||||
#define FMODE_NONOTIFY ((__force fmode_t)16777216) /* 0x1000000 */
|
||||
|
||||
/*
|
||||
* The below are the various read and write types that we support. Some of
|
||||
* them include behavioral modifiers that send information down to the
|
||||
@@ -409,9 +412,6 @@ extern int get_max_files(void);
|
||||
extern int sysctl_nr_open;
|
||||
extern struct inodes_stat_t inodes_stat;
|
||||
extern int leases_enable, lease_break_time;
|
||||
#ifdef CONFIG_DNOTIFY
|
||||
extern int dir_notify_enable;
|
||||
#endif
|
||||
|
||||
struct buffer_head;
|
||||
typedef int (get_block_t)(struct inode *inode, sector_t iblock,
|
||||
@@ -772,12 +772,7 @@ struct inode {
|
||||
|
||||
#ifdef CONFIG_FSNOTIFY
|
||||
__u32 i_fsnotify_mask; /* all events this inode cares about */
|
||||
struct hlist_head i_fsnotify_mark_entries; /* fsnotify mark entries */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INOTIFY
|
||||
struct list_head inotify_watches; /* watches on this inode */
|
||||
struct mutex inotify_mutex; /* protects the watches list */
|
||||
struct hlist_head i_fsnotify_marks;
|
||||
#endif
|
||||
|
||||
unsigned long i_state;
|
||||
@@ -2484,7 +2479,8 @@ int proc_nr_files(struct ctl_table *table, int write,
|
||||
int __init get_filesystem_list(char *buf);
|
||||
|
||||
#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
|
||||
#define OPEN_FMODE(flag) ((__force fmode_t)((flag + 1) & O_ACCMODE))
|
||||
#define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
|
||||
(flag & FMODE_NONOTIFY)))
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_FS_H */
|
||||
|
@@ -11,8 +11,6 @@
|
||||
* (C) Copyright 2005 Robert Love
|
||||
*/
|
||||
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/inotify.h>
|
||||
#include <linux/fsnotify_backend.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -21,35 +19,52 @@
|
||||
* fsnotify_d_instantiate - instantiate a dentry for inode
|
||||
* Called with dcache_lock held.
|
||||
*/
|
||||
static inline void fsnotify_d_instantiate(struct dentry *entry,
|
||||
struct inode *inode)
|
||||
static inline void fsnotify_d_instantiate(struct dentry *dentry,
|
||||
struct inode *inode)
|
||||
{
|
||||
__fsnotify_d_instantiate(entry, inode);
|
||||
|
||||
inotify_d_instantiate(entry, inode);
|
||||
__fsnotify_d_instantiate(dentry, inode);
|
||||
}
|
||||
|
||||
/* Notify this dentry's parent about a child's events. */
|
||||
static inline void fsnotify_parent(struct dentry *dentry, __u32 mask)
|
||||
static inline void fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
|
||||
{
|
||||
__fsnotify_parent(dentry, mask);
|
||||
if (!dentry)
|
||||
dentry = file->f_path.dentry;
|
||||
|
||||
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
|
||||
__fsnotify_parent(file, dentry, mask);
|
||||
}
|
||||
|
||||
/* simple call site for access decisions */
|
||||
static inline int fsnotify_perm(struct file *file, int mask)
|
||||
{
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
__u32 fsnotify_mask = 0;
|
||||
|
||||
if (file->f_mode & FMODE_NONOTIFY)
|
||||
return 0;
|
||||
if (!(mask & (MAY_READ | MAY_OPEN)))
|
||||
return 0;
|
||||
if (mask & MAY_OPEN)
|
||||
fsnotify_mask = FS_OPEN_PERM;
|
||||
else if (mask & MAY_READ)
|
||||
fsnotify_mask = FS_ACCESS_PERM;
|
||||
else
|
||||
BUG();
|
||||
|
||||
return fsnotify(inode, fsnotify_mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* fsnotify_d_move - entry has been moved
|
||||
* Called with dcache_lock and entry->d_lock held.
|
||||
* fsnotify_d_move - dentry has been moved
|
||||
* Called with dcache_lock and dentry->d_lock held.
|
||||
*/
|
||||
static inline void fsnotify_d_move(struct dentry *entry)
|
||||
static inline void fsnotify_d_move(struct dentry *dentry)
|
||||
{
|
||||
/*
|
||||
* On move we need to update entry->d_flags to indicate if the new parent
|
||||
* cares about events from this entry.
|
||||
* On move we need to update dentry->d_flags to indicate if the new parent
|
||||
* cares about events from this dentry.
|
||||
*/
|
||||
__fsnotify_update_dcache_flags(entry);
|
||||
|
||||
inotify_d_move(entry);
|
||||
__fsnotify_update_dcache_flags(dentry);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -57,8 +72,6 @@ static inline void fsnotify_d_move(struct dentry *entry)
|
||||
*/
|
||||
static inline void fsnotify_link_count(struct inode *inode)
|
||||
{
|
||||
inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
|
||||
|
||||
fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||
}
|
||||
|
||||
@@ -66,45 +79,31 @@ static inline void fsnotify_link_count(struct inode *inode)
|
||||
* fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
|
||||
*/
|
||||
static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
|
||||
const char *old_name,
|
||||
const unsigned char *old_name,
|
||||
int isdir, struct inode *target, struct dentry *moved)
|
||||
{
|
||||
struct inode *source = moved->d_inode;
|
||||
u32 in_cookie = inotify_get_cookie();
|
||||
u32 fs_cookie = fsnotify_get_cookie();
|
||||
__u32 old_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_FROM);
|
||||
__u32 new_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_TO);
|
||||
const char *new_name = moved->d_name.name;
|
||||
const unsigned char *new_name = moved->d_name.name;
|
||||
|
||||
if (old_dir == new_dir)
|
||||
old_dir_mask |= FS_DN_RENAME;
|
||||
|
||||
if (isdir) {
|
||||
isdir = IN_ISDIR;
|
||||
old_dir_mask |= FS_IN_ISDIR;
|
||||
new_dir_mask |= FS_IN_ISDIR;
|
||||
}
|
||||
|
||||
inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir, in_cookie, old_name,
|
||||
source);
|
||||
inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, in_cookie, new_name,
|
||||
source);
|
||||
|
||||
fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name, fs_cookie);
|
||||
fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE, new_name, fs_cookie);
|
||||
|
||||
if (target) {
|
||||
inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL);
|
||||
inotify_inode_is_dead(target);
|
||||
|
||||
/* this is really a link_count change not a removal */
|
||||
if (target)
|
||||
fsnotify_link_count(target);
|
||||
}
|
||||
|
||||
if (source) {
|
||||
inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
|
||||
if (source)
|
||||
fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||
}
|
||||
audit_inode_child(moved, new_dir);
|
||||
}
|
||||
|
||||
@@ -116,6 +115,14 @@ static inline void fsnotify_inode_delete(struct inode *inode)
|
||||
__fsnotify_inode_delete(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* fsnotify_vfsmount_delete - a vfsmount is being destroyed, clean up is needed
|
||||
*/
|
||||
static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt)
|
||||
{
|
||||
__fsnotify_vfsmount_delete(mnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* fsnotify_nameremove - a filename was removed from a directory
|
||||
*/
|
||||
@@ -126,7 +133,7 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
|
||||
if (isdir)
|
||||
mask |= FS_IN_ISDIR;
|
||||
|
||||
fsnotify_parent(dentry, mask);
|
||||
fsnotify_parent(NULL, dentry, mask);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -134,9 +141,6 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
|
||||
*/
|
||||
static inline void fsnotify_inoderemove(struct inode *inode)
|
||||
{
|
||||
inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
|
||||
inotify_inode_is_dead(inode);
|
||||
|
||||
fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||
__fsnotify_inode_delete(inode);
|
||||
}
|
||||
@@ -146,8 +150,6 @@ static inline void fsnotify_inoderemove(struct inode *inode)
|
||||
*/
|
||||
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
|
||||
{
|
||||
inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
|
||||
dentry->d_inode);
|
||||
audit_inode_child(dentry, inode);
|
||||
|
||||
fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
|
||||
@@ -160,8 +162,6 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
|
||||
*/
|
||||
static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
|
||||
{
|
||||
inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name,
|
||||
inode);
|
||||
fsnotify_link_count(inode);
|
||||
audit_inode_child(new_dentry, dir);
|
||||
|
||||
@@ -176,7 +176,6 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
|
||||
__u32 mask = (FS_CREATE | FS_IN_ISDIR);
|
||||
struct inode *d_inode = dentry->d_inode;
|
||||
|
||||
inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode);
|
||||
audit_inode_child(dentry, inode);
|
||||
|
||||
fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
|
||||
@@ -185,52 +184,52 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
|
||||
/*
|
||||
* fsnotify_access - file was read
|
||||
*/
|
||||
static inline void fsnotify_access(struct dentry *dentry)
|
||||
static inline void fsnotify_access(struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
__u32 mask = FS_ACCESS;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
mask |= FS_IN_ISDIR;
|
||||
|
||||
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
|
||||
|
||||
fsnotify_parent(dentry, mask);
|
||||
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
||||
fsnotify_parent(file, NULL, mask);
|
||||
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fsnotify_modify - file was modified
|
||||
*/
|
||||
static inline void fsnotify_modify(struct dentry *dentry)
|
||||
static inline void fsnotify_modify(struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
__u32 mask = FS_MODIFY;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
mask |= FS_IN_ISDIR;
|
||||
|
||||
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
|
||||
|
||||
fsnotify_parent(dentry, mask);
|
||||
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
||||
fsnotify_parent(file, NULL, mask);
|
||||
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fsnotify_open - file was opened
|
||||
*/
|
||||
static inline void fsnotify_open(struct dentry *dentry)
|
||||
static inline void fsnotify_open(struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
__u32 mask = FS_OPEN;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
mask |= FS_IN_ISDIR;
|
||||
|
||||
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
|
||||
|
||||
fsnotify_parent(dentry, mask);
|
||||
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
||||
fsnotify_parent(file, NULL, mask);
|
||||
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -238,18 +237,17 @@ static inline void fsnotify_open(struct dentry *dentry)
|
||||
*/
|
||||
static inline void fsnotify_close(struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
fmode_t mode = file->f_mode;
|
||||
__u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
mask |= FS_IN_ISDIR;
|
||||
|
||||
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
|
||||
|
||||
fsnotify_parent(dentry, mask);
|
||||
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
|
||||
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
||||
fsnotify_parent(file, NULL, mask);
|
||||
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -263,9 +261,7 @@ static inline void fsnotify_xattr(struct dentry *dentry)
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
mask |= FS_IN_ISDIR;
|
||||
|
||||
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
|
||||
|
||||
fsnotify_parent(dentry, mask);
|
||||
fsnotify_parent(NULL, dentry, mask);
|
||||
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||
}
|
||||
|
||||
@@ -299,19 +295,18 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
|
||||
if (mask) {
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
mask |= FS_IN_ISDIR;
|
||||
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
|
||||
|
||||
fsnotify_parent(dentry, mask);
|
||||
fsnotify_parent(NULL, dentry, mask);
|
||||
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_INOTIFY) || defined(CONFIG_FSNOTIFY) /* notify helpers */
|
||||
#if defined(CONFIG_FSNOTIFY) /* notify helpers */
|
||||
|
||||
/*
|
||||
* fsnotify_oldname_init - save off the old filename before we change it
|
||||
*/
|
||||
static inline const char *fsnotify_oldname_init(const char *name)
|
||||
static inline const unsigned char *fsnotify_oldname_init(const unsigned char *name)
|
||||
{
|
||||
return kstrdup(name, GFP_KERNEL);
|
||||
}
|
||||
@@ -319,22 +314,22 @@ static inline const char *fsnotify_oldname_init(const char *name)
|
||||
/*
|
||||
* fsnotify_oldname_free - free the name we got from fsnotify_oldname_init
|
||||
*/
|
||||
static inline void fsnotify_oldname_free(const char *old_name)
|
||||
static inline void fsnotify_oldname_free(const unsigned char *old_name)
|
||||
{
|
||||
kfree(old_name);
|
||||
}
|
||||
|
||||
#else /* CONFIG_INOTIFY || CONFIG_FSNOTIFY */
|
||||
#else /* CONFIG_FSNOTIFY */
|
||||
|
||||
static inline const char *fsnotify_oldname_init(const char *name)
|
||||
static inline const char *fsnotify_oldname_init(const unsigned char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void fsnotify_oldname_free(const char *old_name)
|
||||
static inline void fsnotify_oldname_free(const unsigned char *old_name)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* ! CONFIG_INOTIFY */
|
||||
#endif /* CONFIG_FSNOTIFY */
|
||||
|
||||
#endif /* _LINUX_FS_NOTIFY_H */
|
||||
|
@@ -41,6 +41,10 @@
|
||||
#define FS_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
|
||||
#define FS_IN_IGNORED 0x00008000 /* last inotify event here */
|
||||
|
||||
#define FS_OPEN_PERM 0x00010000 /* open event in an permission hook */
|
||||
#define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */
|
||||
|
||||
#define FS_EXCL_UNLINK 0x04000000 /* do not send events if object is unlinked */
|
||||
#define FS_IN_ISDIR 0x40000000 /* event occurred against dir */
|
||||
#define FS_IN_ONESHOT 0x80000000 /* only send event once */
|
||||
|
||||
@@ -58,13 +62,20 @@
|
||||
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE |\
|
||||
FS_DELETE)
|
||||
|
||||
/* listeners that hard code group numbers near the top */
|
||||
#define DNOTIFY_GROUP_NUM UINT_MAX
|
||||
#define INOTIFY_GROUP_NUM (DNOTIFY_GROUP_NUM-1)
|
||||
#define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO)
|
||||
|
||||
#define ALL_FSNOTIFY_EVENTS (FS_ACCESS | FS_MODIFY | FS_ATTRIB | \
|
||||
FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN | \
|
||||
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE | \
|
||||
FS_DELETE | FS_DELETE_SELF | FS_MOVE_SELF | \
|
||||
FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \
|
||||
FS_OPEN_PERM | FS_ACCESS_PERM | FS_EXCL_UNLINK | \
|
||||
FS_IN_ISDIR | FS_IN_ONESHOT | FS_DN_RENAME | \
|
||||
FS_DN_MULTISHOT | FS_EVENT_ON_CHILD)
|
||||
|
||||
struct fsnotify_group;
|
||||
struct fsnotify_event;
|
||||
struct fsnotify_mark_entry;
|
||||
struct fsnotify_mark;
|
||||
struct fsnotify_event_private_data;
|
||||
|
||||
/*
|
||||
@@ -80,10 +91,16 @@ struct fsnotify_event_private_data;
|
||||
* valid group and inode to use to clean up.
|
||||
*/
|
||||
struct fsnotify_ops {
|
||||
bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, __u32 mask);
|
||||
int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event);
|
||||
bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode,
|
||||
struct fsnotify_mark *inode_mark,
|
||||
struct fsnotify_mark *vfsmount_mark,
|
||||
__u32 mask, void *data, int data_type);
|
||||
int (*handle_event)(struct fsnotify_group *group,
|
||||
struct fsnotify_mark *inode_mark,
|
||||
struct fsnotify_mark *vfsmount_mark,
|
||||
struct fsnotify_event *event);
|
||||
void (*free_group_priv)(struct fsnotify_group *group);
|
||||
void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group);
|
||||
void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group);
|
||||
void (*free_event_priv)(struct fsnotify_event_private_data *priv);
|
||||
};
|
||||
|
||||
@@ -94,22 +111,6 @@ struct fsnotify_ops {
|
||||
* everything will be cleaned up.
|
||||
*/
|
||||
struct fsnotify_group {
|
||||
/*
|
||||
* global list of all groups receiving events from fsnotify.
|
||||
* anchored by fsnotify_groups and protected by either fsnotify_grp_mutex
|
||||
* or fsnotify_grp_srcu depending on write vs read.
|
||||
*/
|
||||
struct list_head group_list;
|
||||
|
||||
/*
|
||||
* Defines all of the event types in which this group is interested.
|
||||
* This mask is a bitwise OR of the FS_* events from above. Each time
|
||||
* this mask changes for a group (if it changes) the correct functions
|
||||
* must be called to update the global structures which indicate global
|
||||
* interest in event types.
|
||||
*/
|
||||
__u32 mask;
|
||||
|
||||
/*
|
||||
* How the refcnt is used is up to each group. When the refcnt hits 0
|
||||
* fsnotify will clean up all of the resources associated with this group.
|
||||
@@ -119,7 +120,6 @@ struct fsnotify_group {
|
||||
* closed.
|
||||
*/
|
||||
atomic_t refcnt; /* things with interest in this group */
|
||||
unsigned int group_num; /* simply prevents accidental group collision */
|
||||
|
||||
const struct fsnotify_ops *ops; /* how this group handles things */
|
||||
|
||||
@@ -130,15 +130,12 @@ struct fsnotify_group {
|
||||
unsigned int q_len; /* events on the queue */
|
||||
unsigned int max_events; /* maximum events allowed on the list */
|
||||
|
||||
/* stores all fastapth entries assoc with this group so they can be cleaned on unregister */
|
||||
spinlock_t mark_lock; /* protect mark_entries list */
|
||||
atomic_t num_marks; /* 1 for each mark entry and 1 for not being
|
||||
/* stores all fastpath marks assoc with this group so they can be cleaned on unregister */
|
||||
spinlock_t mark_lock; /* protect marks_list */
|
||||
atomic_t num_marks; /* 1 for each mark and 1 for not being
|
||||
* past the point of no return when freeing
|
||||
* a group */
|
||||
struct list_head mark_entries; /* all inode mark entries for this group */
|
||||
|
||||
/* prevents double list_del of group_list. protected by global fsnotify_grp_mutex */
|
||||
bool on_group_list;
|
||||
struct list_head marks_list; /* all inode marks for this group */
|
||||
|
||||
/* groups can define private fields here or use the void *private */
|
||||
union {
|
||||
@@ -152,6 +149,17 @@ struct fsnotify_group {
|
||||
struct user_struct *user;
|
||||
} inotify_data;
|
||||
#endif
|
||||
#ifdef CONFIG_FANOTIFY
|
||||
struct fanotify_group_private_data {
|
||||
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
||||
/* allows a group to block waiting for a userspace response */
|
||||
struct mutex access_mutex;
|
||||
struct list_head access_list;
|
||||
wait_queue_head_t access_waitq;
|
||||
#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
|
||||
int f_flags;
|
||||
} fanotify_data;
|
||||
#endif /* CONFIG_FANOTIFY */
|
||||
};
|
||||
};
|
||||
|
||||
@@ -195,35 +203,57 @@ struct fsnotify_event {
|
||||
/* to_tell may ONLY be dereferenced during handle_event(). */
|
||||
struct inode *to_tell; /* either the inode the event happened to or its parent */
|
||||
/*
|
||||
* depending on the event type we should have either a path or inode
|
||||
* We hold a reference on path, but NOT on inode. Since we have the ref on
|
||||
* the path, it may be dereferenced at any point during this object's
|
||||
* depending on the event type we should have either a file or inode
|
||||
* We hold a reference on file, but NOT on inode. Since we have the ref on
|
||||
* the file, it may be dereferenced at any point during this object's
|
||||
* lifetime. That reference is dropped when this object's refcnt hits
|
||||
* 0. If this event contains an inode instead of a path, the inode may
|
||||
* 0. If this event contains an inode instead of a file, the inode may
|
||||
* ONLY be used during handle_event().
|
||||
*/
|
||||
union {
|
||||
struct path path;
|
||||
struct file *file;
|
||||
struct inode *inode;
|
||||
};
|
||||
/* when calling fsnotify tell it if the data is a path or inode */
|
||||
#define FSNOTIFY_EVENT_NONE 0
|
||||
#define FSNOTIFY_EVENT_PATH 1
|
||||
#define FSNOTIFY_EVENT_FILE 1
|
||||
#define FSNOTIFY_EVENT_INODE 2
|
||||
#define FSNOTIFY_EVENT_FILE 3
|
||||
int data_type; /* which of the above union we have */
|
||||
atomic_t refcnt; /* how many groups still are using/need to send this event */
|
||||
__u32 mask; /* the type of access, bitwise OR for FS_* event types */
|
||||
|
||||
u32 sync_cookie; /* used to corrolate events, namely inotify mv events */
|
||||
char *file_name;
|
||||
const unsigned char *file_name;
|
||||
size_t name_len;
|
||||
struct pid *tgid;
|
||||
|
||||
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
||||
__u32 response; /* userspace answer to question */
|
||||
#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
|
||||
|
||||
struct list_head private_data_list; /* groups can store private data here */
|
||||
};
|
||||
|
||||
/*
|
||||
* a mark is simply an entry attached to an in core inode which allows an
|
||||
* Inode specific fields in an fsnotify_mark
|
||||
*/
|
||||
struct fsnotify_inode_mark {
|
||||
struct inode *inode; /* inode this mark is associated with */
|
||||
struct hlist_node i_list; /* list of marks by inode->i_fsnotify_marks */
|
||||
struct list_head free_i_list; /* tmp list used when freeing this mark */
|
||||
};
|
||||
|
||||
/*
|
||||
* Mount point specific fields in an fsnotify_mark
|
||||
*/
|
||||
struct fsnotify_vfsmount_mark {
|
||||
struct vfsmount *mnt; /* vfsmount this mark is associated with */
|
||||
struct hlist_node m_list; /* list of marks by inode->i_fsnotify_marks */
|
||||
struct list_head free_m_list; /* tmp list used when freeing this mark */
|
||||
};
|
||||
|
||||
/*
|
||||
* a mark is simply an object attached to an in core inode which allows an
|
||||
* fsnotify listener to indicate they are either no longer interested in events
|
||||
* of a type matching mask or only interested in those events.
|
||||
*
|
||||
@@ -232,19 +262,28 @@ struct fsnotify_event {
|
||||
* (such as dnotify) will flush these when the open fd is closed and not at
|
||||
* inode eviction or modification.
|
||||
*/
|
||||
struct fsnotify_mark_entry {
|
||||
__u32 mask; /* mask this mark entry is for */
|
||||
struct fsnotify_mark {
|
||||
__u32 mask; /* mask this mark is for */
|
||||
/* we hold ref for each i_list and g_list. also one ref for each 'thing'
|
||||
* in kernel that found and may be using this mark. */
|
||||
atomic_t refcnt; /* active things looking at this mark */
|
||||
struct inode *inode; /* inode this entry is associated with */
|
||||
struct fsnotify_group *group; /* group this mark entry is for */
|
||||
struct hlist_node i_list; /* list of mark_entries by inode->i_fsnotify_mark_entries */
|
||||
struct list_head g_list; /* list of mark_entries by group->i_fsnotify_mark_entries */
|
||||
spinlock_t lock; /* protect group, inode, and killme */
|
||||
struct list_head free_i_list; /* tmp list used when freeing this mark */
|
||||
struct fsnotify_group *group; /* group this mark is for */
|
||||
struct list_head g_list; /* list of marks by group->i_fsnotify_marks */
|
||||
spinlock_t lock; /* protect group and inode */
|
||||
union {
|
||||
struct fsnotify_inode_mark i;
|
||||
struct fsnotify_vfsmount_mark m;
|
||||
};
|
||||
__u32 ignored_mask; /* events types to ignore */
|
||||
struct list_head free_g_list; /* tmp list used when freeing this mark */
|
||||
void (*free_mark)(struct fsnotify_mark_entry *entry); /* called on final put+free */
|
||||
#define FSNOTIFY_MARK_FLAG_INODE 0x01
|
||||
#define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02
|
||||
#define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04
|
||||
#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x08
|
||||
#define FSNOTIFY_MARK_FLAG_ALIVE 0x10
|
||||
unsigned int flags; /* vfsmount or inode mark? */
|
||||
struct list_head destroy_list;
|
||||
void (*free_mark)(struct fsnotify_mark *mark); /* called on final put+free */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FSNOTIFY
|
||||
@@ -252,10 +291,11 @@ struct fsnotify_mark_entry {
|
||||
/* called from the vfs helpers */
|
||||
|
||||
/* main fsnotify call to send events */
|
||||
extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
|
||||
const char *name, u32 cookie);
|
||||
extern void __fsnotify_parent(struct dentry *dentry, __u32 mask);
|
||||
extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
|
||||
const unsigned char *name, u32 cookie);
|
||||
extern void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask);
|
||||
extern void __fsnotify_inode_delete(struct inode *inode);
|
||||
extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
|
||||
extern u32 fsnotify_get_cookie(void);
|
||||
|
||||
static inline int fsnotify_inode_watches_children(struct inode *inode)
|
||||
@@ -304,15 +344,9 @@ static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode
|
||||
|
||||
/* called from fsnotify listeners, such as fanotify or dnotify */
|
||||
|
||||
/* must call when a group changes its ->mask */
|
||||
extern void fsnotify_recalc_global_mask(void);
|
||||
/* get a reference to an existing or create a new group */
|
||||
extern struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num,
|
||||
__u32 mask,
|
||||
const struct fsnotify_ops *ops);
|
||||
/* run all marks associated with this group and update group->mask */
|
||||
extern void fsnotify_recalc_group_mask(struct fsnotify_group *group);
|
||||
/* drop reference on a group from fsnotify_obtain_group */
|
||||
extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops);
|
||||
/* drop reference on a group from fsnotify_alloc_group */
|
||||
extern void fsnotify_put_group(struct fsnotify_group *group);
|
||||
|
||||
/* take a reference to an event */
|
||||
@@ -323,8 +357,11 @@ extern struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struc
|
||||
struct fsnotify_event *event);
|
||||
|
||||
/* attach the event to the group notification queue */
|
||||
extern int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
|
||||
struct fsnotify_event_private_data *priv);
|
||||
extern struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group,
|
||||
struct fsnotify_event *event,
|
||||
struct fsnotify_event_private_data *priv,
|
||||
struct fsnotify_event *(*merge)(struct list_head *,
|
||||
struct fsnotify_event *));
|
||||
/* true if the group notification queue is empty */
|
||||
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
|
||||
/* return, but do not dequeue the first event on the notification queue */
|
||||
@@ -334,38 +371,66 @@ extern struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group
|
||||
|
||||
/* functions used to manipulate the marks attached to inodes */
|
||||
|
||||
/* run all marks associated with a vfsmount and update mnt->mnt_fsnotify_mask */
|
||||
extern void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt);
|
||||
/* run all marks associated with an inode and update inode->i_fsnotify_mask */
|
||||
extern void fsnotify_recalc_inode_mask(struct inode *inode);
|
||||
extern void fsnotify_init_mark(struct fsnotify_mark_entry *entry, void (*free_mark)(struct fsnotify_mark_entry *entry));
|
||||
extern void fsnotify_init_mark(struct fsnotify_mark *mark, void (*free_mark)(struct fsnotify_mark *mark));
|
||||
/* find (and take a reference) to a mark associated with group and inode */
|
||||
extern struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *group, struct inode *inode);
|
||||
extern struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, struct inode *inode);
|
||||
/* find (and take a reference) to a mark associated with group and vfsmount */
|
||||
extern struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, struct vfsmount *mnt);
|
||||
/* copy the values from old into new */
|
||||
extern void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old);
|
||||
/* set the ignored_mask of a mark */
|
||||
extern void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mask);
|
||||
/* set the mask of a mark (might pin the object into memory */
|
||||
extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask);
|
||||
/* attach the mark to both the group and the inode */
|
||||
extern int fsnotify_add_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group, struct inode *inode);
|
||||
extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
|
||||
struct inode *inode, struct vfsmount *mnt, int allow_dups);
|
||||
/* given a mark, flag it to be freed when all references are dropped */
|
||||
extern void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry);
|
||||
extern void fsnotify_destroy_mark(struct fsnotify_mark *mark);
|
||||
/* run all the marks in a group, and clear all of the vfsmount marks */
|
||||
extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group);
|
||||
/* run all the marks in a group, and clear all of the inode marks */
|
||||
extern void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group);
|
||||
/* run all the marks in a group, and clear all of the marks where mark->flags & flags is true*/
|
||||
extern void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags);
|
||||
/* run all the marks in a group, and flag them to be freed */
|
||||
extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group);
|
||||
extern void fsnotify_get_mark(struct fsnotify_mark_entry *entry);
|
||||
extern void fsnotify_put_mark(struct fsnotify_mark_entry *entry);
|
||||
extern void fsnotify_get_mark(struct fsnotify_mark *mark);
|
||||
extern void fsnotify_put_mark(struct fsnotify_mark *mark);
|
||||
extern void fsnotify_unmount_inodes(struct list_head *list);
|
||||
|
||||
/* put here because inotify does some weird stuff when destroying watches */
|
||||
extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
|
||||
void *data, int data_is, const char *name,
|
||||
void *data, int data_is,
|
||||
const unsigned char *name,
|
||||
u32 cookie, gfp_t gfp);
|
||||
|
||||
/* fanotify likes to change events after they are on lists... */
|
||||
extern struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event);
|
||||
extern int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
|
||||
struct fsnotify_event *new_event);
|
||||
|
||||
#else
|
||||
|
||||
static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
|
||||
const char *name, u32 cookie)
|
||||
{}
|
||||
static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
|
||||
const unsigned char *name, u32 cookie)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void __fsnotify_parent(struct dentry *dentry, __u32 mask)
|
||||
static inline void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
|
||||
{}
|
||||
|
||||
static inline void __fsnotify_inode_delete(struct inode *inode)
|
||||
{}
|
||||
|
||||
static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
|
||||
{}
|
||||
|
||||
static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
|
||||
{}
|
||||
|
||||
|
@@ -51,6 +51,7 @@ struct inotify_event {
|
||||
/* special flags */
|
||||
#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
|
||||
#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
|
||||
#define IN_EXCL_UNLINK 0x04000000 /* exclude events on unlinked objects */
|
||||
#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
|
||||
#define IN_ISDIR 0x40000000 /* event occurred against dir */
|
||||
#define IN_ONESHOT 0x80000000 /* only send event once */
|
||||
@@ -70,177 +71,17 @@ struct inotify_event {
|
||||
#define IN_NONBLOCK O_NONBLOCK
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/sysctl.h>
|
||||
extern struct ctl_table inotify_table[]; /* for sysctl */
|
||||
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/fs.h>
|
||||
#define ALL_INOTIFY_BITS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
|
||||
IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
|
||||
IN_MOVED_TO | IN_CREATE | IN_DELETE | \
|
||||
IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT | \
|
||||
IN_Q_OVERFLOW | IN_IGNORED | IN_ONLYDIR | \
|
||||
IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_MASK_ADD | \
|
||||
IN_ISDIR | IN_ONESHOT)
|
||||
|
||||
/*
|
||||
* struct inotify_watch - represents a watch request on a specific inode
|
||||
*
|
||||
* h_list is protected by ih->mutex of the associated inotify_handle.
|
||||
* i_list, mask are protected by inode->inotify_mutex of the associated inode.
|
||||
* ih, inode, and wd are never written to once the watch is created.
|
||||
*
|
||||
* Callers must use the established inotify interfaces to access inotify_watch
|
||||
* contents. The content of this structure is private to the inotify
|
||||
* implementation.
|
||||
*/
|
||||
struct inotify_watch {
|
||||
struct list_head h_list; /* entry in inotify_handle's list */
|
||||
struct list_head i_list; /* entry in inode's list */
|
||||
atomic_t count; /* reference count */
|
||||
struct inotify_handle *ih; /* associated inotify handle */
|
||||
struct inode *inode; /* associated inode */
|
||||
__s32 wd; /* watch descriptor */
|
||||
__u32 mask; /* event mask for this watch */
|
||||
};
|
||||
|
||||
struct inotify_operations {
|
||||
void (*handle_event)(struct inotify_watch *, u32, u32, u32,
|
||||
const char *, struct inode *);
|
||||
void (*destroy_watch)(struct inotify_watch *);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_INOTIFY
|
||||
|
||||
/* Kernel API for producing events */
|
||||
|
||||
extern void inotify_d_instantiate(struct dentry *, struct inode *);
|
||||
extern void inotify_d_move(struct dentry *);
|
||||
extern void inotify_inode_queue_event(struct inode *, __u32, __u32,
|
||||
const char *, struct inode *);
|
||||
extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32,
|
||||
const char *);
|
||||
extern void inotify_unmount_inodes(struct list_head *);
|
||||
extern void inotify_inode_is_dead(struct inode *);
|
||||
extern u32 inotify_get_cookie(void);
|
||||
|
||||
/* Kernel Consumer API */
|
||||
|
||||
extern struct inotify_handle *inotify_init(const struct inotify_operations *);
|
||||
extern void inotify_init_watch(struct inotify_watch *);
|
||||
extern void inotify_destroy(struct inotify_handle *);
|
||||
extern __s32 inotify_find_watch(struct inotify_handle *, struct inode *,
|
||||
struct inotify_watch **);
|
||||
extern __s32 inotify_find_update_watch(struct inotify_handle *, struct inode *,
|
||||
u32);
|
||||
extern __s32 inotify_add_watch(struct inotify_handle *, struct inotify_watch *,
|
||||
struct inode *, __u32);
|
||||
extern __s32 inotify_clone_watch(struct inotify_watch *, struct inotify_watch *);
|
||||
extern void inotify_evict_watch(struct inotify_watch *);
|
||||
extern int inotify_rm_watch(struct inotify_handle *, struct inotify_watch *);
|
||||
extern int inotify_rm_wd(struct inotify_handle *, __u32);
|
||||
extern void inotify_remove_watch_locked(struct inotify_handle *,
|
||||
struct inotify_watch *);
|
||||
extern void get_inotify_watch(struct inotify_watch *);
|
||||
extern void put_inotify_watch(struct inotify_watch *);
|
||||
extern int pin_inotify_watch(struct inotify_watch *);
|
||||
extern void unpin_inotify_watch(struct inotify_watch *);
|
||||
|
||||
#else
|
||||
|
||||
static inline void inotify_d_instantiate(struct dentry *dentry,
|
||||
struct inode *inode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void inotify_d_move(struct dentry *dentry)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void inotify_inode_queue_event(struct inode *inode,
|
||||
__u32 mask, __u32 cookie,
|
||||
const char *filename,
|
||||
struct inode *n_inode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void inotify_dentry_parent_queue_event(struct dentry *dentry,
|
||||
__u32 mask, __u32 cookie,
|
||||
const char *filename)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void inotify_unmount_inodes(struct list_head *list)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void inotify_inode_is_dead(struct inode *inode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline u32 inotify_get_cookie(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct inotify_handle *inotify_init(const struct inotify_operations *ops)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void inotify_init_watch(struct inotify_watch *watch)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void inotify_destroy(struct inotify_handle *ih)
|
||||
{
|
||||
}
|
||||
|
||||
static inline __s32 inotify_find_watch(struct inotify_handle *ih, struct inode *inode,
|
||||
struct inotify_watch **watchp)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline __s32 inotify_find_update_watch(struct inotify_handle *ih,
|
||||
struct inode *inode, u32 mask)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline __s32 inotify_add_watch(struct inotify_handle *ih,
|
||||
struct inotify_watch *watch,
|
||||
struct inode *inode, __u32 mask)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int inotify_rm_watch(struct inotify_handle *ih,
|
||||
struct inotify_watch *watch)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int inotify_rm_wd(struct inotify_handle *ih, __u32 wd)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void inotify_remove_watch_locked(struct inotify_handle *ih,
|
||||
struct inotify_watch *watch)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void get_inotify_watch(struct inotify_watch *watch)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void put_inotify_watch(struct inotify_watch *watch)
|
||||
{
|
||||
}
|
||||
|
||||
extern inline int pin_inotify_watch(struct inotify_watch *watch)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern inline void unpin_inotify_watch(struct inotify_watch *watch)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_INOTIFY */
|
||||
|
||||
#endif /* __KERNEL __ */
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_INOTIFY_H */
|
||||
|
@@ -56,7 +56,11 @@ struct vfsmount {
|
||||
struct list_head mnt_mounts; /* list of children, anchored here */
|
||||
struct list_head mnt_child; /* and going through their mnt_child */
|
||||
int mnt_flags;
|
||||
/* 4 bytes hole on 64bits arches */
|
||||
/* 4 bytes hole on 64bits arches without fsnotify */
|
||||
#ifdef CONFIG_FSNOTIFY
|
||||
__u32 mnt_fsnotify_mask;
|
||||
struct hlist_head mnt_fsnotify_marks;
|
||||
#endif
|
||||
const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
|
||||
struct list_head mnt_list;
|
||||
struct list_head mnt_expire; /* link in fs-specific expiry list */
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#define __LINUX_SECURITY_H
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/resource.h>
|
||||
|
@@ -811,6 +811,10 @@ asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *,
|
||||
asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int,
|
||||
struct timespec __user *, const sigset_t __user *,
|
||||
size_t);
|
||||
asmlinkage long sys_fanotify_init(unsigned int flags, unsigned int event_f_flags);
|
||||
asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags,
|
||||
u64 mask, int fd,
|
||||
const char __user *pathname);
|
||||
|
||||
int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
|
||||
|
||||
|
Reference in New Issue
Block a user