Skip to content

Commit 14362a2

Browse files
amir73iljankara
authored andcommitted
fsnotify: introduce mark type iterator
fsnotify_foreach_iter_mark_type() is used to reduce boilerplate code of iterating all marks of a specific group interested in an event by consulting the iterator report_mask. Use an open coded version of that iterator in fsnotify_iter_next() that collects all marks of the current iteration group without consulting the iterator report_mask. At the moment, the two iterator variants are the same, but this decoupling will allow us to exclude some of the group's marks from reporting the event, for example for event on child and inode marks on parent did not request to watch events on children. Fixes: 2f02fd3 ("fanotify: fix ignore mask logic for events on child and on dir") Reported-by: Jan Kara <jack@suse.com> Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz> Link: https://lore.kernel.org/r/20220511190213.831646-2-amir73il@gmail.com
1 parent 5f9d3bd commit 14362a2

3 files changed

Lines changed: 54 additions & 44 deletions

File tree

fs/notify/fanotify/fanotify.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
319319
return 0;
320320
}
321321

322-
fsnotify_foreach_iter_type(type) {
323-
if (!fsnotify_iter_should_report_type(iter_info, type))
324-
continue;
325-
mark = iter_info->marks[type];
326-
322+
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
327323
/* Apply ignore mask regardless of ISDIR and ON_CHILD flags */
328324
marks_ignored_mask |= mark->ignored_mask;
329325

@@ -849,16 +845,14 @@ static struct fanotify_event *fanotify_alloc_event(
849845
*/
850846
static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
851847
{
848+
struct fsnotify_mark *mark;
852849
int type;
853850
__kernel_fsid_t fsid = {};
854851

855-
fsnotify_foreach_iter_type(type) {
852+
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
856853
struct fsnotify_mark_connector *conn;
857854

858-
if (!fsnotify_iter_should_report_type(iter_info, type))
859-
continue;
860-
861-
conn = READ_ONCE(iter_info->marks[type]->connector);
855+
conn = READ_ONCE(mark->connector);
862856
/* Mark is just getting destroyed or created? */
863857
if (!conn)
864858
continue;

fs/notify/fsnotify.c

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -335,31 +335,23 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
335335
struct fsnotify_mark *mark;
336336
int type;
337337

338-
if (WARN_ON(!iter_info->report_mask))
338+
if (!iter_info->report_mask)
339339
return 0;
340340

341341
/* clear ignored on inode modification */
342342
if (mask & FS_MODIFY) {
343-
fsnotify_foreach_iter_type(type) {
344-
if (!fsnotify_iter_should_report_type(iter_info, type))
345-
continue;
346-
mark = iter_info->marks[type];
347-
if (mark &&
348-
!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
343+
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
344+
if (!(mark->flags &
345+
FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
349346
mark->ignored_mask = 0;
350347
}
351348
}
352349

353-
fsnotify_foreach_iter_type(type) {
354-
if (!fsnotify_iter_should_report_type(iter_info, type))
355-
continue;
356-
mark = iter_info->marks[type];
357-
/* does the object mark tell us to do something? */
358-
if (mark) {
359-
group = mark->group;
360-
marks_mask |= mark->mask;
361-
marks_ignored_mask |= mark->ignored_mask;
362-
}
350+
/* Are any of the group marks interested in this event? */
351+
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
352+
group = mark->group;
353+
marks_mask |= mark->mask;
354+
marks_ignored_mask |= mark->ignored_mask;
363355
}
364356

365357
pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignored_mask=%x data=%p data_type=%d dir=%p cookie=%d\n",
@@ -403,11 +395,11 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
403395

404396
/*
405397
* iter_info is a multi head priority queue of marks.
406-
* Pick a subset of marks from queue heads, all with the
407-
* same group and set the report_mask for selected subset.
408-
* Returns the report_mask of the selected subset.
398+
* Pick a subset of marks from queue heads, all with the same group
399+
* and set the report_mask to a subset of the selected marks.
400+
* Returns false if there are no more groups to iterate.
409401
*/
410-
static unsigned int fsnotify_iter_select_report_types(
402+
static bool fsnotify_iter_select_report_types(
411403
struct fsnotify_iter_info *iter_info)
412404
{
413405
struct fsnotify_group *max_prio_group = NULL;
@@ -423,30 +415,37 @@ static unsigned int fsnotify_iter_select_report_types(
423415
}
424416

425417
if (!max_prio_group)
426-
return 0;
418+
return false;
427419

428420
/* Set the report mask for marks from same group as max prio group */
421+
iter_info->current_group = max_prio_group;
429422
iter_info->report_mask = 0;
430423
fsnotify_foreach_iter_type(type) {
431424
mark = iter_info->marks[type];
432-
if (mark &&
433-
fsnotify_compare_groups(max_prio_group, mark->group) == 0)
425+
if (mark && mark->group == iter_info->current_group)
434426
fsnotify_iter_set_report_type(iter_info, type);
435427
}
436428

437-
return iter_info->report_mask;
429+
return true;
438430
}
439431

440432
/*
441-
* Pop from iter_info multi head queue, the marks that were iterated in the
433+
* Pop from iter_info multi head queue, the marks that belong to the group of
442434
* current iteration step.
443435
*/
444436
static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info)
445437
{
438+
struct fsnotify_mark *mark;
446439
int type;
447440

441+
/*
442+
* We cannot use fsnotify_foreach_iter_mark_type() here because we
443+
* may need to advance a mark of type X that belongs to current_group
444+
* but was not selected for reporting.
445+
*/
448446
fsnotify_foreach_iter_type(type) {
449-
if (fsnotify_iter_should_report_type(iter_info, type))
447+
mark = iter_info->marks[type];
448+
if (mark && mark->group == iter_info->current_group)
450449
iter_info->marks[type] =
451450
fsnotify_next_mark(iter_info->marks[type]);
452451
}

include/linux/fsnotify_backend.h

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ static inline bool fsnotify_valid_obj_type(unsigned int obj_type)
399399

400400
struct fsnotify_iter_info {
401401
struct fsnotify_mark *marks[FSNOTIFY_ITER_TYPE_COUNT];
402+
struct fsnotify_group *current_group;
402403
unsigned int report_mask;
403404
int srcu_idx;
404405
};
@@ -415,20 +416,31 @@ static inline void fsnotify_iter_set_report_type(
415416
iter_info->report_mask |= (1U << iter_type);
416417
}
417418

418-
static inline void fsnotify_iter_set_report_type_mark(
419-
struct fsnotify_iter_info *iter_info, int iter_type,
420-
struct fsnotify_mark *mark)
419+
static inline struct fsnotify_mark *fsnotify_iter_mark(
420+
struct fsnotify_iter_info *iter_info, int iter_type)
421421
{
422-
iter_info->marks[iter_type] = mark;
423-
iter_info->report_mask |= (1U << iter_type);
422+
if (fsnotify_iter_should_report_type(iter_info, iter_type))
423+
return iter_info->marks[iter_type];
424+
return NULL;
425+
}
426+
427+
static inline int fsnotify_iter_step(struct fsnotify_iter_info *iter, int type,
428+
struct fsnotify_mark **markp)
429+
{
430+
while (type < FSNOTIFY_ITER_TYPE_COUNT) {
431+
*markp = fsnotify_iter_mark(iter, type);
432+
if (*markp)
433+
break;
434+
type++;
435+
}
436+
return type;
424437
}
425438

426439
#define FSNOTIFY_ITER_FUNCS(name, NAME) \
427440
static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \
428441
struct fsnotify_iter_info *iter_info) \
429442
{ \
430-
return (iter_info->report_mask & (1U << FSNOTIFY_ITER_TYPE_##NAME)) ? \
431-
iter_info->marks[FSNOTIFY_ITER_TYPE_##NAME] : NULL; \
443+
return fsnotify_iter_mark(iter_info, FSNOTIFY_ITER_TYPE_##NAME); \
432444
}
433445

434446
FSNOTIFY_ITER_FUNCS(inode, INODE)
@@ -438,6 +450,11 @@ FSNOTIFY_ITER_FUNCS(sb, SB)
438450

439451
#define fsnotify_foreach_iter_type(type) \
440452
for (type = 0; type < FSNOTIFY_ITER_TYPE_COUNT; type++)
453+
#define fsnotify_foreach_iter_mark_type(iter, mark, type) \
454+
for (type = 0; \
455+
type = fsnotify_iter_step(iter, type, &mark), \
456+
type < FSNOTIFY_ITER_TYPE_COUNT; \
457+
type++)
441458

442459
/*
443460
* fsnotify_connp_t is what we embed in objects which connector can be attached

0 commit comments

Comments
 (0)