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