aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/fsnotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/fsnotify.c')
-rw-r--r--fs/notify/fsnotify.c201
1 files changed, 166 insertions, 35 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index fcc2f064af83..4d2a82c1ceb1 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -21,6 +21,7 @@
21#include <linux/gfp.h> 21#include <linux/gfp.h>
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/mount.h>
24#include <linux/srcu.h> 25#include <linux/srcu.h>
25 26
26#include <linux/fsnotify_backend.h> 27#include <linux/fsnotify_backend.h>
@@ -35,6 +36,11 @@ void __fsnotify_inode_delete(struct inode *inode)
35} 36}
36EXPORT_SYMBOL_GPL(__fsnotify_inode_delete); 37EXPORT_SYMBOL_GPL(__fsnotify_inode_delete);
37 38
39void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
40{
41 fsnotify_clear_marks_by_mount(mnt);
42}
43
38/* 44/*
39 * Given an inode, first check if we care what happens to our children. Inotify 45 * Given an inode, first check if we care what happens to our children. Inotify
40 * and dnotify both tell their parents about events. If we care about any event 46 * and dnotify both tell their parents about events. If we care about any event
@@ -78,13 +84,16 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
78} 84}
79 85
80/* Notify this dentry's parent about a child's events. */ 86/* Notify this dentry's parent about a child's events. */
81void __fsnotify_parent(struct dentry *dentry, __u32 mask) 87void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
82{ 88{
83 struct dentry *parent; 89 struct dentry *parent;
84 struct inode *p_inode; 90 struct inode *p_inode;
85 bool send = false; 91 bool send = false;
86 bool should_update_children = false; 92 bool should_update_children = false;
87 93
94 if (!dentry)
95 dentry = file->f_path.dentry;
96
88 if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED)) 97 if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
89 return; 98 return;
90 99
@@ -115,8 +124,12 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask)
115 * specifies these are events which came from a child. */ 124 * specifies these are events which came from a child. */
116 mask |= FS_EVENT_ON_CHILD; 125 mask |= FS_EVENT_ON_CHILD;
117 126
118 fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE, 127 if (file)
119 dentry->d_name.name, 0); 128 fsnotify(p_inode, mask, file, FSNOTIFY_EVENT_FILE,
129 dentry->d_name.name, 0);
130 else
131 fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
132 dentry->d_name.name, 0);
120 dput(parent); 133 dput(parent);
121 } 134 }
122 135
@@ -127,63 +140,181 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask)
127} 140}
128EXPORT_SYMBOL_GPL(__fsnotify_parent); 141EXPORT_SYMBOL_GPL(__fsnotify_parent);
129 142
143static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
144 struct fsnotify_mark *inode_mark,
145 struct fsnotify_mark *vfsmount_mark,
146 __u32 mask, void *data,
147 int data_is, u32 cookie,
148 const unsigned char *file_name,
149 struct fsnotify_event **event)
150{
151 struct fsnotify_group *group = inode_mark->group;
152 __u32 inode_test_mask = (mask & ~FS_EVENT_ON_CHILD);
153 __u32 vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD);
154
155 pr_debug("%s: group=%p to_tell=%p mnt=%p mark=%p mask=%x data=%p"
156 " data_is=%d cookie=%d event=%p\n", __func__, group, to_tell,
157 mnt, inode_mark, mask, data, data_is, cookie, *event);
158
159 /* clear ignored on inode modification */
160 if (mask & FS_MODIFY) {
161 if (inode_mark &&
162 !(inode_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
163 inode_mark->ignored_mask = 0;
164 if (vfsmount_mark &&
165 !(vfsmount_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
166 vfsmount_mark->ignored_mask = 0;
167 }
168
169 /* does the inode mark tell us to do something? */
170 if (inode_mark) {
171 inode_test_mask &= inode_mark->mask;
172 inode_test_mask &= ~inode_mark->ignored_mask;
173 }
174
175 /* does the vfsmount_mark tell us to do something? */
176 if (vfsmount_mark) {
177 vfsmount_test_mask &= vfsmount_mark->mask;
178 vfsmount_test_mask &= ~vfsmount_mark->ignored_mask;
179 if (inode_mark)
180 vfsmount_test_mask &= ~inode_mark->ignored_mask;
181 }
182
183 if (!inode_test_mask && !vfsmount_test_mask)
184 return 0;
185
186 if (group->ops->should_send_event(group, to_tell, inode_mark,
187 vfsmount_mark, mask, data,
188 data_is) == false)
189 return 0;
190
191 if (!*event) {
192 *event = fsnotify_create_event(to_tell, mask, data,
193 data_is, file_name,
194 cookie, GFP_KERNEL);
195 if (!*event)
196 return -ENOMEM;
197 }
198 return group->ops->handle_event(group, inode_mark, vfsmount_mark, *event);
199}
200
130/* 201/*
131 * This is the main call to fsnotify. The VFS calls into hook specific functions 202 * This is the main call to fsnotify. The VFS calls into hook specific functions
132 * in linux/fsnotify.h. Those functions then in turn call here. Here will call 203 * in linux/fsnotify.h. Those functions then in turn call here. Here will call
133 * out to all of the registered fsnotify_group. Those groups can then use the 204 * out to all of the registered fsnotify_group. Those groups can then use the
134 * notification event in whatever means they feel necessary. 205 * notification event in whatever means they feel necessary.
135 */ 206 */
136void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *file_name, u32 cookie) 207int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
208 const unsigned char *file_name, u32 cookie)
137{ 209{
138 struct fsnotify_group *group; 210 struct hlist_node *inode_node, *vfsmount_node;
211 struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL;
212 struct fsnotify_group *inode_group, *vfsmount_group;
139 struct fsnotify_event *event = NULL; 213 struct fsnotify_event *event = NULL;
140 int idx; 214 struct vfsmount *mnt;
215 int idx, ret = 0;
216 bool used_inode = false, used_vfsmount = false;
141 /* global tests shouldn't care about events on child only the specific event */ 217 /* global tests shouldn't care about events on child only the specific event */
142 __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); 218 __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
143 219
144 if (list_empty(&fsnotify_groups)) 220 if (data_is == FSNOTIFY_EVENT_FILE)
145 return; 221 mnt = ((struct file *)data)->f_path.mnt;
222 else
223 mnt = NULL;
146 224
147 if (!(test_mask & fsnotify_mask))
148 return;
149
150 if (!(test_mask & to_tell->i_fsnotify_mask))
151 return;
152 /* 225 /*
153 * SRCU!! the groups list is very very much read only and the path is 226 * if this is a modify event we may need to clear the ignored masks
154 * very hot. The VAST majority of events are not going to need to do 227 * otherwise return if neither the inode nor the vfsmount care about
155 * anything other than walk the list so it's crazy to pre-allocate. 228 * this type of event.
156 */ 229 */
157 idx = srcu_read_lock(&fsnotify_grp_srcu); 230 if (!(mask & FS_MODIFY) &&
158 list_for_each_entry_rcu(group, &fsnotify_groups, group_list) { 231 !(test_mask & to_tell->i_fsnotify_mask) &&
159 if (test_mask & group->mask) { 232 !(mnt && test_mask & mnt->mnt_fsnotify_mask))
160 if (!group->ops->should_send_event(group, to_tell, mask)) 233 return 0;
161 continue; 234
162 if (!event) { 235 idx = srcu_read_lock(&fsnotify_mark_srcu);
163 event = fsnotify_create_event(to_tell, mask, data, 236
164 data_is, file_name, cookie, 237 if ((mask & FS_MODIFY) ||
165 GFP_KERNEL); 238 (test_mask & to_tell->i_fsnotify_mask))
166 /* shit, we OOM'd and now we can't tell, maybe 239 inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first,
167 * someday someone else will want to do something 240 &fsnotify_mark_srcu);
168 * here */ 241 else
169 if (!event) 242 inode_node = NULL;
170 break; 243
171 } 244 if (mnt) {
172 group->ops->handle_event(group, event); 245 if ((mask & FS_MODIFY) ||
246 (test_mask & mnt->mnt_fsnotify_mask))
247 vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first,
248 &fsnotify_mark_srcu);
249 else
250 vfsmount_node = NULL;
251 } else {
252 mnt = NULL;
253 vfsmount_node = NULL;
254 }
255
256 while (inode_node || vfsmount_node) {
257 if (inode_node) {
258 inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu),
259 struct fsnotify_mark, i.i_list);
260 inode_group = inode_mark->group;
261 } else
262 inode_group = (void *)-1;
263
264 if (vfsmount_node) {
265 vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu),
266 struct fsnotify_mark, m.m_list);
267 vfsmount_group = vfsmount_mark->group;
268 } else
269 vfsmount_group = (void *)-1;
270
271 if (inode_group < vfsmount_group) {
272 /* handle inode */
273 send_to_group(to_tell, NULL, inode_mark, NULL, mask, data,
274 data_is, cookie, file_name, &event);
275 used_inode = true;
276 } else if (vfsmount_group < inode_group) {
277 send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data,
278 data_is, cookie, file_name, &event);
279 used_vfsmount = true;
280 } else {
281 send_to_group(to_tell, mnt, inode_mark, vfsmount_mark,
282 mask, data, data_is, cookie, file_name,
283 &event);
284 used_vfsmount = true;
285 used_inode = true;
173 } 286 }
287
288 if (used_inode)
289 inode_node = srcu_dereference(inode_node->next,
290 &fsnotify_mark_srcu);
291 if (used_vfsmount)
292 vfsmount_node = srcu_dereference(vfsmount_node->next,
293 &fsnotify_mark_srcu);
174 } 294 }
175 srcu_read_unlock(&fsnotify_grp_srcu, idx); 295
296 srcu_read_unlock(&fsnotify_mark_srcu, idx);
176 /* 297 /*
177 * fsnotify_create_event() took a reference so the event can't be cleaned 298 * fsnotify_create_event() took a reference so the event can't be cleaned
178 * up while we are still trying to add it to lists, drop that one. 299 * up while we are still trying to add it to lists, drop that one.
179 */ 300 */
180 if (event) 301 if (event)
181 fsnotify_put_event(event); 302 fsnotify_put_event(event);
303
304 return ret;
182} 305}
183EXPORT_SYMBOL_GPL(fsnotify); 306EXPORT_SYMBOL_GPL(fsnotify);
184 307
185static __init int fsnotify_init(void) 308static __init int fsnotify_init(void)
186{ 309{
187 return init_srcu_struct(&fsnotify_grp_srcu); 310 int ret;
311
312 BUG_ON(hweight32(ALL_FSNOTIFY_EVENTS) != 23);
313
314 ret = init_srcu_struct(&fsnotify_mark_srcu);
315 if (ret)
316 panic("initializing fsnotify_mark_srcu");
317
318 return 0;
188} 319}
189subsys_initcall(fsnotify_init); 320core_initcall(fsnotify_init);