forked from Minki/linux
fanotify: fscking all notification system
fanotify is a novel file notification system which bases notification on giving userspace both an event type (open, close, read, write) and an open file descriptor to the object in question. This should address a number of races and problems with other notification systems like inotify and dnotify and should allow the future implementation of blocking or access controlled notification. These are useful for on access scanners or hierachical storage management schemes. This patch just implements the basics of the fsnotify functions. Signed-off-by: Eric Paris <eparis@redhat.com>
This commit is contained in:
parent
12ed2e36c9
commit
ff0b16a985
@ -3,3 +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"
|
||||||
|
@ -2,3 +2,4 @@ obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o inode_mark.o
|
|||||||
|
|
||||||
obj-y += dnotify/
|
obj-y += dnotify/
|
||||||
obj-y += inotify/
|
obj-y += inotify/
|
||||||
|
obj-y += fanotify/
|
||||||
|
11
fs/notify/fanotify/Kconfig
Normal file
11
fs/notify/fanotify/Kconfig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
config FANOTIFY
|
||||||
|
bool "Filesystem wide access notification"
|
||||||
|
select FSNOTIFY
|
||||||
|
default y
|
||||||
|
---help---
|
||||||
|
Say Y here to enable fanotify suport. fanotify is a file access
|
||||||
|
notification system which differs from inotify in that it sends
|
||||||
|
and open file descriptor to the userspace listener along with
|
||||||
|
the event.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
1
fs/notify/fanotify/Makefile
Normal file
1
fs/notify/fanotify/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
obj-$(CONFIG_FANOTIFY) += fanotify.o
|
78
fs/notify/fanotify/fanotify.c
Normal file
78
fs/notify/fanotify/fanotify.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include <linux/fdtable.h>
|
||||||
|
#include <linux/fsnotify_backend.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h> /* UINT_MAX */
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include "fanotify.h"
|
||||||
|
|
||||||
|
static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
|
||||||
|
BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
|
||||||
|
BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
|
||||||
|
BUILD_BUG_ON(FAN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE);
|
||||||
|
BUILD_BUG_ON(FAN_CLOSE_WRITE != FS_CLOSE_WRITE);
|
||||||
|
BUILD_BUG_ON(FAN_OPEN != FS_OPEN);
|
||||||
|
BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD);
|
||||||
|
BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW);
|
||||||
|
|
||||||
|
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
|
||||||
|
|
||||||
|
ret = fsnotify_add_notify_event(group, event, NULL, NULL);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fanotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
|
||||||
|
struct vfsmount *mnt, __u32 mask, void *data,
|
||||||
|
int data_type)
|
||||||
|
{
|
||||||
|
struct fsnotify_mark *fsn_mark;
|
||||||
|
bool send;
|
||||||
|
|
||||||
|
pr_debug("%s: group=%p inode=%p mask=%x data=%p data_type=%d\n",
|
||||||
|
__func__, group, inode, mask, data, data_type);
|
||||||
|
|
||||||
|
/* sorry, fanotify only gives a damn about files and dirs */
|
||||||
|
if (!S_ISREG(inode->i_mode) &&
|
||||||
|
!S_ISDIR(inode->i_mode))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* if we don't have enough info to send an event to userspace say no */
|
||||||
|
if (data_type != FSNOTIFY_EVENT_PATH)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fsn_mark = fsnotify_find_mark(group, inode);
|
||||||
|
if (!fsn_mark)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* if the event is for a child and this inode doesn't care about
|
||||||
|
* events on the child, don't send it! */
|
||||||
|
if ((mask & FS_EVENT_ON_CHILD) &&
|
||||||
|
!(fsn_mark->mask & FS_EVENT_ON_CHILD)) {
|
||||||
|
send = false;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* We care about children, but do we care about this particular
|
||||||
|
* type of event?
|
||||||
|
*/
|
||||||
|
mask = (mask & ~FS_EVENT_ON_CHILD);
|
||||||
|
send = (fsn_mark->mask & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find took a reference */
|
||||||
|
fsnotify_put_mark(fsn_mark);
|
||||||
|
|
||||||
|
return send;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct fsnotify_ops fanotify_fsnotify_ops = {
|
||||||
|
.handle_event = fanotify_handle_event,
|
||||||
|
.should_send_event = fanotify_should_send_event,
|
||||||
|
.free_group_priv = NULL,
|
||||||
|
.free_event_priv = NULL,
|
||||||
|
.freeing_mark = NULL,
|
||||||
|
};
|
12
fs/notify/fanotify/fanotify.h
Normal file
12
fs/notify/fanotify/fanotify.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include <linux/fanotify.h>
|
||||||
|
#include <linux/fsnotify_backend.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
static inline bool fanotify_mask_valid(__u32 mask)
|
||||||
|
{
|
||||||
|
if (mask & ~((__u32)FAN_ALL_INCOMING_EVENTS))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
@ -210,6 +210,7 @@ unifdef-y += ethtool.h
|
|||||||
unifdef-y += eventpoll.h
|
unifdef-y += eventpoll.h
|
||||||
unifdef-y += signalfd.h
|
unifdef-y += signalfd.h
|
||||||
unifdef-y += ext2_fs.h
|
unifdef-y += ext2_fs.h
|
||||||
|
unifdef-y += fanotify.h
|
||||||
unifdef-y += fb.h
|
unifdef-y += fb.h
|
||||||
unifdef-y += fcntl.h
|
unifdef-y += fcntl.h
|
||||||
unifdef-y += filter.h
|
unifdef-y += filter.h
|
||||||
|
40
include/linux/fanotify.h
Normal file
40
include/linux/fanotify.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#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 */
|
||||||
|
|
||||||
|
/* helper events */
|
||||||
|
#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 legal FAN bits userspace can request (although possibly not all
|
||||||
|
* at the same time.
|
||||||
|
*/
|
||||||
|
#define FAN_ALL_INCOMING_EVENTS (FAN_ALL_EVENTS |\
|
||||||
|
FAN_EVENT_ON_CHILD)
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
#endif /* __KERNEL__ */
|
||||||
|
#endif /* _LINUX_FANOTIFY_H */
|
Loading…
Reference in New Issue
Block a user