Skip to content

Commit

Permalink
fsnotify: fix merge with parent's ignored mask
Browse files Browse the repository at this point in the history
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/20220223151438.790268-2-amir73il@gmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
  • Loading branch information
Amir Goldstein authored and Jan Kara committed Feb 24, 2022
1 parent dfd42fa commit 4f0b903
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 10 deletions.
17 changes: 9 additions & 8 deletions fs/notify/fanotify/fanotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,17 +1003,18 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
__u32 mask, unsigned int flags,
__u32 umask, int *destroy)
{
__u32 oldmask = 0;
__u32 oldmask, newmask;

/* umask bits cannot be removed by user */
mask &= ~umask;
spin_lock(&fsn_mark->lock);
oldmask = fsnotify_calc_mask(fsn_mark);
if (!(flags & FAN_MARK_IGNORED_MASK)) {
oldmask = fsn_mark->mask;
fsn_mark->mask &= ~mask;
} else {
fsn_mark->ignored_mask &= ~mask;
}
newmask = fsnotify_calc_mask(fsn_mark);
/*
* We need to keep the mark around even if remaining mask cannot
* result in any events (e.g. mask == FAN_ONDIR) to support incremenal
Expand All @@ -1023,7 +1024,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
*destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask);
spin_unlock(&fsn_mark->lock);

return mask & oldmask;
return oldmask & ~newmask;
}

static int fanotify_remove_mark(struct fsnotify_group *group,
Expand Down Expand Up @@ -1081,23 +1082,23 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
}

static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
__u32 mask,
unsigned int flags)
__u32 mask, unsigned int flags)
{
__u32 oldmask = -1;
__u32 oldmask, newmask;

spin_lock(&fsn_mark->lock);
oldmask = fsnotify_calc_mask(fsn_mark);
if (!(flags & FAN_MARK_IGNORED_MASK)) {
oldmask = fsn_mark->mask;
fsn_mark->mask |= mask;
} else {
fsn_mark->ignored_mask |= mask;
if (flags & FAN_MARK_IGNORED_SURV_MODIFY)
fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
}
newmask = fsnotify_calc_mask(fsn_mark);
spin_unlock(&fsn_mark->lock);

return mask & ~oldmask;
return newmask & ~oldmask;
}

static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
Expand Down
4 changes: 2 additions & 2 deletions fs/notify/mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
return;
hlist_for_each_entry(mark, &conn->list, obj_list) {
if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)
new_mask |= mark->mask;
new_mask |= fsnotify_calc_mask(mark);
}
*fsnotify_conn_mask_p(conn) = new_mask;
}
Expand Down Expand Up @@ -692,7 +692,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
if (ret)
goto err;

if (mark->mask)
if (mark->mask || mark->ignored_mask)
fsnotify_recalc_mask(mark->connector);

return ret;
Expand Down
15 changes: 15 additions & 0 deletions include/linux/fsnotify_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,21 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group,

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

/* Get mask for calculating object interest taking ignored mask into account */
static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)
{
__u32 mask = mark->mask;

if (!mark->ignored_mask)
return mask;

/*
* If mark is interested in ignoring events on children, the object must
* show interest in those events for fsnotify_parent() to notice it.
*/
return mask | (mark->ignored_mask & ALL_FSNOTIFY_EVENTS);
}

/* Get mask of events for a list of marks */
extern __u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn);
/* Calculate mask of events for a list of marks */
Expand Down

0 comments on commit 4f0b903

Please sign in to comment.