aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2010-08-27 21:24:24 -0400
committerEric Paris <eparis@redhat.com>2010-08-27 21:41:26 -0400
commitf72adfd540bacc4f6ff57a7d708b1a6c8906bdb4 (patch)
treedffd43e47284095e98f2a2ab60f965fc68792008
parenta2f13ad0ba5d94b9768c28469b45ca1e81a2b895 (diff)
fsnotify: fix list walk order
Marks were stored on the inode and vfsmonut mark list in order from highest memory address to lowest memory address. The code to walk those lists thought they were in order from lowest to highest with unpredictable results when trying to match up marks from each. It was possible that extra events would be sent to userspace when inode marks ignoring events wouldn't get matched with the vfsmount marks. This problem only affected fanotify when using both vfsmount and inode marks simultaneously. Signed-off-by: Eric Paris <eparis@redhat.com>
-rw-r--r--fs/notify/fsnotify.c11
1 files changed, 5 insertions, 6 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 6f2777ce87a1..2169aa593d5f 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -261,27 +261,26 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
261 261
262 while (inode_node || vfsmount_node) { 262 while (inode_node || vfsmount_node) {
263 used_inode = used_vfsmount = false; 263 used_inode = used_vfsmount = false;
264 inode_group = vfsmount_group = NULL;
264 265
265 if (inode_node) { 266 if (inode_node) {
266 inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), 267 inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu),
267 struct fsnotify_mark, i.i_list); 268 struct fsnotify_mark, i.i_list);
268 inode_group = inode_mark->group; 269 inode_group = inode_mark->group;
269 } else 270 }
270 inode_group = (void *)-1;
271 271
272 if (vfsmount_node) { 272 if (vfsmount_node) {
273 vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu), 273 vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu),
274 struct fsnotify_mark, m.m_list); 274 struct fsnotify_mark, m.m_list);
275 vfsmount_group = vfsmount_mark->group; 275 vfsmount_group = vfsmount_mark->group;
276 } else 276 }
277 vfsmount_group = (void *)-1;
278 277
279 if (inode_group < vfsmount_group) { 278 if (inode_group > vfsmount_group) {
280 /* handle inode */ 279 /* handle inode */
281 send_to_group(to_tell, NULL, inode_mark, NULL, mask, data, 280 send_to_group(to_tell, NULL, inode_mark, NULL, mask, data,
282 data_is, cookie, file_name, &event); 281 data_is, cookie, file_name, &event);
283 used_inode = true; 282 used_inode = true;
284 } else if (vfsmount_group < inode_group) { 283 } else if (vfsmount_group > inode_group) {
285 send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data, 284 send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data,
286 data_is, cookie, file_name, &event); 285 data_is, cookie, file_name, &event);
287 used_vfsmount = true; 286 used_vfsmount = true;