diff options
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/fs/locks.c b/fs/locks.c index a364ebc5cec3..6970f55daf54 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -212,6 +212,7 @@ struct file_lock_list_struct { | |||
212 | static DEFINE_PER_CPU(struct file_lock_list_struct, file_lock_list); | 212 | static DEFINE_PER_CPU(struct file_lock_list_struct, file_lock_list); |
213 | DEFINE_STATIC_PERCPU_RWSEM(file_rwsem); | 213 | DEFINE_STATIC_PERCPU_RWSEM(file_rwsem); |
214 | 214 | ||
215 | |||
215 | /* | 216 | /* |
216 | * The blocked_hash is used to find POSIX lock loops for deadlock detection. | 217 | * The blocked_hash is used to find POSIX lock loops for deadlock detection. |
217 | * It is protected by blocked_lock_lock. | 218 | * It is protected by blocked_lock_lock. |
@@ -1991,6 +1992,64 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp, | |||
1991 | } | 1992 | } |
1992 | EXPORT_SYMBOL(generic_setlease); | 1993 | EXPORT_SYMBOL(generic_setlease); |
1993 | 1994 | ||
1995 | #if IS_ENABLED(CONFIG_SRCU) | ||
1996 | /* | ||
1997 | * Kernel subsystems can register to be notified on any attempt to set | ||
1998 | * a new lease with the lease_notifier_chain. This is used by (e.g.) nfsd | ||
1999 | * to close files that it may have cached when there is an attempt to set a | ||
2000 | * conflicting lease. | ||
2001 | */ | ||
2002 | static struct srcu_notifier_head lease_notifier_chain; | ||
2003 | |||
2004 | static inline void | ||
2005 | lease_notifier_chain_init(void) | ||
2006 | { | ||
2007 | srcu_init_notifier_head(&lease_notifier_chain); | ||
2008 | } | ||
2009 | |||
2010 | static inline void | ||
2011 | setlease_notifier(long arg, struct file_lock *lease) | ||
2012 | { | ||
2013 | if (arg != F_UNLCK) | ||
2014 | srcu_notifier_call_chain(&lease_notifier_chain, arg, lease); | ||
2015 | } | ||
2016 | |||
2017 | int lease_register_notifier(struct notifier_block *nb) | ||
2018 | { | ||
2019 | return srcu_notifier_chain_register(&lease_notifier_chain, nb); | ||
2020 | } | ||
2021 | EXPORT_SYMBOL_GPL(lease_register_notifier); | ||
2022 | |||
2023 | void lease_unregister_notifier(struct notifier_block *nb) | ||
2024 | { | ||
2025 | srcu_notifier_chain_unregister(&lease_notifier_chain, nb); | ||
2026 | } | ||
2027 | EXPORT_SYMBOL_GPL(lease_unregister_notifier); | ||
2028 | |||
2029 | #else /* !IS_ENABLED(CONFIG_SRCU) */ | ||
2030 | static inline void | ||
2031 | lease_notifier_chain_init(void) | ||
2032 | { | ||
2033 | } | ||
2034 | |||
2035 | static inline void | ||
2036 | setlease_notifier(long arg, struct file_lock *lease) | ||
2037 | { | ||
2038 | } | ||
2039 | |||
2040 | int lease_register_notifier(struct notifier_block *nb) | ||
2041 | { | ||
2042 | return 0; | ||
2043 | } | ||
2044 | EXPORT_SYMBOL_GPL(lease_register_notifier); | ||
2045 | |||
2046 | void lease_unregister_notifier(struct notifier_block *nb) | ||
2047 | { | ||
2048 | } | ||
2049 | EXPORT_SYMBOL_GPL(lease_unregister_notifier); | ||
2050 | |||
2051 | #endif /* IS_ENABLED(CONFIG_SRCU) */ | ||
2052 | |||
1994 | /** | 2053 | /** |
1995 | * vfs_setlease - sets a lease on an open file | 2054 | * vfs_setlease - sets a lease on an open file |
1996 | * @filp: file pointer | 2055 | * @filp: file pointer |
@@ -2011,6 +2070,8 @@ EXPORT_SYMBOL(generic_setlease); | |||
2011 | int | 2070 | int |
2012 | vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) | 2071 | vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) |
2013 | { | 2072 | { |
2073 | if (lease) | ||
2074 | setlease_notifier(arg, *lease); | ||
2014 | if (filp->f_op->setlease) | 2075 | if (filp->f_op->setlease) |
2015 | return filp->f_op->setlease(filp, arg, lease, priv); | 2076 | return filp->f_op->setlease(filp, arg, lease, priv); |
2016 | else | 2077 | else |
@@ -2924,6 +2985,7 @@ static int __init filelock_init(void) | |||
2924 | INIT_HLIST_HEAD(&fll->hlist); | 2985 | INIT_HLIST_HEAD(&fll->hlist); |
2925 | } | 2986 | } |
2926 | 2987 | ||
2988 | lease_notifier_chain_init(); | ||
2927 | return 0; | 2989 | return 0; |
2928 | } | 2990 | } |
2929 | core_initcall(filelock_init); | 2991 | core_initcall(filelock_init); |