aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/fsnotify_backend.h
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-05-21 17:01:20 -0400
committerEric Paris <eparis@redhat.com>2009-06-11 14:57:52 -0400
commit90586523eb4b349806887c62ee70685a49415124 (patch)
tree2ba6da637f897bbb2309b141b81801e4151d87b0 /include/linux/fsnotify_backend.h
parentc9059598ea8981d02356eead3188bf7fa4d717b8 (diff)
fsnotify: unified filesystem notification backend
fsnotify is a backend for filesystem notification. fsnotify does not provide any userspace interface but does provide the basis needed for other notification schemes such as dnotify. fsnotify can be extended to be the backend for inotify or the upcoming fanotify. fsnotify provides a mechanism for "groups" to register for some set of filesystem events and to then deliver those events to those groups for processing. fsnotify has a number of benefits, the first being actually shrinking the size of an inode. Before fsnotify to support both dnotify and inotify an inode had unsigned long i_dnotify_mask; /* Directory notify events */ struct dnotify_struct *i_dnotify; /* for directory notifications */ struct list_head inotify_watches; /* watches on this inode */ struct mutex inotify_mutex; /* protects the watches list But with fsnotify this same functionallity (and more) is done with just __u32 i_fsnotify_mask; /* all events for this inode */ struct hlist_head i_fsnotify_mark_entries; /* marks on this inode */ That's right, inotify, dnotify, and fanotify all in 64 bits. We used that much space just in inotify_watches alone, before this patch set. fsnotify object lifetime and locking is MUCH better than what we have today. inotify locking is incredibly complex. See 8f7b0ba1c8539 as an example of what's been busted since inception. inotify needs to know internal semantics of superblock destruction and unmounting to function. The inode pinning and vfs contortions are horrible. no fsnotify implementers do allocation under locks. This means things like f04b30de3 which (due to an overabundance of caution) changes GFP_KERNEL to GFP_NOFS can be reverted. There are no longer any allocation rules when using or implementing your own fsnotify listener. fsnotify paves the way for fanotify. In brief fanotify is a notification mechanism that delivers the lisener both an 'event' and an open file descriptor to the object in question. This means that fanotify is pathname agnostic. Some on lkml may not care for the original companies or users that pushed for TALPA, but fanotify was designed with flexibility and input for other users in mind. The readahead group expressed interest in fanotify as it could be used to profile disk access on boot without breaking the audit system. The desktop search groups have also expressed interest in fanotify as it solves a number of the race conditions and problems present with managing inotify when more than a limited number of specific files are of interest. fanotify can provide for a userspace access control system which makes it a clean interface for AV vendors to hook without trying to do binary patching on the syscall table, LSM, and everywhere else they do their things today. With this patch series fanotify can be implemented in less than 1200 lines of easy to review code. Almost all of which is the socket based user interface. This patch series builds fsnotify to the point that it can implement dnotify and inotify_user. Patches exist and will be sent soon after acceptance to finish the in kernel inotify conversion (audit) and implement fanotify. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Al Viro <viro@zeniv.linux.org.uk> Cc: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'include/linux/fsnotify_backend.h')
-rw-r--r--include/linux/fsnotify_backend.h177
1 files changed, 177 insertions, 0 deletions
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
new file mode 100644
index 000000000000..1a55718b38aa
--- /dev/null
+++ b/include/linux/fsnotify_backend.h
@@ -0,0 +1,177 @@
1/*
2 * Filesystem access notification for Linux
3 *
4 * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
5 */
6
7#ifndef __LINUX_FSNOTIFY_BACKEND_H
8#define __LINUX_FSNOTIFY_BACKEND_H
9
10#ifdef __KERNEL__
11
12#include <linux/fs.h> /* struct inode */
13#include <linux/list.h>
14#include <linux/path.h> /* struct path */
15#include <linux/spinlock.h>
16#include <linux/types.h>
17
18#include <asm/atomic.h>
19
20/*
21 * IN_* from inotfy.h lines up EXACTLY with FS_*, this is so we can easily
22 * convert between them. dnotify only needs conversion at watch creation
23 * so no perf loss there. fanotify isn't defined yet, so it can use the
24 * wholes if it needs more events.
25 */
26#define FS_ACCESS 0x00000001 /* File was accessed */
27#define FS_MODIFY 0x00000002 /* File was modified */
28#define FS_ATTRIB 0x00000004 /* Metadata changed */
29#define FS_CLOSE_WRITE 0x00000008 /* Writtable file was closed */
30#define FS_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
31#define FS_OPEN 0x00000020 /* File was opened */
32#define FS_MOVED_FROM 0x00000040 /* File was moved from X */
33#define FS_MOVED_TO 0x00000080 /* File was moved to Y */
34#define FS_CREATE 0x00000100 /* Subfile was created */
35#define FS_DELETE 0x00000200 /* Subfile was deleted */
36#define FS_DELETE_SELF 0x00000400 /* Self was deleted */
37#define FS_MOVE_SELF 0x00000800 /* Self was moved */
38
39#define FS_UNMOUNT 0x00002000 /* inode on umount fs */
40#define FS_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
41#define FS_IN_IGNORED 0x00008000 /* last inotify event here */
42
43#define FS_IN_ISDIR 0x40000000 /* event occurred against dir */
44#define FS_IN_ONESHOT 0x80000000 /* only send event once */
45
46#define FS_DN_RENAME 0x10000000 /* file renamed */
47#define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */
48
49struct fsnotify_group;
50struct fsnotify_event;
51
52/*
53 * Each group much define these ops. The fsnotify infrastructure will call
54 * these operations for each relevant group.
55 *
56 * handle_event - main call for a group to handle an fs event
57 * free_group_priv - called when a group refcnt hits 0 to clean up the private union
58 */
59struct fsnotify_ops {
60 int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event);
61 void (*free_group_priv)(struct fsnotify_group *group);
62};
63
64/*
65 * A group is a "thing" that wants to receive notification about filesystem
66 * events. The mask holds the subset of event types this group cares about.
67 * refcnt on a group is up to the implementor and at any moment if it goes 0
68 * everything will be cleaned up.
69 */
70struct fsnotify_group {
71 /*
72 * global list of all groups receiving events from fsnotify.
73 * anchored by fsnotify_groups and protected by either fsnotify_grp_mutex
74 * or fsnotify_grp_srcu depending on write vs read.
75 */
76 struct list_head group_list;
77
78 /*
79 * Defines all of the event types in which this group is interested.
80 * This mask is a bitwise OR of the FS_* events from above. Each time
81 * this mask changes for a group (if it changes) the correct functions
82 * must be called to update the global structures which indicate global
83 * interest in event types.
84 */
85 __u32 mask;
86
87 /*
88 * How the refcnt is used is up to each group. When the refcnt hits 0
89 * fsnotify will clean up all of the resources associated with this group.
90 * As an example, the dnotify group will always have a refcnt=1 and that
91 * will never change. Inotify, on the other hand, has a group per
92 * inotify_init() and the refcnt will hit 0 only when that fd has been
93 * closed.
94 */
95 atomic_t refcnt; /* things with interest in this group */
96 unsigned int group_num; /* simply prevents accidental group collision */
97
98 const struct fsnotify_ops *ops; /* how this group handles things */
99
100 /* prevents double list_del of group_list. protected by global fsnotify_gr_mutex */
101 bool on_group_list;
102
103 /* groups can define private fields here or use the void *private */
104 union {
105 void *private;
106 };
107};
108
109/*
110 * all of the information about the original object we want to now send to
111 * a group. If you want to carry more info from the accessing task to the
112 * listener this structure is where you need to be adding fields.
113 */
114struct fsnotify_event {
115 spinlock_t lock; /* protection for the associated event_holder and private_list */
116 /* to_tell may ONLY be dereferenced during handle_event(). */
117 struct inode *to_tell; /* either the inode the event happened to or its parent */
118 /*
119 * depending on the event type we should have either a path or inode
120 * We hold a reference on path, but NOT on inode. Since we have the ref on
121 * the path, it may be dereferenced at any point during this object's
122 * lifetime. That reference is dropped when this object's refcnt hits
123 * 0. If this event contains an inode instead of a path, the inode may
124 * ONLY be used during handle_event().
125 */
126 union {
127 struct path path;
128 struct inode *inode;
129 };
130/* when calling fsnotify tell it if the data is a path or inode */
131#define FSNOTIFY_EVENT_NONE 0
132#define FSNOTIFY_EVENT_PATH 1
133#define FSNOTIFY_EVENT_INODE 2
134#define FSNOTIFY_EVENT_FILE 3
135 int data_type; /* which of the above union we have */
136 atomic_t refcnt; /* how many groups still are using/need to send this event */
137 __u32 mask; /* the type of access, bitwise OR for FS_* event types */
138};
139
140#ifdef CONFIG_FSNOTIFY
141
142/* called from the vfs helpers */
143
144/* main fsnotify call to send events */
145extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is);
146
147
148/* called from fsnotify listeners, such as fanotify or dnotify */
149
150/* must call when a group changes its ->mask */
151extern void fsnotify_recalc_global_mask(void);
152/* get a reference to an existing or create a new group */
153extern struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num,
154 __u32 mask,
155 const struct fsnotify_ops *ops);
156/* drop reference on a group from fsnotify_obtain_group */
157extern void fsnotify_put_group(struct fsnotify_group *group);
158
159/* take a reference to an event */
160extern void fsnotify_get_event(struct fsnotify_event *event);
161extern void fsnotify_put_event(struct fsnotify_event *event);
162/* find private data previously attached to an event */
163extern struct fsnotify_event_private_data *fsnotify_get_priv_from_event(struct fsnotify_group *group,
164 struct fsnotify_event *event);
165
166/* put here because inotify does some weird stuff when destroying watches */
167extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
168 void *data, int data_is);
169#else
170
171static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is)
172{}
173#endif /* CONFIG_FSNOTIFY */
174
175#endif /* __KERNEL __ */
176
177#endif /* __LINUX_FSNOTIFY_BACKEND_H */