filelock: split leases out of struct file_lock

Add a new struct file_lease and move the lease-specific fields from
struct file_lock to it. Convert the appropriate API calls to take
struct file_lease instead, and convert the callers to use them.

There is zero overlap between the lock manager operations for file
locks and the ones for file leases, so split the lease-related
operations off into a new lease_manager_operations struct.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://lore.kernel.org/r/20240131-flsplit-v3-47-c6129007ee8d@kernel.org
Reviewed-by: NeilBrown <neilb@suse.de>
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Jeff Layton 2024-01-31 18:02:28 -05:00 committed by Christian Brauner
parent 282c30f320
commit c69ff40719
No known key found for this signature in database
GPG key ID: 91C61BC06578DCA2
11 changed files with 153 additions and 98 deletions

View file

@ -1580,7 +1580,7 @@ EXPORT_SYMBOL(alloc_anon_inode);
* All arguments are ignored and it just returns -EINVAL. * All arguments are ignored and it just returns -EINVAL.
*/ */
int int
simple_nosetlease(struct file *filp, int arg, struct file_lock **flp, simple_nosetlease(struct file *filp, int arg, struct file_lease **flp,
void **priv) void **priv)
{ {
return -EINVAL; return -EINVAL;

View file

@ -74,12 +74,17 @@ static struct file_lock *file_lock(struct file_lock_core *flc)
return container_of(flc, struct file_lock, c); return container_of(flc, struct file_lock, c);
} }
static bool lease_breaking(struct file_lock *fl) static struct file_lease *file_lease(struct file_lock_core *flc)
{
return container_of(flc, struct file_lease, c);
}
static bool lease_breaking(struct file_lease *fl)
{ {
return fl->c.flc_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING); return fl->c.flc_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
} }
static int target_leasetype(struct file_lock *fl) static int target_leasetype(struct file_lease *fl)
{ {
if (fl->c.flc_flags & FL_UNLOCK_PENDING) if (fl->c.flc_flags & FL_UNLOCK_PENDING)
return F_UNLCK; return F_UNLCK;
@ -166,6 +171,7 @@ static DEFINE_SPINLOCK(blocked_lock_lock);
static struct kmem_cache *flctx_cache __ro_after_init; static struct kmem_cache *flctx_cache __ro_after_init;
static struct kmem_cache *filelock_cache __ro_after_init; static struct kmem_cache *filelock_cache __ro_after_init;
static struct kmem_cache *filelease_cache __ro_after_init;
static struct file_lock_context * static struct file_lock_context *
locks_get_lock_context(struct inode *inode, int type) locks_get_lock_context(struct inode *inode, int type)
@ -275,6 +281,18 @@ struct file_lock *locks_alloc_lock(void)
} }
EXPORT_SYMBOL_GPL(locks_alloc_lock); EXPORT_SYMBOL_GPL(locks_alloc_lock);
/* Allocate an empty lock structure. */
struct file_lease *locks_alloc_lease(void)
{
struct file_lease *fl = kmem_cache_zalloc(filelease_cache, GFP_KERNEL);
if (fl)
locks_init_lock_heads(&fl->c);
return fl;
}
EXPORT_SYMBOL_GPL(locks_alloc_lease);
void locks_release_private(struct file_lock *fl) void locks_release_private(struct file_lock *fl)
{ {
struct file_lock_core *flc = &fl->c; struct file_lock_core *flc = &fl->c;
@ -336,15 +354,25 @@ void locks_free_lock(struct file_lock *fl)
} }
EXPORT_SYMBOL(locks_free_lock); EXPORT_SYMBOL(locks_free_lock);
/* Free a lease which is not in use. */
void locks_free_lease(struct file_lease *fl)
{
kmem_cache_free(filelease_cache, fl);
}
EXPORT_SYMBOL(locks_free_lease);
static void static void
locks_dispose_list(struct list_head *dispose) locks_dispose_list(struct list_head *dispose)
{ {
struct file_lock *fl; struct file_lock_core *flc;
while (!list_empty(dispose)) { while (!list_empty(dispose)) {
fl = list_first_entry(dispose, struct file_lock, c.flc_list); flc = list_first_entry(dispose, struct file_lock_core, flc_list);
list_del_init(&fl->c.flc_list); list_del_init(&flc->flc_list);
locks_free_lock(fl); if (flc->flc_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
locks_free_lease(file_lease(flc));
else
locks_free_lock(file_lock(flc));
} }
} }
@ -355,6 +383,13 @@ void locks_init_lock(struct file_lock *fl)
} }
EXPORT_SYMBOL(locks_init_lock); EXPORT_SYMBOL(locks_init_lock);
void locks_init_lease(struct file_lease *fl)
{
memset(fl, 0, sizeof(*fl));
locks_init_lock_heads(&fl->c);
}
EXPORT_SYMBOL(locks_init_lease);
/* /*
* Initialize a new lock from an existing file_lock structure. * Initialize a new lock from an existing file_lock structure.
*/ */
@ -518,14 +553,14 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
/* default lease lock manager operations */ /* default lease lock manager operations */
static bool static bool
lease_break_callback(struct file_lock *fl) lease_break_callback(struct file_lease *fl)
{ {
kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG); kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
return false; return false;
} }
static void static void
lease_setup(struct file_lock *fl, void **priv) lease_setup(struct file_lease *fl, void **priv)
{ {
struct file *filp = fl->c.flc_file; struct file *filp = fl->c.flc_file;
struct fasync_struct *fa = *priv; struct fasync_struct *fa = *priv;
@ -541,7 +576,7 @@ lease_setup(struct file_lock *fl, void **priv)
__f_setown(filp, task_pid(current), PIDTYPE_TGID, 0); __f_setown(filp, task_pid(current), PIDTYPE_TGID, 0);
} }
static const struct lock_manager_operations lease_manager_ops = { static const struct lease_manager_operations lease_manager_ops = {
.lm_break = lease_break_callback, .lm_break = lease_break_callback,
.lm_change = lease_modify, .lm_change = lease_modify,
.lm_setup = lease_setup, .lm_setup = lease_setup,
@ -550,7 +585,7 @@ static const struct lock_manager_operations lease_manager_ops = {
/* /*
* Initialize a lease, use the default lock manager operations * Initialize a lease, use the default lock manager operations
*/ */
static int lease_init(struct file *filp, int type, struct file_lock *fl) static int lease_init(struct file *filp, int type, struct file_lease *fl)
{ {
if (assign_type(&fl->c, type) != 0) if (assign_type(&fl->c, type) != 0)
return -EINVAL; return -EINVAL;
@ -560,17 +595,14 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl)
fl->c.flc_file = filp; fl->c.flc_file = filp;
fl->c.flc_flags = FL_LEASE; fl->c.flc_flags = FL_LEASE;
fl->fl_start = 0;
fl->fl_end = OFFSET_MAX;
fl->fl_ops = NULL;
fl->fl_lmops = &lease_manager_ops; fl->fl_lmops = &lease_manager_ops;
return 0; return 0;
} }
/* Allocate a file_lock initialised to this type of lease */ /* Allocate a file_lock initialised to this type of lease */
static struct file_lock *lease_alloc(struct file *filp, int type) static struct file_lease *lease_alloc(struct file *filp, int type)
{ {
struct file_lock *fl = locks_alloc_lock(); struct file_lease *fl = locks_alloc_lease();
int error = -ENOMEM; int error = -ENOMEM;
if (fl == NULL) if (fl == NULL)
@ -578,7 +610,7 @@ static struct file_lock *lease_alloc(struct file *filp, int type)
error = lease_init(filp, type, fl); error = lease_init(filp, type, fl);
if (error) { if (error) {
locks_free_lock(fl); locks_free_lease(fl);
return ERR_PTR(error); return ERR_PTR(error);
} }
return fl; return fl;
@ -1395,7 +1427,7 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
return error; return error;
} }
static void lease_clear_pending(struct file_lock *fl, int arg) static void lease_clear_pending(struct file_lease *fl, int arg)
{ {
switch (arg) { switch (arg) {
case F_UNLCK: case F_UNLCK:
@ -1407,7 +1439,7 @@ static void lease_clear_pending(struct file_lock *fl, int arg)
} }
/* We already had a lease on this file; just change its type */ /* We already had a lease on this file; just change its type */
int lease_modify(struct file_lock *fl, int arg, struct list_head *dispose) int lease_modify(struct file_lease *fl, int arg, struct list_head *dispose)
{ {
int error = assign_type(&fl->c, arg); int error = assign_type(&fl->c, arg);
@ -1442,7 +1474,7 @@ static bool past_time(unsigned long then)
static void time_out_leases(struct inode *inode, struct list_head *dispose) static void time_out_leases(struct inode *inode, struct list_head *dispose)
{ {
struct file_lock_context *ctx = inode->i_flctx; struct file_lock_context *ctx = inode->i_flctx;
struct file_lock *fl, *tmp; struct file_lease *fl, *tmp;
lockdep_assert_held(&ctx->flc_lock); lockdep_assert_held(&ctx->flc_lock);
@ -1458,8 +1490,8 @@ static void time_out_leases(struct inode *inode, struct list_head *dispose)
static bool leases_conflict(struct file_lock_core *lc, struct file_lock_core *bc) static bool leases_conflict(struct file_lock_core *lc, struct file_lock_core *bc)
{ {
bool rc; bool rc;
struct file_lock *lease = file_lock(lc); struct file_lease *lease = file_lease(lc);
struct file_lock *breaker = file_lock(bc); struct file_lease *breaker = file_lease(bc);
if (lease->fl_lmops->lm_breaker_owns_lease if (lease->fl_lmops->lm_breaker_owns_lease
&& lease->fl_lmops->lm_breaker_owns_lease(lease)) && lease->fl_lmops->lm_breaker_owns_lease(lease))
@ -1480,7 +1512,7 @@ static bool leases_conflict(struct file_lock_core *lc, struct file_lock_core *bc
} }
static bool static bool
any_leases_conflict(struct inode *inode, struct file_lock *breaker) any_leases_conflict(struct inode *inode, struct file_lease *breaker)
{ {
struct file_lock_context *ctx = inode->i_flctx; struct file_lock_context *ctx = inode->i_flctx;
struct file_lock_core *flc; struct file_lock_core *flc;
@ -1511,7 +1543,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
{ {
int error = 0; int error = 0;
struct file_lock_context *ctx; struct file_lock_context *ctx;
struct file_lock *new_fl, *fl, *tmp; struct file_lease *new_fl, *fl, *tmp;
unsigned long break_time; unsigned long break_time;
int want_write = (mode & O_ACCMODE) != O_RDONLY; int want_write = (mode & O_ACCMODE) != O_RDONLY;
LIST_HEAD(dispose); LIST_HEAD(dispose);
@ -1571,7 +1603,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
} }
restart: restart:
fl = list_first_entry(&ctx->flc_lease, struct file_lock, c.flc_list); fl = list_first_entry(&ctx->flc_lease, struct file_lease, c.flc_list);
break_time = fl->fl_break_time; break_time = fl->fl_break_time;
if (break_time != 0) if (break_time != 0)
break_time -= jiffies; break_time -= jiffies;
@ -1590,7 +1622,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
percpu_down_read(&file_rwsem); percpu_down_read(&file_rwsem);
spin_lock(&ctx->flc_lock); spin_lock(&ctx->flc_lock);
trace_break_lease_unblock(inode, new_fl); trace_break_lease_unblock(inode, new_fl);
locks_delete_block(new_fl); __locks_delete_block(&new_fl->c);
if (error >= 0) { if (error >= 0) {
/* /*
* Wait for the next conflicting lease that has not been * Wait for the next conflicting lease that has not been
@ -1607,7 +1639,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
percpu_up_read(&file_rwsem); percpu_up_read(&file_rwsem);
locks_dispose_list(&dispose); locks_dispose_list(&dispose);
free_lock: free_lock:
locks_free_lock(new_fl); locks_free_lease(new_fl);
return error; return error;
} }
EXPORT_SYMBOL(__break_lease); EXPORT_SYMBOL(__break_lease);
@ -1625,14 +1657,14 @@ void lease_get_mtime(struct inode *inode, struct timespec64 *time)
{ {
bool has_lease = false; bool has_lease = false;
struct file_lock_context *ctx; struct file_lock_context *ctx;
struct file_lock *fl; struct file_lock_core *flc;
ctx = locks_inode_context(inode); ctx = locks_inode_context(inode);
if (ctx && !list_empty_careful(&ctx->flc_lease)) { if (ctx && !list_empty_careful(&ctx->flc_lease)) {
spin_lock(&ctx->flc_lock); spin_lock(&ctx->flc_lock);
fl = list_first_entry_or_null(&ctx->flc_lease, flc = list_first_entry_or_null(&ctx->flc_lease,
struct file_lock, c.flc_list); struct file_lock_core, flc_list);
if (fl && lock_is_write(fl)) if (flc && flc->flc_type == F_WRLCK)
has_lease = true; has_lease = true;
spin_unlock(&ctx->flc_lock); spin_unlock(&ctx->flc_lock);
} }
@ -1667,7 +1699,7 @@ EXPORT_SYMBOL(lease_get_mtime);
*/ */
int fcntl_getlease(struct file *filp) int fcntl_getlease(struct file *filp)
{ {
struct file_lock *fl; struct file_lease *fl;
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
struct file_lock_context *ctx; struct file_lock_context *ctx;
int type = F_UNLCK; int type = F_UNLCK;
@ -1739,9 +1771,9 @@ check_conflicting_open(struct file *filp, const int arg, int flags)
} }
static int static int
generic_add_lease(struct file *filp, int arg, struct file_lock **flp, void **priv) generic_add_lease(struct file *filp, int arg, struct file_lease **flp, void **priv)
{ {
struct file_lock *fl, *my_fl = NULL, *lease; struct file_lease *fl, *my_fl = NULL, *lease;
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
struct file_lock_context *ctx; struct file_lock_context *ctx;
bool is_deleg = (*flp)->c.flc_flags & FL_DELEG; bool is_deleg = (*flp)->c.flc_flags & FL_DELEG;
@ -1850,7 +1882,7 @@ generic_add_lease(struct file *filp, int arg, struct file_lock **flp, void **pri
static int generic_delete_lease(struct file *filp, void *owner) static int generic_delete_lease(struct file *filp, void *owner)
{ {
int error = -EAGAIN; int error = -EAGAIN;
struct file_lock *fl, *victim = NULL; struct file_lease *fl, *victim = NULL;
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
struct file_lock_context *ctx; struct file_lock_context *ctx;
LIST_HEAD(dispose); LIST_HEAD(dispose);
@ -1890,7 +1922,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
* The (input) flp->fl_lmops->lm_break function is required * The (input) flp->fl_lmops->lm_break function is required
* by break_lease(). * by break_lease().
*/ */
int generic_setlease(struct file *filp, int arg, struct file_lock **flp, int generic_setlease(struct file *filp, int arg, struct file_lease **flp,
void **priv) void **priv)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
@ -1937,7 +1969,7 @@ lease_notifier_chain_init(void)
} }
static inline void static inline void
setlease_notifier(int arg, struct file_lock *lease) setlease_notifier(int arg, struct file_lease *lease)
{ {
if (arg != F_UNLCK) if (arg != F_UNLCK)
srcu_notifier_call_chain(&lease_notifier_chain, arg, lease); srcu_notifier_call_chain(&lease_notifier_chain, arg, lease);
@ -1973,7 +2005,7 @@ EXPORT_SYMBOL_GPL(lease_unregister_notifier);
* may be NULL if the lm_setup operation doesn't require it. * may be NULL if the lm_setup operation doesn't require it.
*/ */
int int
vfs_setlease(struct file *filp, int arg, struct file_lock **lease, void **priv) vfs_setlease(struct file *filp, int arg, struct file_lease **lease, void **priv)
{ {
if (lease) if (lease)
setlease_notifier(arg, *lease); setlease_notifier(arg, *lease);
@ -1986,7 +2018,7 @@ EXPORT_SYMBOL_GPL(vfs_setlease);
static int do_fcntl_add_lease(unsigned int fd, struct file *filp, int arg) static int do_fcntl_add_lease(unsigned int fd, struct file *filp, int arg)
{ {
struct file_lock *fl; struct file_lease *fl;
struct fasync_struct *new; struct fasync_struct *new;
int error; int error;
@ -1996,14 +2028,14 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, int arg)
new = fasync_alloc(); new = fasync_alloc();
if (!new) { if (!new) {
locks_free_lock(fl); locks_free_lease(fl);
return -ENOMEM; return -ENOMEM;
} }
new->fa_fd = fd; new->fa_fd = fd;
error = vfs_setlease(filp, arg, &fl, (void **)&new); error = vfs_setlease(filp, arg, &fl, (void **)&new);
if (fl) if (fl)
locks_free_lock(fl); locks_free_lease(fl);
if (new) if (new)
fasync_free(new); fasync_free(new);
return error; return error;
@ -2626,7 +2658,7 @@ locks_remove_flock(struct file *filp, struct file_lock_context *flctx)
static void static void
locks_remove_lease(struct file *filp, struct file_lock_context *ctx) locks_remove_lease(struct file *filp, struct file_lock_context *ctx)
{ {
struct file_lock *fl, *tmp; struct file_lease *fl, *tmp;
LIST_HEAD(dispose); LIST_HEAD(dispose);
if (list_empty(&ctx->flc_lease)) if (list_empty(&ctx->flc_lease))
@ -2755,14 +2787,16 @@ static void lock_get_status(struct seq_file *f, struct file_lock_core *flc,
} else if (flc->flc_flags & FL_FLOCK) { } else if (flc->flc_flags & FL_FLOCK) {
seq_puts(f, "FLOCK ADVISORY "); seq_puts(f, "FLOCK ADVISORY ");
} else if (flc->flc_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT)) { } else if (flc->flc_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT)) {
type = target_leasetype(fl); struct file_lease *lease = file_lease(flc);
type = target_leasetype(lease);
if (flc->flc_flags & FL_DELEG) if (flc->flc_flags & FL_DELEG)
seq_puts(f, "DELEG "); seq_puts(f, "DELEG ");
else else
seq_puts(f, "LEASE "); seq_puts(f, "LEASE ");
if (lease_breaking(fl)) if (lease_breaking(lease))
seq_puts(f, "BREAKING "); seq_puts(f, "BREAKING ");
else if (flc->flc_file) else if (flc->flc_file)
seq_puts(f, "ACTIVE "); seq_puts(f, "ACTIVE ");
@ -2945,6 +2979,9 @@ static int __init filelock_init(void)
filelock_cache = kmem_cache_create("file_lock_cache", filelock_cache = kmem_cache_create("file_lock_cache",
sizeof(struct file_lock), 0, SLAB_PANIC, NULL); sizeof(struct file_lock), 0, SLAB_PANIC, NULL);
filelease_cache = kmem_cache_create("file_lock_cache",
sizeof(struct file_lease), 0, SLAB_PANIC, NULL);
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
struct file_lock_list_struct *fll = per_cpu_ptr(&file_lock_list, i); struct file_lock_list_struct *fll = per_cpu_ptr(&file_lock_list, i);

View file

@ -330,7 +330,7 @@ extern int update_open_stateid(struct nfs4_state *state,
const nfs4_stateid *deleg_stateid, const nfs4_stateid *deleg_stateid,
fmode_t fmode); fmode_t fmode);
extern int nfs4_proc_setlease(struct file *file, int arg, extern int nfs4_proc_setlease(struct file *file, int arg,
struct file_lock **lease, void **priv); struct file_lease **lease, void **priv);
extern int nfs4_proc_get_lease_time(struct nfs_client *clp, extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
struct nfs_fsinfo *fsinfo); struct nfs_fsinfo *fsinfo);
extern void nfs4_update_changeattr(struct inode *dir, extern void nfs4_update_changeattr(struct inode *dir,

View file

@ -439,7 +439,7 @@ void nfs42_ssc_unregister_ops(void)
} }
#endif /* CONFIG_NFS_V4_2 */ #endif /* CONFIG_NFS_V4_2 */
static int nfs4_setlease(struct file *file, int arg, struct file_lock **lease, static int nfs4_setlease(struct file *file, int arg, struct file_lease **lease,
void **priv) void **priv)
{ {
return nfs4_proc_setlease(file, arg, lease, priv); return nfs4_proc_setlease(file, arg, lease, priv);

View file

@ -7604,7 +7604,7 @@ static int nfs4_delete_lease(struct file *file, void **priv)
return generic_setlease(file, F_UNLCK, NULL, priv); return generic_setlease(file, F_UNLCK, NULL, priv);
} }
static int nfs4_add_lease(struct file *file, int arg, struct file_lock **lease, static int nfs4_add_lease(struct file *file, int arg, struct file_lease **lease,
void **priv) void **priv)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
@ -7622,7 +7622,7 @@ static int nfs4_add_lease(struct file *file, int arg, struct file_lock **lease,
return -EAGAIN; return -EAGAIN;
} }
int nfs4_proc_setlease(struct file *file, int arg, struct file_lock **lease, int nfs4_proc_setlease(struct file *file, int arg, struct file_lease **lease,
void **priv) void **priv)
{ {
switch (arg) { switch (arg) {

View file

@ -25,7 +25,7 @@ static struct kmem_cache *nfs4_layout_cache;
static struct kmem_cache *nfs4_layout_stateid_cache; static struct kmem_cache *nfs4_layout_stateid_cache;
static const struct nfsd4_callback_ops nfsd4_cb_layout_ops; static const struct nfsd4_callback_ops nfsd4_cb_layout_ops;
static const struct lock_manager_operations nfsd4_layouts_lm_ops; static const struct lease_manager_operations nfsd4_layouts_lm_ops;
const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = { const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = {
#ifdef CONFIG_NFSD_FLEXFILELAYOUT #ifdef CONFIG_NFSD_FLEXFILELAYOUT
@ -182,20 +182,19 @@ nfsd4_free_layout_stateid(struct nfs4_stid *stid)
static int static int
nfsd4_layout_setlease(struct nfs4_layout_stateid *ls) nfsd4_layout_setlease(struct nfs4_layout_stateid *ls)
{ {
struct file_lock *fl; struct file_lease *fl;
int status; int status;
if (nfsd4_layout_ops[ls->ls_layout_type]->disable_recalls) if (nfsd4_layout_ops[ls->ls_layout_type]->disable_recalls)
return 0; return 0;
fl = locks_alloc_lock(); fl = locks_alloc_lease();
if (!fl) if (!fl)
return -ENOMEM; return -ENOMEM;
locks_init_lock(fl); locks_init_lease(fl);
fl->fl_lmops = &nfsd4_layouts_lm_ops; fl->fl_lmops = &nfsd4_layouts_lm_ops;
fl->c.flc_flags = FL_LAYOUT; fl->c.flc_flags = FL_LAYOUT;
fl->c.flc_type = F_RDLCK; fl->c.flc_type = F_RDLCK;
fl->fl_end = OFFSET_MAX;
fl->c.flc_owner = ls; fl->c.flc_owner = ls;
fl->c.flc_pid = current->tgid; fl->c.flc_pid = current->tgid;
fl->c.flc_file = ls->ls_file->nf_file; fl->c.flc_file = ls->ls_file->nf_file;
@ -203,7 +202,7 @@ nfsd4_layout_setlease(struct nfs4_layout_stateid *ls)
status = vfs_setlease(fl->c.flc_file, fl->c.flc_type, &fl, status = vfs_setlease(fl->c.flc_file, fl->c.flc_type, &fl,
NULL); NULL);
if (status) { if (status) {
locks_free_lock(fl); locks_free_lease(fl);
return status; return status;
} }
BUG_ON(fl != NULL); BUG_ON(fl != NULL);
@ -724,7 +723,7 @@ static const struct nfsd4_callback_ops nfsd4_cb_layout_ops = {
}; };
static bool static bool
nfsd4_layout_lm_break(struct file_lock *fl) nfsd4_layout_lm_break(struct file_lease *fl)
{ {
/* /*
* We don't want the locks code to timeout the lease for us; * We don't want the locks code to timeout the lease for us;
@ -737,14 +736,14 @@ nfsd4_layout_lm_break(struct file_lock *fl)
} }
static int static int
nfsd4_layout_lm_change(struct file_lock *onlist, int arg, nfsd4_layout_lm_change(struct file_lease *onlist, int arg,
struct list_head *dispose) struct list_head *dispose)
{ {
BUG_ON(!(arg & F_UNLCK)); BUG_ON(!(arg & F_UNLCK));
return lease_modify(onlist, arg, dispose); return lease_modify(onlist, arg, dispose);
} }
static const struct lock_manager_operations nfsd4_layouts_lm_ops = { static const struct lease_manager_operations nfsd4_layouts_lm_ops = {
.lm_break = nfsd4_layout_lm_break, .lm_break = nfsd4_layout_lm_break,
.lm_change = nfsd4_layout_lm_change, .lm_change = nfsd4_layout_lm_change,
}; };

View file

@ -4922,7 +4922,7 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
/* Called from break_lease() with flc_lock held. */ /* Called from break_lease() with flc_lock held. */
static bool static bool
nfsd_break_deleg_cb(struct file_lock *fl) nfsd_break_deleg_cb(struct file_lease *fl)
{ {
struct nfs4_delegation *dp = (struct nfs4_delegation *) fl->c.flc_owner; struct nfs4_delegation *dp = (struct nfs4_delegation *) fl->c.flc_owner;
struct nfs4_file *fp = dp->dl_stid.sc_file; struct nfs4_file *fp = dp->dl_stid.sc_file;
@ -4960,7 +4960,7 @@ nfsd_break_deleg_cb(struct file_lock *fl)
* %true: Lease conflict was resolved * %true: Lease conflict was resolved
* %false: Lease conflict was not resolved. * %false: Lease conflict was not resolved.
*/ */
static bool nfsd_breaker_owns_lease(struct file_lock *fl) static bool nfsd_breaker_owns_lease(struct file_lease *fl)
{ {
struct nfs4_delegation *dl = fl->c.flc_owner; struct nfs4_delegation *dl = fl->c.flc_owner;
struct svc_rqst *rqst; struct svc_rqst *rqst;
@ -4977,7 +4977,7 @@ static bool nfsd_breaker_owns_lease(struct file_lock *fl)
} }
static int static int
nfsd_change_deleg_cb(struct file_lock *onlist, int arg, nfsd_change_deleg_cb(struct file_lease *onlist, int arg,
struct list_head *dispose) struct list_head *dispose)
{ {
struct nfs4_delegation *dp = (struct nfs4_delegation *) onlist->c.flc_owner; struct nfs4_delegation *dp = (struct nfs4_delegation *) onlist->c.flc_owner;
@ -4991,7 +4991,7 @@ nfsd_change_deleg_cb(struct file_lock *onlist, int arg,
return -EAGAIN; return -EAGAIN;
} }
static const struct lock_manager_operations nfsd_lease_mng_ops = { static const struct lease_manager_operations nfsd_lease_mng_ops = {
.lm_breaker_owns_lease = nfsd_breaker_owns_lease, .lm_breaker_owns_lease = nfsd_breaker_owns_lease,
.lm_break = nfsd_break_deleg_cb, .lm_break = nfsd_break_deleg_cb,
.lm_change = nfsd_change_deleg_cb, .lm_change = nfsd_change_deleg_cb,
@ -5331,18 +5331,17 @@ static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
} }
static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, static struct file_lease *nfs4_alloc_init_lease(struct nfs4_delegation *dp,
int flag) int flag)
{ {
struct file_lock *fl; struct file_lease *fl;
fl = locks_alloc_lock(); fl = locks_alloc_lease();
if (!fl) if (!fl)
return NULL; return NULL;
fl->fl_lmops = &nfsd_lease_mng_ops; fl->fl_lmops = &nfsd_lease_mng_ops;
fl->c.flc_flags = FL_DELEG; fl->c.flc_flags = FL_DELEG;
fl->c.flc_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; fl->c.flc_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
fl->fl_end = OFFSET_MAX;
fl->c.flc_owner = (fl_owner_t)dp; fl->c.flc_owner = (fl_owner_t)dp;
fl->c.flc_pid = current->tgid; fl->c.flc_pid = current->tgid;
fl->c.flc_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file; fl->c.flc_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file;
@ -5463,7 +5462,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate; struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
struct nfs4_delegation *dp; struct nfs4_delegation *dp;
struct nfsd_file *nf = NULL; struct nfsd_file *nf = NULL;
struct file_lock *fl; struct file_lease *fl;
u32 dl_type; u32 dl_type;
/* /*
@ -5536,7 +5535,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
status = vfs_setlease(fp->fi_deleg_file->nf_file, status = vfs_setlease(fp->fi_deleg_file->nf_file,
fl->c.flc_type, &fl, NULL); fl->c.flc_type, &fl, NULL);
if (fl) if (fl)
locks_free_lock(fl); locks_free_lease(fl);
if (status) if (status)
goto out_clnt_odstate; goto out_clnt_odstate;
@ -8449,7 +8448,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode)
{ {
__be32 status; __be32 status;
struct file_lock_context *ctx; struct file_lock_context *ctx;
struct file_lock *fl; struct file_lease *fl;
struct nfs4_delegation *dp; struct nfs4_delegation *dp;
ctx = locks_inode_context(inode); ctx = locks_inode_context(inode);
@ -8457,6 +8456,8 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode)
return 0; return 0;
spin_lock(&ctx->flc_lock); spin_lock(&ctx->flc_lock);
for_each_file_lock(fl, &ctx->flc_lease) { for_each_file_lock(fl, &ctx->flc_lease) {
unsigned char type = fl->c.flc_type;
if (fl->c.flc_flags == FL_LAYOUT) if (fl->c.flc_flags == FL_LAYOUT)
continue; continue;
if (fl->fl_lmops != &nfsd_lease_mng_ops) { if (fl->fl_lmops != &nfsd_lease_mng_ops) {
@ -8465,11 +8466,11 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode)
* we are done; there isn't any write delegation * we are done; there isn't any write delegation
* on this inode * on this inode
*/ */
if (lock_is_read(fl)) if (type == F_RDLCK)
break; break;
goto break_lease; goto break_lease;
} }
if (lock_is_write(fl)) { if (type == F_WRLCK) {
dp = fl->c.flc_owner; dp = fl->c.flc_owner;
if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) { if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) {
spin_unlock(&ctx->flc_lock); spin_unlock(&ctx->flc_lock);

View file

@ -1085,7 +1085,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
} }
static int static int
cifs_setlease(struct file *file, int arg, struct file_lock **lease, void **priv) cifs_setlease(struct file *file, int arg, struct file_lease **lease, void **priv)
{ {
/* /*
* Note that this is called by vfs setlease with i_lock held to * Note that this is called by vfs setlease with i_lock held to

View file

@ -27,6 +27,7 @@
#define FILE_LOCK_DEFERRED 1 #define FILE_LOCK_DEFERRED 1
struct file_lock; struct file_lock;
struct file_lease;
struct file_lock_operations { struct file_lock_operations {
void (*fl_copy_lock)(struct file_lock *, struct file_lock *); void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
@ -39,14 +40,17 @@ struct lock_manager_operations {
void (*lm_put_owner)(fl_owner_t); void (*lm_put_owner)(fl_owner_t);
void (*lm_notify)(struct file_lock *); /* unblock callback */ void (*lm_notify)(struct file_lock *); /* unblock callback */
int (*lm_grant)(struct file_lock *, int); int (*lm_grant)(struct file_lock *, int);
bool (*lm_break)(struct file_lock *);
int (*lm_change)(struct file_lock *, int, struct list_head *);
void (*lm_setup)(struct file_lock *, void **);
bool (*lm_breaker_owns_lease)(struct file_lock *);
bool (*lm_lock_expirable)(struct file_lock *cfl); bool (*lm_lock_expirable)(struct file_lock *cfl);
void (*lm_expire_lock)(void); void (*lm_expire_lock)(void);
}; };
struct lease_manager_operations {
bool (*lm_break)(struct file_lease *);
int (*lm_change)(struct file_lease *, int, struct list_head *);
void (*lm_setup)(struct file_lease *, void **);
bool (*lm_breaker_owns_lease)(struct file_lease *);
};
struct lock_manager { struct lock_manager {
struct list_head list; struct list_head list;
/* /*
@ -110,11 +114,6 @@ struct file_lock {
loff_t fl_start; loff_t fl_start;
loff_t fl_end; loff_t fl_end;
struct fasync_struct * fl_fasync; /* for lease break notifications */
/* for lease breaks: */
unsigned long fl_break_time;
unsigned long fl_downgrade_time;
const struct file_lock_operations *fl_ops; /* Callbacks for filesystems */ const struct file_lock_operations *fl_ops; /* Callbacks for filesystems */
const struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */ const struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */
union { union {
@ -131,6 +130,15 @@ struct file_lock {
} fl_u; } fl_u;
} __randomize_layout; } __randomize_layout;
struct file_lease {
struct file_lock_core c;
struct fasync_struct * fl_fasync; /* for lease break notifications */
/* for lease breaks: */
unsigned long fl_break_time;
unsigned long fl_downgrade_time;
const struct lease_manager_operations *fl_lmops; /* Callbacks for lease managers */
} __randomize_layout;
struct file_lock_context { struct file_lock_context {
spinlock_t flc_lock; spinlock_t flc_lock;
struct list_head flc_flock; struct list_head flc_flock;
@ -179,7 +187,7 @@ static inline void locks_wake_up(struct file_lock *fl)
void locks_free_lock_context(struct inode *inode); void locks_free_lock_context(struct inode *inode);
void locks_free_lock(struct file_lock *fl); void locks_free_lock(struct file_lock *fl);
void locks_init_lock(struct file_lock *); void locks_init_lock(struct file_lock *);
struct file_lock * locks_alloc_lock(void); struct file_lock *locks_alloc_lock(void);
void locks_copy_lock(struct file_lock *, struct file_lock *); void locks_copy_lock(struct file_lock *, struct file_lock *);
void locks_copy_conflock(struct file_lock *, struct file_lock *); void locks_copy_conflock(struct file_lock *, struct file_lock *);
void locks_remove_posix(struct file *, fl_owner_t); void locks_remove_posix(struct file *, fl_owner_t);
@ -193,11 +201,15 @@ int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_l
int vfs_cancel_lock(struct file *filp, struct file_lock *fl); int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
bool vfs_inode_has_locks(struct inode *inode); bool vfs_inode_has_locks(struct inode *inode);
int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl); int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl);
void locks_init_lease(struct file_lease *);
void locks_free_lease(struct file_lease *fl);
struct file_lease *locks_alloc_lease(void);
int __break_lease(struct inode *inode, unsigned int flags, unsigned int type); int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
void lease_get_mtime(struct inode *, struct timespec64 *time); void lease_get_mtime(struct inode *, struct timespec64 *time);
int generic_setlease(struct file *, int, struct file_lock **, void **priv); int generic_setlease(struct file *, int, struct file_lease **, void **priv);
int vfs_setlease(struct file *, int, struct file_lock **, void **); int vfs_setlease(struct file *, int, struct file_lease **, void **);
int lease_modify(struct file_lock *, int, struct list_head *); int lease_modify(struct file_lease *, int, struct list_head *);
struct notifier_block; struct notifier_block;
int lease_register_notifier(struct notifier_block *); int lease_register_notifier(struct notifier_block *);
@ -282,6 +294,11 @@ static inline void locks_init_lock(struct file_lock *fl)
return; return;
} }
static inline void locks_init_lease(struct file_lease *fl)
{
return;
}
static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
{ {
return; return;
@ -356,18 +373,18 @@ static inline void lease_get_mtime(struct inode *inode,
} }
static inline int generic_setlease(struct file *filp, int arg, static inline int generic_setlease(struct file *filp, int arg,
struct file_lock **flp, void **priv) struct file_lease **flp, void **priv)
{ {
return -EINVAL; return -EINVAL;
} }
static inline int vfs_setlease(struct file *filp, int arg, static inline int vfs_setlease(struct file *filp, int arg,
struct file_lock **lease, void **priv) struct file_lease **lease, void **priv)
{ {
return -EINVAL; return -EINVAL;
} }
static inline int lease_modify(struct file_lock *fl, int arg, static inline int lease_modify(struct file_lease *fl, int arg,
struct list_head *dispose) struct list_head *dispose)
{ {
return -EINVAL; return -EINVAL;

View file

@ -1064,6 +1064,7 @@ struct file *get_file_active(struct file **f);
typedef void *fl_owner_t; typedef void *fl_owner_t;
struct file_lock; struct file_lock;
struct file_lease;
/* The following constant reflects the upper bound of the file/locking space */ /* The following constant reflects the upper bound of the file/locking space */
#ifndef OFFSET_MAX #ifndef OFFSET_MAX
@ -2005,7 +2006,7 @@ struct file_operations {
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
void (*splice_eof)(struct file *file); void (*splice_eof)(struct file *file);
int (*setlease)(struct file *, int, struct file_lock **, void **); int (*setlease)(struct file *, int, struct file_lease **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset, long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len); loff_t len);
void (*show_fdinfo)(struct seq_file *m, struct file *f); void (*show_fdinfo)(struct seq_file *m, struct file *f);
@ -3238,7 +3239,7 @@ extern int simple_write_begin(struct file *file, struct address_space *mapping,
extern const struct address_space_operations ram_aops; extern const struct address_space_operations ram_aops;
extern int always_delete_dentry(const struct dentry *); extern int always_delete_dentry(const struct dentry *);
extern struct inode *alloc_anon_inode(struct super_block *); extern struct inode *alloc_anon_inode(struct super_block *);
extern int simple_nosetlease(struct file *, int, struct file_lock **, void **); extern int simple_nosetlease(struct file *, int, struct file_lease **, void **);
extern const struct dentry_operations simple_dentry_operations; extern const struct dentry_operations simple_dentry_operations;
extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags); extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);

View file

@ -117,12 +117,12 @@ DEFINE_EVENT(filelock_lock, flock_lock_inode,
TP_ARGS(inode, fl, ret)); TP_ARGS(inode, fl, ret));
DECLARE_EVENT_CLASS(filelock_lease, DECLARE_EVENT_CLASS(filelock_lease,
TP_PROTO(struct inode *inode, struct file_lock *fl), TP_PROTO(struct inode *inode, struct file_lease *fl),
TP_ARGS(inode, fl), TP_ARGS(inode, fl),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(struct file_lock *, fl) __field(struct file_lease *, fl)
__field(unsigned long, i_ino) __field(unsigned long, i_ino)
__field(dev_t, s_dev) __field(dev_t, s_dev)
__field(struct file_lock_core *, blocker) __field(struct file_lock_core *, blocker)
@ -153,23 +153,23 @@ DECLARE_EVENT_CLASS(filelock_lease,
__entry->break_time, __entry->downgrade_time) __entry->break_time, __entry->downgrade_time)
); );
DEFINE_EVENT(filelock_lease, break_lease_noblock, TP_PROTO(struct inode *inode, struct file_lock *fl), DEFINE_EVENT(filelock_lease, break_lease_noblock, TP_PROTO(struct inode *inode, struct file_lease *fl),
TP_ARGS(inode, fl)); TP_ARGS(inode, fl));
DEFINE_EVENT(filelock_lease, break_lease_block, TP_PROTO(struct inode *inode, struct file_lock *fl), DEFINE_EVENT(filelock_lease, break_lease_block, TP_PROTO(struct inode *inode, struct file_lease *fl),
TP_ARGS(inode, fl)); TP_ARGS(inode, fl));
DEFINE_EVENT(filelock_lease, break_lease_unblock, TP_PROTO(struct inode *inode, struct file_lock *fl), DEFINE_EVENT(filelock_lease, break_lease_unblock, TP_PROTO(struct inode *inode, struct file_lease *fl),
TP_ARGS(inode, fl)); TP_ARGS(inode, fl));
DEFINE_EVENT(filelock_lease, generic_delete_lease, TP_PROTO(struct inode *inode, struct file_lock *fl), DEFINE_EVENT(filelock_lease, generic_delete_lease, TP_PROTO(struct inode *inode, struct file_lease *fl),
TP_ARGS(inode, fl)); TP_ARGS(inode, fl));
DEFINE_EVENT(filelock_lease, time_out_leases, TP_PROTO(struct inode *inode, struct file_lock *fl), DEFINE_EVENT(filelock_lease, time_out_leases, TP_PROTO(struct inode *inode, struct file_lease *fl),
TP_ARGS(inode, fl)); TP_ARGS(inode, fl));
TRACE_EVENT(generic_add_lease, TRACE_EVENT(generic_add_lease,
TP_PROTO(struct inode *inode, struct file_lock *fl), TP_PROTO(struct inode *inode, struct file_lease *fl),
TP_ARGS(inode, fl), TP_ARGS(inode, fl),
@ -204,7 +204,7 @@ TRACE_EVENT(generic_add_lease,
); );
TRACE_EVENT(leases_conflict, TRACE_EVENT(leases_conflict,
TP_PROTO(bool conflict, struct file_lock *lease, struct file_lock *breaker), TP_PROTO(bool conflict, struct file_lease *lease, struct file_lease *breaker),
TP_ARGS(conflict, lease, breaker), TP_ARGS(conflict, lease, breaker),