Merge branch 'for-linus' of git://git.infradead.org/users/eparis/notify
* 'for-linus' of git://git.infradead.org/users/eparis/notify: (22 commits) Ensure FMODE_NONOTIFY is not set by userspace make fanotify_read() restartable across signals fsnotify: remove alignment padding from fsnotify_mark on 64 bit builds fs/notify/fanotify/fanotify_user.c: fix warnings fanotify: Fix FAN_CLOSE comments fanotify: do not recalculate the mask if the ignored mask changed fanotify: ignore events on directories unless specifically requested fsnotify: rename FS_IN_ISDIR to FS_ISDIR fanotify: do not send events for irregular files fanotify: limit number of listeners per user fanotify: allow userspace to override max marks fanotify: limit the number of marks in a single fanotify group fanotify: allow userspace to override max queue depth fsnotify: implement a default maximum queue depth fanotify: ignore fanotify ignore marks if open writers fanotify: allow userspace to flush all marks fsnotify: call fsnotify_parent in perm events fsnotify: correctly handle return codes from listeners fanotify: use __aligned_u64 in fanotify userspace metadata fanotify: implement fanotify listener ordering ...
This commit is contained in:
commit
1792f17b72
@ -3,4 +3,4 @@ config FSNOTIFY
|
|||||||
|
|
||||||
source "fs/notify/dnotify/Kconfig"
|
source "fs/notify/dnotify/Kconfig"
|
||||||
source "fs/notify/inotify/Kconfig"
|
source "fs/notify/inotify/Kconfig"
|
||||||
#source "fs/notify/fanotify/Kconfig"
|
source "fs/notify/fanotify/Kconfig"
|
||||||
|
@ -131,6 +131,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
|
|||||||
BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW);
|
BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW);
|
||||||
BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM);
|
BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM);
|
||||||
BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
|
BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
|
||||||
|
BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR);
|
||||||
|
|
||||||
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
|
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
|
||||||
|
|
||||||
@ -160,20 +161,21 @@ static bool fanotify_should_send_event(struct fsnotify_group *group,
|
|||||||
__u32 event_mask, void *data, int data_type)
|
__u32 event_mask, void *data, int data_type)
|
||||||
{
|
{
|
||||||
__u32 marks_mask, marks_ignored_mask;
|
__u32 marks_mask, marks_ignored_mask;
|
||||||
|
struct path *path = data;
|
||||||
|
|
||||||
pr_debug("%s: group=%p to_tell=%p inode_mark=%p vfsmnt_mark=%p "
|
pr_debug("%s: group=%p to_tell=%p inode_mark=%p vfsmnt_mark=%p "
|
||||||
"mask=%x data=%p data_type=%d\n", __func__, group, to_tell,
|
"mask=%x data=%p data_type=%d\n", __func__, group, to_tell,
|
||||||
inode_mark, vfsmnt_mark, event_mask, data, data_type);
|
inode_mark, vfsmnt_mark, event_mask, data, data_type);
|
||||||
|
|
||||||
/* sorry, fanotify only gives a damn about files and dirs */
|
|
||||||
if (!S_ISREG(to_tell->i_mode) &&
|
|
||||||
!S_ISDIR(to_tell->i_mode))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* if we don't have enough info to send an event to userspace say no */
|
/* if we don't have enough info to send an event to userspace say no */
|
||||||
if (data_type != FSNOTIFY_EVENT_PATH)
|
if (data_type != FSNOTIFY_EVENT_PATH)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* sorry, fanotify only gives a damn about files and dirs */
|
||||||
|
if (!S_ISREG(path->dentry->d_inode->i_mode) &&
|
||||||
|
!S_ISDIR(path->dentry->d_inode->i_mode))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (inode_mark && vfsmnt_mark) {
|
if (inode_mark && vfsmnt_mark) {
|
||||||
marks_mask = (vfsmnt_mark->mask | inode_mark->mask);
|
marks_mask = (vfsmnt_mark->mask | inode_mark->mask);
|
||||||
marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask);
|
marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask);
|
||||||
@ -194,16 +196,29 @@ static bool fanotify_should_send_event(struct fsnotify_group *group,
|
|||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(path->dentry->d_inode->i_mode) &&
|
||||||
|
(marks_ignored_mask & FS_ISDIR))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (event_mask & marks_mask & ~marks_ignored_mask)
|
if (event_mask & marks_mask & ~marks_ignored_mask)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fanotify_free_group_priv(struct fsnotify_group *group)
|
||||||
|
{
|
||||||
|
struct user_struct *user;
|
||||||
|
|
||||||
|
user = group->fanotify_data.user;
|
||||||
|
atomic_dec(&user->fanotify_listeners);
|
||||||
|
free_uid(user);
|
||||||
|
}
|
||||||
|
|
||||||
const struct fsnotify_ops fanotify_fsnotify_ops = {
|
const struct fsnotify_ops fanotify_fsnotify_ops = {
|
||||||
.handle_event = fanotify_handle_event,
|
.handle_event = fanotify_handle_event,
|
||||||
.should_send_event = fanotify_should_send_event,
|
.should_send_event = fanotify_should_send_event,
|
||||||
.free_group_priv = NULL,
|
.free_group_priv = fanotify_free_group_priv,
|
||||||
.free_event_priv = NULL,
|
.free_event_priv = NULL,
|
||||||
.freeing_mark = NULL,
|
.freeing_mark = NULL,
|
||||||
};
|
};
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
#include <asm/ioctls.h>
|
#include <asm/ioctls.h>
|
||||||
|
|
||||||
|
#define FANOTIFY_DEFAULT_MAX_EVENTS 16384
|
||||||
|
#define FANOTIFY_DEFAULT_MAX_MARKS 8192
|
||||||
|
#define FANOTIFY_DEFAULT_MAX_LISTENERS 128
|
||||||
|
|
||||||
extern const struct fsnotify_ops fanotify_fsnotify_ops;
|
extern const struct fsnotify_ops fanotify_fsnotify_ops;
|
||||||
|
|
||||||
static struct kmem_cache *fanotify_mark_cache __read_mostly;
|
static struct kmem_cache *fanotify_mark_cache __read_mostly;
|
||||||
@ -326,7 +330,7 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
|
|||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
if (file->f_flags & O_NONBLOCK)
|
if (file->f_flags & O_NONBLOCK)
|
||||||
break;
|
break;
|
||||||
ret = -EINTR;
|
ret = -ERESTARTSYS;
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -372,11 +376,10 @@ static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t
|
|||||||
static int fanotify_release(struct inode *ignored, struct file *file)
|
static int fanotify_release(struct inode *ignored, struct file *file)
|
||||||
{
|
{
|
||||||
struct fsnotify_group *group = file->private_data;
|
struct fsnotify_group *group = file->private_data;
|
||||||
struct fanotify_response_event *re, *lre;
|
|
||||||
|
|
||||||
pr_debug("%s: file=%p group=%p\n", __func__, file, group);
|
|
||||||
|
|
||||||
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
||||||
|
struct fanotify_response_event *re, *lre;
|
||||||
|
|
||||||
mutex_lock(&group->fanotify_data.access_mutex);
|
mutex_lock(&group->fanotify_data.access_mutex);
|
||||||
|
|
||||||
group->fanotify_data.bypass_perm = true;
|
group->fanotify_data.bypass_perm = true;
|
||||||
@ -554,18 +557,24 @@ static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
|
|||||||
__u32 mask,
|
__u32 mask,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
__u32 oldmask;
|
__u32 oldmask = -1;
|
||||||
|
|
||||||
spin_lock(&fsn_mark->lock);
|
spin_lock(&fsn_mark->lock);
|
||||||
if (!(flags & FAN_MARK_IGNORED_MASK)) {
|
if (!(flags & FAN_MARK_IGNORED_MASK)) {
|
||||||
oldmask = fsn_mark->mask;
|
oldmask = fsn_mark->mask;
|
||||||
fsnotify_set_mark_mask_locked(fsn_mark, (oldmask | mask));
|
fsnotify_set_mark_mask_locked(fsn_mark, (oldmask | mask));
|
||||||
} else {
|
} else {
|
||||||
oldmask = fsn_mark->ignored_mask;
|
__u32 tmask = fsn_mark->ignored_mask | mask;
|
||||||
fsnotify_set_mark_ignored_mask_locked(fsn_mark, (oldmask | mask));
|
fsnotify_set_mark_ignored_mask_locked(fsn_mark, tmask);
|
||||||
if (flags & FAN_MARK_IGNORED_SURV_MODIFY)
|
if (flags & FAN_MARK_IGNORED_SURV_MODIFY)
|
||||||
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
|
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(flags & FAN_MARK_ONDIR)) {
|
||||||
|
__u32 tmask = fsn_mark->ignored_mask | FAN_ONDIR;
|
||||||
|
fsnotify_set_mark_ignored_mask_locked(fsn_mark, tmask);
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock(&fsn_mark->lock);
|
spin_unlock(&fsn_mark->lock);
|
||||||
|
|
||||||
return mask & ~oldmask;
|
return mask & ~oldmask;
|
||||||
@ -582,6 +591,9 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
|
|||||||
if (!fsn_mark) {
|
if (!fsn_mark) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks)
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
|
fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
|
||||||
if (!fsn_mark)
|
if (!fsn_mark)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -610,10 +622,23 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
|
|||||||
|
|
||||||
pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
|
pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If some other task has this inode open for write we should not add
|
||||||
|
* an ignored mark, unless that ignored mark is supposed to survive
|
||||||
|
* modification changes anyway.
|
||||||
|
*/
|
||||||
|
if ((flags & FAN_MARK_IGNORED_MASK) &&
|
||||||
|
!(flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
|
||||||
|
(atomic_read(&inode->i_writecount) > 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
fsn_mark = fsnotify_find_inode_mark(group, inode);
|
fsn_mark = fsnotify_find_inode_mark(group, inode);
|
||||||
if (!fsn_mark) {
|
if (!fsn_mark) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks)
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
|
fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
|
||||||
if (!fsn_mark)
|
if (!fsn_mark)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -637,6 +662,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
|||||||
{
|
{
|
||||||
struct fsnotify_group *group;
|
struct fsnotify_group *group;
|
||||||
int f_flags, fd;
|
int f_flags, fd;
|
||||||
|
struct user_struct *user;
|
||||||
|
|
||||||
pr_debug("%s: flags=%d event_f_flags=%d\n",
|
pr_debug("%s: flags=%d event_f_flags=%d\n",
|
||||||
__func__, flags, event_f_flags);
|
__func__, flags, event_f_flags);
|
||||||
@ -647,6 +673,12 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
|||||||
if (flags & ~FAN_ALL_INIT_FLAGS)
|
if (flags & ~FAN_ALL_INIT_FLAGS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
user = get_current_user();
|
||||||
|
if (atomic_read(&user->fanotify_listeners) > FANOTIFY_DEFAULT_MAX_LISTENERS) {
|
||||||
|
free_uid(user);
|
||||||
|
return -EMFILE;
|
||||||
|
}
|
||||||
|
|
||||||
f_flags = O_RDWR | FMODE_NONOTIFY;
|
f_flags = O_RDWR | FMODE_NONOTIFY;
|
||||||
if (flags & FAN_CLOEXEC)
|
if (flags & FAN_CLOEXEC)
|
||||||
f_flags |= O_CLOEXEC;
|
f_flags |= O_CLOEXEC;
|
||||||
@ -658,12 +690,47 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
|||||||
if (IS_ERR(group))
|
if (IS_ERR(group))
|
||||||
return PTR_ERR(group);
|
return PTR_ERR(group);
|
||||||
|
|
||||||
|
group->fanotify_data.user = user;
|
||||||
|
atomic_inc(&user->fanotify_listeners);
|
||||||
|
|
||||||
group->fanotify_data.f_flags = event_f_flags;
|
group->fanotify_data.f_flags = event_f_flags;
|
||||||
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
||||||
mutex_init(&group->fanotify_data.access_mutex);
|
mutex_init(&group->fanotify_data.access_mutex);
|
||||||
init_waitqueue_head(&group->fanotify_data.access_waitq);
|
init_waitqueue_head(&group->fanotify_data.access_waitq);
|
||||||
INIT_LIST_HEAD(&group->fanotify_data.access_list);
|
INIT_LIST_HEAD(&group->fanotify_data.access_list);
|
||||||
#endif
|
#endif
|
||||||
|
switch (flags & FAN_ALL_CLASS_BITS) {
|
||||||
|
case FAN_CLASS_NOTIF:
|
||||||
|
group->priority = FS_PRIO_0;
|
||||||
|
break;
|
||||||
|
case FAN_CLASS_CONTENT:
|
||||||
|
group->priority = FS_PRIO_1;
|
||||||
|
break;
|
||||||
|
case FAN_CLASS_PRE_CONTENT:
|
||||||
|
group->priority = FS_PRIO_2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fd = -EINVAL;
|
||||||
|
goto out_put_group;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & FAN_UNLIMITED_QUEUE) {
|
||||||
|
fd = -EPERM;
|
||||||
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
|
goto out_put_group;
|
||||||
|
group->max_events = UINT_MAX;
|
||||||
|
} else {
|
||||||
|
group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & FAN_UNLIMITED_MARKS) {
|
||||||
|
fd = -EPERM;
|
||||||
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
|
goto out_put_group;
|
||||||
|
group->fanotify_data.max_marks = UINT_MAX;
|
||||||
|
} else {
|
||||||
|
group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS;
|
||||||
|
}
|
||||||
|
|
||||||
fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
|
fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
@ -704,6 +771,12 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
|
|||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mask & FAN_ONDIR) {
|
||||||
|
flags |= FAN_MARK_ONDIR;
|
||||||
|
mask &= ~FAN_ONDIR;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
||||||
if (mask & ~(FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS | FAN_EVENT_ON_CHILD))
|
if (mask & ~(FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS | FAN_EVENT_ON_CHILD))
|
||||||
#else
|
#else
|
||||||
@ -719,6 +792,16 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (unlikely(filp->f_op != &fanotify_fops))
|
if (unlikely(filp->f_op != &fanotify_fops))
|
||||||
goto fput_and_out;
|
goto fput_and_out;
|
||||||
|
group = filp->private_data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* group->priority == FS_PRIO_0 == FAN_CLASS_NOTIF. These are not
|
||||||
|
* allowed to set permissions events.
|
||||||
|
*/
|
||||||
|
ret = -EINVAL;
|
||||||
|
if (mask & FAN_ALL_PERM_EVENTS &&
|
||||||
|
group->priority == FS_PRIO_0)
|
||||||
|
goto fput_and_out;
|
||||||
|
|
||||||
ret = fanotify_find_path(dfd, pathname, &path, flags);
|
ret = fanotify_find_path(dfd, pathname, &path, flags);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -729,7 +812,6 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
|
|||||||
inode = path.dentry->d_inode;
|
inode = path.dentry->d_inode;
|
||||||
else
|
else
|
||||||
mnt = path.mnt;
|
mnt = path.mnt;
|
||||||
group = filp->private_data;
|
|
||||||
|
|
||||||
/* create/update an inode mark */
|
/* create/update an inode mark */
|
||||||
switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
|
switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
|
||||||
|
@ -84,16 +84,17 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Notify this dentry's parent about a child's events. */
|
/* Notify this dentry's parent about a child's events. */
|
||||||
void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
|
int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
|
||||||
{
|
{
|
||||||
struct dentry *parent;
|
struct dentry *parent;
|
||||||
struct inode *p_inode;
|
struct inode *p_inode;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
dentry = path->dentry;
|
dentry = path->dentry;
|
||||||
|
|
||||||
if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
|
if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
parent = dget_parent(dentry);
|
parent = dget_parent(dentry);
|
||||||
p_inode = parent->d_inode;
|
p_inode = parent->d_inode;
|
||||||
@ -106,14 +107,16 @@ void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
|
|||||||
mask |= FS_EVENT_ON_CHILD;
|
mask |= FS_EVENT_ON_CHILD;
|
||||||
|
|
||||||
if (path)
|
if (path)
|
||||||
fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
|
ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
|
||||||
dentry->d_name.name, 0);
|
dentry->d_name.name, 0);
|
||||||
else
|
else
|
||||||
fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
|
ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
|
||||||
dentry->d_name.name, 0);
|
dentry->d_name.name, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
dput(parent);
|
dput(parent);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__fsnotify_parent);
|
EXPORT_SYMBOL_GPL(__fsnotify_parent);
|
||||||
|
|
||||||
@ -252,20 +255,23 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
|
|||||||
|
|
||||||
if (inode_group > vfsmount_group) {
|
if (inode_group > vfsmount_group) {
|
||||||
/* handle inode */
|
/* handle inode */
|
||||||
send_to_group(to_tell, NULL, inode_mark, NULL, mask, data,
|
ret = send_to_group(to_tell, NULL, inode_mark, NULL, mask, data,
|
||||||
data_is, cookie, file_name, &event);
|
data_is, cookie, file_name, &event);
|
||||||
/* we didn't use the vfsmount_mark */
|
/* we didn't use the vfsmount_mark */
|
||||||
vfsmount_group = NULL;
|
vfsmount_group = NULL;
|
||||||
} else if (vfsmount_group > inode_group) {
|
} else if (vfsmount_group > inode_group) {
|
||||||
send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data,
|
ret = send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data,
|
||||||
data_is, cookie, file_name, &event);
|
data_is, cookie, file_name, &event);
|
||||||
inode_group = NULL;
|
inode_group = NULL;
|
||||||
} else {
|
} else {
|
||||||
send_to_group(to_tell, mnt, inode_mark, vfsmount_mark,
|
ret = send_to_group(to_tell, mnt, inode_mark, vfsmount_mark,
|
||||||
mask, data, data_is, cookie, file_name,
|
mask, data, data_is, cookie, file_name,
|
||||||
&event);
|
&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (inode_group)
|
if (inode_group)
|
||||||
inode_node = srcu_dereference(inode_node->next,
|
inode_node = srcu_dereference(inode_node->next,
|
||||||
&fsnotify_mark_srcu);
|
&fsnotify_mark_srcu);
|
||||||
@ -273,7 +279,8 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
|
|||||||
vfsmount_node = srcu_dereference(vfsmount_node->next,
|
vfsmount_node = srcu_dereference(vfsmount_node->next,
|
||||||
&fsnotify_mark_srcu);
|
&fsnotify_mark_srcu);
|
||||||
}
|
}
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
srcu_read_unlock(&fsnotify_mark_srcu, idx);
|
srcu_read_unlock(&fsnotify_mark_srcu, idx);
|
||||||
/*
|
/*
|
||||||
* fsnotify_create_event() took a reference so the event can't be cleaned
|
* fsnotify_create_event() took a reference so the event can't be cleaned
|
||||||
|
@ -177,7 +177,8 @@ void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark,
|
|||||||
* Attach an initialized mark to a given inode.
|
* Attach an initialized mark to a given inode.
|
||||||
* These marks may be used for the fsnotify backend to determine which
|
* These marks may be used for the fsnotify backend to determine which
|
||||||
* event types should be delivered to which group and for which inodes. These
|
* event types should be delivered to which group and for which inodes. These
|
||||||
* marks are ordered according to the group's location in memory.
|
* marks are ordered according to priority, highest number first, and then by
|
||||||
|
* the group's location in memory.
|
||||||
*/
|
*/
|
||||||
int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
|
int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
|
||||||
struct fsnotify_group *group, struct inode *inode,
|
struct fsnotify_group *group, struct inode *inode,
|
||||||
@ -211,7 +212,11 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mark->group < lmark->group)
|
if (mark->group->priority < lmark->group->priority)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((mark->group->priority == lmark->group->priority) &&
|
||||||
|
(mark->group < lmark->group))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list);
|
hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list);
|
||||||
|
@ -862,7 +862,7 @@ static int __init inotify_user_setup(void)
|
|||||||
BUILD_BUG_ON(IN_Q_OVERFLOW != FS_Q_OVERFLOW);
|
BUILD_BUG_ON(IN_Q_OVERFLOW != FS_Q_OVERFLOW);
|
||||||
BUILD_BUG_ON(IN_IGNORED != FS_IN_IGNORED);
|
BUILD_BUG_ON(IN_IGNORED != FS_IN_IGNORED);
|
||||||
BUILD_BUG_ON(IN_EXCL_UNLINK != FS_EXCL_UNLINK);
|
BUILD_BUG_ON(IN_EXCL_UNLINK != FS_EXCL_UNLINK);
|
||||||
BUILD_BUG_ON(IN_ISDIR != FS_IN_ISDIR);
|
BUILD_BUG_ON(IN_ISDIR != FS_ISDIR);
|
||||||
BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
|
BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
|
||||||
|
|
||||||
BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
|
BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
|
||||||
|
@ -169,7 +169,11 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mark->group < lmark->group)
|
if (mark->group->priority < lmark->group->priority)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((mark->group->priority == lmark->group->priority) &&
|
||||||
|
(mark->group < lmark->group))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list);
|
hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list);
|
||||||
|
@ -118,6 +118,7 @@ header-y += eventpoll.h
|
|||||||
header-y += ext2_fs.h
|
header-y += ext2_fs.h
|
||||||
header-y += fadvise.h
|
header-y += fadvise.h
|
||||||
header-y += falloc.h
|
header-y += falloc.h
|
||||||
|
header-y += fanotify.h
|
||||||
header-y += fb.h
|
header-y += fb.h
|
||||||
header-y += fcntl.h
|
header-y += fcntl.h
|
||||||
header-y += fd.h
|
header-y += fd.h
|
||||||
|
@ -6,18 +6,19 @@
|
|||||||
/* the following events that user-space can register for */
|
/* the following events that user-space can register for */
|
||||||
#define FAN_ACCESS 0x00000001 /* File was accessed */
|
#define FAN_ACCESS 0x00000001 /* File was accessed */
|
||||||
#define FAN_MODIFY 0x00000002 /* File was modified */
|
#define FAN_MODIFY 0x00000002 /* File was modified */
|
||||||
#define FAN_CLOSE_WRITE 0x00000008 /* Unwrittable file closed */
|
#define FAN_CLOSE_WRITE 0x00000008 /* Writtable file closed */
|
||||||
#define FAN_CLOSE_NOWRITE 0x00000010 /* Writtable file closed */
|
#define FAN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
|
||||||
#define FAN_OPEN 0x00000020 /* File was opened */
|
#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_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
|
||||||
|
|
||||||
#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */
|
#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */
|
||||||
#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */
|
#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */
|
||||||
|
|
||||||
|
#define FAN_ONDIR 0x40000000 /* event occurred against dir */
|
||||||
|
|
||||||
|
#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */
|
||||||
|
|
||||||
/* helper events */
|
/* helper events */
|
||||||
#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
|
#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
|
||||||
|
|
||||||
@ -25,7 +26,19 @@
|
|||||||
#define FAN_CLOEXEC 0x00000001
|
#define FAN_CLOEXEC 0x00000001
|
||||||
#define FAN_NONBLOCK 0x00000002
|
#define FAN_NONBLOCK 0x00000002
|
||||||
|
|
||||||
#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK)
|
/* These are NOT bitwise flags. Both bits are used togther. */
|
||||||
|
#define FAN_CLASS_NOTIF 0x00000000
|
||||||
|
#define FAN_CLASS_CONTENT 0x00000004
|
||||||
|
#define FAN_CLASS_PRE_CONTENT 0x00000008
|
||||||
|
#define FAN_ALL_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \
|
||||||
|
FAN_CLASS_PRE_CONTENT)
|
||||||
|
|
||||||
|
#define FAN_UNLIMITED_QUEUE 0x00000010
|
||||||
|
#define FAN_UNLIMITED_MARKS 0x00000020
|
||||||
|
|
||||||
|
#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \
|
||||||
|
FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\
|
||||||
|
FAN_UNLIMITED_MARKS)
|
||||||
|
|
||||||
/* flags used for fanotify_modify_mark() */
|
/* flags used for fanotify_modify_mark() */
|
||||||
#define FAN_MARK_ADD 0x00000001
|
#define FAN_MARK_ADD 0x00000001
|
||||||
@ -36,6 +49,10 @@
|
|||||||
#define FAN_MARK_IGNORED_MASK 0x00000020
|
#define FAN_MARK_IGNORED_MASK 0x00000020
|
||||||
#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040
|
#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040
|
||||||
#define FAN_MARK_FLUSH 0x00000080
|
#define FAN_MARK_FLUSH 0x00000080
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
/* not valid from userspace, only kernel internal */
|
||||||
|
#define FAN_MARK_ONDIR 0x00000100
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\
|
#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\
|
||||||
FAN_MARK_REMOVE |\
|
FAN_MARK_REMOVE |\
|
||||||
@ -43,7 +60,8 @@
|
|||||||
FAN_MARK_ONLYDIR |\
|
FAN_MARK_ONLYDIR |\
|
||||||
FAN_MARK_MOUNT |\
|
FAN_MARK_MOUNT |\
|
||||||
FAN_MARK_IGNORED_MASK |\
|
FAN_MARK_IGNORED_MASK |\
|
||||||
FAN_MARK_IGNORED_SURV_MODIFY)
|
FAN_MARK_IGNORED_SURV_MODIFY |\
|
||||||
|
FAN_MARK_FLUSH)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All of the events - we build the list by hand so that we can add flags in
|
* All of the events - we build the list by hand so that we can add flags in
|
||||||
@ -70,10 +88,10 @@
|
|||||||
struct fanotify_event_metadata {
|
struct fanotify_event_metadata {
|
||||||
__u32 event_len;
|
__u32 event_len;
|
||||||
__u32 vers;
|
__u32 vers;
|
||||||
__u64 mask;
|
__aligned_u64 mask;
|
||||||
__s32 fd;
|
__s32 fd;
|
||||||
__s32 pid;
|
__s32 pid;
|
||||||
} __attribute__ ((packed));
|
};
|
||||||
|
|
||||||
struct fanotify_response {
|
struct fanotify_response {
|
||||||
__s32 fd;
|
__s32 fd;
|
||||||
|
@ -26,12 +26,12 @@ static inline void fsnotify_d_instantiate(struct dentry *dentry,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Notify this dentry's parent about a child's events. */
|
/* Notify this dentry's parent about a child's events. */
|
||||||
static inline void fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
|
static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
|
||||||
{
|
{
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
dentry = path->dentry;
|
dentry = path->dentry;
|
||||||
|
|
||||||
__fsnotify_parent(path, dentry, mask);
|
return __fsnotify_parent(path, dentry, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* simple call site for access decisions */
|
/* simple call site for access decisions */
|
||||||
@ -40,6 +40,7 @@ static inline int fsnotify_perm(struct file *file, int mask)
|
|||||||
struct path *path = &file->f_path;
|
struct path *path = &file->f_path;
|
||||||
struct inode *inode = path->dentry->d_inode;
|
struct inode *inode = path->dentry->d_inode;
|
||||||
__u32 fsnotify_mask = 0;
|
__u32 fsnotify_mask = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (file->f_mode & FMODE_NONOTIFY)
|
if (file->f_mode & FMODE_NONOTIFY)
|
||||||
return 0;
|
return 0;
|
||||||
@ -52,6 +53,10 @@ static inline int fsnotify_perm(struct file *file, int mask)
|
|||||||
else
|
else
|
||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
|
ret = fsnotify_parent(path, NULL, fsnotify_mask);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
|
return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +98,8 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
|
|||||||
old_dir_mask |= FS_DN_RENAME;
|
old_dir_mask |= FS_DN_RENAME;
|
||||||
|
|
||||||
if (isdir) {
|
if (isdir) {
|
||||||
old_dir_mask |= FS_IN_ISDIR;
|
old_dir_mask |= FS_ISDIR;
|
||||||
new_dir_mask |= FS_IN_ISDIR;
|
new_dir_mask |= FS_ISDIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name, fs_cookie);
|
fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name, fs_cookie);
|
||||||
@ -132,7 +137,7 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
|
|||||||
__u32 mask = FS_DELETE;
|
__u32 mask = FS_DELETE;
|
||||||
|
|
||||||
if (isdir)
|
if (isdir)
|
||||||
mask |= FS_IN_ISDIR;
|
mask |= FS_ISDIR;
|
||||||
|
|
||||||
fsnotify_parent(NULL, dentry, mask);
|
fsnotify_parent(NULL, dentry, mask);
|
||||||
}
|
}
|
||||||
@ -174,7 +179,7 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct
|
|||||||
*/
|
*/
|
||||||
static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
|
static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
__u32 mask = (FS_CREATE | FS_IN_ISDIR);
|
__u32 mask = (FS_CREATE | FS_ISDIR);
|
||||||
struct inode *d_inode = dentry->d_inode;
|
struct inode *d_inode = dentry->d_inode;
|
||||||
|
|
||||||
audit_inode_child(dentry, inode);
|
audit_inode_child(dentry, inode);
|
||||||
@ -192,7 +197,7 @@ static inline void fsnotify_access(struct file *file)
|
|||||||
__u32 mask = FS_ACCESS;
|
__u32 mask = FS_ACCESS;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
mask |= FS_IN_ISDIR;
|
mask |= FS_ISDIR;
|
||||||
|
|
||||||
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
||||||
fsnotify_parent(path, NULL, mask);
|
fsnotify_parent(path, NULL, mask);
|
||||||
@ -210,7 +215,7 @@ static inline void fsnotify_modify(struct file *file)
|
|||||||
__u32 mask = FS_MODIFY;
|
__u32 mask = FS_MODIFY;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
mask |= FS_IN_ISDIR;
|
mask |= FS_ISDIR;
|
||||||
|
|
||||||
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
||||||
fsnotify_parent(path, NULL, mask);
|
fsnotify_parent(path, NULL, mask);
|
||||||
@ -228,12 +233,13 @@ static inline void fsnotify_open(struct file *file)
|
|||||||
__u32 mask = FS_OPEN;
|
__u32 mask = FS_OPEN;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
mask |= FS_IN_ISDIR;
|
mask |= FS_ISDIR;
|
||||||
|
|
||||||
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
/* FMODE_NONOTIFY must never be set from user */
|
||||||
fsnotify_parent(path, NULL, mask);
|
file->f_mode &= ~FMODE_NONOTIFY;
|
||||||
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
|
|
||||||
}
|
fsnotify_parent(path, NULL, mask);
|
||||||
|
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -247,7 +253,7 @@ static inline void fsnotify_close(struct file *file)
|
|||||||
__u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
|
__u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
mask |= FS_IN_ISDIR;
|
mask |= FS_ISDIR;
|
||||||
|
|
||||||
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
if (!(file->f_mode & FMODE_NONOTIFY)) {
|
||||||
fsnotify_parent(path, NULL, mask);
|
fsnotify_parent(path, NULL, mask);
|
||||||
@ -264,7 +270,7 @@ static inline void fsnotify_xattr(struct dentry *dentry)
|
|||||||
__u32 mask = FS_ATTRIB;
|
__u32 mask = FS_ATTRIB;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
mask |= FS_IN_ISDIR;
|
mask |= FS_ISDIR;
|
||||||
|
|
||||||
fsnotify_parent(NULL, dentry, mask);
|
fsnotify_parent(NULL, dentry, mask);
|
||||||
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||||
@ -299,7 +305,7 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
|
|||||||
|
|
||||||
if (mask) {
|
if (mask) {
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
mask |= FS_IN_ISDIR;
|
mask |= FS_ISDIR;
|
||||||
|
|
||||||
fsnotify_parent(NULL, dentry, mask);
|
fsnotify_parent(NULL, dentry, mask);
|
||||||
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
#define FS_ACCESS_PERM 0x00020000 /* access event in a permissions 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_EXCL_UNLINK 0x04000000 /* do not send events if object is unlinked */
|
||||||
#define FS_IN_ISDIR 0x40000000 /* event occurred against dir */
|
#define FS_ISDIR 0x40000000 /* event occurred against dir */
|
||||||
#define FS_IN_ONESHOT 0x80000000 /* only send event once */
|
#define FS_IN_ONESHOT 0x80000000 /* only send event once */
|
||||||
|
|
||||||
#define FS_DN_RENAME 0x10000000 /* file renamed */
|
#define FS_DN_RENAME 0x10000000 /* file renamed */
|
||||||
@ -64,13 +64,15 @@
|
|||||||
|
|
||||||
#define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO)
|
#define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO)
|
||||||
|
|
||||||
|
#define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM)
|
||||||
|
|
||||||
#define ALL_FSNOTIFY_EVENTS (FS_ACCESS | FS_MODIFY | FS_ATTRIB | \
|
#define ALL_FSNOTIFY_EVENTS (FS_ACCESS | FS_MODIFY | FS_ATTRIB | \
|
||||||
FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN | \
|
FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN | \
|
||||||
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE | \
|
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE | \
|
||||||
FS_DELETE | FS_DELETE_SELF | FS_MOVE_SELF | \
|
FS_DELETE | FS_DELETE_SELF | FS_MOVE_SELF | \
|
||||||
FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \
|
FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \
|
||||||
FS_OPEN_PERM | FS_ACCESS_PERM | FS_EXCL_UNLINK | \
|
FS_OPEN_PERM | FS_ACCESS_PERM | FS_EXCL_UNLINK | \
|
||||||
FS_IN_ISDIR | FS_IN_ONESHOT | FS_DN_RENAME | \
|
FS_ISDIR | FS_IN_ONESHOT | FS_DN_RENAME | \
|
||||||
FS_DN_MULTISHOT | FS_EVENT_ON_CHILD)
|
FS_DN_MULTISHOT | FS_EVENT_ON_CHILD)
|
||||||
|
|
||||||
struct fsnotify_group;
|
struct fsnotify_group;
|
||||||
@ -129,6 +131,14 @@ struct fsnotify_group {
|
|||||||
wait_queue_head_t notification_waitq; /* read() on the notification file blocks on this waitq */
|
wait_queue_head_t notification_waitq; /* read() on the notification file blocks on this waitq */
|
||||||
unsigned int q_len; /* events on the queue */
|
unsigned int q_len; /* events on the queue */
|
||||||
unsigned int max_events; /* maximum events allowed on the list */
|
unsigned int max_events; /* maximum events allowed on the list */
|
||||||
|
/*
|
||||||
|
* Valid fsnotify group priorities. Events are send in order from highest
|
||||||
|
* priority to lowest priority. We default to the lowest priority.
|
||||||
|
*/
|
||||||
|
#define FS_PRIO_0 0 /* normal notifiers, no permissions */
|
||||||
|
#define FS_PRIO_1 1 /* fanotify content based access control */
|
||||||
|
#define FS_PRIO_2 2 /* fanotify pre-content access */
|
||||||
|
unsigned int priority;
|
||||||
|
|
||||||
/* stores all fastpath marks assoc with this group so they can be cleaned on unregister */
|
/* stores all fastpath marks assoc with this group so they can be cleaned on unregister */
|
||||||
spinlock_t mark_lock; /* protect marks_list */
|
spinlock_t mark_lock; /* protect marks_list */
|
||||||
@ -159,6 +169,8 @@ struct fsnotify_group {
|
|||||||
bool bypass_perm; /* protected by access_mutex */
|
bool bypass_perm; /* protected by access_mutex */
|
||||||
#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
|
#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
|
||||||
int f_flags;
|
int f_flags;
|
||||||
|
unsigned int max_marks;
|
||||||
|
struct user_struct *user;
|
||||||
} fanotify_data;
|
} fanotify_data;
|
||||||
#endif /* CONFIG_FANOTIFY */
|
#endif /* CONFIG_FANOTIFY */
|
||||||
};
|
};
|
||||||
@ -275,8 +287,8 @@ struct fsnotify_mark {
|
|||||||
struct fsnotify_inode_mark i;
|
struct fsnotify_inode_mark i;
|
||||||
struct fsnotify_vfsmount_mark m;
|
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 */
|
struct list_head free_g_list; /* tmp list used when freeing this mark */
|
||||||
|
__u32 ignored_mask; /* events types to ignore */
|
||||||
#define FSNOTIFY_MARK_FLAG_INODE 0x01
|
#define FSNOTIFY_MARK_FLAG_INODE 0x01
|
||||||
#define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02
|
#define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02
|
||||||
#define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04
|
#define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04
|
||||||
@ -294,7 +306,7 @@ struct fsnotify_mark {
|
|||||||
/* main fsnotify call to send events */
|
/* main fsnotify call to send events */
|
||||||
extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
|
extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
|
||||||
const unsigned char *name, u32 cookie);
|
const unsigned char *name, u32 cookie);
|
||||||
extern void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask);
|
extern int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask);
|
||||||
extern void __fsnotify_inode_delete(struct inode *inode);
|
extern void __fsnotify_inode_delete(struct inode *inode);
|
||||||
extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
|
extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
|
||||||
extern u32 fsnotify_get_cookie(void);
|
extern u32 fsnotify_get_cookie(void);
|
||||||
@ -423,8 +435,10 @@ static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int da
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
|
static inline int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
|
||||||
{}
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void __fsnotify_inode_delete(struct inode *inode)
|
static inline void __fsnotify_inode_delete(struct inode *inode)
|
||||||
{}
|
{}
|
||||||
|
@ -672,6 +672,9 @@ struct user_struct {
|
|||||||
atomic_t inotify_watches; /* How many inotify watches does this user have? */
|
atomic_t inotify_watches; /* How many inotify watches does this user have? */
|
||||||
atomic_t inotify_devs; /* How many inotify devs does this user have opened? */
|
atomic_t inotify_devs; /* How many inotify devs does this user have opened? */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_FANOTIFY
|
||||||
|
atomic_t fanotify_listeners;
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_EPOLL
|
#ifdef CONFIG_EPOLL
|
||||||
atomic_t epoll_watches; /* The number of file descriptors currently watched */
|
atomic_t epoll_watches; /* The number of file descriptors currently watched */
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user