2019-05-19 16:51:48 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2009-12-18 05:24:27 +03:00
/*
* Copyright ( C ) 2008 Red Hat , Inc . , Eric Paris < eparis @ redhat . com >
*/
/*
* fsnotify inode mark locking / lifetime / and refcnting
*
* REFCNT :
2013-07-09 02:59:46 +04:00
* The group - > recnt and mark - > refcnt tell how many " things " in the kernel
* currently are referencing the objects . Both kind of objects typically will
* live inside the kernel with a refcnt of 2 , one for its creation and one for
* the reference a group and a mark hold to each other .
* If you are holding the appropriate locks , you can take a reference and the
* object itself is guaranteed to survive until the reference is dropped .
2009-12-18 05:24:27 +03:00
*
* LOCKING :
2013-07-09 02:59:46 +04:00
* There are 3 locks involved with fsnotify inode marks and they MUST be taken
* in order as follows :
2009-12-18 05:24:27 +03:00
*
2013-07-09 02:59:46 +04:00
* group - > mark_mutex
2009-12-18 05:24:27 +03:00
* mark - > lock
2017-02-01 10:19:43 +03:00
* mark - > connector - > lock
2009-12-18 05:24:27 +03:00
*
2013-07-09 02:59:46 +04:00
* group - > mark_mutex protects the marks_list anchored inside a given group and
* each mark is hooked via the g_list . It also protects the groups private
* data ( i . e group limits ) .
* mark - > lock protects the marks attributes like its masks and flags .
* Furthermore it protects the access to a reference of the group that the mark
* is assigned to as well as the access to a reference of the inode / vfsmount
* that is being watched by the mark .
2009-12-18 05:24:27 +03:00
*
2017-02-01 10:19:43 +03:00
* mark - > connector - > lock protects the list of marks anchored inside an
* inode / vfsmount and each mark is hooked via the i_list .
2009-12-18 05:24:27 +03:00
*
2017-02-01 10:19:43 +03:00
* A list of notification marks relating to inode / mnt is contained in
* fsnotify_mark_connector . That structure is alive as long as there are any
2016-12-21 14:15:30 +03:00
* marks in the list and is also protected by fsnotify_mark_srcu . A mark gets
* detached from fsnotify_mark_connector when last reference to the mark is
* dropped . Thus having mark reference is enough to protect mark - > connector
* pointer and to make sure fsnotify_mark_connector cannot disappear . Also
* because we remove mark from g_list before dropping mark reference associated
* with that , any mark found through g_list is guaranteed to have
* mark - > connector set until we drop group - > mark_mutex .
2009-12-18 05:24:27 +03:00
*
* LIFETIME :
* Inode marks survive between when they are added to an inode and when their
2016-12-16 12:53:32 +03:00
* refcnt = = 0. Marks are also protected by fsnotify_mark_srcu .
2009-12-18 05:24:27 +03:00
*
* The inode mark can be cleared for a number of different reasons including :
* - The inode is unlinked for the last time . ( fsnotify_inode_remove )
* - The inode is being evicted from cache . ( fsnotify_inode_delete )
* - The fs the inode is on is unmounted . ( fsnotify_inode_delete / fsnotify_unmount_inodes )
* - Something explicitly requests that it be removed . ( fsnotify_destroy_mark )
* - The fsnotify_group associated with the mark is going away and all such marks
2017-01-04 12:51:58 +03:00
* need to be cleaned up . ( fsnotify_clear_marks_by_group )
2009-12-18 05:24:27 +03:00
*
* This has the very interesting property of being able to run concurrently with
* any ( or all ) other directions .
*/
# include <linux/fs.h>
# include <linux/init.h>
# include <linux/kernel.h>
2010-07-28 18:18:38 +04:00
# include <linux/kthread.h>
2009-12-18 05:24:27 +03:00
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
2010-07-28 18:18:38 +04:00
# include <linux/srcu.h>
2019-01-10 20:04:37 +03:00
# include <linux/ratelimit.h>
2009-12-18 05:24:27 +03:00
2011-07-27 03:09:06 +04:00
# include <linux/atomic.h>
2009-12-18 05:24:27 +03:00
# include <linux/fsnotify_backend.h>
# include "fsnotify.h"
2016-02-18 00:11:21 +03:00
# define FSNOTIFY_REAPER_DELAY (1) /* 1 jiffy */
2010-07-28 18:18:38 +04:00
struct srcu_struct fsnotify_mark_srcu ;
2017-03-14 14:31:02 +03:00
struct kmem_cache * fsnotify_mark_connector_cachep ;
2016-02-18 00:11:18 +03:00
static DEFINE_SPINLOCK ( destroy_lock ) ;
static LIST_HEAD ( destroy_list ) ;
2017-02-01 11:21:58 +03:00
static struct fsnotify_mark_connector * connector_destroy_list ;
2016-02-18 00:11:21 +03:00
2016-05-20 03:08:59 +03:00
static void fsnotify_mark_destroy_workfn ( struct work_struct * work ) ;
static DECLARE_DELAYED_WORK ( reaper_work , fsnotify_mark_destroy_workfn ) ;
2010-07-28 18:18:38 +04:00
2017-02-01 11:21:58 +03:00
static void fsnotify_connector_destroy_workfn ( struct work_struct * work ) ;
static DECLARE_WORK ( connector_reaper_work , fsnotify_connector_destroy_workfn ) ;
2009-12-18 05:24:27 +03:00
void fsnotify_get_mark ( struct fsnotify_mark * mark )
{
2017-10-20 13:26:02 +03:00
WARN_ON_ONCE ( ! refcount_read ( & mark - > refcnt ) ) ;
refcount_inc ( & mark - > refcnt ) ;
2009-12-18 05:24:27 +03:00
}
2018-06-23 17:54:50 +03:00
static __u32 * fsnotify_conn_mask_p ( struct fsnotify_mark_connector * conn )
{
if ( conn - > type = = FSNOTIFY_OBJ_TYPE_INODE )
return & fsnotify_conn_inode ( conn ) - > i_fsnotify_mask ;
else if ( conn - > type = = FSNOTIFY_OBJ_TYPE_VFSMOUNT )
return & fsnotify_conn_mount ( conn ) - > mnt_fsnotify_mask ;
2018-09-01 10:41:11 +03:00
else if ( conn - > type = = FSNOTIFY_OBJ_TYPE_SB )
return & fsnotify_conn_sb ( conn ) - > s_fsnotify_mask ;
2018-06-23 17:54:50 +03:00
return NULL ;
}
__u32 fsnotify_conn_mask ( struct fsnotify_mark_connector * conn )
{
if ( WARN_ON ( ! fsnotify_valid_obj_type ( conn - > type ) ) )
return 0 ;
return * fsnotify_conn_mask_p ( conn ) ;
}
2022-04-22 15:03:22 +03:00
static void fsnotify_get_inode_ref ( struct inode * inode )
{
ihold ( inode ) ;
atomic_long_inc ( & inode - > i_sb - > s_fsnotify_connectors ) ;
}
/*
* Grab or drop inode reference for the connector if needed .
*
* When it ' s time to drop the reference , we only clear the HAS_IREF flag and
* return the inode object . fsnotify_drop_object ( ) will be resonsible for doing
* iput ( ) outside of spinlocks . This happens when last mark that wanted iref is
* detached .
*/
static struct inode * fsnotify_update_iref ( struct fsnotify_mark_connector * conn ,
bool want_iref )
{
bool has_iref = conn - > flags & FSNOTIFY_CONN_FLAG_HAS_IREF ;
struct inode * inode = NULL ;
if ( conn - > type ! = FSNOTIFY_OBJ_TYPE_INODE | |
want_iref = = has_iref )
return NULL ;
if ( want_iref ) {
/* Pin inode if any mark wants inode refcount held */
fsnotify_get_inode_ref ( fsnotify_conn_inode ( conn ) ) ;
conn - > flags | = FSNOTIFY_CONN_FLAG_HAS_IREF ;
} else {
/* Unpin inode after detach of last mark that wanted iref */
inode = fsnotify_conn_inode ( conn ) ;
conn - > flags & = ~ FSNOTIFY_CONN_FLAG_HAS_IREF ;
}
return inode ;
}
static void * __fsnotify_recalc_mask ( struct fsnotify_mark_connector * conn )
2014-12-13 03:58:36 +03:00
{
u32 new_mask = 0 ;
2022-04-22 15:03:22 +03:00
bool want_iref = false ;
2014-12-13 03:58:36 +03:00
struct fsnotify_mark * mark ;
2017-02-01 10:19:43 +03:00
assert_spin_locked ( & conn - > lock ) ;
2018-08-20 14:55:45 +03:00
/* We can get detached connector here when inode is getting unlinked. */
if ( ! fsnotify_valid_obj_type ( conn - > type ) )
2022-04-22 15:03:22 +03:00
return NULL ;
2016-12-21 14:15:30 +03:00
hlist_for_each_entry ( mark , & conn - > list , obj_list ) {
2022-04-22 15:03:22 +03:00
if ( ! ( mark - > flags & FSNOTIFY_MARK_FLAG_ATTACHED ) )
continue ;
new_mask | = fsnotify_calc_mask ( mark ) ;
if ( conn - > type = = FSNOTIFY_OBJ_TYPE_INODE & &
! ( mark - > flags & FSNOTIFY_MARK_FLAG_NO_IREF ) )
want_iref = true ;
2016-12-21 14:15:30 +03:00
}
2018-06-23 17:54:50 +03:00
* fsnotify_conn_mask_p ( conn ) = new_mask ;
2022-04-22 15:03:22 +03:00
return fsnotify_update_iref ( conn , want_iref ) ;
2017-03-15 11:16:27 +03:00
}
/*
* Calculate mask of events for a list of marks . The caller must make sure
2018-06-23 17:54:49 +03:00
* connector and connector - > obj cannot disappear under us . Callers achieve
2016-12-21 14:15:30 +03:00
* this by holding a mark - > lock or mark - > group - > mark_mutex for a mark on this
* list .
2017-03-15 11:16:27 +03:00
*/
void fsnotify_recalc_mask ( struct fsnotify_mark_connector * conn )
{
if ( ! conn )
return ;
2017-02-01 10:19:43 +03:00
spin_lock ( & conn - > lock ) ;
2017-03-15 11:16:27 +03:00
__fsnotify_recalc_mask ( conn ) ;
2017-02-01 10:19:43 +03:00
spin_unlock ( & conn - > lock ) ;
2018-04-21 02:10:49 +03:00
if ( conn - > type = = FSNOTIFY_OBJ_TYPE_INODE )
2018-06-23 17:54:49 +03:00
__fsnotify_update_child_dentry_flags (
fsnotify_conn_inode ( conn ) ) ;
2014-12-13 03:58:36 +03:00
}
2017-02-01 11:21:58 +03:00
/* Free all connectors queued for freeing once SRCU period ends */
static void fsnotify_connector_destroy_workfn ( struct work_struct * work )
{
struct fsnotify_mark_connector * conn , * free ;
spin_lock ( & destroy_lock ) ;
conn = connector_destroy_list ;
connector_destroy_list = NULL ;
spin_unlock ( & destroy_lock ) ;
synchronize_srcu ( & fsnotify_mark_srcu ) ;
while ( conn ) {
free = conn ;
conn = conn - > destroy_next ;
kmem_cache_free ( fsnotify_mark_connector_cachep , free ) ;
}
}
2021-08-10 18:12:18 +03:00
static void fsnotify_put_inode_ref ( struct inode * inode )
{
struct super_block * sb = inode - > i_sb ;
iput ( inode ) ;
2021-08-10 18:12:19 +03:00
if ( atomic_long_dec_and_test ( & sb - > s_fsnotify_connectors ) )
wake_up_var ( & sb - > s_fsnotify_connectors ) ;
}
static void fsnotify_get_sb_connectors ( struct fsnotify_mark_connector * conn )
{
struct super_block * sb = fsnotify_connector_sb ( conn ) ;
if ( sb )
atomic_long_inc ( & sb - > s_fsnotify_connectors ) ;
}
static void fsnotify_put_sb_connectors ( struct fsnotify_mark_connector * conn )
{
struct super_block * sb = fsnotify_connector_sb ( conn ) ;
if ( sb & & atomic_long_dec_and_test ( & sb - > s_fsnotify_connectors ) )
wake_up_var ( & sb - > s_fsnotify_connectors ) ;
2021-08-10 18:12:18 +03:00
}
2018-10-17 14:07:05 +03:00
static void * fsnotify_detach_connector_from_object (
struct fsnotify_mark_connector * conn ,
unsigned int * type )
2017-02-01 11:21:58 +03:00
{
struct inode * inode = NULL ;
2018-10-17 14:07:05 +03:00
* type = conn - > type ;
2018-06-23 17:54:49 +03:00
if ( conn - > type = = FSNOTIFY_OBJ_TYPE_DETACHED )
return NULL ;
2018-04-21 02:10:49 +03:00
if ( conn - > type = = FSNOTIFY_OBJ_TYPE_INODE ) {
2018-06-23 17:54:49 +03:00
inode = fsnotify_conn_inode ( conn ) ;
2017-02-01 11:21:58 +03:00
inode - > i_fsnotify_mask = 0 ;
2022-04-22 15:03:22 +03:00
/* Unpin inode when detaching from connector */
if ( ! ( conn - > flags & FSNOTIFY_CONN_FLAG_HAS_IREF ) )
inode = NULL ;
2018-04-21 02:10:49 +03:00
} else if ( conn - > type = = FSNOTIFY_OBJ_TYPE_VFSMOUNT ) {
2018-06-23 17:54:49 +03:00
fsnotify_conn_mount ( conn ) - > mnt_fsnotify_mask = 0 ;
2018-09-01 10:41:11 +03:00
} else if ( conn - > type = = FSNOTIFY_OBJ_TYPE_SB ) {
fsnotify_conn_sb ( conn ) - > s_fsnotify_mask = 0 ;
2017-02-01 11:21:58 +03:00
}
2021-08-10 18:12:19 +03:00
fsnotify_put_sb_connectors ( conn ) ;
2018-06-23 17:54:49 +03:00
rcu_assign_pointer ( * ( conn - > obj ) , NULL ) ;
conn - > obj = NULL ;
conn - > type = FSNOTIFY_OBJ_TYPE_DETACHED ;
2017-02-01 11:21:58 +03:00
return inode ;
}
2016-12-21 14:15:30 +03:00
static void fsnotify_final_mark_destroy ( struct fsnotify_mark * mark )
{
2016-12-21 20:06:12 +03:00
struct fsnotify_group * group = mark - > group ;
if ( WARN_ON_ONCE ( ! group ) )
return ;
group - > ops - > free_mark ( mark ) ;
fsnotify_put_group ( group ) ;
2016-12-21 14:15:30 +03:00
}
2018-10-17 14:07:05 +03:00
/* Drop object reference originally held by a connector */
static void fsnotify_drop_object ( unsigned int type , void * objp )
{
if ( ! objp )
return ;
/* Currently only inode references are passed to be dropped */
if ( WARN_ON_ONCE ( type ! = FSNOTIFY_OBJ_TYPE_INODE ) )
return ;
2021-08-10 18:12:18 +03:00
fsnotify_put_inode_ref ( objp ) ;
2018-10-17 14:07:05 +03:00
}
2016-12-21 14:15:30 +03:00
void fsnotify_put_mark ( struct fsnotify_mark * mark )
2017-03-15 11:48:11 +03:00
{
2019-04-24 19:39:57 +03:00
struct fsnotify_mark_connector * conn = READ_ONCE ( mark - > connector ) ;
2018-10-17 14:07:05 +03:00
void * objp = NULL ;
unsigned int type = FSNOTIFY_OBJ_TYPE_DETACHED ;
2017-02-01 11:21:58 +03:00
bool free_conn = false ;
2017-03-15 11:48:11 +03:00
2016-12-21 14:15:30 +03:00
/* Catch marks that were actually never attached to object */
2019-04-24 19:39:57 +03:00
if ( ! conn ) {
2017-10-20 13:26:02 +03:00
if ( refcount_dec_and_test ( & mark - > refcnt ) )
2016-12-21 14:15:30 +03:00
fsnotify_final_mark_destroy ( mark ) ;
return ;
}
/*
* We have to be careful so that traversals of obj_list under lock can
* safely grab mark reference .
*/
2019-04-24 19:39:57 +03:00
if ( ! refcount_dec_and_lock ( & mark - > refcnt , & conn - > lock ) )
2016-12-21 14:15:30 +03:00
return ;
2017-03-15 11:48:11 +03:00
hlist_del_init_rcu ( & mark - > obj_list ) ;
if ( hlist_empty ( & conn - > list ) ) {
2018-10-17 14:07:05 +03:00
objp = fsnotify_detach_connector_from_object ( conn , & type ) ;
2017-02-01 11:21:58 +03:00
free_conn = true ;
} else {
2022-04-22 15:03:22 +03:00
objp = __fsnotify_recalc_mask ( conn ) ;
type = conn - > type ;
2017-03-15 11:48:11 +03:00
}
2019-04-24 19:39:57 +03:00
WRITE_ONCE ( mark - > connector , NULL ) ;
2017-02-01 10:19:43 +03:00
spin_unlock ( & conn - > lock ) ;
2017-03-15 11:48:11 +03:00
2018-10-17 14:07:05 +03:00
fsnotify_drop_object ( type , objp ) ;
2016-12-21 14:15:30 +03:00
2017-02-01 11:21:58 +03:00
if ( free_conn ) {
spin_lock ( & destroy_lock ) ;
conn - > destroy_next = connector_destroy_list ;
connector_destroy_list = conn ;
spin_unlock ( & destroy_lock ) ;
queue_work ( system_unbound_wq , & connector_reaper_work ) ;
}
2016-12-21 14:15:30 +03:00
/*
* Note that we didn ' t update flags telling whether inode cares about
* what ' s happening with children . We update these flags from
* __fsnotify_parent ( ) lazily when next event happens on one of our
* children .
*/
spin_lock ( & destroy_lock ) ;
list_add ( & mark - > g_list , & destroy_list ) ;
spin_unlock ( & destroy_lock ) ;
queue_delayed_work ( system_unbound_wq , & reaper_work ,
FSNOTIFY_REAPER_DELAY ) ;
2017-03-15 11:48:11 +03:00
}
2019-08-18 21:18:46 +03:00
EXPORT_SYMBOL_GPL ( fsnotify_put_mark ) ;
2017-03-15 11:48:11 +03:00
2017-10-30 23:14:55 +03:00
/*
* Get mark reference when we found the mark via lockless traversal of object
* list . Mark can be already removed from the list by now and on its way to be
* destroyed once SRCU period ends .
*
* Also pin the group so it doesn ' t disappear under us .
*/
static bool fsnotify_get_mark_safe ( struct fsnotify_mark * mark )
2016-11-10 18:02:11 +03:00
{
2017-10-30 23:14:55 +03:00
if ( ! mark )
return true ;
2016-11-10 18:02:11 +03:00
2017-10-20 13:26:02 +03:00
if ( refcount_inc_not_zero ( & mark - > refcnt ) ) {
2017-10-30 23:14:56 +03:00
spin_lock ( & mark - > lock ) ;
if ( mark - > flags & FSNOTIFY_MARK_FLAG_ATTACHED ) {
/* mark is attached, group is still alive then */
atomic_inc ( & mark - > group - > user_waits ) ;
spin_unlock ( & mark - > lock ) ;
return true ;
}
spin_unlock ( & mark - > lock ) ;
fsnotify_put_mark ( mark ) ;
}
2017-10-30 23:14:55 +03:00
return false ;
}
/*
* Puts marks and wakes up group destruction if necessary .
*
* Pairs with fsnotify_get_mark_safe ( )
*/
static void fsnotify_put_mark_wake ( struct fsnotify_mark * mark )
{
if ( mark ) {
struct fsnotify_group * group = mark - > group ;
fsnotify_put_mark ( mark ) ;
/*
* We abuse notification_waitq on group shutdown for waiting for
* all marks pinned when waiting for userspace .
*/
if ( atomic_dec_and_test ( & group - > user_waits ) & & group - > shutdown )
wake_up ( & group - > notification_waitq ) ;
2016-11-10 18:02:11 +03:00
}
2017-10-30 23:14:55 +03:00
}
bool fsnotify_prepare_user_wait ( struct fsnotify_iter_info * iter_info )
2020-04-14 00:42:40 +03:00
__releases ( & fsnotify_mark_srcu )
2017-10-30 23:14:55 +03:00
{
2018-04-21 02:10:52 +03:00
int type ;
2021-11-29 23:15:28 +03:00
fsnotify_foreach_iter_type ( type ) {
2018-04-21 02:10:52 +03:00
/* This can fail if mark is being removed */
2020-04-14 00:42:40 +03:00
if ( ! fsnotify_get_mark_safe ( iter_info - > marks [ type ] ) ) {
__release ( & fsnotify_mark_srcu ) ;
2018-04-21 02:10:52 +03:00
goto fail ;
2020-04-14 00:42:40 +03:00
}
2016-11-10 18:02:11 +03:00
}
/*
* Now that both marks are pinned by refcount in the inode / vfsmount
* lists , we can drop SRCU lock , and safely resume the list iteration
* once userspace returns .
*/
srcu_read_unlock ( & fsnotify_mark_srcu , iter_info - > srcu_idx ) ;
return true ;
2018-04-21 02:10:52 +03:00
fail :
for ( type - - ; type > = 0 ; type - - )
fsnotify_put_mark_wake ( iter_info - > marks [ type ] ) ;
return false ;
2016-11-10 18:02:11 +03:00
}
void fsnotify_finish_user_wait ( struct fsnotify_iter_info * iter_info )
2020-04-14 00:42:40 +03:00
__acquires ( & fsnotify_mark_srcu )
2016-11-10 18:02:11 +03:00
{
2018-04-21 02:10:52 +03:00
int type ;
2016-11-10 18:02:11 +03:00
iter_info - > srcu_idx = srcu_read_lock ( & fsnotify_mark_srcu ) ;
2021-11-29 23:15:28 +03:00
fsnotify_foreach_iter_type ( type )
2018-04-21 02:10:52 +03:00
fsnotify_put_mark_wake ( iter_info - > marks [ type ] ) ;
2016-11-10 18:02:11 +03:00
}
2009-12-18 05:24:27 +03:00
/*
2016-12-21 14:15:30 +03:00
* Mark mark as detached , remove it from group list . Mark still stays in object
* list until its last reference is dropped . Note that we rely on mark being
* removed from group list before corresponding reference to it is dropped . In
* particular we rely on mark - > connector being valid while we hold
* group - > mark_mutex if we found the mark through g_list .
2015-09-05 01:43:12 +03:00
*
2016-11-09 16:54:20 +03:00
* Must be called with group - > mark_mutex held . The caller must either hold
* reference to the mark or be protected by fsnotify_mark_srcu .
2009-12-18 05:24:27 +03:00
*/
2015-09-05 01:43:12 +03:00
void fsnotify_detach_mark ( struct fsnotify_mark * mark )
2009-12-18 05:24:27 +03:00
{
2022-04-22 15:03:17 +03:00
fsnotify_group_assert_locked ( mark - > group ) ;
2016-11-09 16:54:20 +03:00
WARN_ON_ONCE ( ! srcu_read_lock_held ( & fsnotify_mark_srcu ) & &
2017-10-20 13:26:02 +03:00
refcount_read ( & mark - > refcnt ) < 1 +
2016-11-09 16:54:20 +03:00
! ! ( mark - > flags & FSNOTIFY_MARK_FLAG_ATTACHED ) ) ;
2011-06-14 19:29:52 +04:00
2011-06-14 19:29:48 +04:00
spin_lock ( & mark - > lock ) ;
2010-07-28 18:18:38 +04:00
/* something else already called this function on this mark */
2015-09-05 01:43:12 +03:00
if ( ! ( mark - > flags & FSNOTIFY_MARK_FLAG_ATTACHED ) ) {
2009-12-18 05:24:27 +03:00
spin_unlock ( & mark - > lock ) ;
2011-06-14 19:29:51 +04:00
return ;
2009-12-18 05:24:27 +03:00
}
2015-09-05 01:43:12 +03:00
mark - > flags & = ~ FSNOTIFY_MARK_FLAG_ATTACHED ;
2009-12-18 05:24:27 +03:00
list_del_init ( & mark - > g_list ) ;
spin_unlock ( & mark - > lock ) ;
2011-06-14 19:29:52 +04:00
2016-11-09 16:54:20 +03:00
/* Drop mark reference acquired in fsnotify_add_mark_locked() */
fsnotify_put_mark ( mark ) ;
2015-09-05 01:43:12 +03:00
}
/*
2016-11-09 16:54:20 +03:00
* Free fsnotify mark . The mark is actually only marked as being freed . The
* freeing is actually happening only once last reference to the mark is
* dropped from a workqueue which first waits for srcu period end .
2016-05-20 03:08:59 +03:00
*
2016-11-09 16:54:20 +03:00
* Caller must have a reference to the mark or be protected by
* fsnotify_mark_srcu .
2015-09-05 01:43:12 +03:00
*/
2016-11-09 16:54:20 +03:00
void fsnotify_free_mark ( struct fsnotify_mark * mark )
2015-09-05 01:43:12 +03:00
{
struct fsnotify_group * group = mark - > group ;
spin_lock ( & mark - > lock ) ;
/* something else already called this function on this mark */
if ( ! ( mark - > flags & FSNOTIFY_MARK_FLAG_ALIVE ) ) {
spin_unlock ( & mark - > lock ) ;
2016-11-09 16:54:20 +03:00
return ;
2015-09-05 01:43:12 +03:00
}
mark - > flags & = ~ FSNOTIFY_MARK_FLAG_ALIVE ;
spin_unlock ( & mark - > lock ) ;
2009-12-18 05:24:27 +03:00
2015-07-22 02:06:53 +03:00
/*
* Some groups like to know that marks are being freed . This is a
* callback to the group function to let it know that this mark
* is being freed .
*/
if ( group - > ops - > freeing_mark )
group - > ops - > freeing_mark ( mark , group ) ;
2011-06-14 19:29:52 +04:00
}
void fsnotify_destroy_mark ( struct fsnotify_mark * mark ,
struct fsnotify_group * group )
{
2022-04-22 15:03:17 +03:00
fsnotify_group_lock ( group ) ;
2015-09-05 01:43:12 +03:00
fsnotify_detach_mark ( mark ) ;
2022-04-22 15:03:17 +03:00
fsnotify_group_unlock ( group ) ;
2015-09-05 01:43:12 +03:00
fsnotify_free_mark ( mark ) ;
2009-12-18 05:24:27 +03:00
}
2019-08-18 21:18:46 +03:00
EXPORT_SYMBOL_GPL ( fsnotify_destroy_mark ) ;
2009-12-18 05:24:27 +03:00
2014-11-14 02:19:33 +03:00
/*
* Sorting function for lists of fsnotify marks .
*
* Fanotify supports different notification classes ( reflected as priority of
* notification group ) . Events shall be passed to notification groups in
* decreasing priority order . To achieve this marks in notification lists for
* inodes and vfsmounts are sorted so that priorities of corresponding groups
* are descending .
*
* Furthermore correct handling of the ignore mask requires processing inode
* and vfsmount marks of each group together . Using the group address as
* further sort criterion provides a unique sorting order and thus we can
* merge inode and vfsmount lists of marks in linear time and find groups
* present in both lists .
*
* A return value of 1 signifies that b has priority over a .
* A return value of 0 signifies that the two marks have to be handled together .
* A return value of - 1 signifies that a has priority over b .
*/
int fsnotify_compare_groups ( struct fsnotify_group * a , struct fsnotify_group * b )
{
if ( a = = b )
return 0 ;
if ( ! a )
return 1 ;
if ( ! b )
return - 1 ;
if ( a - > priority < b - > priority )
return 1 ;
if ( a - > priority > b - > priority )
return - 1 ;
if ( a < b )
return 1 ;
return - 1 ;
}
2018-06-23 17:54:47 +03:00
static int fsnotify_attach_connector_to_object ( fsnotify_connp_t * connp ,
2023-11-30 19:56:18 +03:00
unsigned int obj_type )
2017-03-14 14:31:02 +03:00
{
struct fsnotify_mark_connector * conn ;
2017-03-14 18:11:23 +03:00
conn = kmem_cache_alloc ( fsnotify_mark_connector_cachep , GFP_KERNEL ) ;
2017-03-14 14:31:02 +03:00
if ( ! conn )
return - ENOMEM ;
2017-02-01 10:19:43 +03:00
spin_lock_init ( & conn - > lock ) ;
2017-03-14 14:31:02 +03:00
INIT_HLIST_HEAD ( & conn - > list ) ;
2022-04-22 15:03:22 +03:00
conn - > flags = 0 ;
2021-11-29 23:15:27 +03:00
conn - > type = obj_type ;
2018-06-23 17:54:49 +03:00
conn - > obj = connp ;
2023-11-30 19:56:18 +03:00
conn - > flags = 0 ;
2021-08-10 18:12:19 +03:00
fsnotify_get_sb_connectors ( conn ) ;
2021-08-10 18:12:17 +03:00
2017-03-14 14:31:02 +03:00
/*
2017-02-01 10:19:43 +03:00
* cmpxchg ( ) provides the barrier so that readers of * connp can see
* only initialized structure
2017-03-14 14:31:02 +03:00
*/
2017-02-01 10:19:43 +03:00
if ( cmpxchg ( connp , NULL , conn ) ) {
/* Someone else created list structure for us */
2021-09-09 14:56:34 +03:00
fsnotify_put_sb_connectors ( conn ) ;
2017-03-14 18:11:23 +03:00
kmem_cache_free ( fsnotify_mark_connector_cachep , conn ) ;
2017-02-01 10:19:43 +03:00
}
2017-03-14 14:31:02 +03:00
return 0 ;
}
2017-02-01 11:21:58 +03:00
/*
* Get mark connector , make sure it is alive and return with its lock held .
* This is for users that get connector pointer from inode or mount . Users that
* hold reference to a mark on the list may directly lock connector - > lock as
* they are sure list cannot go away under them .
*/
static struct fsnotify_mark_connector * fsnotify_grab_connector (
2018-06-23 17:54:47 +03:00
fsnotify_connp_t * connp )
2017-02-01 11:21:58 +03:00
{
struct fsnotify_mark_connector * conn ;
int idx ;
idx = srcu_read_lock ( & fsnotify_mark_srcu ) ;
conn = srcu_dereference ( * connp , & fsnotify_mark_srcu ) ;
if ( ! conn )
goto out ;
spin_lock ( & conn - > lock ) ;
2018-04-21 02:10:49 +03:00
if ( conn - > type = = FSNOTIFY_OBJ_TYPE_DETACHED ) {
2017-02-01 11:21:58 +03:00
spin_unlock ( & conn - > lock ) ;
srcu_read_unlock ( & fsnotify_mark_srcu , idx ) ;
return NULL ;
}
out :
srcu_read_unlock ( & fsnotify_mark_srcu , idx ) ;
return conn ;
}
2017-03-14 14:31:02 +03:00
/*
* Add mark into proper place in given list of marks . These marks may be used
* for the fsnotify backend to determine which event types should be delivered
* to which group and for which inodes . These marks are ordered according to
* priority , highest number first , and then by the group ' s location in memory .
*/
2017-03-14 18:11:23 +03:00
static int fsnotify_add_mark_list ( struct fsnotify_mark * mark ,
2021-11-29 23:15:27 +03:00
fsnotify_connp_t * connp ,
2023-11-30 19:56:18 +03:00
unsigned int obj_type , int add_flags )
2014-12-13 03:58:36 +03:00
{
struct fsnotify_mark * lmark , * last = NULL ;
2017-03-14 14:31:02 +03:00
struct fsnotify_mark_connector * conn ;
2014-12-13 03:58:36 +03:00
int cmp ;
2017-03-14 18:11:23 +03:00
int err = 0 ;
2021-11-29 23:15:27 +03:00
if ( WARN_ON ( ! fsnotify_valid_obj_type ( obj_type ) ) )
2017-03-14 18:11:23 +03:00
return - EINVAL ;
2019-01-10 20:04:37 +03:00
2017-02-01 11:21:58 +03:00
restart :
spin_lock ( & mark - > lock ) ;
conn = fsnotify_grab_connector ( connp ) ;
if ( ! conn ) {
spin_unlock ( & mark - > lock ) ;
2023-11-30 19:56:18 +03:00
err = fsnotify_attach_connector_to_object ( connp , obj_type ) ;
2017-03-14 14:31:02 +03:00
if ( err )
return err ;
2017-02-01 11:21:58 +03:00
goto restart ;
2017-03-14 14:31:02 +03:00
}
2014-12-13 03:58:36 +03:00
/* is mark the first mark? */
2017-03-14 14:31:02 +03:00
if ( hlist_empty ( & conn - > list ) ) {
hlist_add_head_rcu ( & mark - > obj_list , & conn - > list ) ;
2017-03-14 16:29:35 +03:00
goto added ;
2014-12-13 03:58:36 +03:00
}
/* should mark be in the middle of the current list? */
2017-03-14 14:31:02 +03:00
hlist_for_each_entry ( lmark , & conn - > list , obj_list ) {
2014-12-13 03:58:36 +03:00
last = lmark ;
2016-12-21 14:15:30 +03:00
if ( ( lmark - > group = = mark - > group ) & &
( lmark - > flags & FSNOTIFY_MARK_FLAG_ATTACHED ) & &
2022-04-22 15:03:16 +03:00
! ( mark - > group - > flags & FSNOTIFY_GROUP_DUPS ) ) {
2017-03-14 18:11:23 +03:00
err = - EEXIST ;
goto out_err ;
}
2014-12-13 03:58:36 +03:00
cmp = fsnotify_compare_groups ( lmark - > group , mark - > group ) ;
if ( cmp > = 0 ) {
hlist_add_before_rcu ( & mark - > obj_list , & lmark - > obj_list ) ;
2017-03-14 16:29:35 +03:00
goto added ;
2014-12-13 03:58:36 +03:00
}
}
BUG_ON ( last = = NULL ) ;
/* mark should be the last entry. last is the current last entry */
hlist_add_behind_rcu ( & mark - > obj_list , & last - > obj_list ) ;
2017-03-14 16:29:35 +03:00
added :
2019-05-01 19:05:11 +03:00
/*
* Since connector is attached to object using cmpxchg ( ) we are
* guaranteed that connector initialization is fully visible by anyone
* seeing mark - > connector set .
*/
2019-04-24 19:39:57 +03:00
WRITE_ONCE ( mark - > connector , conn ) ;
2017-03-14 18:11:23 +03:00
out_err :
2017-02-01 10:19:43 +03:00
spin_unlock ( & conn - > lock ) ;
2017-03-14 18:11:23 +03:00
spin_unlock ( & mark - > lock ) ;
return err ;
2014-12-13 03:58:36 +03:00
}
2009-12-18 05:24:27 +03:00
/*
* Attach an initialized mark to a given group and fs object .
* These marks may be used for the fsnotify backend to determine which
* event types should be delivered to which group .
*/
2018-06-23 17:54:48 +03:00
int fsnotify_add_mark_locked ( struct fsnotify_mark * mark ,
2021-11-29 23:15:27 +03:00
fsnotify_connp_t * connp , unsigned int obj_type ,
2023-11-30 19:56:18 +03:00
int add_flags )
2009-12-18 05:24:27 +03:00
{
2016-12-21 20:32:48 +03:00
struct fsnotify_group * group = mark - > group ;
2009-12-18 05:24:27 +03:00
int ret = 0 ;
2022-04-22 15:03:17 +03:00
fsnotify_group_assert_locked ( group ) ;
2009-12-18 05:24:27 +03:00
/*
* LOCKING ORDER ! ! ! !
2011-06-14 19:29:50 +04:00
* group - > mark_mutex
2011-06-14 19:29:48 +04:00
* mark - > lock
2017-02-01 10:19:43 +03:00
* mark - > connector - > lock
2009-12-18 05:24:27 +03:00
*/
2011-06-14 19:29:48 +04:00
spin_lock ( & mark - > lock ) ;
2015-09-05 01:43:12 +03:00
mark - > flags | = FSNOTIFY_MARK_FLAG_ALIVE | FSNOTIFY_MARK_FLAG_ATTACHED ;
2010-07-28 18:18:38 +04:00
2009-12-18 05:24:27 +03:00
list_add ( & mark - > g_list , & group - > marks_list ) ;
2016-12-21 14:15:30 +03:00
fsnotify_get_mark ( mark ) ; /* for g_list */
2009-12-18 05:24:27 +03:00
spin_unlock ( & mark - > lock ) ;
2023-11-30 19:56:18 +03:00
ret = fsnotify_add_mark_list ( mark , connp , obj_type , add_flags ) ;
2017-03-14 18:11:23 +03:00
if ( ret )
goto err ;
2022-04-22 15:03:22 +03:00
fsnotify_recalc_mask ( mark - > connector ) ;
2009-12-18 05:24:27 +03:00
return ret ;
err :
2017-10-31 12:09:25 +03:00
spin_lock ( & mark - > lock ) ;
2016-11-09 16:54:20 +03:00
mark - > flags & = ~ ( FSNOTIFY_MARK_FLAG_ALIVE |
FSNOTIFY_MARK_FLAG_ATTACHED ) ;
2009-12-18 05:24:27 +03:00
list_del_init ( & mark - > g_list ) ;
2017-10-31 12:09:25 +03:00
spin_unlock ( & mark - > lock ) ;
2009-12-18 05:24:27 +03:00
2016-11-09 16:54:20 +03:00
fsnotify_put_mark ( mark ) ;
2009-12-18 05:24:27 +03:00
return ret ;
}
2018-06-23 17:54:48 +03:00
int fsnotify_add_mark ( struct fsnotify_mark * mark , fsnotify_connp_t * connp ,
2023-11-30 19:56:18 +03:00
unsigned int obj_type , int add_flags )
2011-06-14 19:29:52 +04:00
{
int ret ;
2016-12-21 20:32:48 +03:00
struct fsnotify_group * group = mark - > group ;
2022-04-22 15:03:17 +03:00
fsnotify_group_lock ( group ) ;
2023-11-30 19:56:18 +03:00
ret = fsnotify_add_mark_locked ( mark , connp , obj_type , add_flags ) ;
2022-04-22 15:03:17 +03:00
fsnotify_group_unlock ( group ) ;
2011-06-14 19:29:52 +04:00
return ret ;
}
2019-08-18 21:18:46 +03:00
EXPORT_SYMBOL_GPL ( fsnotify_add_mark ) ;
2011-06-14 19:29:52 +04:00
2014-12-13 03:58:36 +03:00
/*
* Given a list of marks , find the mark associated with given group . If found
* take a reference to that mark and return it , else return NULL .
*/
2018-06-23 17:54:47 +03:00
struct fsnotify_mark * fsnotify_find_mark ( fsnotify_connp_t * connp ,
struct fsnotify_group * group )
2014-12-13 03:58:36 +03:00
{
2017-02-01 11:21:58 +03:00
struct fsnotify_mark_connector * conn ;
2014-12-13 03:58:36 +03:00
struct fsnotify_mark * mark ;
2017-02-01 11:21:58 +03:00
conn = fsnotify_grab_connector ( connp ) ;
2017-03-14 14:31:02 +03:00
if ( ! conn )
return NULL ;
hlist_for_each_entry ( mark , & conn - > list , obj_list ) {
2016-12-21 14:15:30 +03:00
if ( mark - > group = = group & &
( mark - > flags & FSNOTIFY_MARK_FLAG_ATTACHED ) ) {
2014-12-13 03:58:36 +03:00
fsnotify_get_mark ( mark ) ;
2017-02-01 10:19:43 +03:00
spin_unlock ( & conn - > lock ) ;
2014-12-13 03:58:36 +03:00
return mark ;
}
}
2017-02-01 10:19:43 +03:00
spin_unlock ( & conn - > lock ) ;
2014-12-13 03:58:36 +03:00
return NULL ;
}
2019-08-18 21:18:46 +03:00
EXPORT_SYMBOL_GPL ( fsnotify_find_mark ) ;
2014-12-13 03:58:36 +03:00
2018-04-21 02:10:49 +03:00
/* Clear any marks in a group with given type mask */
2017-01-04 12:33:18 +03:00
void fsnotify_clear_marks_by_group ( struct fsnotify_group * group ,
2021-11-29 23:15:27 +03:00
unsigned int obj_type )
2009-12-18 05:24:27 +03:00
{
struct fsnotify_mark * lmark , * mark ;
2015-08-07 01:46:42 +03:00
LIST_HEAD ( to_free ) ;
2017-01-04 12:51:58 +03:00
struct list_head * head = & to_free ;
2009-12-18 05:24:27 +03:00
2017-01-04 12:51:58 +03:00
/* Skip selection step if we want to clear all marks. */
2021-11-29 23:15:27 +03:00
if ( obj_type = = FSNOTIFY_OBJ_TYPE_ANY ) {
2017-01-04 12:51:58 +03:00
head = & group - > marks_list ;
goto clear ;
}
2015-08-07 01:46:42 +03:00
/*
* We have to be really careful here . Anytime we drop mark_mutex , e . g .
* fsnotify_clear_marks_by_inode ( ) can come and free marks . Even in our
* to_free list so we have to use mark_mutex even when accessing that
* list . And freeing mark requires us to drop mark_mutex . So we can
* reliably free only the first mark in the list . That ' s why we first
* move marks to free to to_free list in one go and then free marks in
* to_free list one by one .
*/
2022-04-22 15:03:17 +03:00
fsnotify_group_lock ( group ) ;
2009-12-18 05:24:27 +03:00
list_for_each_entry_safe ( mark , lmark , & group - > marks_list , g_list ) {
2021-11-29 23:15:27 +03:00
if ( mark - > connector - > type = = obj_type )
2015-08-07 01:46:42 +03:00
list_move ( & mark - > g_list , & to_free ) ;
2009-12-18 05:24:27 +03:00
}
2022-04-22 15:03:17 +03:00
fsnotify_group_unlock ( group ) ;
2015-08-07 01:46:42 +03:00
2017-01-04 12:51:58 +03:00
clear :
2015-08-07 01:46:42 +03:00
while ( 1 ) {
2022-04-22 15:03:17 +03:00
fsnotify_group_lock ( group ) ;
2017-01-04 12:51:58 +03:00
if ( list_empty ( head ) ) {
2022-04-22 15:03:17 +03:00
fsnotify_group_unlock ( group ) ;
2015-08-07 01:46:42 +03:00
break ;
}
2017-01-04 12:51:58 +03:00
mark = list_first_entry ( head , struct fsnotify_mark , g_list ) ;
2015-08-07 01:46:42 +03:00
fsnotify_get_mark ( mark ) ;
2015-09-05 01:43:12 +03:00
fsnotify_detach_mark ( mark ) ;
2022-04-22 15:03:17 +03:00
fsnotify_group_unlock ( group ) ;
2015-09-05 01:43:12 +03:00
fsnotify_free_mark ( mark ) ;
2015-08-07 01:46:42 +03:00
fsnotify_put_mark ( mark ) ;
}
2009-12-18 05:24:27 +03:00
}
2018-06-23 17:54:47 +03:00
/* Destroy all marks attached to an object via connector */
void fsnotify_destroy_marks ( fsnotify_connp_t * connp )
2017-02-01 11:23:48 +03:00
{
2017-02-01 11:21:58 +03:00
struct fsnotify_mark_connector * conn ;
2016-12-21 14:15:30 +03:00
struct fsnotify_mark * mark , * old_mark = NULL ;
2018-10-17 14:07:05 +03:00
void * objp ;
unsigned int type ;
2017-02-01 11:23:48 +03:00
2016-12-21 14:15:30 +03:00
conn = fsnotify_grab_connector ( connp ) ;
if ( ! conn )
return ;
/*
* We have to be careful since we can race with e . g .
* fsnotify_clear_marks_by_group ( ) and once we drop the conn - > lock , the
* list can get modified . However we are holding mark reference and
* thus our mark cannot be removed from obj_list so we can continue
* iteration after regaining conn - > lock .
*/
hlist_for_each_entry ( mark , & conn - > list , obj_list ) {
2017-02-01 11:23:48 +03:00
fsnotify_get_mark ( mark ) ;
2017-02-01 10:19:43 +03:00
spin_unlock ( & conn - > lock ) ;
2016-12-21 14:15:30 +03:00
if ( old_mark )
fsnotify_put_mark ( old_mark ) ;
old_mark = mark ;
2017-02-01 11:23:48 +03:00
fsnotify_destroy_mark ( mark , mark - > group ) ;
2016-12-21 14:15:30 +03:00
spin_lock ( & conn - > lock ) ;
2017-02-01 11:23:48 +03:00
}
2016-12-21 14:15:30 +03:00
/*
* Detach list from object now so that we don ' t pin inode until all
* mark references get dropped . It would lead to strange results such
* as delaying inode deletion or blocking unmount .
*/
2018-10-17 14:07:05 +03:00
objp = fsnotify_detach_connector_from_object ( conn , & type ) ;
2016-12-21 14:15:30 +03:00
spin_unlock ( & conn - > lock ) ;
if ( old_mark )
fsnotify_put_mark ( old_mark ) ;
2018-10-17 14:07:05 +03:00
fsnotify_drop_object ( type , objp ) ;
2017-02-01 11:23:48 +03:00
}
2009-12-18 05:24:27 +03:00
/*
* Nothing fancy , just initialize lists and locks and counters .
*/
void fsnotify_init_mark ( struct fsnotify_mark * mark ,
2016-12-21 20:06:12 +03:00
struct fsnotify_group * group )
2009-12-18 05:24:27 +03:00
{
2009-12-18 05:24:27 +03:00
memset ( mark , 0 , sizeof ( * mark ) ) ;
2009-12-18 05:24:27 +03:00
spin_lock_init ( & mark - > lock ) ;
2017-10-20 13:26:02 +03:00
refcount_set ( & mark - > refcnt , 1 ) ;
2016-12-21 20:32:48 +03:00
fsnotify_get_group ( group ) ;
mark - > group = group ;
2019-04-24 19:39:57 +03:00
WRITE_ONCE ( mark - > connector , NULL ) ;
2009-12-18 05:24:27 +03:00
}
2019-08-18 21:18:46 +03:00
EXPORT_SYMBOL_GPL ( fsnotify_init_mark ) ;
2016-02-18 00:11:18 +03:00
2016-05-20 03:08:59 +03:00
/*
* Destroy all marks in destroy_list , waits for SRCU period to finish before
* actually freeing marks .
*/
2016-12-21 16:48:18 +03:00
static void fsnotify_mark_destroy_workfn ( struct work_struct * work )
2016-02-18 00:11:18 +03:00
{
struct fsnotify_mark * mark , * next ;
struct list_head private_destroy_list ;
2016-02-18 00:11:21 +03:00
spin_lock ( & destroy_lock ) ;
/* exchange the list head */
list_replace_init ( & destroy_list , & private_destroy_list ) ;
spin_unlock ( & destroy_lock ) ;
2016-02-18 00:11:18 +03:00
2016-02-18 00:11:21 +03:00
synchronize_srcu ( & fsnotify_mark_srcu ) ;
2016-02-18 00:11:18 +03:00
2016-02-18 00:11:21 +03:00
list_for_each_entry_safe ( mark , next , & private_destroy_list , g_list ) {
list_del_init ( & mark - > g_list ) ;
2016-12-21 14:15:30 +03:00
fsnotify_final_mark_destroy ( mark ) ;
2016-02-18 00:11:18 +03:00
}
}
2016-05-20 03:08:59 +03:00
2016-12-21 16:48:18 +03:00
/* Wait for all marks queued for destruction to be actually destroyed */
void fsnotify_wait_marks_destroyed ( void )
2016-05-20 03:08:59 +03:00
{
2016-12-21 16:48:18 +03:00
flush_delayed_work ( & reaper_work ) ;
2016-05-20 03:08:59 +03:00
}
2019-08-18 21:18:46 +03:00
EXPORT_SYMBOL_GPL ( fsnotify_wait_marks_destroyed ) ;