Skip to content

Commit 18f6622

Browse files
Jeff LaytonJ. Bruce Fields
authored andcommitted
locks: create a new notifier chain for lease attempts
With the new file caching infrastructure in nfsd, we can end up holding files open for an indefinite period of time, even when they are still idle. This may prevent the kernel from handing out leases on the file, which is something we don't want to block. Fix this by running a SRCU notifier call chain whenever on any lease attempt. nfsd can then purge the cache for that inode before returning. Since SRCU is only conditionally compiled in, we must only define the new chain if it's enabled, and users of the chain must ensure that SRCU is enabled. Signed-off-by: Jeff Layton <jeff.layton@primarydata.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
1 parent f69d6d8 commit 18f6622

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

fs/locks.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,6 +1990,64 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
19901990
}
19911991
EXPORT_SYMBOL(generic_setlease);
19921992

1993+
#if IS_ENABLED(CONFIG_SRCU)
1994+
/*
1995+
* Kernel subsystems can register to be notified on any attempt to set
1996+
* a new lease with the lease_notifier_chain. This is used by (e.g.) nfsd
1997+
* to close files that it may have cached when there is an attempt to set a
1998+
* conflicting lease.
1999+
*/
2000+
static struct srcu_notifier_head lease_notifier_chain;
2001+
2002+
static inline void
2003+
lease_notifier_chain_init(void)
2004+
{
2005+
srcu_init_notifier_head(&lease_notifier_chain);
2006+
}
2007+
2008+
static inline void
2009+
setlease_notifier(long arg, struct file_lock *lease)
2010+
{
2011+
if (arg != F_UNLCK)
2012+
srcu_notifier_call_chain(&lease_notifier_chain, arg, lease);
2013+
}
2014+
2015+
int lease_register_notifier(struct notifier_block *nb)
2016+
{
2017+
return srcu_notifier_chain_register(&lease_notifier_chain, nb);
2018+
}
2019+
EXPORT_SYMBOL_GPL(lease_register_notifier);
2020+
2021+
void lease_unregister_notifier(struct notifier_block *nb)
2022+
{
2023+
srcu_notifier_chain_unregister(&lease_notifier_chain, nb);
2024+
}
2025+
EXPORT_SYMBOL_GPL(lease_unregister_notifier);
2026+
2027+
#else /* !IS_ENABLED(CONFIG_SRCU) */
2028+
static inline void
2029+
lease_notifier_chain_init(void)
2030+
{
2031+
}
2032+
2033+
static inline void
2034+
setlease_notifier(long arg, struct file_lock *lease)
2035+
{
2036+
}
2037+
2038+
int lease_register_notifier(struct notifier_block *nb)
2039+
{
2040+
return 0;
2041+
}
2042+
EXPORT_SYMBOL_GPL(lease_register_notifier);
2043+
2044+
void lease_unregister_notifier(struct notifier_block *nb)
2045+
{
2046+
}
2047+
EXPORT_SYMBOL_GPL(lease_unregister_notifier);
2048+
2049+
#endif /* IS_ENABLED(CONFIG_SRCU) */
2050+
19932051
/**
19942052
* vfs_setlease - sets a lease on an open file
19952053
* @filp: file pointer
@@ -2010,6 +2068,8 @@ EXPORT_SYMBOL(generic_setlease);
20102068
int
20112069
vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
20122070
{
2071+
if (lease)
2072+
setlease_notifier(arg, *lease);
20132073
if (filp->f_op->setlease)
20142074
return filp->f_op->setlease(filp, arg, lease, priv);
20152075
else
@@ -2923,6 +2983,7 @@ static int __init filelock_init(void)
29232983
INIT_HLIST_HEAD(&fll->hlist);
29242984
}
29252985

2986+
lease_notifier_chain_init();
29262987
return 0;
29272988
}
29282989
core_initcall(filelock_init);

include/linux/fs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,11 @@ extern void lease_get_mtime(struct inode *, struct timespec64 *time);
11551155
extern int generic_setlease(struct file *, long, struct file_lock **, void **priv);
11561156
extern int vfs_setlease(struct file *, long, struct file_lock **, void **);
11571157
extern int lease_modify(struct file_lock *, int, struct list_head *);
1158+
1159+
struct notifier_block;
1160+
extern int lease_register_notifier(struct notifier_block *);
1161+
extern void lease_unregister_notifier(struct notifier_block *);
1162+
11581163
struct files_struct;
11591164
extern void show_fd_locks(struct seq_file *f,
11601165
struct file *filp, struct files_struct *files);

0 commit comments

Comments
 (0)