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