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.c69
1 files changed, 45 insertions, 24 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 4788c866473a..4678b416241e 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -144,14 +144,15 @@ void __fsnotify_flush_ignored_mask(struct inode *inode, void *data, int data_is)
144{ 144{
145 struct fsnotify_mark *mark; 145 struct fsnotify_mark *mark;
146 struct hlist_node *node; 146 struct hlist_node *node;
147 int idx;
148
149 idx = srcu_read_lock(&fsnotify_mark_srcu);
147 150
148 if (!hlist_empty(&inode->i_fsnotify_marks)) { 151 if (!hlist_empty(&inode->i_fsnotify_marks)) {
149 spin_lock(&inode->i_lock); 152 hlist_for_each_entry_rcu(mark, node, &inode->i_fsnotify_marks, i.i_list) {
150 hlist_for_each_entry(mark, node, &inode->i_fsnotify_marks, i.i_list) {
151 if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) 153 if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
152 mark->ignored_mask = 0; 154 mark->ignored_mask = 0;
153 } 155 }
154 spin_unlock(&inode->i_lock);
155 } 156 }
156 157
157 if (data_is == FSNOTIFY_EVENT_FILE) { 158 if (data_is == FSNOTIFY_EVENT_FILE) {
@@ -159,14 +160,14 @@ void __fsnotify_flush_ignored_mask(struct inode *inode, void *data, int data_is)
159 160
160 mnt = ((struct file *)data)->f_path.mnt; 161 mnt = ((struct file *)data)->f_path.mnt;
161 if (mnt && !hlist_empty(&mnt->mnt_fsnotify_marks)) { 162 if (mnt && !hlist_empty(&mnt->mnt_fsnotify_marks)) {
162 spin_lock(&mnt->mnt_root->d_lock); 163 hlist_for_each_entry_rcu(mark, node, &mnt->mnt_fsnotify_marks, m.m_list) {
163 hlist_for_each_entry(mark, node, &mnt->mnt_fsnotify_marks, m.m_list) {
164 if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) 164 if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
165 mark->ignored_mask = 0; 165 mark->ignored_mask = 0;
166 } 166 }
167 spin_unlock(&mnt->mnt_root->d_lock);
168 } 167 }
169 } 168 }
169
170 srcu_read_unlock(&fsnotify_mark_srcu, idx);
170} 171}
171 172
172static int send_to_group(struct fsnotify_group *group, struct inode *to_tell, 173static int send_to_group(struct fsnotify_group *group, struct inode *to_tell,
@@ -208,8 +209,10 @@ static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt)
208int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, 209int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
209 const unsigned char *file_name, u32 cookie) 210 const unsigned char *file_name, u32 cookie)
210{ 211{
212 struct fsnotify_mark *mark;
211 struct fsnotify_group *group; 213 struct fsnotify_group *group;
212 struct fsnotify_event *event = NULL; 214 struct fsnotify_event *event = NULL;
215 struct hlist_node *node;
213 struct vfsmount *mnt = NULL; 216 struct vfsmount *mnt = NULL;
214 int idx, ret = 0; 217 int idx, ret = 0;
215 /* global tests shouldn't care about events on child only the specific event */ 218 /* global tests shouldn't care about events on child only the specific event */
@@ -237,35 +240,47 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
237 !needed_by_vfsmount(test_mask, mnt)) 240 !needed_by_vfsmount(test_mask, mnt))
238 return 0; 241 return 0;
239 242
240 /* 243 idx = srcu_read_lock(&fsnotify_mark_srcu);
241 * SRCU!! the groups list is very very much read only and the path is
242 * very hot. The VAST majority of events are not going to need to do
243 * anything other than walk the list so it's crazy to pre-allocate.
244 */
245 idx = srcu_read_lock(&fsnotify_grp_srcu);
246 244
247 if (test_mask & to_tell->i_fsnotify_mask) { 245 if (test_mask & to_tell->i_fsnotify_mask) {
248 list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) { 246 hlist_for_each_entry_rcu(mark, node, &to_tell->i_fsnotify_marks, i.i_list) {
249 if (test_mask & group->mask) { 247
250 ret = send_to_group(group, to_tell, NULL, mask, data, data_is, 248 pr_debug("%s: inode_loop: mark=%p mark->mask=%x mark->ignored_mask=%x\n",
251 cookie, file_name, &event); 249 __func__, mark, mark->mask, mark->ignored_mask);
250
251 if (test_mask & mark->mask & ~mark->ignored_mask) {
252 group = mark->group;
253 if (!group)
254 continue;
255 ret = send_to_group(group, to_tell, NULL, mask,
256 data, data_is, cookie, file_name,
257 &event);
252 if (ret) 258 if (ret)
253 goto out; 259 goto out;
254 } 260 }
255 } 261 }
256 } 262 }
257 if (needed_by_vfsmount(test_mask, mnt)) { 263
258 list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) { 264 if (mnt && (test_mask & mnt->mnt_fsnotify_mask)) {
259 if (test_mask & group->mask) { 265 hlist_for_each_entry_rcu(mark, node, &mnt->mnt_fsnotify_marks, m.m_list) {
260 ret = send_to_group(group, to_tell, mnt, mask, data, data_is, 266
261 cookie, file_name, &event); 267 pr_debug("%s: mnt_loop: mark=%p mark->mask=%x mark->ignored_mask=%x\n",
268 __func__, mark, mark->mask, mark->ignored_mask);
269
270 if (test_mask & mark->mask & ~mark->ignored_mask) {
271 group = mark->group;
272 if (!group)
273 continue;
274 ret = send_to_group(group, to_tell, mnt, mask,
275 data, data_is, cookie, file_name,
276 &event);
262 if (ret) 277 if (ret)
263 goto out; 278 goto out;
264 } 279 }
265 } 280 }
266 } 281 }
267out: 282out:
268 srcu_read_unlock(&fsnotify_grp_srcu, idx); 283 srcu_read_unlock(&fsnotify_mark_srcu, idx);
269 /* 284 /*
270 * fsnotify_create_event() took a reference so the event can't be cleaned 285 * fsnotify_create_event() took a reference so the event can't be cleaned
271 * up while we are still trying to add it to lists, drop that one. 286 * up while we are still trying to add it to lists, drop that one.
@@ -279,8 +294,14 @@ EXPORT_SYMBOL_GPL(fsnotify);
279 294
280static __init int fsnotify_init(void) 295static __init int fsnotify_init(void)
281{ 296{
297 int ret;
298
282 BUG_ON(hweight32(ALL_FSNOTIFY_EVENTS) != 23); 299 BUG_ON(hweight32(ALL_FSNOTIFY_EVENTS) != 23);
283 300
284 return init_srcu_struct(&fsnotify_grp_srcu); 301 ret = init_srcu_struct(&fsnotify_mark_srcu);
302 if (ret)
303 panic("initializing fsnotify_mark_srcu");
304
305 return 0;
285} 306}
286subsys_initcall(fsnotify_init); 307core_initcall(fsnotify_init);