@@ -184,8 +184,6 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask
184
184
EXPORT_SYMBOL_GPL (__fsnotify_parent );
185
185
186
186
static int send_to_group (struct inode * to_tell ,
187
- struct fsnotify_mark * inode_mark ,
188
- struct fsnotify_mark * vfsmount_mark ,
189
187
__u32 mask , const void * data ,
190
188
int data_is , u32 cookie ,
191
189
const unsigned char * file_name ,
@@ -195,48 +193,45 @@ static int send_to_group(struct inode *to_tell,
195
193
__u32 test_mask = (mask & ~FS_EVENT_ON_CHILD );
196
194
__u32 marks_mask = 0 ;
197
195
__u32 marks_ignored_mask = 0 ;
196
+ struct fsnotify_mark * mark ;
197
+ int type ;
198
198
199
- if (unlikely (!inode_mark && !vfsmount_mark )) {
200
- BUG ();
199
+ if (WARN_ON (!iter_info -> report_mask ))
201
200
return 0 ;
202
- }
203
201
204
202
/* clear ignored on inode modification */
205
203
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
+ }
219
212
}
220
213
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
+ }
226
224
}
227
225
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"
230
227
" 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 );
234
230
235
231
if (!(test_mask & marks_mask & ~marks_ignored_mask ))
236
232
return 0 ;
237
233
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 ,
240
235
file_name , cookie , iter_info );
241
236
}
242
237
@@ -263,6 +258,57 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
263
258
return hlist_entry_safe (node , struct fsnotify_mark , obj_list );
264
259
}
265
260
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
+
266
312
/*
267
313
* This is the main call to fsnotify. The VFS calls into hook specific functions
268
314
* 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,
307
353
308
354
if ((mask & FS_MODIFY ) ||
309
355
(test_mask & to_tell -> i_fsnotify_mask )) {
310
- iter_info .inode_mark =
356
+ iter_info .marks [ FSNOTIFY_OBJ_TYPE_INODE ] =
311
357
fsnotify_first_mark (& to_tell -> i_fsnotify_marks );
312
358
}
313
359
314
360
if (mnt && ((mask & FS_MODIFY ) ||
315
361
(test_mask & mnt -> mnt_fsnotify_mask ))) {
316
- iter_info .inode_mark =
362
+ iter_info .marks [ FSNOTIFY_OBJ_TYPE_INODE ] =
317
363
fsnotify_first_mark (& to_tell -> i_fsnotify_marks );
318
- iter_info .vfsmount_mark =
364
+ iter_info .marks [ FSNOTIFY_OBJ_TYPE_VFSMOUNT ] =
319
365
fsnotify_first_mark (& mnt -> mnt_fsnotify_marks );
320
366
}
321
367
@@ -324,32 +370,14 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
324
370
* ignore masks are properly reflected for mount mark notifications.
325
371
* That's why this traversal is so complicated...
326
372
*/
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 );
343
376
344
377
if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS ))
345
378
goto out ;
346
379
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 );
353
381
}
354
382
ret = 0 ;
355
383
out :
0 commit comments