Skip to content

Commit 04e317b

Browse files
amir73iljankara
authored andcommitted
fsnotify: optimize FS_MODIFY events with no ignored masks
fsnotify() treats FS_MODIFY events specially - it does not skip them even if the FS_MODIFY event does not apear in the object's fsnotify mask. This is because send_to_group() checks if FS_MODIFY needs to clear ignored mask of marks. The common case is that an object does not have any mark with ignored mask and in particular, that it does not have a mark with ignored mask and without the FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY flag. Set FS_MODIFY in object's fsnotify mask during fsnotify_recalc_mask() if object has a mark with an ignored mask and without the FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY flag and remove the special treatment of FS_MODIFY in fsnotify(), so that FS_MODIFY events could be optimized in the common case. Call fsnotify_recalc_mask() from fanotify after adding or removing an ignored mask from a mark without FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY or when adding the FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY flag to a mark with ignored mask (the flag cannot be removed by fanotify uapi). Performance results for doing 10000000 write(2)s to tmpfs: vanilla patched without notification mark 25.486+-1.054 24.965+-0.244 with notification mark 30.111+-0.139 26.891+-1.355 So we can see the overhead of notification subsystem has been drastically reduced. Link: https://lore.kernel.org/r/[email protected] Suggested-by: Jan Kara <[email protected]> Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent 4f0b903 commit 04e317b

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

fs/notify/fanotify/fanotify_user.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,8 +1081,28 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
10811081
flags, umask);
10821082
}
10831083

1084+
static void fanotify_mark_add_ignored_mask(struct fsnotify_mark *fsn_mark,
1085+
__u32 mask, unsigned int flags,
1086+
__u32 *removed)
1087+
{
1088+
fsn_mark->ignored_mask |= mask;
1089+
1090+
/*
1091+
* Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to
1092+
* the removal of the FS_MODIFY bit in calculated mask if it was set
1093+
* because of an ignored mask that is now going to survive FS_MODIFY.
1094+
*/
1095+
if ((flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
1096+
!(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) {
1097+
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
1098+
if (!(fsn_mark->mask & FS_MODIFY))
1099+
*removed = FS_MODIFY;
1100+
}
1101+
}
1102+
10841103
static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
1085-
__u32 mask, unsigned int flags)
1104+
__u32 mask, unsigned int flags,
1105+
__u32 *removed)
10861106
{
10871107
__u32 oldmask, newmask;
10881108

@@ -1091,9 +1111,7 @@ static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
10911111
if (!(flags & FAN_MARK_IGNORED_MASK)) {
10921112
fsn_mark->mask |= mask;
10931113
} else {
1094-
fsn_mark->ignored_mask |= mask;
1095-
if (flags & FAN_MARK_IGNORED_SURV_MODIFY)
1096-
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
1114+
fanotify_mark_add_ignored_mask(fsn_mark, mask, flags, removed);
10971115
}
10981116
newmask = fsnotify_calc_mask(fsn_mark);
10991117
spin_unlock(&fsn_mark->lock);
@@ -1156,7 +1174,7 @@ static int fanotify_add_mark(struct fsnotify_group *group,
11561174
__kernel_fsid_t *fsid)
11571175
{
11581176
struct fsnotify_mark *fsn_mark;
1159-
__u32 added;
1177+
__u32 added, removed = 0;
11601178
int ret = 0;
11611179

11621180
mutex_lock(&group->mark_mutex);
@@ -1179,8 +1197,8 @@ static int fanotify_add_mark(struct fsnotify_group *group,
11791197
goto out;
11801198
}
11811199

1182-
added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
1183-
if (added & ~fsnotify_conn_mask(fsn_mark->connector))
1200+
added = fanotify_mark_add_to_mask(fsn_mark, mask, flags, &removed);
1201+
if (removed || (added & ~fsnotify_conn_mask(fsn_mark->connector)))
11841202
fsnotify_recalc_mask(fsn_mark->connector);
11851203

11861204
out:

fs/notify/fsnotify.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,11 +531,13 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
531531

532532

533533
/*
534-
* if this is a modify event we may need to clear the ignored masks
535-
* otherwise return if none of the marks care about this type of event.
534+
* If this is a modify event we may need to clear some ignored masks.
535+
* In that case, the object with ignored masks will have the FS_MODIFY
536+
* event in its mask.
537+
* Otherwise, return if none of the marks care about this type of event.
536538
*/
537539
test_mask = (mask & ALL_FSNOTIFY_EVENTS);
538-
if (!(mask & FS_MODIFY) && !(test_mask & marks_mask))
540+
if (!(test_mask & marks_mask))
539541
return 0;
540542

541543
iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);

include/linux/fsnotify_backend.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,10 @@ static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)
609609
if (!mark->ignored_mask)
610610
return mask;
611611

612+
/* Interest in FS_MODIFY may be needed for clearing ignored mask */
613+
if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
614+
mask |= FS_MODIFY;
615+
612616
/*
613617
* If mark is interested in ignoring events on children, the object must
614618
* show interest in those events for fsnotify_parent() to notice it.

0 commit comments

Comments
 (0)