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/* 78c2ecf20Sopenharmony_ci * Basic idea behind the notification queue: An fsnotify group (like inotify) 88c2ecf20Sopenharmony_ci * sends the userspace notification about events asynchronously some time after 98c2ecf20Sopenharmony_ci * the event happened. When inotify gets an event it will need to add that 108c2ecf20Sopenharmony_ci * event to the group notify queue. Since a single event might need to be on 118c2ecf20Sopenharmony_ci * multiple group's notification queues we can't add the event directly to each 128c2ecf20Sopenharmony_ci * queue and instead add a small "event_holder" to each queue. This event_holder 138c2ecf20Sopenharmony_ci * has a pointer back to the original event. Since the majority of events are 148c2ecf20Sopenharmony_ci * going to end up on one, and only one, notification queue we embed one 158c2ecf20Sopenharmony_ci * event_holder into each event. This means we have a single allocation instead 168c2ecf20Sopenharmony_ci * of always needing two. If the embedded event_holder is already in use by 178c2ecf20Sopenharmony_ci * another group a new event_holder (from fsnotify_event_holder_cachep) will be 188c2ecf20Sopenharmony_ci * allocated and used. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/fs.h> 228c2ecf20Sopenharmony_ci#include <linux/init.h> 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/list.h> 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci#include <linux/mount.h> 278c2ecf20Sopenharmony_ci#include <linux/mutex.h> 288c2ecf20Sopenharmony_ci#include <linux/namei.h> 298c2ecf20Sopenharmony_ci#include <linux/path.h> 308c2ecf20Sopenharmony_ci#include <linux/slab.h> 318c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/atomic.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/fsnotify_backend.h> 368c2ecf20Sopenharmony_ci#include "fsnotify.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/** 418c2ecf20Sopenharmony_ci * fsnotify_get_cookie - return a unique cookie for use in synchronizing events. 428c2ecf20Sopenharmony_ci * Called from fsnotify_move, which is inlined into filesystem modules. 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ciu32 fsnotify_get_cookie(void) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci return atomic_inc_return(&fsnotify_sync_cookie); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify_get_cookie); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* return true if the notify queue is empty, false otherwise */ 518c2ecf20Sopenharmony_cibool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci assert_spin_locked(&group->notification_lock); 548c2ecf20Sopenharmony_ci return list_empty(&group->notification_list) ? true : false; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_civoid fsnotify_destroy_event(struct fsnotify_group *group, 588c2ecf20Sopenharmony_ci struct fsnotify_event *event) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci /* Overflow events are per-group and we don't want to free them */ 618c2ecf20Sopenharmony_ci if (!event || event == group->overflow_event) 628c2ecf20Sopenharmony_ci return; 638c2ecf20Sopenharmony_ci /* 648c2ecf20Sopenharmony_ci * If the event is still queued, we have a problem... Do an unreliable 658c2ecf20Sopenharmony_ci * lockless check first to avoid locking in the common case. The 668c2ecf20Sopenharmony_ci * locking may be necessary for permission events which got removed 678c2ecf20Sopenharmony_ci * from the list by a different CPU than the one freeing the event. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci if (!list_empty(&event->list)) { 708c2ecf20Sopenharmony_ci spin_lock(&group->notification_lock); 718c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&event->list)); 728c2ecf20Sopenharmony_ci spin_unlock(&group->notification_lock); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci group->ops->free_event(event); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * Add an event to the group notification queue. The group can later pull this 798c2ecf20Sopenharmony_ci * event off the queue to deal with. The function returns 0 if the event was 808c2ecf20Sopenharmony_ci * added to the queue, 1 if the event was merged with some other queued event, 818c2ecf20Sopenharmony_ci * 2 if the event was not queued - either the queue of events has overflown 828c2ecf20Sopenharmony_ci * or the group is shutting down. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ciint fsnotify_add_event(struct fsnotify_group *group, 858c2ecf20Sopenharmony_ci struct fsnotify_event *event, 868c2ecf20Sopenharmony_ci int (*merge)(struct list_head *, 878c2ecf20Sopenharmony_ci struct fsnotify_event *)) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci int ret = 0; 908c2ecf20Sopenharmony_ci struct list_head *list = &group->notification_list; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci pr_debug("%s: group=%p event=%p\n", __func__, group, event); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci spin_lock(&group->notification_lock); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (group->shutdown) { 978c2ecf20Sopenharmony_ci spin_unlock(&group->notification_lock); 988c2ecf20Sopenharmony_ci return 2; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (event == group->overflow_event || 1028c2ecf20Sopenharmony_ci group->q_len >= group->max_events) { 1038c2ecf20Sopenharmony_ci ret = 2; 1048c2ecf20Sopenharmony_ci /* Queue overflow event only if it isn't already queued */ 1058c2ecf20Sopenharmony_ci if (!list_empty(&group->overflow_event->list)) { 1068c2ecf20Sopenharmony_ci spin_unlock(&group->notification_lock); 1078c2ecf20Sopenharmony_ci return ret; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci event = group->overflow_event; 1108c2ecf20Sopenharmony_ci goto queue; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!list_empty(list) && merge) { 1148c2ecf20Sopenharmony_ci ret = merge(list, event); 1158c2ecf20Sopenharmony_ci if (ret) { 1168c2ecf20Sopenharmony_ci spin_unlock(&group->notification_lock); 1178c2ecf20Sopenharmony_ci return ret; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciqueue: 1228c2ecf20Sopenharmony_ci group->q_len++; 1238c2ecf20Sopenharmony_ci list_add_tail(&event->list, list); 1248c2ecf20Sopenharmony_ci spin_unlock(&group->notification_lock); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci wake_up(&group->notification_waitq); 1278c2ecf20Sopenharmony_ci kill_fasync(&group->fsn_fa, SIGIO, POLL_IN); 1288c2ecf20Sopenharmony_ci return ret; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid fsnotify_remove_queued_event(struct fsnotify_group *group, 1328c2ecf20Sopenharmony_ci struct fsnotify_event *event) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci assert_spin_locked(&group->notification_lock); 1358c2ecf20Sopenharmony_ci /* 1368c2ecf20Sopenharmony_ci * We need to init list head for the case of overflow event so that 1378c2ecf20Sopenharmony_ci * check in fsnotify_add_event() works 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci list_del_init(&event->list); 1408c2ecf20Sopenharmony_ci group->q_len--; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * Remove and return the first event from the notification list. It is the 1458c2ecf20Sopenharmony_ci * responsibility of the caller to destroy the obtained event 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_cistruct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct fsnotify_event *event; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci assert_spin_locked(&group->notification_lock); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci pr_debug("%s: group=%p\n", __func__, group); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci event = list_first_entry(&group->notification_list, 1568c2ecf20Sopenharmony_ci struct fsnotify_event, list); 1578c2ecf20Sopenharmony_ci fsnotify_remove_queued_event(group, event); 1588c2ecf20Sopenharmony_ci return event; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* 1628c2ecf20Sopenharmony_ci * This will not remove the event, that must be done with 1638c2ecf20Sopenharmony_ci * fsnotify_remove_first_event() 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_cistruct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci assert_spin_locked(&group->notification_lock); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return list_first_entry(&group->notification_list, 1708c2ecf20Sopenharmony_ci struct fsnotify_event, list); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* 1748c2ecf20Sopenharmony_ci * Called when a group is being torn down to clean up any outstanding 1758c2ecf20Sopenharmony_ci * event notifications. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_civoid fsnotify_flush_notify(struct fsnotify_group *group) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct fsnotify_event *event; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci spin_lock(&group->notification_lock); 1828c2ecf20Sopenharmony_ci while (!fsnotify_notify_queue_is_empty(group)) { 1838c2ecf20Sopenharmony_ci event = fsnotify_remove_first_event(group); 1848c2ecf20Sopenharmony_ci spin_unlock(&group->notification_lock); 1858c2ecf20Sopenharmony_ci fsnotify_destroy_event(group, event); 1868c2ecf20Sopenharmony_ci spin_lock(&group->notification_lock); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci spin_unlock(&group->notification_lock); 1898c2ecf20Sopenharmony_ci} 190