aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/notify/Kconfig13
-rw-r--r--fs/notify/Makefile2
-rw-r--r--fs/notify/fsnotify.c79
-rw-r--r--fs/notify/fsnotify.h15
-rw-r--r--fs/notify/group.c198
-rw-r--r--fs/notify/inotify/inotify.c20
-rw-r--r--fs/notify/notification.c121
-rw-r--r--include/linux/fsnotify.h115
-rw-r--r--include/linux/fsnotify_backend.h177
9 files changed, 705 insertions, 35 deletions
diff --git a/fs/notify/Kconfig b/fs/notify/Kconfig
index 50914d7303c6..31dac7e3b0f1 100644
--- a/fs/notify/Kconfig
+++ b/fs/notify/Kconfig
@@ -1,2 +1,15 @@
1config FSNOTIFY
2 bool "Filesystem notification backend"
3 default y
4 ---help---
5 fsnotify is a backend for filesystem notification. fsnotify does
6 not provide any userspace interface but does provide the basis
7 needed for other notification schemes such as dnotify, inotify,
8 and fanotify.
9
10 Say Y here to enable fsnotify suport.
11
12 If unsure, say Y.
13
1source "fs/notify/dnotify/Kconfig" 14source "fs/notify/dnotify/Kconfig"
2source "fs/notify/inotify/Kconfig" 15source "fs/notify/inotify/Kconfig"
diff --git a/fs/notify/Makefile b/fs/notify/Makefile
index 5a95b6010ce7..db5467b5b58d 100644
--- a/fs/notify/Makefile
+++ b/fs/notify/Makefile
@@ -1,2 +1,4 @@
1obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o
2
1obj-y += dnotify/ 3obj-y += dnotify/
2obj-y += inotify/ 4obj-y += inotify/
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
new file mode 100644
index 000000000000..56bee0f10c38
--- /dev/null
+++ b/fs/notify/fsnotify.c
@@ -0,0 +1,79 @@
1/*
2 * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19#include <linux/dcache.h>
20#include <linux/fs.h>
21#include <linux/init.h>
22#include <linux/module.h>
23#include <linux/srcu.h>
24
25#include <linux/fsnotify_backend.h>
26#include "fsnotify.h"
27
28/*
29 * This is the main call to fsnotify. The VFS calls into hook specific functions
30 * in linux/fsnotify.h. Those functions then in turn call here. Here will call
31 * out to all of the registered fsnotify_group. Those groups can then use the
32 * notification event in whatever means they feel necessary.
33 */
34void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is)
35{
36 struct fsnotify_group *group;
37 struct fsnotify_event *event = NULL;
38 int idx;
39
40 if (list_empty(&fsnotify_groups))
41 return;
42
43 if (!(mask & fsnotify_mask))
44 return;
45
46 /*
47 * SRCU!! the groups list is very very much read only and the path is
48 * very hot. The VAST majority of events are not going to need to do
49 * anything other than walk the list so it's crazy to pre-allocate.
50 */
51 idx = srcu_read_lock(&fsnotify_grp_srcu);
52 list_for_each_entry_rcu(group, &fsnotify_groups, group_list) {
53 if (mask & group->mask) {
54 if (!event) {
55 event = fsnotify_create_event(to_tell, mask, data, data_is);
56 /* shit, we OOM'd and now we can't tell, maybe
57 * someday someone else will want to do something
58 * here */
59 if (!event)
60 break;
61 }
62 group->ops->handle_event(group, event);
63 }
64 }
65 srcu_read_unlock(&fsnotify_grp_srcu, idx);
66 /*
67 * fsnotify_create_event() took a reference so the event can't be cleaned
68 * up while we are still trying to add it to lists, drop that one.
69 */
70 if (event)
71 fsnotify_put_event(event);
72}
73EXPORT_SYMBOL_GPL(fsnotify);
74
75static __init int fsnotify_init(void)
76{
77 return init_srcu_struct(&fsnotify_grp_srcu);
78}
79subsys_initcall(fsnotify_init);
diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h
new file mode 100644
index 000000000000..c6a8bd476572
--- /dev/null
+++ b/fs/notify/fsnotify.h
@@ -0,0 +1,15 @@
1#ifndef __FS_NOTIFY_FSNOTIFY_H_
2#define __FS_NOTIFY_FSNOTIFY_H_
3
4#include <linux/list.h>
5#include <linux/fsnotify.h>
6#include <linux/srcu.h>
7#include <linux/types.h>
8
9/* protects reads of fsnotify_groups */
10extern struct srcu_struct fsnotify_grp_srcu;
11/* all groups which receive fsnotify events */
12extern struct list_head fsnotify_groups;
13/* all bitwise OR of all event types (FS_*) for all fsnotify_groups */
14extern __u32 fsnotify_mask;
15#endif /* __FS_NOTIFY_FSNOTIFY_H_ */
diff --git a/fs/notify/group.c b/fs/notify/group.c
new file mode 100644
index 000000000000..c6812953b968
--- /dev/null
+++ b/fs/notify/group.c
@@ -0,0 +1,198 @@
1/*
2 * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19#include <linux/list.h>
20#include <linux/mutex.h>
21#include <linux/slab.h>
22#include <linux/srcu.h>
23#include <linux/rculist.h>
24#include <linux/wait.h>
25
26#include <linux/fsnotify_backend.h>
27#include "fsnotify.h"
28
29#include <asm/atomic.h>
30
31/* protects writes to fsnotify_groups and fsnotify_mask */
32static DEFINE_MUTEX(fsnotify_grp_mutex);
33/* protects reads while running the fsnotify_groups list */
34struct srcu_struct fsnotify_grp_srcu;
35/* all groups registered to receive filesystem notifications */
36LIST_HEAD(fsnotify_groups);
37/* bitwise OR of all events (FS_*) interesting to some group on this system */
38__u32 fsnotify_mask;
39
40/*
41 * When a new group registers or changes it's set of interesting events
42 * this function updates the fsnotify_mask to contain all interesting events
43 */
44void fsnotify_recalc_global_mask(void)
45{
46 struct fsnotify_group *group;
47 __u32 mask = 0;
48 int idx;
49
50 idx = srcu_read_lock(&fsnotify_grp_srcu);
51 list_for_each_entry_rcu(group, &fsnotify_groups, group_list)
52 mask |= group->mask;
53 srcu_read_unlock(&fsnotify_grp_srcu, idx);
54 fsnotify_mask = mask;
55}
56
57/*
58 * Take a reference to a group so things found under the fsnotify_grp_mutex
59 * can't get freed under us
60 */
61static void fsnotify_get_group(struct fsnotify_group *group)
62{
63 atomic_inc(&group->refcnt);
64}
65
66/*
67 * Final freeing of a group
68 */
69static void fsnotify_destroy_group(struct fsnotify_group *group)
70{
71 if (group->ops->free_group_priv)
72 group->ops->free_group_priv(group);
73
74 kfree(group);
75}
76
77/*
78 * Remove this group from the global list of groups that will get events
79 * this can be done even if there are still references and things still using
80 * this group. This just stops the group from getting new events.
81 */
82static void __fsnotify_evict_group(struct fsnotify_group *group)
83{
84 BUG_ON(!mutex_is_locked(&fsnotify_grp_mutex));
85
86 if (group->on_group_list)
87 list_del_rcu(&group->group_list);
88 group->on_group_list = 0;
89}
90
91/*
92 * Called when a group is no longer interested in getting events. This can be
93 * used if a group is misbehaving or if for some reason a group should no longer
94 * get any filesystem events.
95 */
96void fsnotify_evict_group(struct fsnotify_group *group)
97{
98 mutex_lock(&fsnotify_grp_mutex);
99 __fsnotify_evict_group(group);
100 mutex_unlock(&fsnotify_grp_mutex);
101}
102
103/*
104 * Drop a reference to a group. Free it if it's through.
105 */
106void fsnotify_put_group(struct fsnotify_group *group)
107{
108 if (!atomic_dec_and_mutex_lock(&group->refcnt, &fsnotify_grp_mutex))
109 return;
110
111 /*
112 * OK, now we know that there's no other users *and* we hold mutex,
113 * so no new references will appear
114 */
115 __fsnotify_evict_group(group);
116
117 /*
118 * now it's off the list, so the only thing we might care about is
119 * srcu access....
120 */
121 mutex_unlock(&fsnotify_grp_mutex);
122 synchronize_srcu(&fsnotify_grp_srcu);
123
124 /* and now it is really dead. _Nothing_ could be seeing it */
125 fsnotify_recalc_global_mask();
126 fsnotify_destroy_group(group);
127}
128
129/*
130 * Simply run the fsnotify_groups list and find a group which matches
131 * the given parameters. If a group is found we take a reference to that
132 * group.
133 */
134static struct fsnotify_group *fsnotify_find_group(unsigned int group_num, __u32 mask,
135 const struct fsnotify_ops *ops)
136{
137 struct fsnotify_group *group_iter;
138 struct fsnotify_group *group = NULL;
139
140 BUG_ON(!mutex_is_locked(&fsnotify_grp_mutex));
141
142 list_for_each_entry_rcu(group_iter, &fsnotify_groups, group_list) {
143 if (group_iter->group_num == group_num) {
144 if ((group_iter->mask == mask) &&
145 (group_iter->ops == ops)) {
146 fsnotify_get_group(group_iter);
147 group = group_iter;
148 } else
149 group = ERR_PTR(-EEXIST);
150 }
151 }
152 return group;
153}
154
155/*
156 * Either finds an existing group which matches the group_num, mask, and ops or
157 * creates a new group and adds it to the global group list. In either case we
158 * take a reference for the group returned.
159 */
160struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num, __u32 mask,
161 const struct fsnotify_ops *ops)
162{
163 struct fsnotify_group *group, *tgroup;
164
165 /* very low use, simpler locking if we just always alloc */
166 group = kmalloc(sizeof(struct fsnotify_group), GFP_KERNEL);
167 if (!group)
168 return ERR_PTR(-ENOMEM);
169
170 atomic_set(&group->refcnt, 1);
171
172 group->on_group_list = 0;
173 group->group_num = group_num;
174 group->mask = mask;
175
176 group->ops = ops;
177
178 mutex_lock(&fsnotify_grp_mutex);
179 tgroup = fsnotify_find_group(group_num, mask, ops);
180 if (tgroup) {
181 /* group already exists */
182 mutex_unlock(&fsnotify_grp_mutex);
183 /* destroy the new one we made */
184 fsnotify_put_group(group);
185 return tgroup;
186 }
187
188 /* group not found, add a new one */
189 list_add_rcu(&group->group_list, &fsnotify_groups);
190 group->on_group_list = 1;
191
192 mutex_unlock(&fsnotify_grp_mutex);
193
194 if (mask)
195 fsnotify_recalc_global_mask();
196
197 return group;
198}
diff --git a/fs/notify/inotify/inotify.c b/fs/notify/inotify/inotify.c
index 220c13f0d73d..40b1cf914ccb 100644
--- a/fs/notify/inotify/inotify.c
+++ b/fs/notify/inotify/inotify.c
@@ -32,6 +32,7 @@
32#include <linux/list.h> 32#include <linux/list.h>
33#include <linux/writeback.h> 33#include <linux/writeback.h>
34#include <linux/inotify.h> 34#include <linux/inotify.h>
35#include <linux/fsnotify_backend.h>
35 36
36static atomic_t inotify_cookie; 37static atomic_t inotify_cookie;
37 38
@@ -905,6 +906,25 @@ EXPORT_SYMBOL_GPL(inotify_rm_watch);
905 */ 906 */
906static int __init inotify_setup(void) 907static int __init inotify_setup(void)
907{ 908{
909 BUILD_BUG_ON(IN_ACCESS != FS_ACCESS);
910 BUILD_BUG_ON(IN_MODIFY != FS_MODIFY);
911 BUILD_BUG_ON(IN_ATTRIB != FS_ATTRIB);
912 BUILD_BUG_ON(IN_CLOSE_WRITE != FS_CLOSE_WRITE);
913 BUILD_BUG_ON(IN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE);
914 BUILD_BUG_ON(IN_OPEN != FS_OPEN);
915 BUILD_BUG_ON(IN_MOVED_FROM != FS_MOVED_FROM);
916 BUILD_BUG_ON(IN_MOVED_TO != FS_MOVED_TO);
917 BUILD_BUG_ON(IN_CREATE != FS_CREATE);
918 BUILD_BUG_ON(IN_DELETE != FS_DELETE);
919 BUILD_BUG_ON(IN_DELETE_SELF != FS_DELETE_SELF);
920 BUILD_BUG_ON(IN_MOVE_SELF != FS_MOVE_SELF);
921 BUILD_BUG_ON(IN_Q_OVERFLOW != FS_Q_OVERFLOW);
922
923 BUILD_BUG_ON(IN_UNMOUNT != FS_UNMOUNT);
924 BUILD_BUG_ON(IN_ISDIR != FS_IN_ISDIR);
925 BUILD_BUG_ON(IN_IGNORED != FS_IN_IGNORED);
926 BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
927
908 atomic_set(&inotify_cookie, 0); 928 atomic_set(&inotify_cookie, 0);
909 929
910 return 0; 930 return 0;
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
new file mode 100644
index 000000000000..b8e9a87f8f58
--- /dev/null
+++ b/fs/notify/notification.c
@@ -0,0 +1,121 @@
1/*
2 * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19#include <linux/fs.h>
20#include <linux/init.h>
21#include <linux/kernel.h>
22#include <linux/list.h>
23#include <linux/mount.h>
24#include <linux/mutex.h>
25#include <linux/namei.h>
26#include <linux/path.h>
27#include <linux/slab.h>
28#include <linux/spinlock.h>
29
30#include <asm/atomic.h>
31
32#include <linux/fsnotify_backend.h>
33#include "fsnotify.h"
34
35static struct kmem_cache *fsnotify_event_cachep;
36
37void fsnotify_get_event(struct fsnotify_event *event)
38{
39 atomic_inc(&event->refcnt);
40}
41
42void fsnotify_put_event(struct fsnotify_event *event)
43{
44 if (!event)
45 return;
46
47 if (atomic_dec_and_test(&event->refcnt)) {
48 if (event->data_type == FSNOTIFY_EVENT_PATH)
49 path_put(&event->path);
50
51 kmem_cache_free(fsnotify_event_cachep, event);
52 }
53}
54
55/*
56 * Allocate a new event which will be sent to each group's handle_event function
57 * if the group was interested in this particular event.
58 */
59struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
60 void *data, int data_type)
61{
62 struct fsnotify_event *event;
63
64 event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
65 if (!event)
66 return NULL;
67
68 atomic_set(&event->refcnt, 1);
69
70 spin_lock_init(&event->lock);
71
72 event->path.dentry = NULL;
73 event->path.mnt = NULL;
74 event->inode = NULL;
75
76 event->to_tell = to_tell;
77
78 switch (data_type) {
79 case FSNOTIFY_EVENT_FILE: {
80 struct file *file = data;
81 struct path *path = &file->f_path;
82 event->path.dentry = path->dentry;
83 event->path.mnt = path->mnt;
84 path_get(&event->path);
85 event->data_type = FSNOTIFY_EVENT_PATH;
86 break;
87 }
88 case FSNOTIFY_EVENT_PATH: {
89 struct path *path = data;
90 event->path.dentry = path->dentry;
91 event->path.mnt = path->mnt;
92 path_get(&event->path);
93 event->data_type = FSNOTIFY_EVENT_PATH;
94 break;
95 }
96 case FSNOTIFY_EVENT_INODE:
97 event->inode = data;
98 event->data_type = FSNOTIFY_EVENT_INODE;
99 break;
100 case FSNOTIFY_EVENT_NONE:
101 event->inode = NULL;
102 event->path.dentry = NULL;
103 event->path.mnt = NULL;
104 break;
105 default:
106 BUG();
107 }
108
109 event->mask = mask;
110
111 return event;
112}
113
114__init int fsnotify_notification_init(void)
115{
116 fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC);
117
118 return 0;
119}
120subsys_initcall(fsnotify_notification_init);
121
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 00fbd5b245c9..6c9ebefdac8e 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -13,6 +13,7 @@
13 13
14#include <linux/dnotify.h> 14#include <linux/dnotify.h>
15#include <linux/inotify.h> 15#include <linux/inotify.h>
16#include <linux/fsnotify_backend.h>
16#include <linux/audit.h> 17#include <linux/audit.h>
17 18
18/* 19/*
@@ -35,6 +36,16 @@ static inline void fsnotify_d_move(struct dentry *entry)
35} 36}
36 37
37/* 38/*
39 * fsnotify_link_count - inode's link count changed
40 */
41static inline void fsnotify_link_count(struct inode *inode)
42{
43 inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
44
45 fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE);
46}
47
48/*
38 * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir 49 * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
39 */ 50 */
40static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, 51static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
@@ -43,28 +54,47 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
43{ 54{
44 struct inode *source = moved->d_inode; 55 struct inode *source = moved->d_inode;
45 u32 cookie = inotify_get_cookie(); 56 u32 cookie = inotify_get_cookie();
57 __u32 old_dir_mask = 0;
58 __u32 new_dir_mask = 0;
46 59
47 if (old_dir == new_dir) 60 if (old_dir == new_dir) {
48 inode_dir_notify(old_dir, DN_RENAME); 61 inode_dir_notify(old_dir, DN_RENAME);
49 else { 62 old_dir_mask = FS_DN_RENAME;
63 } else {
50 inode_dir_notify(old_dir, DN_DELETE); 64 inode_dir_notify(old_dir, DN_DELETE);
65 old_dir_mask = FS_DELETE;
51 inode_dir_notify(new_dir, DN_CREATE); 66 inode_dir_notify(new_dir, DN_CREATE);
67 new_dir_mask = FS_CREATE;
52 } 68 }
53 69
54 if (isdir) 70 if (isdir) {
55 isdir = IN_ISDIR; 71 isdir = IN_ISDIR;
72 old_dir_mask |= FS_IN_ISDIR;
73 new_dir_mask |= FS_IN_ISDIR;
74 }
75
76 old_dir_mask |= FS_MOVED_FROM;
77 new_dir_mask |= FS_MOVED_TO;
78
56 inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name, 79 inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name,
57 source); 80 source);
58 inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name, 81 inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name,
59 source); 82 source);
60 83
84 fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE);
85 fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE);
86
61 if (target) { 87 if (target) {
62 inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL); 88 inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL);
63 inotify_inode_is_dead(target); 89 inotify_inode_is_dead(target);
90
91 /* this is really a link_count change not a removal */
92 fsnotify_link_count(target);
64 } 93 }
65 94
66 if (source) { 95 if (source) {
67 inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL); 96 inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
97 fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE);
68 } 98 }
69 audit_inode_child(new_name, moved, new_dir); 99 audit_inode_child(new_name, moved, new_dir);
70} 100}
@@ -74,10 +104,12 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
74 */ 104 */
75static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) 105static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
76{ 106{
107 __u32 mask = FS_DELETE;
108
77 if (isdir) 109 if (isdir)
78 isdir = IN_ISDIR; 110 mask |= FS_IN_ISDIR;
79 dnotify_parent(dentry, DN_DELETE); 111 dnotify_parent(dentry, DN_DELETE);
80 inotify_dentry_parent_queue_event(dentry, IN_DELETE|isdir, 0, dentry->d_name.name); 112 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
81} 113}
82 114
83/* 115/*
@@ -87,14 +119,8 @@ static inline void fsnotify_inoderemove(struct inode *inode)
87{ 119{
88 inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL); 120 inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
89 inotify_inode_is_dead(inode); 121 inotify_inode_is_dead(inode);
90}
91 122
92/* 123 fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE);
93 * fsnotify_link_count - inode's link count changed
94 */
95static inline void fsnotify_link_count(struct inode *inode)
96{
97 inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
98} 124}
99 125
100/* 126/*
@@ -106,6 +132,8 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
106 inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name, 132 inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
107 dentry->d_inode); 133 dentry->d_inode);
108 audit_inode_child(dentry->d_name.name, dentry, inode); 134 audit_inode_child(dentry->d_name.name, dentry, inode);
135
136 fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE);
109} 137}
110 138
111/* 139/*
@@ -120,6 +148,8 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct
120 inode); 148 inode);
121 fsnotify_link_count(inode); 149 fsnotify_link_count(inode);
122 audit_inode_child(new_dentry->d_name.name, new_dentry, dir); 150 audit_inode_child(new_dentry->d_name.name, new_dentry, dir);
151
152 fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE);
123} 153}
124 154
125/* 155/*
@@ -127,10 +157,14 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct
127 */ 157 */
128static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) 158static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
129{ 159{
160 __u32 mask = (FS_CREATE | FS_IN_ISDIR);
161 struct inode *d_inode = dentry->d_inode;
162
130 inode_dir_notify(inode, DN_CREATE); 163 inode_dir_notify(inode, DN_CREATE);
131 inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, 164 inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode);
132 dentry->d_name.name, dentry->d_inode);
133 audit_inode_child(dentry->d_name.name, dentry, inode); 165 audit_inode_child(dentry->d_name.name, dentry, inode);
166
167 fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE);
134} 168}
135 169
136/* 170/*
@@ -139,14 +173,16 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
139static inline void fsnotify_access(struct dentry *dentry) 173static inline void fsnotify_access(struct dentry *dentry)
140{ 174{
141 struct inode *inode = dentry->d_inode; 175 struct inode *inode = dentry->d_inode;
142 u32 mask = IN_ACCESS; 176 __u32 mask = FS_ACCESS;
143 177
144 if (S_ISDIR(inode->i_mode)) 178 if (S_ISDIR(inode->i_mode))
145 mask |= IN_ISDIR; 179 mask |= FS_IN_ISDIR;
146 180
147 dnotify_parent(dentry, DN_ACCESS); 181 dnotify_parent(dentry, DN_ACCESS);
148 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); 182 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
149 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 183 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
184
185 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
150} 186}
151 187
152/* 188/*
@@ -155,14 +191,16 @@ static inline void fsnotify_access(struct dentry *dentry)
155static inline void fsnotify_modify(struct dentry *dentry) 191static inline void fsnotify_modify(struct dentry *dentry)
156{ 192{
157 struct inode *inode = dentry->d_inode; 193 struct inode *inode = dentry->d_inode;
158 u32 mask = IN_MODIFY; 194 __u32 mask = FS_MODIFY;
159 195
160 if (S_ISDIR(inode->i_mode)) 196 if (S_ISDIR(inode->i_mode))
161 mask |= IN_ISDIR; 197 mask |= FS_IN_ISDIR;
162 198
163 dnotify_parent(dentry, DN_MODIFY); 199 dnotify_parent(dentry, DN_MODIFY);
164 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); 200 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
165 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 201 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
202
203 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
166} 204}
167 205
168/* 206/*
@@ -171,13 +209,15 @@ static inline void fsnotify_modify(struct dentry *dentry)
171static inline void fsnotify_open(struct dentry *dentry) 209static inline void fsnotify_open(struct dentry *dentry)
172{ 210{
173 struct inode *inode = dentry->d_inode; 211 struct inode *inode = dentry->d_inode;
174 u32 mask = IN_OPEN; 212 __u32 mask = FS_OPEN;
175 213
176 if (S_ISDIR(inode->i_mode)) 214 if (S_ISDIR(inode->i_mode))
177 mask |= IN_ISDIR; 215 mask |= FS_IN_ISDIR;
178 216
179 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); 217 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
180 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 218 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
219
220 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
181} 221}
182 222
183/* 223/*
@@ -189,13 +229,15 @@ static inline void fsnotify_close(struct file *file)
189 struct inode *inode = dentry->d_inode; 229 struct inode *inode = dentry->d_inode;
190 const char *name = dentry->d_name.name; 230 const char *name = dentry->d_name.name;
191 fmode_t mode = file->f_mode; 231 fmode_t mode = file->f_mode;
192 u32 mask = (mode & FMODE_WRITE) ? IN_CLOSE_WRITE : IN_CLOSE_NOWRITE; 232 __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
193 233
194 if (S_ISDIR(inode->i_mode)) 234 if (S_ISDIR(inode->i_mode))
195 mask |= IN_ISDIR; 235 mask |= FS_IN_ISDIR;
196 236
197 inotify_dentry_parent_queue_event(dentry, mask, 0, name); 237 inotify_dentry_parent_queue_event(dentry, mask, 0, name);
198 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 238 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
239
240 fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE);
199} 241}
200 242
201/* 243/*
@@ -204,13 +246,15 @@ static inline void fsnotify_close(struct file *file)
204static inline void fsnotify_xattr(struct dentry *dentry) 246static inline void fsnotify_xattr(struct dentry *dentry)
205{ 247{
206 struct inode *inode = dentry->d_inode; 248 struct inode *inode = dentry->d_inode;
207 u32 mask = IN_ATTRIB; 249 __u32 mask = FS_ATTRIB;
208 250
209 if (S_ISDIR(inode->i_mode)) 251 if (S_ISDIR(inode->i_mode))
210 mask |= IN_ISDIR; 252 mask |= FS_IN_ISDIR;
211 253
212 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); 254 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
213 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 255 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
256
257 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE);
214} 258}
215 259
216/* 260/*
@@ -221,34 +265,34 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
221{ 265{
222 struct inode *inode = dentry->d_inode; 266 struct inode *inode = dentry->d_inode;
223 int dn_mask = 0; 267 int dn_mask = 0;
224 u32 in_mask = 0; 268 __u32 in_mask = 0;
225 269
226 if (ia_valid & ATTR_UID) { 270 if (ia_valid & ATTR_UID) {
227 in_mask |= IN_ATTRIB; 271 in_mask |= FS_ATTRIB;
228 dn_mask |= DN_ATTRIB; 272 dn_mask |= DN_ATTRIB;
229 } 273 }
230 if (ia_valid & ATTR_GID) { 274 if (ia_valid & ATTR_GID) {
231 in_mask |= IN_ATTRIB; 275 in_mask |= FS_ATTRIB;
232 dn_mask |= DN_ATTRIB; 276 dn_mask |= DN_ATTRIB;
233 } 277 }
234 if (ia_valid & ATTR_SIZE) { 278 if (ia_valid & ATTR_SIZE) {
235 in_mask |= IN_MODIFY; 279 in_mask |= FS_MODIFY;
236 dn_mask |= DN_MODIFY; 280 dn_mask |= DN_MODIFY;
237 } 281 }
238 /* both times implies a utime(s) call */ 282 /* both times implies a utime(s) call */
239 if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) 283 if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME))
240 { 284 {
241 in_mask |= IN_ATTRIB; 285 in_mask |= FS_ATTRIB;
242 dn_mask |= DN_ATTRIB; 286 dn_mask |= DN_ATTRIB;
243 } else if (ia_valid & ATTR_ATIME) { 287 } else if (ia_valid & ATTR_ATIME) {
244 in_mask |= IN_ACCESS; 288 in_mask |= FS_ACCESS;
245 dn_mask |= DN_ACCESS; 289 dn_mask |= DN_ACCESS;
246 } else if (ia_valid & ATTR_MTIME) { 290 } else if (ia_valid & ATTR_MTIME) {
247 in_mask |= IN_MODIFY; 291 in_mask |= FS_MODIFY;
248 dn_mask |= DN_MODIFY; 292 dn_mask |= DN_MODIFY;
249 } 293 }
250 if (ia_valid & ATTR_MODE) { 294 if (ia_valid & ATTR_MODE) {
251 in_mask |= IN_ATTRIB; 295 in_mask |= FS_ATTRIB;
252 dn_mask |= DN_ATTRIB; 296 dn_mask |= DN_ATTRIB;
253 } 297 }
254 298
@@ -256,14 +300,15 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
256 dnotify_parent(dentry, dn_mask); 300 dnotify_parent(dentry, dn_mask);
257 if (in_mask) { 301 if (in_mask) {
258 if (S_ISDIR(inode->i_mode)) 302 if (S_ISDIR(inode->i_mode))
259 in_mask |= IN_ISDIR; 303 in_mask |= FS_IN_ISDIR;
260 inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL); 304 inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL);
261 inotify_dentry_parent_queue_event(dentry, in_mask, 0, 305 inotify_dentry_parent_queue_event(dentry, in_mask, 0,
262 dentry->d_name.name); 306 dentry->d_name.name);
307 fsnotify(inode, in_mask, inode, FSNOTIFY_EVENT_INODE);
263 } 308 }
264} 309}
265 310
266#ifdef CONFIG_INOTIFY /* inotify helpers */ 311#if defined(CONFIG_INOTIFY) || defined(CONFIG_FSNOTIFY) /* notify helpers */
267 312
268/* 313/*
269 * fsnotify_oldname_init - save off the old filename before we change it 314 * fsnotify_oldname_init - save off the old filename before we change it
@@ -281,7 +326,7 @@ static inline void fsnotify_oldname_free(const char *old_name)
281 kfree(old_name); 326 kfree(old_name);
282} 327}
283 328
284#else /* CONFIG_INOTIFY */ 329#else /* CONFIG_INOTIFY || CONFIG_FSNOTIFY */
285 330
286static inline const char *fsnotify_oldname_init(const char *name) 331static inline const char *fsnotify_oldname_init(const char *name)
287{ 332{
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 */