Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47d9c7cc authored by Amir Goldstein's avatar Amir Goldstein Committed by Jan Kara
Browse files

fsnotify: generalize iteration of marks by object type



Make some code that handles marks of object types inode and vfsmount
generic, so it can handle other object types.

Introduce fsnotify_foreach_obj_type macro to iterate marks by object type
and fsnotify_iter_{should|set}_report_type macros to set/test report_mask.

This is going to be used for adding mark of another object type
(super block mark).

Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent d9a6f30b
Loading
Loading
Loading
Loading
+28 −24
Original line number Diff line number Diff line
@@ -269,25 +269,29 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
static unsigned int fsnotify_iter_select_report_types(
		struct fsnotify_iter_info *iter_info)
{
	struct fsnotify_mark *inode_mark = iter_info->inode_mark;
	struct fsnotify_mark *vfsmount_mark = iter_info->vfsmount_mark;
	int cmp;
	struct fsnotify_group *max_prio_group = NULL;
	struct fsnotify_mark *mark;
	int type;

	/* Choose max prio group among groups of all queue heads */
	fsnotify_foreach_obj_type(type) {
		mark = iter_info->marks[type];
		if (mark &&
		    fsnotify_compare_groups(max_prio_group, mark->group) > 0)
			max_prio_group = mark->group;
	}

	if (!inode_mark && !vfsmount_mark)
	if (!max_prio_group)
		return 0;

	if (inode_mark && vfsmount_mark) {
		cmp = fsnotify_compare_groups(inode_mark->group,
					      vfsmount_mark->group);
	} else {
		cmp = inode_mark ? -1 : 1;
	}

	/* Set the report mask for marks from same group as max prio group */
	iter_info->report_mask = 0;
	if (cmp <= 0)
		iter_info->report_mask |= FSNOTIFY_OBJ_TYPE_INODE_FL;
	if (cmp >= 0)
		iter_info->report_mask |= FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL;
	fsnotify_foreach_obj_type(type) {
		mark = iter_info->marks[type];
		if (mark &&
		    fsnotify_compare_groups(max_prio_group, mark->group) == 0)
			fsnotify_iter_set_report_type(iter_info, type);
	}

	return iter_info->report_mask;
}
@@ -298,13 +302,13 @@ static unsigned int fsnotify_iter_select_report_types(
 */
static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info)
{
	if (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_INODE_FL)
		iter_info->inode_mark =
			fsnotify_next_mark(iter_info->inode_mark);
	int type;

	if (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL)
		iter_info->vfsmount_mark =
			fsnotify_next_mark(iter_info->vfsmount_mark);
	fsnotify_foreach_obj_type(type) {
		if (fsnotify_iter_should_report_type(iter_info, type))
			iter_info->marks[type] =
				fsnotify_next_mark(iter_info->marks[type]);
	}
}

/*
@@ -351,15 +355,15 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,

	if ((mask & FS_MODIFY) ||
	    (test_mask & to_tell->i_fsnotify_mask)) {
		iter_info.inode_mark =
		iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
			fsnotify_first_mark(&to_tell->i_fsnotify_marks);
	}

	if (mnt && ((mask & FS_MODIFY) ||
		    (test_mask & mnt->mnt_fsnotify_mask))) {
		iter_info.inode_mark =
		iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
			fsnotify_first_mark(&to_tell->i_fsnotify_marks);
		iter_info.vfsmount_mark =
		iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] =
			fsnotify_first_mark(&mnt->mnt_fsnotify_marks);
	}

+4 −4
Original line number Diff line number Diff line
@@ -485,10 +485,10 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
				    struct fsnotify_group *group)
{
	struct inotify_inode_mark *i_mark;
	struct fsnotify_iter_info iter_info = {
		.inode_mark = fsn_mark,
		.report_mask = FSNOTIFY_OBJ_TYPE_INODE_FL,
	};
	struct fsnotify_iter_info iter_info = { };

	fsnotify_iter_set_report_type_mark(&iter_info, FSNOTIFY_OBJ_TYPE_INODE,
					   fsn_mark);

	/* Queue ignore event for the watch */
	inotify_handle_event(group, NULL, FS_IN_IGNORED, NULL,
+15 −8
Original line number Diff line number Diff line
@@ -294,12 +294,12 @@ static void fsnotify_put_mark_wake(struct fsnotify_mark *mark)

bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
{
	int type;

	fsnotify_foreach_obj_type(type) {
		/* This can fail if mark is being removed */
	if (!fsnotify_get_mark_safe(iter_info->inode_mark))
		return false;
	if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) {
		fsnotify_put_mark_wake(iter_info->inode_mark);
		return false;
		if (!fsnotify_get_mark_safe(iter_info->marks[type]))
			goto fail;
	}

	/*
@@ -310,13 +310,20 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
	srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx);

	return true;

fail:
	for (type--; type >= 0; type--)
		fsnotify_put_mark_wake(iter_info->marks[type]);
	return false;
}

void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info)
{
	int type;

	iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
	fsnotify_put_mark_wake(iter_info->inode_mark);
	fsnotify_put_mark_wake(iter_info->vfsmount_mark);
	fsnotify_foreach_obj_type(type)
		fsnotify_put_mark_wake(iter_info->marks[type]);
}

/*
+25 −3
Original line number Diff line number Diff line
@@ -211,23 +211,45 @@ enum fsnotify_obj_type {
#define FSNOTIFY_OBJ_ALL_TYPES_MASK	((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1)

struct fsnotify_iter_info {
	struct fsnotify_mark *inode_mark;
	struct fsnotify_mark *vfsmount_mark;
	struct fsnotify_mark *marks[FSNOTIFY_OBJ_TYPE_COUNT];
	unsigned int report_mask;
	int srcu_idx;
};

static inline bool fsnotify_iter_should_report_type(
		struct fsnotify_iter_info *iter_info, int type)
{
	return (iter_info->report_mask & (1U << type));
}

static inline void fsnotify_iter_set_report_type(
		struct fsnotify_iter_info *iter_info, int type)
{
	iter_info->report_mask |= (1U << type);
}

static inline void fsnotify_iter_set_report_type_mark(
		struct fsnotify_iter_info *iter_info, int type,
		struct fsnotify_mark *mark)
{
	iter_info->marks[type] = mark;
	iter_info->report_mask |= (1U << type);
}

#define FSNOTIFY_ITER_FUNCS(name, NAME) \
static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \
		struct fsnotify_iter_info *iter_info) \
{ \
	return (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_##NAME##_FL) ? \
		iter_info->name##_mark : NULL; \
		iter_info->marks[FSNOTIFY_OBJ_TYPE_##NAME] : NULL; \
}

FSNOTIFY_ITER_FUNCS(inode, INODE)
FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT)

#define fsnotify_foreach_obj_type(type) \
	for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; type++)

/*
 * Inode / vfsmount point to this structure which tracks all marks attached to
 * the inode / vfsmount. The reference to inode / vfsmount is held by this