162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/list.h>
762306a36Sopenharmony_ci#include <linux/mutex.h>
862306a36Sopenharmony_ci#include <linux/slab.h>
962306a36Sopenharmony_ci#include <linux/srcu.h>
1062306a36Sopenharmony_ci#include <linux/rculist.h>
1162306a36Sopenharmony_ci#include <linux/wait.h>
1262306a36Sopenharmony_ci#include <linux/memcontrol.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/fsnotify_backend.h>
1562306a36Sopenharmony_ci#include "fsnotify.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/atomic.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * Final freeing of a group
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_cistatic void fsnotify_final_destroy_group(struct fsnotify_group *group)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	if (group->ops->free_group_priv)
2562306a36Sopenharmony_ci		group->ops->free_group_priv(group);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	mem_cgroup_put(group->memcg);
2862306a36Sopenharmony_ci	mutex_destroy(&group->mark_mutex);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	kfree(group);
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * Stop queueing new events for this group. Once this function returns
3562306a36Sopenharmony_ci * fsnotify_add_event() will not add any new events to the group's queue.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_civoid fsnotify_group_stop_queueing(struct fsnotify_group *group)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	spin_lock(&group->notification_lock);
4062306a36Sopenharmony_ci	group->shutdown = true;
4162306a36Sopenharmony_ci	spin_unlock(&group->notification_lock);
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/*
4562306a36Sopenharmony_ci * Trying to get rid of a group. Remove all marks, flush all events and release
4662306a36Sopenharmony_ci * the group reference.
4762306a36Sopenharmony_ci * Note that another thread calling fsnotify_clear_marks_by_group() may still
4862306a36Sopenharmony_ci * hold a ref to the group.
4962306a36Sopenharmony_ci */
5062306a36Sopenharmony_civoid fsnotify_destroy_group(struct fsnotify_group *group)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	/*
5362306a36Sopenharmony_ci	 * Stop queueing new events. The code below is careful enough to not
5462306a36Sopenharmony_ci	 * require this but fanotify needs to stop queuing events even before
5562306a36Sopenharmony_ci	 * fsnotify_destroy_group() is called and this makes the other callers
5662306a36Sopenharmony_ci	 * of fsnotify_destroy_group() to see the same behavior.
5762306a36Sopenharmony_ci	 */
5862306a36Sopenharmony_ci	fsnotify_group_stop_queueing(group);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* Clear all marks for this group and queue them for destruction */
6162306a36Sopenharmony_ci	fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_ANY);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/*
6462306a36Sopenharmony_ci	 * Some marks can still be pinned when waiting for response from
6562306a36Sopenharmony_ci	 * userspace. Wait for those now. fsnotify_prepare_user_wait() will
6662306a36Sopenharmony_ci	 * not succeed now so this wait is race-free.
6762306a36Sopenharmony_ci	 */
6862306a36Sopenharmony_ci	wait_event(group->notification_waitq, !atomic_read(&group->user_waits));
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/*
7162306a36Sopenharmony_ci	 * Wait until all marks get really destroyed. We could actually destroy
7262306a36Sopenharmony_ci	 * them ourselves instead of waiting for worker to do it, however that
7362306a36Sopenharmony_ci	 * would be racy as worker can already be processing some marks before
7462306a36Sopenharmony_ci	 * we even entered fsnotify_destroy_group().
7562306a36Sopenharmony_ci	 */
7662306a36Sopenharmony_ci	fsnotify_wait_marks_destroyed();
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/*
7962306a36Sopenharmony_ci	 * Since we have waited for fsnotify_mark_srcu in
8062306a36Sopenharmony_ci	 * fsnotify_mark_destroy_list() there can be no outstanding event
8162306a36Sopenharmony_ci	 * notification against this group. So clearing the notification queue
8262306a36Sopenharmony_ci	 * of all events is reliable now.
8362306a36Sopenharmony_ci	 */
8462306a36Sopenharmony_ci	fsnotify_flush_notify(group);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/*
8762306a36Sopenharmony_ci	 * Destroy overflow event (we cannot use fsnotify_destroy_event() as
8862306a36Sopenharmony_ci	 * that deliberately ignores overflow events.
8962306a36Sopenharmony_ci	 */
9062306a36Sopenharmony_ci	if (group->overflow_event)
9162306a36Sopenharmony_ci		group->ops->free_event(group, group->overflow_event);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	fsnotify_put_group(group);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/*
9762306a36Sopenharmony_ci * Get reference to a group.
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_civoid fsnotify_get_group(struct fsnotify_group *group)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	refcount_inc(&group->refcnt);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/*
10562306a36Sopenharmony_ci * Drop a reference to a group.  Free it if it's through.
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_civoid fsnotify_put_group(struct fsnotify_group *group)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	if (refcount_dec_and_test(&group->refcnt))
11062306a36Sopenharmony_ci		fsnotify_final_destroy_group(group);
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_put_group);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic struct fsnotify_group *__fsnotify_alloc_group(
11562306a36Sopenharmony_ci				const struct fsnotify_ops *ops,
11662306a36Sopenharmony_ci				int flags, gfp_t gfp)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	static struct lock_class_key nofs_marks_lock;
11962306a36Sopenharmony_ci	struct fsnotify_group *group;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	group = kzalloc(sizeof(struct fsnotify_group), gfp);
12262306a36Sopenharmony_ci	if (!group)
12362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* set to 0 when there a no external references to this group */
12662306a36Sopenharmony_ci	refcount_set(&group->refcnt, 1);
12762306a36Sopenharmony_ci	atomic_set(&group->user_waits, 0);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	spin_lock_init(&group->notification_lock);
13062306a36Sopenharmony_ci	INIT_LIST_HEAD(&group->notification_list);
13162306a36Sopenharmony_ci	init_waitqueue_head(&group->notification_waitq);
13262306a36Sopenharmony_ci	group->max_events = UINT_MAX;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	mutex_init(&group->mark_mutex);
13562306a36Sopenharmony_ci	INIT_LIST_HEAD(&group->marks_list);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	group->ops = ops;
13862306a36Sopenharmony_ci	group->flags = flags;
13962306a36Sopenharmony_ci	/*
14062306a36Sopenharmony_ci	 * For most backends, eviction of inode with a mark is not expected,
14162306a36Sopenharmony_ci	 * because marks hold a refcount on the inode against eviction.
14262306a36Sopenharmony_ci	 *
14362306a36Sopenharmony_ci	 * Use a different lockdep class for groups that support evictable
14462306a36Sopenharmony_ci	 * inode marks, because with evictable marks, mark_mutex is NOT
14562306a36Sopenharmony_ci	 * fs-reclaim safe - the mutex is taken when evicting inodes.
14662306a36Sopenharmony_ci	 */
14762306a36Sopenharmony_ci	if (flags & FSNOTIFY_GROUP_NOFS)
14862306a36Sopenharmony_ci		lockdep_set_class(&group->mark_mutex, &nofs_marks_lock);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return group;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/*
15462306a36Sopenharmony_ci * Create a new fsnotify_group and hold a reference for the group returned.
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_cistruct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops,
15762306a36Sopenharmony_ci					    int flags)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	gfp_t gfp = (flags & FSNOTIFY_GROUP_USER) ? GFP_KERNEL_ACCOUNT :
16062306a36Sopenharmony_ci						    GFP_KERNEL;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return __fsnotify_alloc_group(ops, flags, gfp);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_alloc_group);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ciint fsnotify_fasync(int fd, struct file *file, int on)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct fsnotify_group *group = file->private_data;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO;
17162306a36Sopenharmony_ci}
172