summaryrefslogtreecommitdiffstats
path: root/fs/notify/fanotify/fanotify.c
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 21:24:25 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:58:54 -0400
commitff0b16a9850e8a240ad59e10b0a1291a8fcf7cbc (patch)
treefe6fad578cfb2b8528828d4f77e5494542a1fb34 /fs/notify/fanotify/fanotify.c
parent12ed2e36c98aec6c41559222e311f4aa15d254b6 (diff)
downloadlinux-ff0b16a9850e8a240ad59e10b0a1291a8fcf7cbc.tar.bz2
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>
Diffstat (limited to 'fs/notify/fanotify/fanotify.c')
-rw-r--r--fs/notify/fanotify/fanotify.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
new file mode 100644
index 000000000000..3ffb9dbcab08
--- /dev/null
+++ b/fs/notify/fanotify/fanotify.c
@@ -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,
+};