Commit a8988507 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'fsnotify_for_v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fsnotify updates from Jan Kara:
 "A few fsnotify improvements and cleanups"

* tag 'fsnotify_for_v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  fsnotify: remove redundant parameter judgment
  fsnotify: optimize FS_MODIFY events with no ignored masks
  fsnotify: fix merge with parent's ignored mask
parents cb7cbaae f92ca72b
Loading
Loading
Loading
Loading
+33 −14
Original line number Diff line number Diff line
@@ -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
@@ -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,
@@ -1080,24 +1081,42 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
				    flags, umask);
}

static void fanotify_mark_add_ignored_mask(struct fsnotify_mark *fsn_mark,
					   __u32 mask, unsigned int flags,
					   __u32 *removed)
{
	fsn_mark->ignored_mask |= mask;

	/*
	 * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to
	 * the removal of the FS_MODIFY bit in calculated mask if it was set
	 * because of an ignored mask that is now going to survive FS_MODIFY.
	 */
	if ((flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
	    !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) {
		fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
		if (!(fsn_mark->mask & FS_MODIFY))
			*removed = FS_MODIFY;
	}
}

static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
				       __u32 mask,
				       unsigned int flags)
				       __u32 mask, unsigned int flags,
				       __u32 *removed)
{
	__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;
		fanotify_mark_add_ignored_mask(fsn_mark, mask, flags, removed);
	}
	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,
@@ -1155,7 +1174,7 @@ static int fanotify_add_mark(struct fsnotify_group *group,
			     __kernel_fsid_t *fsid)
{
	struct fsnotify_mark *fsn_mark;
	__u32 added;
	__u32 added, removed = 0;
	int ret = 0;

	mutex_lock(&group->mark_mutex);
@@ -1178,8 +1197,8 @@ static int fanotify_add_mark(struct fsnotify_group *group,
			goto out;
	}

	added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
	if (added & ~fsnotify_conn_mask(fsn_mark->connector))
	added = fanotify_mark_add_to_mask(fsn_mark, mask, flags, &removed);
	if (removed || (added & ~fsnotify_conn_mask(fsn_mark->connector)))
		fsnotify_recalc_mask(fsn_mark->connector);

out:
+7 −7
Original line number Diff line number Diff line
@@ -70,7 +70,6 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
		spin_unlock(&inode->i_lock);
		spin_unlock(&sb->s_inode_list_lock);

		if (iput_inode)
		iput(iput_inode);

		/* for each watch, send FS_UNMOUNT and then remove it */
@@ -85,7 +84,6 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
	}
	spin_unlock(&sb->s_inode_list_lock);

	if (iput_inode)
	iput(iput_inode);
}

@@ -531,11 +529,13 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,


	/*
	 * if this is a modify event we may need to clear the ignored masks
	 * otherwise return if none of the marks care about this type of event.
	 * If this is a modify event we may need to clear some ignored masks.
	 * In that case, the object with ignored masks will have the FS_MODIFY
	 * event in its mask.
	 * Otherwise, return if none of the marks care about this type of event.
	 */
	test_mask = (mask & ALL_FSNOTIFY_EVENTS);
	if (!(mask & FS_MODIFY) && !(test_mask & marks_mask))
	if (!(test_mask & marks_mask))
		return 0;

	iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
+2 −2
Original line number Diff line number Diff line
@@ -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;
}
@@ -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;
+19 −0
Original line number Diff line number Diff line
@@ -601,6 +601,25 @@ 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;

	/* Interest in FS_MODIFY may be needed for clearing ignored mask */
	if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
		mask |= FS_MODIFY;

	/*
	 * 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 */