aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2010-08-18 12:25:50 -0400
committerEric Paris <eparis@redhat.com>2010-08-22 20:09:41 -0400
commit84e1ab4d875922c034db7f4f814ac445a20a14bd (patch)
tree79c5755b8293f69c81e9942eeb54a62a81c9dc4b
parent88b2dbdbed551e4e21fdc8c56a15e198c52274e2 (diff)
fsnotify: fix ignored mask handling between inode and vfsmount marks
The interesting 2 list lockstep walking didn't quite work out if the inode marks only had ignores and the vfsmount list requested events. The code to shortcut list traversal would not run the inode list since it didn't have real event requests. This code forces inode list traversal when a vfsmount mark matches the event type. Maybe we could add an i_fsnotify_ignored_mask field to struct inode to get the shortcut back, but it doesn't seem worth it to grow struct inode again. I bet with the recent changes to lock the way we do now it would actually not be a major perf hit to just drop i_fsnotify_mark_mask altogether. But that is for another day. Signed-off-by: Eric Paris <eparis@redhat.com>
-rw-r--r--fs/notify/fsnotify.c35
1 files changed, 17 insertions, 18 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 59dc7a02bd0c..6f2777ce87a1 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -149,8 +149,8 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
149 struct fsnotify_event **event) 149 struct fsnotify_event **event)
150{ 150{
151 struct fsnotify_group *group = NULL; 151 struct fsnotify_group *group = NULL;
152 __u32 inode_test_mask = (mask & ~FS_EVENT_ON_CHILD); 152 __u32 inode_test_mask = 0;
153 __u32 vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD); 153 __u32 vfsmount_test_mask = 0;
154 154
155 if (unlikely(!inode_mark && !vfsmount_mark)) { 155 if (unlikely(!inode_mark && !vfsmount_mark)) {
156 BUG(); 156 BUG();
@@ -170,12 +170,14 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
170 /* does the inode mark tell us to do something? */ 170 /* does the inode mark tell us to do something? */
171 if (inode_mark) { 171 if (inode_mark) {
172 group = inode_mark->group; 172 group = inode_mark->group;
173 inode_test_mask = (mask & ~FS_EVENT_ON_CHILD);
173 inode_test_mask &= inode_mark->mask; 174 inode_test_mask &= inode_mark->mask;
174 inode_test_mask &= ~inode_mark->ignored_mask; 175 inode_test_mask &= ~inode_mark->ignored_mask;
175 } 176 }
176 177
177 /* does the vfsmount_mark tell us to do something? */ 178 /* does the vfsmount_mark tell us to do something? */
178 if (vfsmount_mark) { 179 if (vfsmount_mark) {
180 vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD);
179 group = vfsmount_mark->group; 181 group = vfsmount_mark->group;
180 vfsmount_test_mask &= vfsmount_mark->mask; 182 vfsmount_test_mask &= vfsmount_mark->mask;
181 vfsmount_test_mask &= ~vfsmount_mark->ignored_mask; 183 vfsmount_test_mask &= ~vfsmount_mark->ignored_mask;
@@ -183,9 +185,12 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
183 vfsmount_test_mask &= ~inode_mark->ignored_mask; 185 vfsmount_test_mask &= ~inode_mark->ignored_mask;
184 } 186 }
185 187
186 pr_debug("%s: group=%p to_tell=%p mnt=%p mark=%p mask=%x data=%p" 188 pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x inode_mark=%p"
187 " data_is=%d cookie=%d event=%p\n", __func__, group, to_tell, 189 " inode_test_mask=%x vfsmount_mark=%p vfsmount_test_mask=%x"
188 mnt, inode_mark, mask, data, data_is, cookie, *event); 190 " data=%p data_is=%d cookie=%d event=%p\n",
191 __func__, group, to_tell, mnt, mask, inode_mark,
192 inode_test_mask, vfsmount_mark, vfsmount_test_mask, data,
193 data_is, cookie, *event);
189 194
190 if (!inode_test_mask && !vfsmount_test_mask) 195 if (!inode_test_mask && !vfsmount_test_mask)
191 return 0; 196 return 0;
@@ -214,7 +219,7 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
214int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, 219int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
215 const unsigned char *file_name, u32 cookie) 220 const unsigned char *file_name, u32 cookie)
216{ 221{
217 struct hlist_node *inode_node, *vfsmount_node; 222 struct hlist_node *inode_node = NULL, *vfsmount_node = NULL;
218 struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL; 223 struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL;
219 struct fsnotify_group *inode_group, *vfsmount_group; 224 struct fsnotify_group *inode_group, *vfsmount_group;
220 struct fsnotify_event *event = NULL; 225 struct fsnotify_event *event = NULL;
@@ -245,19 +250,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
245 (test_mask & to_tell->i_fsnotify_mask)) 250 (test_mask & to_tell->i_fsnotify_mask))
246 inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first, 251 inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first,
247 &fsnotify_mark_srcu); 252 &fsnotify_mark_srcu);
248 else
249 inode_node = NULL;
250 253
251 if (mnt) { 254 if (mnt && ((mask & FS_MODIFY) ||
252 if ((mask & FS_MODIFY) || 255 (test_mask & mnt->mnt_fsnotify_mask))) {
253 (test_mask & mnt->mnt_fsnotify_mask)) 256 vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first,
254 vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first, 257 &fsnotify_mark_srcu);
255 &fsnotify_mark_srcu); 258 inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first,
256 else 259 &fsnotify_mark_srcu);
257 vfsmount_node = NULL;
258 } else {
259 mnt = NULL;
260 vfsmount_node = NULL;
261 } 260 }
262 261
263 while (inode_node || vfsmount_node) { 262 while (inode_node || vfsmount_node) {