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