xref: /linux/fs/notify/group.c (revision c441bfb5f2866de71e092c1b9d866a65978dfe1a)
1c82ee6d3SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
290586523SEric Paris /*
390586523SEric Paris  *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
490586523SEric Paris  */
590586523SEric Paris 
690586523SEric Paris #include <linux/list.h>
790586523SEric Paris #include <linux/mutex.h>
890586523SEric Paris #include <linux/slab.h>
990586523SEric Paris #include <linux/srcu.h>
1090586523SEric Paris #include <linux/rculist.h>
1190586523SEric Paris #include <linux/wait.h>
12d46eb14bSShakeel Butt #include <linux/memcontrol.h>
1390586523SEric Paris 
1490586523SEric Paris #include <linux/fsnotify_backend.h>
1590586523SEric Paris #include "fsnotify.h"
1690586523SEric Paris 
1760063497SArun Sharma #include <linux/atomic.h>
1890586523SEric Paris 
193be25f49SEric Paris /*
2090586523SEric Paris  * Final freeing of a group
2190586523SEric Paris  */
22cafbaae8SAndrew Morton static void fsnotify_final_destroy_group(struct fsnotify_group *group)
2390586523SEric Paris {
2490586523SEric Paris 	if (group->ops->free_group_priv)
2590586523SEric Paris 		group->ops->free_group_priv(group);
2690586523SEric Paris 
27d46eb14bSShakeel Butt 	mem_cgroup_put(group->memcg);
28191e1656SFabian Frederick 	mutex_destroy(&group->mark_mutex);
29d46eb14bSShakeel Butt 
3090586523SEric Paris 	kfree(group);
3190586523SEric Paris }
3290586523SEric Paris 
3390586523SEric Paris /*
3412703dbfSJan Kara  * Stop queueing new events for this group. Once this function returns
3512703dbfSJan Kara  * fsnotify_add_event() will not add any new events to the group's queue.
3612703dbfSJan Kara  */
3712703dbfSJan Kara void fsnotify_group_stop_queueing(struct fsnotify_group *group)
3812703dbfSJan Kara {
39c21dbe20SJan Kara 	spin_lock(&group->notification_lock);
4012703dbfSJan Kara 	group->shutdown = true;
41c21dbe20SJan Kara 	spin_unlock(&group->notification_lock);
4212703dbfSJan Kara }
4312703dbfSJan Kara 
4412703dbfSJan Kara /*
4523e964c2SLino Sanfilippo  * Trying to get rid of a group. Remove all marks, flush all events and release
4623e964c2SLino Sanfilippo  * the group reference.
4723e964c2SLino Sanfilippo  * Note that another thread calling fsnotify_clear_marks_by_group() may still
4823e964c2SLino Sanfilippo  * hold a ref to the group.
493be25f49SEric Paris  */
50d8153d4dSLino Sanfilippo void fsnotify_destroy_group(struct fsnotify_group *group)
513be25f49SEric Paris {
5212703dbfSJan Kara 	/*
5312703dbfSJan Kara 	 * Stop queueing new events. The code below is careful enough to not
5412703dbfSJan Kara 	 * require this but fanotify needs to stop queuing events even before
5512703dbfSJan Kara 	 * fsnotify_destroy_group() is called and this makes the other callers
5612703dbfSJan Kara 	 * of fsnotify_destroy_group() to see the same behavior.
5712703dbfSJan Kara 	 */
5812703dbfSJan Kara 	fsnotify_group_stop_queueing(group);
5912703dbfSJan Kara 
60f09b04a0SJan Kara 	/* Clear all marks for this group and queue them for destruction */
61d6f7b98bSAmir Goldstein 	fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES_MASK);
622e37c6caSJan Kara 
632e37c6caSJan Kara 	/*
642e37c6caSJan Kara 	 * Some marks can still be pinned when waiting for response from
652e37c6caSJan Kara 	 * userspace. Wait for those now. fsnotify_prepare_user_wait() will
662e37c6caSJan Kara 	 * not succeed now so this wait is race-free.
672e37c6caSJan Kara 	 */
682e37c6caSJan Kara 	wait_event(group->notification_waitq, !atomic_read(&group->user_waits));
693be25f49SEric Paris 
7035e48176SJan Kara 	/*
71f09b04a0SJan Kara 	 * Wait until all marks get really destroyed. We could actually destroy
72f09b04a0SJan Kara 	 * them ourselves instead of waiting for worker to do it, however that
73f09b04a0SJan Kara 	 * would be racy as worker can already be processing some marks before
74f09b04a0SJan Kara 	 * we even entered fsnotify_destroy_group().
7535e48176SJan Kara 	 */
76f09b04a0SJan Kara 	fsnotify_wait_marks_destroyed();
7775c1be48SEric Paris 
7835e48176SJan Kara 	/*
7935e48176SJan Kara 	 * Since we have waited for fsnotify_mark_srcu in
8035e48176SJan Kara 	 * fsnotify_mark_destroy_list() there can be no outstanding event
8135e48176SJan Kara 	 * notification against this group. So clearing the notification queue
8235e48176SJan Kara 	 * of all events is reliable now.
8335e48176SJan Kara 	 */
8423e964c2SLino Sanfilippo 	fsnotify_flush_notify(group);
8523e964c2SLino Sanfilippo 
86ff57cd58SJan Kara 	/*
87ff57cd58SJan Kara 	 * Destroy overflow event (we cannot use fsnotify_destroy_event() as
88ff57cd58SJan Kara 	 * that deliberately ignores overflow events.
89ff57cd58SJan Kara 	 */
90ff57cd58SJan Kara 	if (group->overflow_event)
91ff57cd58SJan Kara 		group->ops->free_event(group->overflow_event);
92ff57cd58SJan Kara 
9323e964c2SLino Sanfilippo 	fsnotify_put_group(group);
943be25f49SEric Paris }
953be25f49SEric Paris 
963be25f49SEric Paris /*
9798612952SLino Sanfilippo  * Get reference to a group.
9898612952SLino Sanfilippo  */
9998612952SLino Sanfilippo void fsnotify_get_group(struct fsnotify_group *group)
10098612952SLino Sanfilippo {
1017761daa6SElena Reshetova 	refcount_inc(&group->refcnt);
10298612952SLino Sanfilippo }
10398612952SLino Sanfilippo 
10498612952SLino Sanfilippo /*
10590586523SEric Paris  * Drop a reference to a group.  Free it if it's through.
10690586523SEric Paris  */
10790586523SEric Paris void fsnotify_put_group(struct fsnotify_group *group)
10890586523SEric Paris {
1097761daa6SElena Reshetova 	if (refcount_dec_and_test(&group->refcnt))
11023e964c2SLino Sanfilippo 		fsnotify_final_destroy_group(group);
11190586523SEric Paris }
112b72679eeSTrond Myklebust EXPORT_SYMBOL_GPL(fsnotify_put_group);
11390586523SEric Paris 
114*ac7b79fdSShakeel Butt static struct fsnotify_group *__fsnotify_alloc_group(
115*ac7b79fdSShakeel Butt 				const struct fsnotify_ops *ops, gfp_t gfp)
11690586523SEric Paris {
11774be0cc8SEric Paris 	struct fsnotify_group *group;
11890586523SEric Paris 
119*ac7b79fdSShakeel Butt 	group = kzalloc(sizeof(struct fsnotify_group), gfp);
12090586523SEric Paris 	if (!group)
12190586523SEric Paris 		return ERR_PTR(-ENOMEM);
12290586523SEric Paris 
12336fddebaSEric Paris 	/* set to 0 when there a no external references to this group */
1247761daa6SElena Reshetova 	refcount_set(&group->refcnt, 1);
125abc77577SJan Kara 	atomic_set(&group->user_waits, 0);
12636fddebaSEric Paris 
127c21dbe20SJan Kara 	spin_lock_init(&group->notification_lock);
128a2d8bc6cSEric Paris 	INIT_LIST_HEAD(&group->notification_list);
129a2d8bc6cSEric Paris 	init_waitqueue_head(&group->notification_waitq);
130a2d8bc6cSEric Paris 	group->max_events = UINT_MAX;
131a2d8bc6cSEric Paris 
132986ab098SLino Sanfilippo 	mutex_init(&group->mark_mutex);
133e61ce867SEric Paris 	INIT_LIST_HEAD(&group->marks_list);
1343be25f49SEric Paris 
13590586523SEric Paris 	group->ops = ops;
13690586523SEric Paris 
13790586523SEric Paris 	return group;
13890586523SEric Paris }
139*ac7b79fdSShakeel Butt 
140*ac7b79fdSShakeel Butt /*
141*ac7b79fdSShakeel Butt  * Create a new fsnotify_group and hold a reference for the group returned.
142*ac7b79fdSShakeel Butt  */
143*ac7b79fdSShakeel Butt struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
144*ac7b79fdSShakeel Butt {
145*ac7b79fdSShakeel Butt 	return __fsnotify_alloc_group(ops, GFP_KERNEL);
146*ac7b79fdSShakeel Butt }
147b72679eeSTrond Myklebust EXPORT_SYMBOL_GPL(fsnotify_alloc_group);
1480a6b6bd5SEric Paris 
149*ac7b79fdSShakeel Butt /*
150*ac7b79fdSShakeel Butt  * Create a new fsnotify_group and hold a reference for the group returned.
151*ac7b79fdSShakeel Butt  */
152*ac7b79fdSShakeel Butt struct fsnotify_group *fsnotify_alloc_user_group(const struct fsnotify_ops *ops)
153*ac7b79fdSShakeel Butt {
154*ac7b79fdSShakeel Butt 	return __fsnotify_alloc_group(ops, GFP_KERNEL_ACCOUNT);
155*ac7b79fdSShakeel Butt }
156*ac7b79fdSShakeel Butt EXPORT_SYMBOL_GPL(fsnotify_alloc_user_group);
157*ac7b79fdSShakeel Butt 
1580a6b6bd5SEric Paris int fsnotify_fasync(int fd, struct file *file, int on)
1590a6b6bd5SEric Paris {
1600a6b6bd5SEric Paris 	struct fsnotify_group *group = file->private_data;
1610a6b6bd5SEric Paris 
1620a6b6bd5SEric Paris 	return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO;
1630a6b6bd5SEric Paris }
164