18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/list.h>
78c2ecf20Sopenharmony_ci#include <linux/mutex.h>
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <linux/srcu.h>
108c2ecf20Sopenharmony_ci#include <linux/rculist.h>
118c2ecf20Sopenharmony_ci#include <linux/wait.h>
128c2ecf20Sopenharmony_ci#include <linux/memcontrol.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/fsnotify_backend.h>
158c2ecf20Sopenharmony_ci#include "fsnotify.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/atomic.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Final freeing of a group
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_cistatic void fsnotify_final_destroy_group(struct fsnotify_group *group)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	if (group->ops->free_group_priv)
258c2ecf20Sopenharmony_ci		group->ops->free_group_priv(group);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	mem_cgroup_put(group->memcg);
288c2ecf20Sopenharmony_ci	mutex_destroy(&group->mark_mutex);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	kfree(group);
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * Stop queueing new events for this group. Once this function returns
358c2ecf20Sopenharmony_ci * fsnotify_add_event() will not add any new events to the group's queue.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_civoid fsnotify_group_stop_queueing(struct fsnotify_group *group)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	spin_lock(&group->notification_lock);
408c2ecf20Sopenharmony_ci	group->shutdown = true;
418c2ecf20Sopenharmony_ci	spin_unlock(&group->notification_lock);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/*
458c2ecf20Sopenharmony_ci * Trying to get rid of a group. Remove all marks, flush all events and release
468c2ecf20Sopenharmony_ci * the group reference.
478c2ecf20Sopenharmony_ci * Note that another thread calling fsnotify_clear_marks_by_group() may still
488c2ecf20Sopenharmony_ci * hold a ref to the group.
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_civoid fsnotify_destroy_group(struct fsnotify_group *group)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	/*
538c2ecf20Sopenharmony_ci	 * Stop queueing new events. The code below is careful enough to not
548c2ecf20Sopenharmony_ci	 * require this but fanotify needs to stop queuing events even before
558c2ecf20Sopenharmony_ci	 * fsnotify_destroy_group() is called and this makes the other callers
568c2ecf20Sopenharmony_ci	 * of fsnotify_destroy_group() to see the same behavior.
578c2ecf20Sopenharmony_ci	 */
588c2ecf20Sopenharmony_ci	fsnotify_group_stop_queueing(group);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	/* Clear all marks for this group and queue them for destruction */
618c2ecf20Sopenharmony_ci	fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES_MASK);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/*
648c2ecf20Sopenharmony_ci	 * Some marks can still be pinned when waiting for response from
658c2ecf20Sopenharmony_ci	 * userspace. Wait for those now. fsnotify_prepare_user_wait() will
668c2ecf20Sopenharmony_ci	 * not succeed now so this wait is race-free.
678c2ecf20Sopenharmony_ci	 */
688c2ecf20Sopenharmony_ci	wait_event(group->notification_waitq, !atomic_read(&group->user_waits));
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/*
718c2ecf20Sopenharmony_ci	 * Wait until all marks get really destroyed. We could actually destroy
728c2ecf20Sopenharmony_ci	 * them ourselves instead of waiting for worker to do it, however that
738c2ecf20Sopenharmony_ci	 * would be racy as worker can already be processing some marks before
748c2ecf20Sopenharmony_ci	 * we even entered fsnotify_destroy_group().
758c2ecf20Sopenharmony_ci	 */
768c2ecf20Sopenharmony_ci	fsnotify_wait_marks_destroyed();
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/*
798c2ecf20Sopenharmony_ci	 * Since we have waited for fsnotify_mark_srcu in
808c2ecf20Sopenharmony_ci	 * fsnotify_mark_destroy_list() there can be no outstanding event
818c2ecf20Sopenharmony_ci	 * notification against this group. So clearing the notification queue
828c2ecf20Sopenharmony_ci	 * of all events is reliable now.
838c2ecf20Sopenharmony_ci	 */
848c2ecf20Sopenharmony_ci	fsnotify_flush_notify(group);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/*
878c2ecf20Sopenharmony_ci	 * Destroy overflow event (we cannot use fsnotify_destroy_event() as
888c2ecf20Sopenharmony_ci	 * that deliberately ignores overflow events.
898c2ecf20Sopenharmony_ci	 */
908c2ecf20Sopenharmony_ci	if (group->overflow_event)
918c2ecf20Sopenharmony_ci		group->ops->free_event(group->overflow_event);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	fsnotify_put_group(group);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/*
978c2ecf20Sopenharmony_ci * Get reference to a group.
988c2ecf20Sopenharmony_ci */
998c2ecf20Sopenharmony_civoid fsnotify_get_group(struct fsnotify_group *group)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	refcount_inc(&group->refcnt);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/*
1058c2ecf20Sopenharmony_ci * Drop a reference to a group.  Free it if it's through.
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_civoid fsnotify_put_group(struct fsnotify_group *group)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	if (refcount_dec_and_test(&group->refcnt))
1108c2ecf20Sopenharmony_ci		fsnotify_final_destroy_group(group);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_put_group);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/*
1158c2ecf20Sopenharmony_ci * Create a new fsnotify_group and hold a reference for the group returned.
1168c2ecf20Sopenharmony_ci */
1178c2ecf20Sopenharmony_cistruct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct fsnotify_group *group;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	group = kzalloc(sizeof(struct fsnotify_group), GFP_KERNEL);
1228c2ecf20Sopenharmony_ci	if (!group)
1238c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	/* set to 0 when there a no external references to this group */
1268c2ecf20Sopenharmony_ci	refcount_set(&group->refcnt, 1);
1278c2ecf20Sopenharmony_ci	atomic_set(&group->num_marks, 0);
1288c2ecf20Sopenharmony_ci	atomic_set(&group->user_waits, 0);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	spin_lock_init(&group->notification_lock);
1318c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&group->notification_list);
1328c2ecf20Sopenharmony_ci	init_waitqueue_head(&group->notification_waitq);
1338c2ecf20Sopenharmony_ci	group->max_events = UINT_MAX;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	mutex_init(&group->mark_mutex);
1368c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&group->marks_list);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	group->ops = ops;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return group;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_alloc_group);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ciint fsnotify_fasync(int fd, struct file *file, int on)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct fsnotify_group *group = file->private_data;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO;
1498c2ecf20Sopenharmony_ci}
150