Skip to content

Commit 4f0b903

Browse files
amir73iljankara
authored andcommitted
fsnotify: fix merge with parent's ignored mask
fsnotify_parent() does not consider the parent's mark at all unless the parent inode shows interest in events on children and in the specific event. So unless parent added an event to both its mark mask and ignored mask, the event will not be ignored. Fix this by declaring the interest of an object in an event when the event is in either a mark mask or ignored mask. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent dfd42fa commit 4f0b903

File tree

3 files changed

+26
-10
lines changed

3 files changed

+26
-10
lines changed

fs/notify/fanotify/fanotify_user.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,17 +1003,18 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
10031003
__u32 mask, unsigned int flags,
10041004
__u32 umask, int *destroy)
10051005
{
1006-
__u32 oldmask = 0;
1006+
__u32 oldmask, newmask;
10071007

10081008
/* umask bits cannot be removed by user */
10091009
mask &= ~umask;
10101010
spin_lock(&fsn_mark->lock);
1011+
oldmask = fsnotify_calc_mask(fsn_mark);
10111012
if (!(flags & FAN_MARK_IGNORED_MASK)) {
1012-
oldmask = fsn_mark->mask;
10131013
fsn_mark->mask &= ~mask;
10141014
} else {
10151015
fsn_mark->ignored_mask &= ~mask;
10161016
}
1017+
newmask = fsnotify_calc_mask(fsn_mark);
10171018
/*
10181019
* We need to keep the mark around even if remaining mask cannot
10191020
* result in any events (e.g. mask == FAN_ONDIR) to support incremenal
@@ -1023,7 +1024,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
10231024
*destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask);
10241025
spin_unlock(&fsn_mark->lock);
10251026

1026-
return mask & oldmask;
1027+
return oldmask & ~newmask;
10271028
}
10281029

10291030
static int fanotify_remove_mark(struct fsnotify_group *group,
@@ -1081,23 +1082,23 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
10811082
}
10821083

10831084
static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
1084-
__u32 mask,
1085-
unsigned int flags)
1085+
__u32 mask, unsigned int flags)
10861086
{
1087-
__u32 oldmask = -1;
1087+
__u32 oldmask, newmask;
10881088

10891089
spin_lock(&fsn_mark->lock);
1090+
oldmask = fsnotify_calc_mask(fsn_mark);
10901091
if (!(flags & FAN_MARK_IGNORED_MASK)) {
1091-
oldmask = fsn_mark->mask;
10921092
fsn_mark->mask |= mask;
10931093
} else {
10941094
fsn_mark->ignored_mask |= mask;
10951095
if (flags & FAN_MARK_IGNORED_SURV_MODIFY)
10961096
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
10971097
}
1098+
newmask = fsnotify_calc_mask(fsn_mark);
10981099
spin_unlock(&fsn_mark->lock);
10991100

1100-
return mask & ~oldmask;
1101+
return newmask & ~oldmask;
11011102
}
11021103

11031104
static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,

fs/notify/mark.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
127127
return;
128128
hlist_for_each_entry(mark, &conn->list, obj_list) {
129129
if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)
130-
new_mask |= mark->mask;
130+
new_mask |= fsnotify_calc_mask(mark);
131131
}
132132
*fsnotify_conn_mask_p(conn) = new_mask;
133133
}
@@ -692,7 +692,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
692692
if (ret)
693693
goto err;
694694

695-
if (mark->mask)
695+
if (mark->mask || mark->ignored_mask)
696696
fsnotify_recalc_mask(mark->connector);
697697

698698
return ret;

include/linux/fsnotify_backend.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,21 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group,
601601

602602
/* functions used to manipulate the marks attached to inodes */
603603

604+
/* Get mask for calculating object interest taking ignored mask into account */
605+
static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)
606+
{
607+
__u32 mask = mark->mask;
608+
609+
if (!mark->ignored_mask)
610+
return mask;
611+
612+
/*
613+
* If mark is interested in ignoring events on children, the object must
614+
* show interest in those events for fsnotify_parent() to notice it.
615+
*/
616+
return mask | (mark->ignored_mask & ALL_FSNOTIFY_EVENTS);
617+
}
618+
604619
/* Get mask of events for a list of marks */
605620
extern __u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn);
606621
/* Calculate mask of events for a list of marks */

0 commit comments

Comments
 (0)