@@ -184,8 +184,6 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask
184184EXPORT_SYMBOL_GPL (__fsnotify_parent );
185185
186186static int send_to_group (struct inode * to_tell ,
187- struct fsnotify_mark * inode_mark ,
188- struct fsnotify_mark * vfsmount_mark ,
189187 __u32 mask , const void * data ,
190188 int data_is , u32 cookie ,
191189 const unsigned char * file_name ,
@@ -195,48 +193,45 @@ static int send_to_group(struct inode *to_tell,
195193 __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD );
196194 __u32 marks_mask = 0 ;
197195 __u32 marks_ignored_mask = 0 ;
196+ struct fsnotify_mark * mark ;
197+ int type ;
198198
199- if (unlikely (!inode_mark && !vfsmount_mark )) {
200- BUG ();
199+ if (WARN_ON (!iter_info -> report_mask ))
201200 return 0 ;
202- }
203201
204202 /* clear ignored on inode modification */
205203 if (mask & FS_MODIFY ) {
206- if (inode_mark &&
207- !(inode_mark -> flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ))
208- inode_mark -> ignored_mask = 0 ;
209- if (vfsmount_mark &&
210- !(vfsmount_mark -> flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ))
211- vfsmount_mark -> ignored_mask = 0 ;
212- }
213-
214- /* does the inode mark tell us to do something? */
215- if (inode_mark ) {
216- group = inode_mark -> group ;
217- marks_mask |= inode_mark -> mask ;
218- marks_ignored_mask |= inode_mark -> ignored_mask ;
204+ fsnotify_foreach_obj_type (type ) {
205+ if (!fsnotify_iter_should_report_type (iter_info , type ))
206+ continue ;
207+ mark = iter_info -> marks [type ];
208+ if (mark &&
209+ !(mark -> flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ))
210+ mark -> ignored_mask = 0 ;
211+ }
219212 }
220213
221- /* does the vfsmount_mark tell us to do something? */
222- if (vfsmount_mark ) {
223- group = vfsmount_mark -> group ;
224- marks_mask |= vfsmount_mark -> mask ;
225- marks_ignored_mask |= vfsmount_mark -> ignored_mask ;
214+ fsnotify_foreach_obj_type (type ) {
215+ if (!fsnotify_iter_should_report_type (iter_info , type ))
216+ continue ;
217+ mark = iter_info -> marks [type ];
218+ /* does the object mark tell us to do something? */
219+ if (mark ) {
220+ group = mark -> group ;
221+ marks_mask |= mark -> mask ;
222+ marks_ignored_mask |= mark -> ignored_mask ;
223+ }
226224 }
227225
228- pr_debug ("%s: group=%p to_tell=%p mask=%x inode_mark=%p"
229- " vfsmount_mark=%p marks_mask=%x marks_ignored_mask=%x"
226+ pr_debug ("%s: group=%p to_tell=%p mask=%x marks_mask=%x marks_ignored_mask=%x"
230227 " data=%p data_is=%d cookie=%d\n" ,
231- __func__ , group , to_tell , mask , inode_mark , vfsmount_mark ,
232- marks_mask , marks_ignored_mask , data ,
233- data_is , cookie );
228+ __func__ , group , to_tell , mask , marks_mask , marks_ignored_mask ,
229+ data , data_is , cookie );
234230
235231 if (!(test_mask & marks_mask & ~marks_ignored_mask ))
236232 return 0 ;
237233
238- return group -> ops -> handle_event (group , to_tell , inode_mark ,
239- vfsmount_mark , mask , data , data_is ,
234+ return group -> ops -> handle_event (group , to_tell , mask , data , data_is ,
240235 file_name , cookie , iter_info );
241236}
242237
@@ -263,6 +258,57 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
263258 return hlist_entry_safe (node , struct fsnotify_mark , obj_list );
264259}
265260
261+ /*
262+ * iter_info is a multi head priority queue of marks.
263+ * Pick a subset of marks from queue heads, all with the
264+ * same group and set the report_mask for selected subset.
265+ * Returns the report_mask of the selected subset.
266+ */
267+ static unsigned int fsnotify_iter_select_report_types (
268+ struct fsnotify_iter_info * iter_info )
269+ {
270+ struct fsnotify_group * max_prio_group = NULL ;
271+ struct fsnotify_mark * mark ;
272+ int type ;
273+
274+ /* Choose max prio group among groups of all queue heads */
275+ fsnotify_foreach_obj_type (type ) {
276+ mark = iter_info -> marks [type ];
277+ if (mark &&
278+ fsnotify_compare_groups (max_prio_group , mark -> group ) > 0 )
279+ max_prio_group = mark -> group ;
280+ }
281+
282+ if (!max_prio_group )
283+ return 0 ;
284+
285+ /* Set the report mask for marks from same group as max prio group */
286+ iter_info -> report_mask = 0 ;
287+ fsnotify_foreach_obj_type (type ) {
288+ mark = iter_info -> marks [type ];
289+ if (mark &&
290+ fsnotify_compare_groups (max_prio_group , mark -> group ) == 0 )
291+ fsnotify_iter_set_report_type (iter_info , type );
292+ }
293+
294+ return iter_info -> report_mask ;
295+ }
296+
297+ /*
298+ * Pop from iter_info multi head queue, the marks that were iterated in the
299+ * current iteration step.
300+ */
301+ static void fsnotify_iter_next (struct fsnotify_iter_info * iter_info )
302+ {
303+ int type ;
304+
305+ fsnotify_foreach_obj_type (type ) {
306+ if (fsnotify_iter_should_report_type (iter_info , type ))
307+ iter_info -> marks [type ] =
308+ fsnotify_next_mark (iter_info -> marks [type ]);
309+ }
310+ }
311+
266312/*
267313 * This is the main call to fsnotify. The VFS calls into hook specific functions
268314 * in linux/fsnotify.h. Those functions then in turn call here. Here will call
@@ -307,15 +353,15 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
307353
308354 if ((mask & FS_MODIFY ) ||
309355 (test_mask & to_tell -> i_fsnotify_mask )) {
310- iter_info .inode_mark =
356+ iter_info .marks [ FSNOTIFY_OBJ_TYPE_INODE ] =
311357 fsnotify_first_mark (& to_tell -> i_fsnotify_marks );
312358 }
313359
314360 if (mnt && ((mask & FS_MODIFY ) ||
315361 (test_mask & mnt -> mnt_fsnotify_mask ))) {
316- iter_info .inode_mark =
362+ iter_info .marks [ FSNOTIFY_OBJ_TYPE_INODE ] =
317363 fsnotify_first_mark (& to_tell -> i_fsnotify_marks );
318- iter_info .vfsmount_mark =
364+ iter_info .marks [ FSNOTIFY_OBJ_TYPE_VFSMOUNT ] =
319365 fsnotify_first_mark (& mnt -> mnt_fsnotify_marks );
320366 }
321367
@@ -324,32 +370,14 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
324370 * ignore masks are properly reflected for mount mark notifications.
325371 * That's why this traversal is so complicated...
326372 */
327- while (iter_info .inode_mark || iter_info .vfsmount_mark ) {
328- struct fsnotify_mark * inode_mark = iter_info .inode_mark ;
329- struct fsnotify_mark * vfsmount_mark = iter_info .vfsmount_mark ;
330-
331- if (inode_mark && vfsmount_mark ) {
332- int cmp = fsnotify_compare_groups (inode_mark -> group ,
333- vfsmount_mark -> group );
334- if (cmp > 0 )
335- inode_mark = NULL ;
336- else if (cmp < 0 )
337- vfsmount_mark = NULL ;
338- }
339-
340- ret = send_to_group (to_tell , inode_mark , vfsmount_mark , mask ,
341- data , data_is , cookie , file_name ,
342- & iter_info );
373+ while (fsnotify_iter_select_report_types (& iter_info )) {
374+ ret = send_to_group (to_tell , mask , data , data_is , cookie ,
375+ file_name , & iter_info );
343376
344377 if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS ))
345378 goto out ;
346379
347- if (inode_mark )
348- iter_info .inode_mark =
349- fsnotify_next_mark (iter_info .inode_mark );
350- if (vfsmount_mark )
351- iter_info .vfsmount_mark =
352- fsnotify_next_mark (iter_info .vfsmount_mark );
380+ fsnotify_iter_next (& iter_info );
353381 }
354382 ret = 0 ;
355383out :
0 commit comments