162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/locks.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * We implement four types of file locks: BSD locks, posix locks, open
662306a36Sopenharmony_ci * file description locks, and leases.  For details about BSD locks,
762306a36Sopenharmony_ci * see the flock(2) man page; for details about the other three, see
862306a36Sopenharmony_ci * fcntl(2).
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Locking conflicts and dependencies:
1262306a36Sopenharmony_ci * If multiple threads attempt to lock the same byte (or flock the same file)
1362306a36Sopenharmony_ci * only one can be granted the lock, and other must wait their turn.
1462306a36Sopenharmony_ci * The first lock has been "applied" or "granted", the others are "waiting"
1562306a36Sopenharmony_ci * and are "blocked" by the "applied" lock..
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * Waiting and applied locks are all kept in trees whose properties are:
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *	- the root of a tree may be an applied or waiting lock.
2062306a36Sopenharmony_ci *	- every other node in the tree is a waiting lock that
2162306a36Sopenharmony_ci *	  conflicts with every ancestor of that node.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Every such tree begins life as a waiting singleton which obviously
2462306a36Sopenharmony_ci * satisfies the above properties.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * The only ways we modify trees preserve these properties:
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci *	1. We may add a new leaf node, but only after first verifying that it
2962306a36Sopenharmony_ci *	   conflicts with all of its ancestors.
3062306a36Sopenharmony_ci *	2. We may remove the root of a tree, creating a new singleton
3162306a36Sopenharmony_ci *	   tree from the root and N new trees rooted in the immediate
3262306a36Sopenharmony_ci *	   children.
3362306a36Sopenharmony_ci *	3. If the root of a tree is not currently an applied lock, we may
3462306a36Sopenharmony_ci *	   apply it (if possible).
3562306a36Sopenharmony_ci *	4. We may upgrade the root of the tree (either extend its range,
3662306a36Sopenharmony_ci *	   or upgrade its entire range from read to write).
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * When an applied lock is modified in a way that reduces or downgrades any
3962306a36Sopenharmony_ci * part of its range, we remove all its children (2 above).  This particularly
4062306a36Sopenharmony_ci * happens when a lock is unlocked.
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * For each of those child trees we "wake up" the thread which is
4362306a36Sopenharmony_ci * waiting for the lock so it can continue handling as follows: if the
4462306a36Sopenharmony_ci * root of the tree applies, we do so (3).  If it doesn't, it must
4562306a36Sopenharmony_ci * conflict with some applied lock.  We remove (wake up) all of its children
4662306a36Sopenharmony_ci * (2), and add it is a new leaf to the tree rooted in the applied
4762306a36Sopenharmony_ci * lock (1).  We then repeat the process recursively with those
4862306a36Sopenharmony_ci * children.
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#include <linux/capability.h>
5362306a36Sopenharmony_ci#include <linux/file.h>
5462306a36Sopenharmony_ci#include <linux/fdtable.h>
5562306a36Sopenharmony_ci#include <linux/filelock.h>
5662306a36Sopenharmony_ci#include <linux/fs.h>
5762306a36Sopenharmony_ci#include <linux/init.h>
5862306a36Sopenharmony_ci#include <linux/security.h>
5962306a36Sopenharmony_ci#include <linux/slab.h>
6062306a36Sopenharmony_ci#include <linux/syscalls.h>
6162306a36Sopenharmony_ci#include <linux/time.h>
6262306a36Sopenharmony_ci#include <linux/rcupdate.h>
6362306a36Sopenharmony_ci#include <linux/pid_namespace.h>
6462306a36Sopenharmony_ci#include <linux/hashtable.h>
6562306a36Sopenharmony_ci#include <linux/percpu.h>
6662306a36Sopenharmony_ci#include <linux/sysctl.h>
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
6962306a36Sopenharmony_ci#include <trace/events/filelock.h>
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#include <linux/uaccess.h>
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define IS_POSIX(fl)	(fl->fl_flags & FL_POSIX)
7462306a36Sopenharmony_ci#define IS_FLOCK(fl)	(fl->fl_flags & FL_FLOCK)
7562306a36Sopenharmony_ci#define IS_LEASE(fl)	(fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
7662306a36Sopenharmony_ci#define IS_OFDLCK(fl)	(fl->fl_flags & FL_OFDLCK)
7762306a36Sopenharmony_ci#define IS_REMOTELCK(fl)	(fl->fl_pid <= 0)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic bool lease_breaking(struct file_lock *fl)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int target_leasetype(struct file_lock *fl)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	if (fl->fl_flags & FL_UNLOCK_PENDING)
8762306a36Sopenharmony_ci		return F_UNLCK;
8862306a36Sopenharmony_ci	if (fl->fl_flags & FL_DOWNGRADE_PENDING)
8962306a36Sopenharmony_ci		return F_RDLCK;
9062306a36Sopenharmony_ci	return fl->fl_type;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int leases_enable = 1;
9462306a36Sopenharmony_cistatic int lease_break_time = 45;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL
9762306a36Sopenharmony_cistatic struct ctl_table locks_sysctls[] = {
9862306a36Sopenharmony_ci	{
9962306a36Sopenharmony_ci		.procname	= "leases-enable",
10062306a36Sopenharmony_ci		.data		= &leases_enable,
10162306a36Sopenharmony_ci		.maxlen		= sizeof(int),
10262306a36Sopenharmony_ci		.mode		= 0644,
10362306a36Sopenharmony_ci		.proc_handler	= proc_dointvec,
10462306a36Sopenharmony_ci	},
10562306a36Sopenharmony_ci#ifdef CONFIG_MMU
10662306a36Sopenharmony_ci	{
10762306a36Sopenharmony_ci		.procname	= "lease-break-time",
10862306a36Sopenharmony_ci		.data		= &lease_break_time,
10962306a36Sopenharmony_ci		.maxlen		= sizeof(int),
11062306a36Sopenharmony_ci		.mode		= 0644,
11162306a36Sopenharmony_ci		.proc_handler	= proc_dointvec,
11262306a36Sopenharmony_ci	},
11362306a36Sopenharmony_ci#endif /* CONFIG_MMU */
11462306a36Sopenharmony_ci	{}
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int __init init_fs_locks_sysctls(void)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	register_sysctl_init("fs", locks_sysctls);
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ciearly_initcall(init_fs_locks_sysctls);
12362306a36Sopenharmony_ci#endif /* CONFIG_SYSCTL */
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/*
12662306a36Sopenharmony_ci * The global file_lock_list is only used for displaying /proc/locks, so we
12762306a36Sopenharmony_ci * keep a list on each CPU, with each list protected by its own spinlock.
12862306a36Sopenharmony_ci * Global serialization is done using file_rwsem.
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * Note that alterations to the list also require that the relevant flc_lock is
13162306a36Sopenharmony_ci * held.
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_cistruct file_lock_list_struct {
13462306a36Sopenharmony_ci	spinlock_t		lock;
13562306a36Sopenharmony_ci	struct hlist_head	hlist;
13662306a36Sopenharmony_ci};
13762306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct file_lock_list_struct, file_lock_list);
13862306a36Sopenharmony_ciDEFINE_STATIC_PERCPU_RWSEM(file_rwsem);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*
14262306a36Sopenharmony_ci * The blocked_hash is used to find POSIX lock loops for deadlock detection.
14362306a36Sopenharmony_ci * It is protected by blocked_lock_lock.
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci * We hash locks by lockowner in order to optimize searching for the lock a
14662306a36Sopenharmony_ci * particular lockowner is waiting on.
14762306a36Sopenharmony_ci *
14862306a36Sopenharmony_ci * FIXME: make this value scale via some heuristic? We generally will want more
14962306a36Sopenharmony_ci * buckets when we have more lockowners holding locks, but that's a little
15062306a36Sopenharmony_ci * difficult to determine without knowing what the workload will look like.
15162306a36Sopenharmony_ci */
15262306a36Sopenharmony_ci#define BLOCKED_HASH_BITS	7
15362306a36Sopenharmony_cistatic DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/*
15662306a36Sopenharmony_ci * This lock protects the blocked_hash. Generally, if you're accessing it, you
15762306a36Sopenharmony_ci * want to be holding this lock.
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * In addition, it also protects the fl->fl_blocked_requests list, and the
16062306a36Sopenharmony_ci * fl->fl_blocker pointer for file_lock structures that are acting as lock
16162306a36Sopenharmony_ci * requests (in contrast to those that are acting as records of acquired locks).
16262306a36Sopenharmony_ci *
16362306a36Sopenharmony_ci * Note that when we acquire this lock in order to change the above fields,
16462306a36Sopenharmony_ci * we often hold the flc_lock as well. In certain cases, when reading the fields
16562306a36Sopenharmony_ci * protected by this lock, we can skip acquiring it iff we already hold the
16662306a36Sopenharmony_ci * flc_lock.
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(blocked_lock_lock);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic struct kmem_cache *flctx_cache __read_mostly;
17162306a36Sopenharmony_cistatic struct kmem_cache *filelock_cache __read_mostly;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic struct file_lock_context *
17462306a36Sopenharmony_cilocks_get_lock_context(struct inode *inode, int type)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct file_lock_context *ctx;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* paired with cmpxchg() below */
17962306a36Sopenharmony_ci	ctx = locks_inode_context(inode);
18062306a36Sopenharmony_ci	if (likely(ctx) || type == F_UNLCK)
18162306a36Sopenharmony_ci		goto out;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	ctx = kmem_cache_alloc(flctx_cache, GFP_KERNEL);
18462306a36Sopenharmony_ci	if (!ctx)
18562306a36Sopenharmony_ci		goto out;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	spin_lock_init(&ctx->flc_lock);
18862306a36Sopenharmony_ci	INIT_LIST_HEAD(&ctx->flc_flock);
18962306a36Sopenharmony_ci	INIT_LIST_HEAD(&ctx->flc_posix);
19062306a36Sopenharmony_ci	INIT_LIST_HEAD(&ctx->flc_lease);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/*
19362306a36Sopenharmony_ci	 * Assign the pointer if it's not already assigned. If it is, then
19462306a36Sopenharmony_ci	 * free the context we just allocated.
19562306a36Sopenharmony_ci	 */
19662306a36Sopenharmony_ci	if (cmpxchg(&inode->i_flctx, NULL, ctx)) {
19762306a36Sopenharmony_ci		kmem_cache_free(flctx_cache, ctx);
19862306a36Sopenharmony_ci		ctx = locks_inode_context(inode);
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ciout:
20162306a36Sopenharmony_ci	trace_locks_get_lock_context(inode, type, ctx);
20262306a36Sopenharmony_ci	return ctx;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic void
20662306a36Sopenharmony_cilocks_dump_ctx_list(struct list_head *list, char *list_type)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct file_lock *fl;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	list_for_each_entry(fl, list, fl_list) {
21162306a36Sopenharmony_ci		pr_warn("%s: fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u\n", list_type, fl->fl_owner, fl->fl_flags, fl->fl_type, fl->fl_pid);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic void
21662306a36Sopenharmony_cilocks_check_ctx_lists(struct inode *inode)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	struct file_lock_context *ctx = inode->i_flctx;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (unlikely(!list_empty(&ctx->flc_flock) ||
22162306a36Sopenharmony_ci		     !list_empty(&ctx->flc_posix) ||
22262306a36Sopenharmony_ci		     !list_empty(&ctx->flc_lease))) {
22362306a36Sopenharmony_ci		pr_warn("Leaked locks on dev=0x%x:0x%x ino=0x%lx:\n",
22462306a36Sopenharmony_ci			MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev),
22562306a36Sopenharmony_ci			inode->i_ino);
22662306a36Sopenharmony_ci		locks_dump_ctx_list(&ctx->flc_flock, "FLOCK");
22762306a36Sopenharmony_ci		locks_dump_ctx_list(&ctx->flc_posix, "POSIX");
22862306a36Sopenharmony_ci		locks_dump_ctx_list(&ctx->flc_lease, "LEASE");
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic void
23362306a36Sopenharmony_cilocks_check_ctx_file_list(struct file *filp, struct list_head *list,
23462306a36Sopenharmony_ci				char *list_type)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	struct file_lock *fl;
23762306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	list_for_each_entry(fl, list, fl_list)
24062306a36Sopenharmony_ci		if (fl->fl_file == filp)
24162306a36Sopenharmony_ci			pr_warn("Leaked %s lock on dev=0x%x:0x%x ino=0x%lx "
24262306a36Sopenharmony_ci				" fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u\n",
24362306a36Sopenharmony_ci				list_type, MAJOR(inode->i_sb->s_dev),
24462306a36Sopenharmony_ci				MINOR(inode->i_sb->s_dev), inode->i_ino,
24562306a36Sopenharmony_ci				fl->fl_owner, fl->fl_flags, fl->fl_type, fl->fl_pid);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_civoid
24962306a36Sopenharmony_cilocks_free_lock_context(struct inode *inode)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct file_lock_context *ctx = locks_inode_context(inode);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (unlikely(ctx)) {
25462306a36Sopenharmony_ci		locks_check_ctx_lists(inode);
25562306a36Sopenharmony_ci		kmem_cache_free(flctx_cache, ctx);
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic void locks_init_lock_heads(struct file_lock *fl)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	INIT_HLIST_NODE(&fl->fl_link);
26262306a36Sopenharmony_ci	INIT_LIST_HEAD(&fl->fl_list);
26362306a36Sopenharmony_ci	INIT_LIST_HEAD(&fl->fl_blocked_requests);
26462306a36Sopenharmony_ci	INIT_LIST_HEAD(&fl->fl_blocked_member);
26562306a36Sopenharmony_ci	init_waitqueue_head(&fl->fl_wait);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/* Allocate an empty lock structure. */
26962306a36Sopenharmony_cistruct file_lock *locks_alloc_lock(void)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct file_lock *fl = kmem_cache_zalloc(filelock_cache, GFP_KERNEL);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (fl)
27462306a36Sopenharmony_ci		locks_init_lock_heads(fl);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return fl;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_alloc_lock);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_civoid locks_release_private(struct file_lock *fl)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	BUG_ON(waitqueue_active(&fl->fl_wait));
28362306a36Sopenharmony_ci	BUG_ON(!list_empty(&fl->fl_list));
28462306a36Sopenharmony_ci	BUG_ON(!list_empty(&fl->fl_blocked_requests));
28562306a36Sopenharmony_ci	BUG_ON(!list_empty(&fl->fl_blocked_member));
28662306a36Sopenharmony_ci	BUG_ON(!hlist_unhashed(&fl->fl_link));
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (fl->fl_ops) {
28962306a36Sopenharmony_ci		if (fl->fl_ops->fl_release_private)
29062306a36Sopenharmony_ci			fl->fl_ops->fl_release_private(fl);
29162306a36Sopenharmony_ci		fl->fl_ops = NULL;
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (fl->fl_lmops) {
29562306a36Sopenharmony_ci		if (fl->fl_lmops->lm_put_owner) {
29662306a36Sopenharmony_ci			fl->fl_lmops->lm_put_owner(fl->fl_owner);
29762306a36Sopenharmony_ci			fl->fl_owner = NULL;
29862306a36Sopenharmony_ci		}
29962306a36Sopenharmony_ci		fl->fl_lmops = NULL;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_release_private);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/**
30562306a36Sopenharmony_ci * locks_owner_has_blockers - Check for blocking lock requests
30662306a36Sopenharmony_ci * @flctx: file lock context
30762306a36Sopenharmony_ci * @owner: lock owner
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Return values:
31062306a36Sopenharmony_ci *   %true: @owner has at least one blocker
31162306a36Sopenharmony_ci *   %false: @owner has no blockers
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_cibool locks_owner_has_blockers(struct file_lock_context *flctx,
31462306a36Sopenharmony_ci		fl_owner_t owner)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct file_lock *fl;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	spin_lock(&flctx->flc_lock);
31962306a36Sopenharmony_ci	list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
32062306a36Sopenharmony_ci		if (fl->fl_owner != owner)
32162306a36Sopenharmony_ci			continue;
32262306a36Sopenharmony_ci		if (!list_empty(&fl->fl_blocked_requests)) {
32362306a36Sopenharmony_ci			spin_unlock(&flctx->flc_lock);
32462306a36Sopenharmony_ci			return true;
32562306a36Sopenharmony_ci		}
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci	spin_unlock(&flctx->flc_lock);
32862306a36Sopenharmony_ci	return false;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_owner_has_blockers);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci/* Free a lock which is not in use. */
33362306a36Sopenharmony_civoid locks_free_lock(struct file_lock *fl)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	locks_release_private(fl);
33662306a36Sopenharmony_ci	kmem_cache_free(filelock_cache, fl);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ciEXPORT_SYMBOL(locks_free_lock);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic void
34162306a36Sopenharmony_cilocks_dispose_list(struct list_head *dispose)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct file_lock *fl;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	while (!list_empty(dispose)) {
34662306a36Sopenharmony_ci		fl = list_first_entry(dispose, struct file_lock, fl_list);
34762306a36Sopenharmony_ci		list_del_init(&fl->fl_list);
34862306a36Sopenharmony_ci		locks_free_lock(fl);
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_civoid locks_init_lock(struct file_lock *fl)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	memset(fl, 0, sizeof(struct file_lock));
35562306a36Sopenharmony_ci	locks_init_lock_heads(fl);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ciEXPORT_SYMBOL(locks_init_lock);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/*
36062306a36Sopenharmony_ci * Initialize a new lock from an existing file_lock structure.
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_civoid locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	new->fl_owner = fl->fl_owner;
36562306a36Sopenharmony_ci	new->fl_pid = fl->fl_pid;
36662306a36Sopenharmony_ci	new->fl_file = NULL;
36762306a36Sopenharmony_ci	new->fl_flags = fl->fl_flags;
36862306a36Sopenharmony_ci	new->fl_type = fl->fl_type;
36962306a36Sopenharmony_ci	new->fl_start = fl->fl_start;
37062306a36Sopenharmony_ci	new->fl_end = fl->fl_end;
37162306a36Sopenharmony_ci	new->fl_lmops = fl->fl_lmops;
37262306a36Sopenharmony_ci	new->fl_ops = NULL;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (fl->fl_lmops) {
37562306a36Sopenharmony_ci		if (fl->fl_lmops->lm_get_owner)
37662306a36Sopenharmony_ci			fl->fl_lmops->lm_get_owner(fl->fl_owner);
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ciEXPORT_SYMBOL(locks_copy_conflock);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_civoid locks_copy_lock(struct file_lock *new, struct file_lock *fl)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	/* "new" must be a freshly-initialized lock */
38462306a36Sopenharmony_ci	WARN_ON_ONCE(new->fl_ops);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	locks_copy_conflock(new, fl);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	new->fl_file = fl->fl_file;
38962306a36Sopenharmony_ci	new->fl_ops = fl->fl_ops;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (fl->fl_ops) {
39262306a36Sopenharmony_ci		if (fl->fl_ops->fl_copy_lock)
39362306a36Sopenharmony_ci			fl->fl_ops->fl_copy_lock(new, fl);
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ciEXPORT_SYMBOL(locks_copy_lock);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic void locks_move_blocks(struct file_lock *new, struct file_lock *fl)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	struct file_lock *f;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/*
40362306a36Sopenharmony_ci	 * As ctx->flc_lock is held, new requests cannot be added to
40462306a36Sopenharmony_ci	 * ->fl_blocked_requests, so we don't need a lock to check if it
40562306a36Sopenharmony_ci	 * is empty.
40662306a36Sopenharmony_ci	 */
40762306a36Sopenharmony_ci	if (list_empty(&fl->fl_blocked_requests))
40862306a36Sopenharmony_ci		return;
40962306a36Sopenharmony_ci	spin_lock(&blocked_lock_lock);
41062306a36Sopenharmony_ci	list_splice_init(&fl->fl_blocked_requests, &new->fl_blocked_requests);
41162306a36Sopenharmony_ci	list_for_each_entry(f, &new->fl_blocked_requests, fl_blocked_member)
41262306a36Sopenharmony_ci		f->fl_blocker = new;
41362306a36Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic inline int flock_translate_cmd(int cmd) {
41762306a36Sopenharmony_ci	switch (cmd) {
41862306a36Sopenharmony_ci	case LOCK_SH:
41962306a36Sopenharmony_ci		return F_RDLCK;
42062306a36Sopenharmony_ci	case LOCK_EX:
42162306a36Sopenharmony_ci		return F_WRLCK;
42262306a36Sopenharmony_ci	case LOCK_UN:
42362306a36Sopenharmony_ci		return F_UNLCK;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci	return -EINVAL;
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci/* Fill in a file_lock structure with an appropriate FLOCK lock. */
42962306a36Sopenharmony_cistatic void flock_make_lock(struct file *filp, struct file_lock *fl, int type)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	locks_init_lock(fl);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	fl->fl_file = filp;
43462306a36Sopenharmony_ci	fl->fl_owner = filp;
43562306a36Sopenharmony_ci	fl->fl_pid = current->tgid;
43662306a36Sopenharmony_ci	fl->fl_flags = FL_FLOCK;
43762306a36Sopenharmony_ci	fl->fl_type = type;
43862306a36Sopenharmony_ci	fl->fl_end = OFFSET_MAX;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic int assign_type(struct file_lock *fl, int type)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	switch (type) {
44462306a36Sopenharmony_ci	case F_RDLCK:
44562306a36Sopenharmony_ci	case F_WRLCK:
44662306a36Sopenharmony_ci	case F_UNLCK:
44762306a36Sopenharmony_ci		fl->fl_type = type;
44862306a36Sopenharmony_ci		break;
44962306a36Sopenharmony_ci	default:
45062306a36Sopenharmony_ci		return -EINVAL;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	return 0;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
45662306a36Sopenharmony_ci				 struct flock64 *l)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	switch (l->l_whence) {
45962306a36Sopenharmony_ci	case SEEK_SET:
46062306a36Sopenharmony_ci		fl->fl_start = 0;
46162306a36Sopenharmony_ci		break;
46262306a36Sopenharmony_ci	case SEEK_CUR:
46362306a36Sopenharmony_ci		fl->fl_start = filp->f_pos;
46462306a36Sopenharmony_ci		break;
46562306a36Sopenharmony_ci	case SEEK_END:
46662306a36Sopenharmony_ci		fl->fl_start = i_size_read(file_inode(filp));
46762306a36Sopenharmony_ci		break;
46862306a36Sopenharmony_ci	default:
46962306a36Sopenharmony_ci		return -EINVAL;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci	if (l->l_start > OFFSET_MAX - fl->fl_start)
47262306a36Sopenharmony_ci		return -EOVERFLOW;
47362306a36Sopenharmony_ci	fl->fl_start += l->l_start;
47462306a36Sopenharmony_ci	if (fl->fl_start < 0)
47562306a36Sopenharmony_ci		return -EINVAL;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* POSIX-1996 leaves the case l->l_len < 0 undefined;
47862306a36Sopenharmony_ci	   POSIX-2001 defines it. */
47962306a36Sopenharmony_ci	if (l->l_len > 0) {
48062306a36Sopenharmony_ci		if (l->l_len - 1 > OFFSET_MAX - fl->fl_start)
48162306a36Sopenharmony_ci			return -EOVERFLOW;
48262306a36Sopenharmony_ci		fl->fl_end = fl->fl_start + (l->l_len - 1);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	} else if (l->l_len < 0) {
48562306a36Sopenharmony_ci		if (fl->fl_start + l->l_len < 0)
48662306a36Sopenharmony_ci			return -EINVAL;
48762306a36Sopenharmony_ci		fl->fl_end = fl->fl_start - 1;
48862306a36Sopenharmony_ci		fl->fl_start += l->l_len;
48962306a36Sopenharmony_ci	} else
49062306a36Sopenharmony_ci		fl->fl_end = OFFSET_MAX;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	fl->fl_owner = current->files;
49362306a36Sopenharmony_ci	fl->fl_pid = current->tgid;
49462306a36Sopenharmony_ci	fl->fl_file = filp;
49562306a36Sopenharmony_ci	fl->fl_flags = FL_POSIX;
49662306a36Sopenharmony_ci	fl->fl_ops = NULL;
49762306a36Sopenharmony_ci	fl->fl_lmops = NULL;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	return assign_type(fl, l->l_type);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
50362306a36Sopenharmony_ci * style lock.
50462306a36Sopenharmony_ci */
50562306a36Sopenharmony_cistatic int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
50662306a36Sopenharmony_ci			       struct flock *l)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct flock64 ll = {
50962306a36Sopenharmony_ci		.l_type = l->l_type,
51062306a36Sopenharmony_ci		.l_whence = l->l_whence,
51162306a36Sopenharmony_ci		.l_start = l->l_start,
51262306a36Sopenharmony_ci		.l_len = l->l_len,
51362306a36Sopenharmony_ci	};
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	return flock64_to_posix_lock(filp, fl, &ll);
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci/* default lease lock manager operations */
51962306a36Sopenharmony_cistatic bool
52062306a36Sopenharmony_cilease_break_callback(struct file_lock *fl)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
52362306a36Sopenharmony_ci	return false;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic void
52762306a36Sopenharmony_cilease_setup(struct file_lock *fl, void **priv)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct file *filp = fl->fl_file;
53062306a36Sopenharmony_ci	struct fasync_struct *fa = *priv;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/*
53362306a36Sopenharmony_ci	 * fasync_insert_entry() returns the old entry if any. If there was no
53462306a36Sopenharmony_ci	 * old entry, then it used "priv" and inserted it into the fasync list.
53562306a36Sopenharmony_ci	 * Clear the pointer to indicate that it shouldn't be freed.
53662306a36Sopenharmony_ci	 */
53762306a36Sopenharmony_ci	if (!fasync_insert_entry(fa->fa_fd, filp, &fl->fl_fasync, fa))
53862306a36Sopenharmony_ci		*priv = NULL;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	__f_setown(filp, task_pid(current), PIDTYPE_TGID, 0);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic const struct lock_manager_operations lease_manager_ops = {
54462306a36Sopenharmony_ci	.lm_break = lease_break_callback,
54562306a36Sopenharmony_ci	.lm_change = lease_modify,
54662306a36Sopenharmony_ci	.lm_setup = lease_setup,
54762306a36Sopenharmony_ci};
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci/*
55062306a36Sopenharmony_ci * Initialize a lease, use the default lock manager operations
55162306a36Sopenharmony_ci */
55262306a36Sopenharmony_cistatic int lease_init(struct file *filp, int type, struct file_lock *fl)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	if (assign_type(fl, type) != 0)
55562306a36Sopenharmony_ci		return -EINVAL;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	fl->fl_owner = filp;
55862306a36Sopenharmony_ci	fl->fl_pid = current->tgid;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	fl->fl_file = filp;
56162306a36Sopenharmony_ci	fl->fl_flags = FL_LEASE;
56262306a36Sopenharmony_ci	fl->fl_start = 0;
56362306a36Sopenharmony_ci	fl->fl_end = OFFSET_MAX;
56462306a36Sopenharmony_ci	fl->fl_ops = NULL;
56562306a36Sopenharmony_ci	fl->fl_lmops = &lease_manager_ops;
56662306a36Sopenharmony_ci	return 0;
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci/* Allocate a file_lock initialised to this type of lease */
57062306a36Sopenharmony_cistatic struct file_lock *lease_alloc(struct file *filp, int type)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	struct file_lock *fl = locks_alloc_lock();
57362306a36Sopenharmony_ci	int error = -ENOMEM;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (fl == NULL)
57662306a36Sopenharmony_ci		return ERR_PTR(error);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	error = lease_init(filp, type, fl);
57962306a36Sopenharmony_ci	if (error) {
58062306a36Sopenharmony_ci		locks_free_lock(fl);
58162306a36Sopenharmony_ci		return ERR_PTR(error);
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci	return fl;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci/* Check if two locks overlap each other.
58762306a36Sopenharmony_ci */
58862306a36Sopenharmony_cistatic inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	return ((fl1->fl_end >= fl2->fl_start) &&
59162306a36Sopenharmony_ci		(fl2->fl_end >= fl1->fl_start));
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/*
59562306a36Sopenharmony_ci * Check whether two locks have the same owner.
59662306a36Sopenharmony_ci */
59762306a36Sopenharmony_cistatic int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	return fl1->fl_owner == fl2->fl_owner;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci/* Must be called with the flc_lock held! */
60362306a36Sopenharmony_cistatic void locks_insert_global_locks(struct file_lock *fl)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct file_lock_list_struct *fll = this_cpu_ptr(&file_lock_list);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	percpu_rwsem_assert_held(&file_rwsem);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	spin_lock(&fll->lock);
61062306a36Sopenharmony_ci	fl->fl_link_cpu = smp_processor_id();
61162306a36Sopenharmony_ci	hlist_add_head(&fl->fl_link, &fll->hlist);
61262306a36Sopenharmony_ci	spin_unlock(&fll->lock);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci/* Must be called with the flc_lock held! */
61662306a36Sopenharmony_cistatic void locks_delete_global_locks(struct file_lock *fl)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	struct file_lock_list_struct *fll;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	percpu_rwsem_assert_held(&file_rwsem);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/*
62362306a36Sopenharmony_ci	 * Avoid taking lock if already unhashed. This is safe since this check
62462306a36Sopenharmony_ci	 * is done while holding the flc_lock, and new insertions into the list
62562306a36Sopenharmony_ci	 * also require that it be held.
62662306a36Sopenharmony_ci	 */
62762306a36Sopenharmony_ci	if (hlist_unhashed(&fl->fl_link))
62862306a36Sopenharmony_ci		return;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	fll = per_cpu_ptr(&file_lock_list, fl->fl_link_cpu);
63162306a36Sopenharmony_ci	spin_lock(&fll->lock);
63262306a36Sopenharmony_ci	hlist_del_init(&fl->fl_link);
63362306a36Sopenharmony_ci	spin_unlock(&fll->lock);
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic unsigned long
63762306a36Sopenharmony_ciposix_owner_key(struct file_lock *fl)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	return (unsigned long)fl->fl_owner;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic void locks_insert_global_blocked(struct file_lock *waiter)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	lockdep_assert_held(&blocked_lock_lock);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter));
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic void locks_delete_global_blocked(struct file_lock *waiter)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	lockdep_assert_held(&blocked_lock_lock);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	hash_del(&waiter->fl_link);
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci/* Remove waiter from blocker's block list.
65762306a36Sopenharmony_ci * When blocker ends up pointing to itself then the list is empty.
65862306a36Sopenharmony_ci *
65962306a36Sopenharmony_ci * Must be called with blocked_lock_lock held.
66062306a36Sopenharmony_ci */
66162306a36Sopenharmony_cistatic void __locks_delete_block(struct file_lock *waiter)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	locks_delete_global_blocked(waiter);
66462306a36Sopenharmony_ci	list_del_init(&waiter->fl_blocked_member);
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void __locks_wake_up_blocks(struct file_lock *blocker)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	while (!list_empty(&blocker->fl_blocked_requests)) {
67062306a36Sopenharmony_ci		struct file_lock *waiter;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci		waiter = list_first_entry(&blocker->fl_blocked_requests,
67362306a36Sopenharmony_ci					  struct file_lock, fl_blocked_member);
67462306a36Sopenharmony_ci		__locks_delete_block(waiter);
67562306a36Sopenharmony_ci		if (waiter->fl_lmops && waiter->fl_lmops->lm_notify)
67662306a36Sopenharmony_ci			waiter->fl_lmops->lm_notify(waiter);
67762306a36Sopenharmony_ci		else
67862306a36Sopenharmony_ci			wake_up(&waiter->fl_wait);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		/*
68162306a36Sopenharmony_ci		 * The setting of fl_blocker to NULL marks the "done"
68262306a36Sopenharmony_ci		 * point in deleting a block. Paired with acquire at the top
68362306a36Sopenharmony_ci		 * of locks_delete_block().
68462306a36Sopenharmony_ci		 */
68562306a36Sopenharmony_ci		smp_store_release(&waiter->fl_blocker, NULL);
68662306a36Sopenharmony_ci	}
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci/**
69062306a36Sopenharmony_ci *	locks_delete_block - stop waiting for a file lock
69162306a36Sopenharmony_ci *	@waiter: the lock which was waiting
69262306a36Sopenharmony_ci *
69362306a36Sopenharmony_ci *	lockd/nfsd need to disconnect the lock while working on it.
69462306a36Sopenharmony_ci */
69562306a36Sopenharmony_ciint locks_delete_block(struct file_lock *waiter)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	int status = -ENOENT;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/*
70062306a36Sopenharmony_ci	 * If fl_blocker is NULL, it won't be set again as this thread "owns"
70162306a36Sopenharmony_ci	 * the lock and is the only one that might try to claim the lock.
70262306a36Sopenharmony_ci	 *
70362306a36Sopenharmony_ci	 * We use acquire/release to manage fl_blocker so that we can
70462306a36Sopenharmony_ci	 * optimize away taking the blocked_lock_lock in many cases.
70562306a36Sopenharmony_ci	 *
70662306a36Sopenharmony_ci	 * The smp_load_acquire guarantees two things:
70762306a36Sopenharmony_ci	 *
70862306a36Sopenharmony_ci	 * 1/ that fl_blocked_requests can be tested locklessly. If something
70962306a36Sopenharmony_ci	 * was recently added to that list it must have been in a locked region
71062306a36Sopenharmony_ci	 * *before* the locked region when fl_blocker was set to NULL.
71162306a36Sopenharmony_ci	 *
71262306a36Sopenharmony_ci	 * 2/ that no other thread is accessing 'waiter', so it is safe to free
71362306a36Sopenharmony_ci	 * it.  __locks_wake_up_blocks is careful not to touch waiter after
71462306a36Sopenharmony_ci	 * fl_blocker is released.
71562306a36Sopenharmony_ci	 *
71662306a36Sopenharmony_ci	 * If a lockless check of fl_blocker shows it to be NULL, we know that
71762306a36Sopenharmony_ci	 * no new locks can be inserted into its fl_blocked_requests list, and
71862306a36Sopenharmony_ci	 * can avoid doing anything further if the list is empty.
71962306a36Sopenharmony_ci	 */
72062306a36Sopenharmony_ci	if (!smp_load_acquire(&waiter->fl_blocker) &&
72162306a36Sopenharmony_ci	    list_empty(&waiter->fl_blocked_requests))
72262306a36Sopenharmony_ci		return status;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	spin_lock(&blocked_lock_lock);
72562306a36Sopenharmony_ci	if (waiter->fl_blocker)
72662306a36Sopenharmony_ci		status = 0;
72762306a36Sopenharmony_ci	__locks_wake_up_blocks(waiter);
72862306a36Sopenharmony_ci	__locks_delete_block(waiter);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	/*
73162306a36Sopenharmony_ci	 * The setting of fl_blocker to NULL marks the "done" point in deleting
73262306a36Sopenharmony_ci	 * a block. Paired with acquire at the top of this function.
73362306a36Sopenharmony_ci	 */
73462306a36Sopenharmony_ci	smp_store_release(&waiter->fl_blocker, NULL);
73562306a36Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
73662306a36Sopenharmony_ci	return status;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ciEXPORT_SYMBOL(locks_delete_block);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci/* Insert waiter into blocker's block list.
74162306a36Sopenharmony_ci * We use a circular list so that processes can be easily woken up in
74262306a36Sopenharmony_ci * the order they blocked. The documentation doesn't require this but
74362306a36Sopenharmony_ci * it seems like the reasonable thing to do.
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci * Must be called with both the flc_lock and blocked_lock_lock held. The
74662306a36Sopenharmony_ci * fl_blocked_requests list itself is protected by the blocked_lock_lock,
74762306a36Sopenharmony_ci * but by ensuring that the flc_lock is also held on insertions we can avoid
74862306a36Sopenharmony_ci * taking the blocked_lock_lock in some cases when we see that the
74962306a36Sopenharmony_ci * fl_blocked_requests list is empty.
75062306a36Sopenharmony_ci *
75162306a36Sopenharmony_ci * Rather than just adding to the list, we check for conflicts with any existing
75262306a36Sopenharmony_ci * waiters, and add beneath any waiter that blocks the new waiter.
75362306a36Sopenharmony_ci * Thus wakeups don't happen until needed.
75462306a36Sopenharmony_ci */
75562306a36Sopenharmony_cistatic void __locks_insert_block(struct file_lock *blocker,
75662306a36Sopenharmony_ci				 struct file_lock *waiter,
75762306a36Sopenharmony_ci				 bool conflict(struct file_lock *,
75862306a36Sopenharmony_ci					       struct file_lock *))
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	struct file_lock *fl;
76162306a36Sopenharmony_ci	BUG_ON(!list_empty(&waiter->fl_blocked_member));
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cinew_blocker:
76462306a36Sopenharmony_ci	list_for_each_entry(fl, &blocker->fl_blocked_requests, fl_blocked_member)
76562306a36Sopenharmony_ci		if (conflict(fl, waiter)) {
76662306a36Sopenharmony_ci			blocker =  fl;
76762306a36Sopenharmony_ci			goto new_blocker;
76862306a36Sopenharmony_ci		}
76962306a36Sopenharmony_ci	waiter->fl_blocker = blocker;
77062306a36Sopenharmony_ci	list_add_tail(&waiter->fl_blocked_member, &blocker->fl_blocked_requests);
77162306a36Sopenharmony_ci	if (IS_POSIX(blocker) && !IS_OFDLCK(blocker))
77262306a36Sopenharmony_ci		locks_insert_global_blocked(waiter);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/* The requests in waiter->fl_blocked are known to conflict with
77562306a36Sopenharmony_ci	 * waiter, but might not conflict with blocker, or the requests
77662306a36Sopenharmony_ci	 * and lock which block it.  So they all need to be woken.
77762306a36Sopenharmony_ci	 */
77862306a36Sopenharmony_ci	__locks_wake_up_blocks(waiter);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci/* Must be called with flc_lock held. */
78262306a36Sopenharmony_cistatic void locks_insert_block(struct file_lock *blocker,
78362306a36Sopenharmony_ci			       struct file_lock *waiter,
78462306a36Sopenharmony_ci			       bool conflict(struct file_lock *,
78562306a36Sopenharmony_ci					     struct file_lock *))
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	spin_lock(&blocked_lock_lock);
78862306a36Sopenharmony_ci	__locks_insert_block(blocker, waiter, conflict);
78962306a36Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci/*
79362306a36Sopenharmony_ci * Wake up processes blocked waiting for blocker.
79462306a36Sopenharmony_ci *
79562306a36Sopenharmony_ci * Must be called with the inode->flc_lock held!
79662306a36Sopenharmony_ci */
79762306a36Sopenharmony_cistatic void locks_wake_up_blocks(struct file_lock *blocker)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	/*
80062306a36Sopenharmony_ci	 * Avoid taking global lock if list is empty. This is safe since new
80162306a36Sopenharmony_ci	 * blocked requests are only added to the list under the flc_lock, and
80262306a36Sopenharmony_ci	 * the flc_lock is always held here. Note that removal from the
80362306a36Sopenharmony_ci	 * fl_blocked_requests list does not require the flc_lock, so we must
80462306a36Sopenharmony_ci	 * recheck list_empty() after acquiring the blocked_lock_lock.
80562306a36Sopenharmony_ci	 */
80662306a36Sopenharmony_ci	if (list_empty(&blocker->fl_blocked_requests))
80762306a36Sopenharmony_ci		return;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	spin_lock(&blocked_lock_lock);
81062306a36Sopenharmony_ci	__locks_wake_up_blocks(blocker);
81162306a36Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic void
81562306a36Sopenharmony_cilocks_insert_lock_ctx(struct file_lock *fl, struct list_head *before)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	list_add_tail(&fl->fl_list, before);
81862306a36Sopenharmony_ci	locks_insert_global_locks(fl);
81962306a36Sopenharmony_ci}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_cistatic void
82262306a36Sopenharmony_cilocks_unlink_lock_ctx(struct file_lock *fl)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	locks_delete_global_locks(fl);
82562306a36Sopenharmony_ci	list_del_init(&fl->fl_list);
82662306a36Sopenharmony_ci	locks_wake_up_blocks(fl);
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic void
83062306a36Sopenharmony_cilocks_delete_lock_ctx(struct file_lock *fl, struct list_head *dispose)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	locks_unlink_lock_ctx(fl);
83362306a36Sopenharmony_ci	if (dispose)
83462306a36Sopenharmony_ci		list_add(&fl->fl_list, dispose);
83562306a36Sopenharmony_ci	else
83662306a36Sopenharmony_ci		locks_free_lock(fl);
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci/* Determine if lock sys_fl blocks lock caller_fl. Common functionality
84062306a36Sopenharmony_ci * checks for shared/exclusive status of overlapping locks.
84162306a36Sopenharmony_ci */
84262306a36Sopenharmony_cistatic bool locks_conflict(struct file_lock *caller_fl,
84362306a36Sopenharmony_ci			   struct file_lock *sys_fl)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	if (sys_fl->fl_type == F_WRLCK)
84662306a36Sopenharmony_ci		return true;
84762306a36Sopenharmony_ci	if (caller_fl->fl_type == F_WRLCK)
84862306a36Sopenharmony_ci		return true;
84962306a36Sopenharmony_ci	return false;
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci/* Determine if lock sys_fl blocks lock caller_fl. POSIX specific
85362306a36Sopenharmony_ci * checking before calling the locks_conflict().
85462306a36Sopenharmony_ci */
85562306a36Sopenharmony_cistatic bool posix_locks_conflict(struct file_lock *caller_fl,
85662306a36Sopenharmony_ci				 struct file_lock *sys_fl)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	/* POSIX locks owned by the same process do not conflict with
85962306a36Sopenharmony_ci	 * each other.
86062306a36Sopenharmony_ci	 */
86162306a36Sopenharmony_ci	if (posix_same_owner(caller_fl, sys_fl))
86262306a36Sopenharmony_ci		return false;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	/* Check whether they overlap */
86562306a36Sopenharmony_ci	if (!locks_overlap(caller_fl, sys_fl))
86662306a36Sopenharmony_ci		return false;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	return locks_conflict(caller_fl, sys_fl);
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci/* Determine if lock sys_fl blocks lock caller_fl. Used on xx_GETLK
87262306a36Sopenharmony_ci * path so checks for additional GETLK-specific things like F_UNLCK.
87362306a36Sopenharmony_ci */
87462306a36Sopenharmony_cistatic bool posix_test_locks_conflict(struct file_lock *caller_fl,
87562306a36Sopenharmony_ci				      struct file_lock *sys_fl)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	/* F_UNLCK checks any locks on the same fd. */
87862306a36Sopenharmony_ci	if (caller_fl->fl_type == F_UNLCK) {
87962306a36Sopenharmony_ci		if (!posix_same_owner(caller_fl, sys_fl))
88062306a36Sopenharmony_ci			return false;
88162306a36Sopenharmony_ci		return locks_overlap(caller_fl, sys_fl);
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci	return posix_locks_conflict(caller_fl, sys_fl);
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific
88762306a36Sopenharmony_ci * checking before calling the locks_conflict().
88862306a36Sopenharmony_ci */
88962306a36Sopenharmony_cistatic bool flock_locks_conflict(struct file_lock *caller_fl,
89062306a36Sopenharmony_ci				 struct file_lock *sys_fl)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	/* FLOCK locks referring to the same filp do not conflict with
89362306a36Sopenharmony_ci	 * each other.
89462306a36Sopenharmony_ci	 */
89562306a36Sopenharmony_ci	if (caller_fl->fl_file == sys_fl->fl_file)
89662306a36Sopenharmony_ci		return false;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	return locks_conflict(caller_fl, sys_fl);
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_civoid
90262306a36Sopenharmony_ciposix_test_lock(struct file *filp, struct file_lock *fl)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	struct file_lock *cfl;
90562306a36Sopenharmony_ci	struct file_lock_context *ctx;
90662306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
90762306a36Sopenharmony_ci	void *owner;
90862306a36Sopenharmony_ci	void (*func)(void);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	ctx = locks_inode_context(inode);
91162306a36Sopenharmony_ci	if (!ctx || list_empty_careful(&ctx->flc_posix)) {
91262306a36Sopenharmony_ci		fl->fl_type = F_UNLCK;
91362306a36Sopenharmony_ci		return;
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ciretry:
91762306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
91862306a36Sopenharmony_ci	list_for_each_entry(cfl, &ctx->flc_posix, fl_list) {
91962306a36Sopenharmony_ci		if (!posix_test_locks_conflict(fl, cfl))
92062306a36Sopenharmony_ci			continue;
92162306a36Sopenharmony_ci		if (cfl->fl_lmops && cfl->fl_lmops->lm_lock_expirable
92262306a36Sopenharmony_ci			&& (*cfl->fl_lmops->lm_lock_expirable)(cfl)) {
92362306a36Sopenharmony_ci			owner = cfl->fl_lmops->lm_mod_owner;
92462306a36Sopenharmony_ci			func = cfl->fl_lmops->lm_expire_lock;
92562306a36Sopenharmony_ci			__module_get(owner);
92662306a36Sopenharmony_ci			spin_unlock(&ctx->flc_lock);
92762306a36Sopenharmony_ci			(*func)();
92862306a36Sopenharmony_ci			module_put(owner);
92962306a36Sopenharmony_ci			goto retry;
93062306a36Sopenharmony_ci		}
93162306a36Sopenharmony_ci		locks_copy_conflock(fl, cfl);
93262306a36Sopenharmony_ci		goto out;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci	fl->fl_type = F_UNLCK;
93562306a36Sopenharmony_ciout:
93662306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
93762306a36Sopenharmony_ci	return;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ciEXPORT_SYMBOL(posix_test_lock);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci/*
94262306a36Sopenharmony_ci * Deadlock detection:
94362306a36Sopenharmony_ci *
94462306a36Sopenharmony_ci * We attempt to detect deadlocks that are due purely to posix file
94562306a36Sopenharmony_ci * locks.
94662306a36Sopenharmony_ci *
94762306a36Sopenharmony_ci * We assume that a task can be waiting for at most one lock at a time.
94862306a36Sopenharmony_ci * So for any acquired lock, the process holding that lock may be
94962306a36Sopenharmony_ci * waiting on at most one other lock.  That lock in turns may be held by
95062306a36Sopenharmony_ci * someone waiting for at most one other lock.  Given a requested lock
95162306a36Sopenharmony_ci * caller_fl which is about to wait for a conflicting lock block_fl, we
95262306a36Sopenharmony_ci * follow this chain of waiters to ensure we are not about to create a
95362306a36Sopenharmony_ci * cycle.
95462306a36Sopenharmony_ci *
95562306a36Sopenharmony_ci * Since we do this before we ever put a process to sleep on a lock, we
95662306a36Sopenharmony_ci * are ensured that there is never a cycle; that is what guarantees that
95762306a36Sopenharmony_ci * the while() loop in posix_locks_deadlock() eventually completes.
95862306a36Sopenharmony_ci *
95962306a36Sopenharmony_ci * Note: the above assumption may not be true when handling lock
96062306a36Sopenharmony_ci * requests from a broken NFS client. It may also fail in the presence
96162306a36Sopenharmony_ci * of tasks (such as posix threads) sharing the same open file table.
96262306a36Sopenharmony_ci * To handle those cases, we just bail out after a few iterations.
96362306a36Sopenharmony_ci *
96462306a36Sopenharmony_ci * For FL_OFDLCK locks, the owner is the filp, not the files_struct.
96562306a36Sopenharmony_ci * Because the owner is not even nominally tied to a thread of
96662306a36Sopenharmony_ci * execution, the deadlock detection below can't reasonably work well. Just
96762306a36Sopenharmony_ci * skip it for those.
96862306a36Sopenharmony_ci *
96962306a36Sopenharmony_ci * In principle, we could do a more limited deadlock detection on FL_OFDLCK
97062306a36Sopenharmony_ci * locks that just checks for the case where two tasks are attempting to
97162306a36Sopenharmony_ci * upgrade from read to write locks on the same inode.
97262306a36Sopenharmony_ci */
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci#define MAX_DEADLK_ITERATIONS 10
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci/* Find a lock that the owner of the given block_fl is blocking on. */
97762306a36Sopenharmony_cistatic struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	struct file_lock *fl;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) {
98262306a36Sopenharmony_ci		if (posix_same_owner(fl, block_fl)) {
98362306a36Sopenharmony_ci			while (fl->fl_blocker)
98462306a36Sopenharmony_ci				fl = fl->fl_blocker;
98562306a36Sopenharmony_ci			return fl;
98662306a36Sopenharmony_ci		}
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci	return NULL;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci/* Must be called with the blocked_lock_lock held! */
99262306a36Sopenharmony_cistatic int posix_locks_deadlock(struct file_lock *caller_fl,
99362306a36Sopenharmony_ci				struct file_lock *block_fl)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	int i = 0;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	lockdep_assert_held(&blocked_lock_lock);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	/*
100062306a36Sopenharmony_ci	 * This deadlock detector can't reasonably detect deadlocks with
100162306a36Sopenharmony_ci	 * FL_OFDLCK locks, since they aren't owned by a process, per-se.
100262306a36Sopenharmony_ci	 */
100362306a36Sopenharmony_ci	if (IS_OFDLCK(caller_fl))
100462306a36Sopenharmony_ci		return 0;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	while ((block_fl = what_owner_is_waiting_for(block_fl))) {
100762306a36Sopenharmony_ci		if (i++ > MAX_DEADLK_ITERATIONS)
100862306a36Sopenharmony_ci			return 0;
100962306a36Sopenharmony_ci		if (posix_same_owner(caller_fl, block_fl))
101062306a36Sopenharmony_ci			return 1;
101162306a36Sopenharmony_ci	}
101262306a36Sopenharmony_ci	return 0;
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
101662306a36Sopenharmony_ci * after any leases, but before any posix locks.
101762306a36Sopenharmony_ci *
101862306a36Sopenharmony_ci * Note that if called with an FL_EXISTS argument, the caller may determine
101962306a36Sopenharmony_ci * whether or not a lock was successfully freed by testing the return
102062306a36Sopenharmony_ci * value for -ENOENT.
102162306a36Sopenharmony_ci */
102262306a36Sopenharmony_cistatic int flock_lock_inode(struct inode *inode, struct file_lock *request)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	struct file_lock *new_fl = NULL;
102562306a36Sopenharmony_ci	struct file_lock *fl;
102662306a36Sopenharmony_ci	struct file_lock_context *ctx;
102762306a36Sopenharmony_ci	int error = 0;
102862306a36Sopenharmony_ci	bool found = false;
102962306a36Sopenharmony_ci	LIST_HEAD(dispose);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	ctx = locks_get_lock_context(inode, request->fl_type);
103262306a36Sopenharmony_ci	if (!ctx) {
103362306a36Sopenharmony_ci		if (request->fl_type != F_UNLCK)
103462306a36Sopenharmony_ci			return -ENOMEM;
103562306a36Sopenharmony_ci		return (request->fl_flags & FL_EXISTS) ? -ENOENT : 0;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {
103962306a36Sopenharmony_ci		new_fl = locks_alloc_lock();
104062306a36Sopenharmony_ci		if (!new_fl)
104162306a36Sopenharmony_ci			return -ENOMEM;
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	percpu_down_read(&file_rwsem);
104562306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
104662306a36Sopenharmony_ci	if (request->fl_flags & FL_ACCESS)
104762306a36Sopenharmony_ci		goto find_conflict;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
105062306a36Sopenharmony_ci		if (request->fl_file != fl->fl_file)
105162306a36Sopenharmony_ci			continue;
105262306a36Sopenharmony_ci		if (request->fl_type == fl->fl_type)
105362306a36Sopenharmony_ci			goto out;
105462306a36Sopenharmony_ci		found = true;
105562306a36Sopenharmony_ci		locks_delete_lock_ctx(fl, &dispose);
105662306a36Sopenharmony_ci		break;
105762306a36Sopenharmony_ci	}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	if (request->fl_type == F_UNLCK) {
106062306a36Sopenharmony_ci		if ((request->fl_flags & FL_EXISTS) && !found)
106162306a36Sopenharmony_ci			error = -ENOENT;
106262306a36Sopenharmony_ci		goto out;
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cifind_conflict:
106662306a36Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
106762306a36Sopenharmony_ci		if (!flock_locks_conflict(request, fl))
106862306a36Sopenharmony_ci			continue;
106962306a36Sopenharmony_ci		error = -EAGAIN;
107062306a36Sopenharmony_ci		if (!(request->fl_flags & FL_SLEEP))
107162306a36Sopenharmony_ci			goto out;
107262306a36Sopenharmony_ci		error = FILE_LOCK_DEFERRED;
107362306a36Sopenharmony_ci		locks_insert_block(fl, request, flock_locks_conflict);
107462306a36Sopenharmony_ci		goto out;
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci	if (request->fl_flags & FL_ACCESS)
107762306a36Sopenharmony_ci		goto out;
107862306a36Sopenharmony_ci	locks_copy_lock(new_fl, request);
107962306a36Sopenharmony_ci	locks_move_blocks(new_fl, request);
108062306a36Sopenharmony_ci	locks_insert_lock_ctx(new_fl, &ctx->flc_flock);
108162306a36Sopenharmony_ci	new_fl = NULL;
108262306a36Sopenharmony_ci	error = 0;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ciout:
108562306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
108662306a36Sopenharmony_ci	percpu_up_read(&file_rwsem);
108762306a36Sopenharmony_ci	if (new_fl)
108862306a36Sopenharmony_ci		locks_free_lock(new_fl);
108962306a36Sopenharmony_ci	locks_dispose_list(&dispose);
109062306a36Sopenharmony_ci	trace_flock_lock_inode(inode, request, error);
109162306a36Sopenharmony_ci	return error;
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_cistatic int posix_lock_inode(struct inode *inode, struct file_lock *request,
109562306a36Sopenharmony_ci			    struct file_lock *conflock)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	struct file_lock *fl, *tmp;
109862306a36Sopenharmony_ci	struct file_lock *new_fl = NULL;
109962306a36Sopenharmony_ci	struct file_lock *new_fl2 = NULL;
110062306a36Sopenharmony_ci	struct file_lock *left = NULL;
110162306a36Sopenharmony_ci	struct file_lock *right = NULL;
110262306a36Sopenharmony_ci	struct file_lock_context *ctx;
110362306a36Sopenharmony_ci	int error;
110462306a36Sopenharmony_ci	bool added = false;
110562306a36Sopenharmony_ci	LIST_HEAD(dispose);
110662306a36Sopenharmony_ci	void *owner;
110762306a36Sopenharmony_ci	void (*func)(void);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	ctx = locks_get_lock_context(inode, request->fl_type);
111062306a36Sopenharmony_ci	if (!ctx)
111162306a36Sopenharmony_ci		return (request->fl_type == F_UNLCK) ? 0 : -ENOMEM;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	/*
111462306a36Sopenharmony_ci	 * We may need two file_lock structures for this operation,
111562306a36Sopenharmony_ci	 * so we get them in advance to avoid races.
111662306a36Sopenharmony_ci	 *
111762306a36Sopenharmony_ci	 * In some cases we can be sure, that no new locks will be needed
111862306a36Sopenharmony_ci	 */
111962306a36Sopenharmony_ci	if (!(request->fl_flags & FL_ACCESS) &&
112062306a36Sopenharmony_ci	    (request->fl_type != F_UNLCK ||
112162306a36Sopenharmony_ci	     request->fl_start != 0 || request->fl_end != OFFSET_MAX)) {
112262306a36Sopenharmony_ci		new_fl = locks_alloc_lock();
112362306a36Sopenharmony_ci		new_fl2 = locks_alloc_lock();
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ciretry:
112762306a36Sopenharmony_ci	percpu_down_read(&file_rwsem);
112862306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
112962306a36Sopenharmony_ci	/*
113062306a36Sopenharmony_ci	 * New lock request. Walk all POSIX locks and look for conflicts. If
113162306a36Sopenharmony_ci	 * there are any, either return error or put the request on the
113262306a36Sopenharmony_ci	 * blocker's list of waiters and the global blocked_hash.
113362306a36Sopenharmony_ci	 */
113462306a36Sopenharmony_ci	if (request->fl_type != F_UNLCK) {
113562306a36Sopenharmony_ci		list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
113662306a36Sopenharmony_ci			if (!posix_locks_conflict(request, fl))
113762306a36Sopenharmony_ci				continue;
113862306a36Sopenharmony_ci			if (fl->fl_lmops && fl->fl_lmops->lm_lock_expirable
113962306a36Sopenharmony_ci				&& (*fl->fl_lmops->lm_lock_expirable)(fl)) {
114062306a36Sopenharmony_ci				owner = fl->fl_lmops->lm_mod_owner;
114162306a36Sopenharmony_ci				func = fl->fl_lmops->lm_expire_lock;
114262306a36Sopenharmony_ci				__module_get(owner);
114362306a36Sopenharmony_ci				spin_unlock(&ctx->flc_lock);
114462306a36Sopenharmony_ci				percpu_up_read(&file_rwsem);
114562306a36Sopenharmony_ci				(*func)();
114662306a36Sopenharmony_ci				module_put(owner);
114762306a36Sopenharmony_ci				goto retry;
114862306a36Sopenharmony_ci			}
114962306a36Sopenharmony_ci			if (conflock)
115062306a36Sopenharmony_ci				locks_copy_conflock(conflock, fl);
115162306a36Sopenharmony_ci			error = -EAGAIN;
115262306a36Sopenharmony_ci			if (!(request->fl_flags & FL_SLEEP))
115362306a36Sopenharmony_ci				goto out;
115462306a36Sopenharmony_ci			/*
115562306a36Sopenharmony_ci			 * Deadlock detection and insertion into the blocked
115662306a36Sopenharmony_ci			 * locks list must be done while holding the same lock!
115762306a36Sopenharmony_ci			 */
115862306a36Sopenharmony_ci			error = -EDEADLK;
115962306a36Sopenharmony_ci			spin_lock(&blocked_lock_lock);
116062306a36Sopenharmony_ci			/*
116162306a36Sopenharmony_ci			 * Ensure that we don't find any locks blocked on this
116262306a36Sopenharmony_ci			 * request during deadlock detection.
116362306a36Sopenharmony_ci			 */
116462306a36Sopenharmony_ci			__locks_wake_up_blocks(request);
116562306a36Sopenharmony_ci			if (likely(!posix_locks_deadlock(request, fl))) {
116662306a36Sopenharmony_ci				error = FILE_LOCK_DEFERRED;
116762306a36Sopenharmony_ci				__locks_insert_block(fl, request,
116862306a36Sopenharmony_ci						     posix_locks_conflict);
116962306a36Sopenharmony_ci			}
117062306a36Sopenharmony_ci			spin_unlock(&blocked_lock_lock);
117162306a36Sopenharmony_ci			goto out;
117262306a36Sopenharmony_ci		}
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/* If we're just looking for a conflict, we're done. */
117662306a36Sopenharmony_ci	error = 0;
117762306a36Sopenharmony_ci	if (request->fl_flags & FL_ACCESS)
117862306a36Sopenharmony_ci		goto out;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* Find the first old lock with the same owner as the new lock */
118162306a36Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
118262306a36Sopenharmony_ci		if (posix_same_owner(request, fl))
118362306a36Sopenharmony_ci			break;
118462306a36Sopenharmony_ci	}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/* Process locks with this owner. */
118762306a36Sopenharmony_ci	list_for_each_entry_safe_from(fl, tmp, &ctx->flc_posix, fl_list) {
118862306a36Sopenharmony_ci		if (!posix_same_owner(request, fl))
118962306a36Sopenharmony_ci			break;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci		/* Detect adjacent or overlapping regions (if same lock type) */
119262306a36Sopenharmony_ci		if (request->fl_type == fl->fl_type) {
119362306a36Sopenharmony_ci			/* In all comparisons of start vs end, use
119462306a36Sopenharmony_ci			 * "start - 1" rather than "end + 1". If end
119562306a36Sopenharmony_ci			 * is OFFSET_MAX, end + 1 will become negative.
119662306a36Sopenharmony_ci			 */
119762306a36Sopenharmony_ci			if (fl->fl_end < request->fl_start - 1)
119862306a36Sopenharmony_ci				continue;
119962306a36Sopenharmony_ci			/* If the next lock in the list has entirely bigger
120062306a36Sopenharmony_ci			 * addresses than the new one, insert the lock here.
120162306a36Sopenharmony_ci			 */
120262306a36Sopenharmony_ci			if (fl->fl_start - 1 > request->fl_end)
120362306a36Sopenharmony_ci				break;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci			/* If we come here, the new and old lock are of the
120662306a36Sopenharmony_ci			 * same type and adjacent or overlapping. Make one
120762306a36Sopenharmony_ci			 * lock yielding from the lower start address of both
120862306a36Sopenharmony_ci			 * locks to the higher end address.
120962306a36Sopenharmony_ci			 */
121062306a36Sopenharmony_ci			if (fl->fl_start > request->fl_start)
121162306a36Sopenharmony_ci				fl->fl_start = request->fl_start;
121262306a36Sopenharmony_ci			else
121362306a36Sopenharmony_ci				request->fl_start = fl->fl_start;
121462306a36Sopenharmony_ci			if (fl->fl_end < request->fl_end)
121562306a36Sopenharmony_ci				fl->fl_end = request->fl_end;
121662306a36Sopenharmony_ci			else
121762306a36Sopenharmony_ci				request->fl_end = fl->fl_end;
121862306a36Sopenharmony_ci			if (added) {
121962306a36Sopenharmony_ci				locks_delete_lock_ctx(fl, &dispose);
122062306a36Sopenharmony_ci				continue;
122162306a36Sopenharmony_ci			}
122262306a36Sopenharmony_ci			request = fl;
122362306a36Sopenharmony_ci			added = true;
122462306a36Sopenharmony_ci		} else {
122562306a36Sopenharmony_ci			/* Processing for different lock types is a bit
122662306a36Sopenharmony_ci			 * more complex.
122762306a36Sopenharmony_ci			 */
122862306a36Sopenharmony_ci			if (fl->fl_end < request->fl_start)
122962306a36Sopenharmony_ci				continue;
123062306a36Sopenharmony_ci			if (fl->fl_start > request->fl_end)
123162306a36Sopenharmony_ci				break;
123262306a36Sopenharmony_ci			if (request->fl_type == F_UNLCK)
123362306a36Sopenharmony_ci				added = true;
123462306a36Sopenharmony_ci			if (fl->fl_start < request->fl_start)
123562306a36Sopenharmony_ci				left = fl;
123662306a36Sopenharmony_ci			/* If the next lock in the list has a higher end
123762306a36Sopenharmony_ci			 * address than the new one, insert the new one here.
123862306a36Sopenharmony_ci			 */
123962306a36Sopenharmony_ci			if (fl->fl_end > request->fl_end) {
124062306a36Sopenharmony_ci				right = fl;
124162306a36Sopenharmony_ci				break;
124262306a36Sopenharmony_ci			}
124362306a36Sopenharmony_ci			if (fl->fl_start >= request->fl_start) {
124462306a36Sopenharmony_ci				/* The new lock completely replaces an old
124562306a36Sopenharmony_ci				 * one (This may happen several times).
124662306a36Sopenharmony_ci				 */
124762306a36Sopenharmony_ci				if (added) {
124862306a36Sopenharmony_ci					locks_delete_lock_ctx(fl, &dispose);
124962306a36Sopenharmony_ci					continue;
125062306a36Sopenharmony_ci				}
125162306a36Sopenharmony_ci				/*
125262306a36Sopenharmony_ci				 * Replace the old lock with new_fl, and
125362306a36Sopenharmony_ci				 * remove the old one. It's safe to do the
125462306a36Sopenharmony_ci				 * insert here since we know that we won't be
125562306a36Sopenharmony_ci				 * using new_fl later, and that the lock is
125662306a36Sopenharmony_ci				 * just replacing an existing lock.
125762306a36Sopenharmony_ci				 */
125862306a36Sopenharmony_ci				error = -ENOLCK;
125962306a36Sopenharmony_ci				if (!new_fl)
126062306a36Sopenharmony_ci					goto out;
126162306a36Sopenharmony_ci				locks_copy_lock(new_fl, request);
126262306a36Sopenharmony_ci				locks_move_blocks(new_fl, request);
126362306a36Sopenharmony_ci				request = new_fl;
126462306a36Sopenharmony_ci				new_fl = NULL;
126562306a36Sopenharmony_ci				locks_insert_lock_ctx(request, &fl->fl_list);
126662306a36Sopenharmony_ci				locks_delete_lock_ctx(fl, &dispose);
126762306a36Sopenharmony_ci				added = true;
126862306a36Sopenharmony_ci			}
126962306a36Sopenharmony_ci		}
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	/*
127362306a36Sopenharmony_ci	 * The above code only modifies existing locks in case of merging or
127462306a36Sopenharmony_ci	 * replacing. If new lock(s) need to be inserted all modifications are
127562306a36Sopenharmony_ci	 * done below this, so it's safe yet to bail out.
127662306a36Sopenharmony_ci	 */
127762306a36Sopenharmony_ci	error = -ENOLCK; /* "no luck" */
127862306a36Sopenharmony_ci	if (right && left == right && !new_fl2)
127962306a36Sopenharmony_ci		goto out;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	error = 0;
128262306a36Sopenharmony_ci	if (!added) {
128362306a36Sopenharmony_ci		if (request->fl_type == F_UNLCK) {
128462306a36Sopenharmony_ci			if (request->fl_flags & FL_EXISTS)
128562306a36Sopenharmony_ci				error = -ENOENT;
128662306a36Sopenharmony_ci			goto out;
128762306a36Sopenharmony_ci		}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci		if (!new_fl) {
129062306a36Sopenharmony_ci			error = -ENOLCK;
129162306a36Sopenharmony_ci			goto out;
129262306a36Sopenharmony_ci		}
129362306a36Sopenharmony_ci		locks_copy_lock(new_fl, request);
129462306a36Sopenharmony_ci		locks_move_blocks(new_fl, request);
129562306a36Sopenharmony_ci		locks_insert_lock_ctx(new_fl, &fl->fl_list);
129662306a36Sopenharmony_ci		fl = new_fl;
129762306a36Sopenharmony_ci		new_fl = NULL;
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci	if (right) {
130062306a36Sopenharmony_ci		if (left == right) {
130162306a36Sopenharmony_ci			/* The new lock breaks the old one in two pieces,
130262306a36Sopenharmony_ci			 * so we have to use the second new lock.
130362306a36Sopenharmony_ci			 */
130462306a36Sopenharmony_ci			left = new_fl2;
130562306a36Sopenharmony_ci			new_fl2 = NULL;
130662306a36Sopenharmony_ci			locks_copy_lock(left, right);
130762306a36Sopenharmony_ci			locks_insert_lock_ctx(left, &fl->fl_list);
130862306a36Sopenharmony_ci		}
130962306a36Sopenharmony_ci		right->fl_start = request->fl_end + 1;
131062306a36Sopenharmony_ci		locks_wake_up_blocks(right);
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci	if (left) {
131362306a36Sopenharmony_ci		left->fl_end = request->fl_start - 1;
131462306a36Sopenharmony_ci		locks_wake_up_blocks(left);
131562306a36Sopenharmony_ci	}
131662306a36Sopenharmony_ci out:
131762306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
131862306a36Sopenharmony_ci	percpu_up_read(&file_rwsem);
131962306a36Sopenharmony_ci	trace_posix_lock_inode(inode, request, error);
132062306a36Sopenharmony_ci	/*
132162306a36Sopenharmony_ci	 * Free any unused locks.
132262306a36Sopenharmony_ci	 */
132362306a36Sopenharmony_ci	if (new_fl)
132462306a36Sopenharmony_ci		locks_free_lock(new_fl);
132562306a36Sopenharmony_ci	if (new_fl2)
132662306a36Sopenharmony_ci		locks_free_lock(new_fl2);
132762306a36Sopenharmony_ci	locks_dispose_list(&dispose);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	return error;
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci/**
133362306a36Sopenharmony_ci * posix_lock_file - Apply a POSIX-style lock to a file
133462306a36Sopenharmony_ci * @filp: The file to apply the lock to
133562306a36Sopenharmony_ci * @fl: The lock to be applied
133662306a36Sopenharmony_ci * @conflock: Place to return a copy of the conflicting lock, if found.
133762306a36Sopenharmony_ci *
133862306a36Sopenharmony_ci * Add a POSIX style lock to a file.
133962306a36Sopenharmony_ci * We merge adjacent & overlapping locks whenever possible.
134062306a36Sopenharmony_ci * POSIX locks are sorted by owner task, then by starting address
134162306a36Sopenharmony_ci *
134262306a36Sopenharmony_ci * Note that if called with an FL_EXISTS argument, the caller may determine
134362306a36Sopenharmony_ci * whether or not a lock was successfully freed by testing the return
134462306a36Sopenharmony_ci * value for -ENOENT.
134562306a36Sopenharmony_ci */
134662306a36Sopenharmony_ciint posix_lock_file(struct file *filp, struct file_lock *fl,
134762306a36Sopenharmony_ci			struct file_lock *conflock)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci	return posix_lock_inode(file_inode(filp), fl, conflock);
135062306a36Sopenharmony_ci}
135162306a36Sopenharmony_ciEXPORT_SYMBOL(posix_lock_file);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci/**
135462306a36Sopenharmony_ci * posix_lock_inode_wait - Apply a POSIX-style lock to a file
135562306a36Sopenharmony_ci * @inode: inode of file to which lock request should be applied
135662306a36Sopenharmony_ci * @fl: The lock to be applied
135762306a36Sopenharmony_ci *
135862306a36Sopenharmony_ci * Apply a POSIX style lock request to an inode.
135962306a36Sopenharmony_ci */
136062306a36Sopenharmony_cistatic int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
136162306a36Sopenharmony_ci{
136262306a36Sopenharmony_ci	int error;
136362306a36Sopenharmony_ci	might_sleep ();
136462306a36Sopenharmony_ci	for (;;) {
136562306a36Sopenharmony_ci		error = posix_lock_inode(inode, fl, NULL);
136662306a36Sopenharmony_ci		if (error != FILE_LOCK_DEFERRED)
136762306a36Sopenharmony_ci			break;
136862306a36Sopenharmony_ci		error = wait_event_interruptible(fl->fl_wait,
136962306a36Sopenharmony_ci					list_empty(&fl->fl_blocked_member));
137062306a36Sopenharmony_ci		if (error)
137162306a36Sopenharmony_ci			break;
137262306a36Sopenharmony_ci	}
137362306a36Sopenharmony_ci	locks_delete_block(fl);
137462306a36Sopenharmony_ci	return error;
137562306a36Sopenharmony_ci}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_cistatic void lease_clear_pending(struct file_lock *fl, int arg)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	switch (arg) {
138062306a36Sopenharmony_ci	case F_UNLCK:
138162306a36Sopenharmony_ci		fl->fl_flags &= ~FL_UNLOCK_PENDING;
138262306a36Sopenharmony_ci		fallthrough;
138362306a36Sopenharmony_ci	case F_RDLCK:
138462306a36Sopenharmony_ci		fl->fl_flags &= ~FL_DOWNGRADE_PENDING;
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci/* We already had a lease on this file; just change its type */
138962306a36Sopenharmony_ciint lease_modify(struct file_lock *fl, int arg, struct list_head *dispose)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	int error = assign_type(fl, arg);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	if (error)
139462306a36Sopenharmony_ci		return error;
139562306a36Sopenharmony_ci	lease_clear_pending(fl, arg);
139662306a36Sopenharmony_ci	locks_wake_up_blocks(fl);
139762306a36Sopenharmony_ci	if (arg == F_UNLCK) {
139862306a36Sopenharmony_ci		struct file *filp = fl->fl_file;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci		f_delown(filp);
140162306a36Sopenharmony_ci		filp->f_owner.signum = 0;
140262306a36Sopenharmony_ci		fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
140362306a36Sopenharmony_ci		if (fl->fl_fasync != NULL) {
140462306a36Sopenharmony_ci			printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
140562306a36Sopenharmony_ci			fl->fl_fasync = NULL;
140662306a36Sopenharmony_ci		}
140762306a36Sopenharmony_ci		locks_delete_lock_ctx(fl, dispose);
140862306a36Sopenharmony_ci	}
140962306a36Sopenharmony_ci	return 0;
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ciEXPORT_SYMBOL(lease_modify);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_cistatic bool past_time(unsigned long then)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	if (!then)
141662306a36Sopenharmony_ci		/* 0 is a special value meaning "this never expires": */
141762306a36Sopenharmony_ci		return false;
141862306a36Sopenharmony_ci	return time_after(jiffies, then);
141962306a36Sopenharmony_ci}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_cistatic void time_out_leases(struct inode *inode, struct list_head *dispose)
142262306a36Sopenharmony_ci{
142362306a36Sopenharmony_ci	struct file_lock_context *ctx = inode->i_flctx;
142462306a36Sopenharmony_ci	struct file_lock *fl, *tmp;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	lockdep_assert_held(&ctx->flc_lock);
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) {
142962306a36Sopenharmony_ci		trace_time_out_leases(inode, fl);
143062306a36Sopenharmony_ci		if (past_time(fl->fl_downgrade_time))
143162306a36Sopenharmony_ci			lease_modify(fl, F_RDLCK, dispose);
143262306a36Sopenharmony_ci		if (past_time(fl->fl_break_time))
143362306a36Sopenharmony_ci			lease_modify(fl, F_UNLCK, dispose);
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_cistatic bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	bool rc;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (lease->fl_lmops->lm_breaker_owns_lease
144262306a36Sopenharmony_ci			&& lease->fl_lmops->lm_breaker_owns_lease(lease))
144362306a36Sopenharmony_ci		return false;
144462306a36Sopenharmony_ci	if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT)) {
144562306a36Sopenharmony_ci		rc = false;
144662306a36Sopenharmony_ci		goto trace;
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci	if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) {
144962306a36Sopenharmony_ci		rc = false;
145062306a36Sopenharmony_ci		goto trace;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	rc = locks_conflict(breaker, lease);
145462306a36Sopenharmony_citrace:
145562306a36Sopenharmony_ci	trace_leases_conflict(rc, lease, breaker);
145662306a36Sopenharmony_ci	return rc;
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_cistatic bool
146062306a36Sopenharmony_ciany_leases_conflict(struct inode *inode, struct file_lock *breaker)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	struct file_lock_context *ctx = inode->i_flctx;
146362306a36Sopenharmony_ci	struct file_lock *fl;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	lockdep_assert_held(&ctx->flc_lock);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
146862306a36Sopenharmony_ci		if (leases_conflict(fl, breaker))
146962306a36Sopenharmony_ci			return true;
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci	return false;
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci/**
147562306a36Sopenharmony_ci *	__break_lease	-	revoke all outstanding leases on file
147662306a36Sopenharmony_ci *	@inode: the inode of the file to return
147762306a36Sopenharmony_ci *	@mode: O_RDONLY: break only write leases; O_WRONLY or O_RDWR:
147862306a36Sopenharmony_ci *	    break all leases
147962306a36Sopenharmony_ci *	@type: FL_LEASE: break leases and delegations; FL_DELEG: break
148062306a36Sopenharmony_ci *	    only delegations
148162306a36Sopenharmony_ci *
148262306a36Sopenharmony_ci *	break_lease (inlined for speed) has checked there already is at least
148362306a36Sopenharmony_ci *	some kind of lock (maybe a lease) on this file.  Leases are broken on
148462306a36Sopenharmony_ci *	a call to open() or truncate().  This function can sleep unless you
148562306a36Sopenharmony_ci *	specified %O_NONBLOCK to your open().
148662306a36Sopenharmony_ci */
148762306a36Sopenharmony_ciint __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
148862306a36Sopenharmony_ci{
148962306a36Sopenharmony_ci	int error = 0;
149062306a36Sopenharmony_ci	struct file_lock_context *ctx;
149162306a36Sopenharmony_ci	struct file_lock *new_fl, *fl, *tmp;
149262306a36Sopenharmony_ci	unsigned long break_time;
149362306a36Sopenharmony_ci	int want_write = (mode & O_ACCMODE) != O_RDONLY;
149462306a36Sopenharmony_ci	LIST_HEAD(dispose);
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK);
149762306a36Sopenharmony_ci	if (IS_ERR(new_fl))
149862306a36Sopenharmony_ci		return PTR_ERR(new_fl);
149962306a36Sopenharmony_ci	new_fl->fl_flags = type;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	/* typically we will check that ctx is non-NULL before calling */
150262306a36Sopenharmony_ci	ctx = locks_inode_context(inode);
150362306a36Sopenharmony_ci	if (!ctx) {
150462306a36Sopenharmony_ci		WARN_ON_ONCE(1);
150562306a36Sopenharmony_ci		goto free_lock;
150662306a36Sopenharmony_ci	}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	percpu_down_read(&file_rwsem);
150962306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	time_out_leases(inode, &dispose);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	if (!any_leases_conflict(inode, new_fl))
151462306a36Sopenharmony_ci		goto out;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	break_time = 0;
151762306a36Sopenharmony_ci	if (lease_break_time > 0) {
151862306a36Sopenharmony_ci		break_time = jiffies + lease_break_time * HZ;
151962306a36Sopenharmony_ci		if (break_time == 0)
152062306a36Sopenharmony_ci			break_time++;	/* so that 0 means no break time */
152162306a36Sopenharmony_ci	}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) {
152462306a36Sopenharmony_ci		if (!leases_conflict(fl, new_fl))
152562306a36Sopenharmony_ci			continue;
152662306a36Sopenharmony_ci		if (want_write) {
152762306a36Sopenharmony_ci			if (fl->fl_flags & FL_UNLOCK_PENDING)
152862306a36Sopenharmony_ci				continue;
152962306a36Sopenharmony_ci			fl->fl_flags |= FL_UNLOCK_PENDING;
153062306a36Sopenharmony_ci			fl->fl_break_time = break_time;
153162306a36Sopenharmony_ci		} else {
153262306a36Sopenharmony_ci			if (lease_breaking(fl))
153362306a36Sopenharmony_ci				continue;
153462306a36Sopenharmony_ci			fl->fl_flags |= FL_DOWNGRADE_PENDING;
153562306a36Sopenharmony_ci			fl->fl_downgrade_time = break_time;
153662306a36Sopenharmony_ci		}
153762306a36Sopenharmony_ci		if (fl->fl_lmops->lm_break(fl))
153862306a36Sopenharmony_ci			locks_delete_lock_ctx(fl, &dispose);
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	if (list_empty(&ctx->flc_lease))
154262306a36Sopenharmony_ci		goto out;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	if (mode & O_NONBLOCK) {
154562306a36Sopenharmony_ci		trace_break_lease_noblock(inode, new_fl);
154662306a36Sopenharmony_ci		error = -EWOULDBLOCK;
154762306a36Sopenharmony_ci		goto out;
154862306a36Sopenharmony_ci	}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_cirestart:
155162306a36Sopenharmony_ci	fl = list_first_entry(&ctx->flc_lease, struct file_lock, fl_list);
155262306a36Sopenharmony_ci	break_time = fl->fl_break_time;
155362306a36Sopenharmony_ci	if (break_time != 0)
155462306a36Sopenharmony_ci		break_time -= jiffies;
155562306a36Sopenharmony_ci	if (break_time == 0)
155662306a36Sopenharmony_ci		break_time++;
155762306a36Sopenharmony_ci	locks_insert_block(fl, new_fl, leases_conflict);
155862306a36Sopenharmony_ci	trace_break_lease_block(inode, new_fl);
155962306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
156062306a36Sopenharmony_ci	percpu_up_read(&file_rwsem);
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	locks_dispose_list(&dispose);
156362306a36Sopenharmony_ci	error = wait_event_interruptible_timeout(new_fl->fl_wait,
156462306a36Sopenharmony_ci					list_empty(&new_fl->fl_blocked_member),
156562306a36Sopenharmony_ci					break_time);
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	percpu_down_read(&file_rwsem);
156862306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
156962306a36Sopenharmony_ci	trace_break_lease_unblock(inode, new_fl);
157062306a36Sopenharmony_ci	locks_delete_block(new_fl);
157162306a36Sopenharmony_ci	if (error >= 0) {
157262306a36Sopenharmony_ci		/*
157362306a36Sopenharmony_ci		 * Wait for the next conflicting lease that has not been
157462306a36Sopenharmony_ci		 * broken yet
157562306a36Sopenharmony_ci		 */
157662306a36Sopenharmony_ci		if (error == 0)
157762306a36Sopenharmony_ci			time_out_leases(inode, &dispose);
157862306a36Sopenharmony_ci		if (any_leases_conflict(inode, new_fl))
157962306a36Sopenharmony_ci			goto restart;
158062306a36Sopenharmony_ci		error = 0;
158162306a36Sopenharmony_ci	}
158262306a36Sopenharmony_ciout:
158362306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
158462306a36Sopenharmony_ci	percpu_up_read(&file_rwsem);
158562306a36Sopenharmony_ci	locks_dispose_list(&dispose);
158662306a36Sopenharmony_cifree_lock:
158762306a36Sopenharmony_ci	locks_free_lock(new_fl);
158862306a36Sopenharmony_ci	return error;
158962306a36Sopenharmony_ci}
159062306a36Sopenharmony_ciEXPORT_SYMBOL(__break_lease);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci/**
159362306a36Sopenharmony_ci *	lease_get_mtime - update modified time of an inode with exclusive lease
159462306a36Sopenharmony_ci *	@inode: the inode
159562306a36Sopenharmony_ci *      @time:  pointer to a timespec which contains the last modified time
159662306a36Sopenharmony_ci *
159762306a36Sopenharmony_ci * This is to force NFS clients to flush their caches for files with
159862306a36Sopenharmony_ci * exclusive leases.  The justification is that if someone has an
159962306a36Sopenharmony_ci * exclusive lease, then they could be modifying it.
160062306a36Sopenharmony_ci */
160162306a36Sopenharmony_civoid lease_get_mtime(struct inode *inode, struct timespec64 *time)
160262306a36Sopenharmony_ci{
160362306a36Sopenharmony_ci	bool has_lease = false;
160462306a36Sopenharmony_ci	struct file_lock_context *ctx;
160562306a36Sopenharmony_ci	struct file_lock *fl;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	ctx = locks_inode_context(inode);
160862306a36Sopenharmony_ci	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
160962306a36Sopenharmony_ci		spin_lock(&ctx->flc_lock);
161062306a36Sopenharmony_ci		fl = list_first_entry_or_null(&ctx->flc_lease,
161162306a36Sopenharmony_ci					      struct file_lock, fl_list);
161262306a36Sopenharmony_ci		if (fl && (fl->fl_type == F_WRLCK))
161362306a36Sopenharmony_ci			has_lease = true;
161462306a36Sopenharmony_ci		spin_unlock(&ctx->flc_lock);
161562306a36Sopenharmony_ci	}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	if (has_lease)
161862306a36Sopenharmony_ci		*time = current_time(inode);
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ciEXPORT_SYMBOL(lease_get_mtime);
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci/**
162362306a36Sopenharmony_ci *	fcntl_getlease - Enquire what lease is currently active
162462306a36Sopenharmony_ci *	@filp: the file
162562306a36Sopenharmony_ci *
162662306a36Sopenharmony_ci *	The value returned by this function will be one of
162762306a36Sopenharmony_ci *	(if no lease break is pending):
162862306a36Sopenharmony_ci *
162962306a36Sopenharmony_ci *	%F_RDLCK to indicate a shared lease is held.
163062306a36Sopenharmony_ci *
163162306a36Sopenharmony_ci *	%F_WRLCK to indicate an exclusive lease is held.
163262306a36Sopenharmony_ci *
163362306a36Sopenharmony_ci *	%F_UNLCK to indicate no lease is held.
163462306a36Sopenharmony_ci *
163562306a36Sopenharmony_ci *	(if a lease break is pending):
163662306a36Sopenharmony_ci *
163762306a36Sopenharmony_ci *	%F_RDLCK to indicate an exclusive lease needs to be
163862306a36Sopenharmony_ci *		changed to a shared lease (or removed).
163962306a36Sopenharmony_ci *
164062306a36Sopenharmony_ci *	%F_UNLCK to indicate the lease needs to be removed.
164162306a36Sopenharmony_ci *
164262306a36Sopenharmony_ci *	XXX: sfr & willy disagree over whether F_INPROGRESS
164362306a36Sopenharmony_ci *	should be returned to userspace.
164462306a36Sopenharmony_ci */
164562306a36Sopenharmony_ciint fcntl_getlease(struct file *filp)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	struct file_lock *fl;
164862306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
164962306a36Sopenharmony_ci	struct file_lock_context *ctx;
165062306a36Sopenharmony_ci	int type = F_UNLCK;
165162306a36Sopenharmony_ci	LIST_HEAD(dispose);
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	ctx = locks_inode_context(inode);
165462306a36Sopenharmony_ci	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
165562306a36Sopenharmony_ci		percpu_down_read(&file_rwsem);
165662306a36Sopenharmony_ci		spin_lock(&ctx->flc_lock);
165762306a36Sopenharmony_ci		time_out_leases(inode, &dispose);
165862306a36Sopenharmony_ci		list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
165962306a36Sopenharmony_ci			if (fl->fl_file != filp)
166062306a36Sopenharmony_ci				continue;
166162306a36Sopenharmony_ci			type = target_leasetype(fl);
166262306a36Sopenharmony_ci			break;
166362306a36Sopenharmony_ci		}
166462306a36Sopenharmony_ci		spin_unlock(&ctx->flc_lock);
166562306a36Sopenharmony_ci		percpu_up_read(&file_rwsem);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci		locks_dispose_list(&dispose);
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci	return type;
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci/**
167362306a36Sopenharmony_ci * check_conflicting_open - see if the given file points to an inode that has
167462306a36Sopenharmony_ci *			    an existing open that would conflict with the
167562306a36Sopenharmony_ci *			    desired lease.
167662306a36Sopenharmony_ci * @filp:	file to check
167762306a36Sopenharmony_ci * @arg:	type of lease that we're trying to acquire
167862306a36Sopenharmony_ci * @flags:	current lock flags
167962306a36Sopenharmony_ci *
168062306a36Sopenharmony_ci * Check to see if there's an existing open fd on this file that would
168162306a36Sopenharmony_ci * conflict with the lease we're trying to set.
168262306a36Sopenharmony_ci */
168362306a36Sopenharmony_cistatic int
168462306a36Sopenharmony_cicheck_conflicting_open(struct file *filp, const int arg, int flags)
168562306a36Sopenharmony_ci{
168662306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
168762306a36Sopenharmony_ci	int self_wcount = 0, self_rcount = 0;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	if (flags & FL_LAYOUT)
169062306a36Sopenharmony_ci		return 0;
169162306a36Sopenharmony_ci	if (flags & FL_DELEG)
169262306a36Sopenharmony_ci		/* We leave these checks to the caller */
169362306a36Sopenharmony_ci		return 0;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	if (arg == F_RDLCK)
169662306a36Sopenharmony_ci		return inode_is_open_for_write(inode) ? -EAGAIN : 0;
169762306a36Sopenharmony_ci	else if (arg != F_WRLCK)
169862306a36Sopenharmony_ci		return 0;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	/*
170162306a36Sopenharmony_ci	 * Make sure that only read/write count is from lease requestor.
170262306a36Sopenharmony_ci	 * Note that this will result in denying write leases when i_writecount
170362306a36Sopenharmony_ci	 * is negative, which is what we want.  (We shouldn't grant write leases
170462306a36Sopenharmony_ci	 * on files open for execution.)
170562306a36Sopenharmony_ci	 */
170662306a36Sopenharmony_ci	if (filp->f_mode & FMODE_WRITE)
170762306a36Sopenharmony_ci		self_wcount = 1;
170862306a36Sopenharmony_ci	else if (filp->f_mode & FMODE_READ)
170962306a36Sopenharmony_ci		self_rcount = 1;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	if (atomic_read(&inode->i_writecount) != self_wcount ||
171262306a36Sopenharmony_ci	    atomic_read(&inode->i_readcount) != self_rcount)
171362306a36Sopenharmony_ci		return -EAGAIN;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	return 0;
171662306a36Sopenharmony_ci}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_cistatic int
171962306a36Sopenharmony_cigeneric_add_lease(struct file *filp, int arg, struct file_lock **flp, void **priv)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	struct file_lock *fl, *my_fl = NULL, *lease;
172262306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
172362306a36Sopenharmony_ci	struct file_lock_context *ctx;
172462306a36Sopenharmony_ci	bool is_deleg = (*flp)->fl_flags & FL_DELEG;
172562306a36Sopenharmony_ci	int error;
172662306a36Sopenharmony_ci	LIST_HEAD(dispose);
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	lease = *flp;
172962306a36Sopenharmony_ci	trace_generic_add_lease(inode, lease);
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	/* Note that arg is never F_UNLCK here */
173262306a36Sopenharmony_ci	ctx = locks_get_lock_context(inode, arg);
173362306a36Sopenharmony_ci	if (!ctx)
173462306a36Sopenharmony_ci		return -ENOMEM;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	/*
173762306a36Sopenharmony_ci	 * In the delegation case we need mutual exclusion with
173862306a36Sopenharmony_ci	 * a number of operations that take the i_mutex.  We trylock
173962306a36Sopenharmony_ci	 * because delegations are an optional optimization, and if
174062306a36Sopenharmony_ci	 * there's some chance of a conflict--we'd rather not
174162306a36Sopenharmony_ci	 * bother, maybe that's a sign this just isn't a good file to
174262306a36Sopenharmony_ci	 * hand out a delegation on.
174362306a36Sopenharmony_ci	 */
174462306a36Sopenharmony_ci	if (is_deleg && !inode_trylock(inode))
174562306a36Sopenharmony_ci		return -EAGAIN;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	percpu_down_read(&file_rwsem);
174862306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
174962306a36Sopenharmony_ci	time_out_leases(inode, &dispose);
175062306a36Sopenharmony_ci	error = check_conflicting_open(filp, arg, lease->fl_flags);
175162306a36Sopenharmony_ci	if (error)
175262306a36Sopenharmony_ci		goto out;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	/*
175562306a36Sopenharmony_ci	 * At this point, we know that if there is an exclusive
175662306a36Sopenharmony_ci	 * lease on this file, then we hold it on this filp
175762306a36Sopenharmony_ci	 * (otherwise our open of this file would have blocked).
175862306a36Sopenharmony_ci	 * And if we are trying to acquire an exclusive lease,
175962306a36Sopenharmony_ci	 * then the file is not open by anyone (including us)
176062306a36Sopenharmony_ci	 * except for this filp.
176162306a36Sopenharmony_ci	 */
176262306a36Sopenharmony_ci	error = -EAGAIN;
176362306a36Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
176462306a36Sopenharmony_ci		if (fl->fl_file == filp &&
176562306a36Sopenharmony_ci		    fl->fl_owner == lease->fl_owner) {
176662306a36Sopenharmony_ci			my_fl = fl;
176762306a36Sopenharmony_ci			continue;
176862306a36Sopenharmony_ci		}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci		/*
177162306a36Sopenharmony_ci		 * No exclusive leases if someone else has a lease on
177262306a36Sopenharmony_ci		 * this file:
177362306a36Sopenharmony_ci		 */
177462306a36Sopenharmony_ci		if (arg == F_WRLCK)
177562306a36Sopenharmony_ci			goto out;
177662306a36Sopenharmony_ci		/*
177762306a36Sopenharmony_ci		 * Modifying our existing lease is OK, but no getting a
177862306a36Sopenharmony_ci		 * new lease if someone else is opening for write:
177962306a36Sopenharmony_ci		 */
178062306a36Sopenharmony_ci		if (fl->fl_flags & FL_UNLOCK_PENDING)
178162306a36Sopenharmony_ci			goto out;
178262306a36Sopenharmony_ci	}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	if (my_fl != NULL) {
178562306a36Sopenharmony_ci		lease = my_fl;
178662306a36Sopenharmony_ci		error = lease->fl_lmops->lm_change(lease, arg, &dispose);
178762306a36Sopenharmony_ci		if (error)
178862306a36Sopenharmony_ci			goto out;
178962306a36Sopenharmony_ci		goto out_setup;
179062306a36Sopenharmony_ci	}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	error = -EINVAL;
179362306a36Sopenharmony_ci	if (!leases_enable)
179462306a36Sopenharmony_ci		goto out;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	locks_insert_lock_ctx(lease, &ctx->flc_lease);
179762306a36Sopenharmony_ci	/*
179862306a36Sopenharmony_ci	 * The check in break_lease() is lockless. It's possible for another
179962306a36Sopenharmony_ci	 * open to race in after we did the earlier check for a conflicting
180062306a36Sopenharmony_ci	 * open but before the lease was inserted. Check again for a
180162306a36Sopenharmony_ci	 * conflicting open and cancel the lease if there is one.
180262306a36Sopenharmony_ci	 *
180362306a36Sopenharmony_ci	 * We also add a barrier here to ensure that the insertion of the lock
180462306a36Sopenharmony_ci	 * precedes these checks.
180562306a36Sopenharmony_ci	 */
180662306a36Sopenharmony_ci	smp_mb();
180762306a36Sopenharmony_ci	error = check_conflicting_open(filp, arg, lease->fl_flags);
180862306a36Sopenharmony_ci	if (error) {
180962306a36Sopenharmony_ci		locks_unlink_lock_ctx(lease);
181062306a36Sopenharmony_ci		goto out;
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ciout_setup:
181462306a36Sopenharmony_ci	if (lease->fl_lmops->lm_setup)
181562306a36Sopenharmony_ci		lease->fl_lmops->lm_setup(lease, priv);
181662306a36Sopenharmony_ciout:
181762306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
181862306a36Sopenharmony_ci	percpu_up_read(&file_rwsem);
181962306a36Sopenharmony_ci	locks_dispose_list(&dispose);
182062306a36Sopenharmony_ci	if (is_deleg)
182162306a36Sopenharmony_ci		inode_unlock(inode);
182262306a36Sopenharmony_ci	if (!error && !my_fl)
182362306a36Sopenharmony_ci		*flp = NULL;
182462306a36Sopenharmony_ci	return error;
182562306a36Sopenharmony_ci}
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_cistatic int generic_delete_lease(struct file *filp, void *owner)
182862306a36Sopenharmony_ci{
182962306a36Sopenharmony_ci	int error = -EAGAIN;
183062306a36Sopenharmony_ci	struct file_lock *fl, *victim = NULL;
183162306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
183262306a36Sopenharmony_ci	struct file_lock_context *ctx;
183362306a36Sopenharmony_ci	LIST_HEAD(dispose);
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	ctx = locks_inode_context(inode);
183662306a36Sopenharmony_ci	if (!ctx) {
183762306a36Sopenharmony_ci		trace_generic_delete_lease(inode, NULL);
183862306a36Sopenharmony_ci		return error;
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	percpu_down_read(&file_rwsem);
184262306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
184362306a36Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
184462306a36Sopenharmony_ci		if (fl->fl_file == filp &&
184562306a36Sopenharmony_ci		    fl->fl_owner == owner) {
184662306a36Sopenharmony_ci			victim = fl;
184762306a36Sopenharmony_ci			break;
184862306a36Sopenharmony_ci		}
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci	trace_generic_delete_lease(inode, victim);
185162306a36Sopenharmony_ci	if (victim)
185262306a36Sopenharmony_ci		error = fl->fl_lmops->lm_change(victim, F_UNLCK, &dispose);
185362306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
185462306a36Sopenharmony_ci	percpu_up_read(&file_rwsem);
185562306a36Sopenharmony_ci	locks_dispose_list(&dispose);
185662306a36Sopenharmony_ci	return error;
185762306a36Sopenharmony_ci}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci/**
186062306a36Sopenharmony_ci *	generic_setlease	-	sets a lease on an open file
186162306a36Sopenharmony_ci *	@filp:	file pointer
186262306a36Sopenharmony_ci *	@arg:	type of lease to obtain
186362306a36Sopenharmony_ci *	@flp:	input - file_lock to use, output - file_lock inserted
186462306a36Sopenharmony_ci *	@priv:	private data for lm_setup (may be NULL if lm_setup
186562306a36Sopenharmony_ci *		doesn't require it)
186662306a36Sopenharmony_ci *
186762306a36Sopenharmony_ci *	The (input) flp->fl_lmops->lm_break function is required
186862306a36Sopenharmony_ci *	by break_lease().
186962306a36Sopenharmony_ci */
187062306a36Sopenharmony_ciint generic_setlease(struct file *filp, int arg, struct file_lock **flp,
187162306a36Sopenharmony_ci			void **priv)
187262306a36Sopenharmony_ci{
187362306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
187462306a36Sopenharmony_ci	vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_idmap(filp), inode);
187562306a36Sopenharmony_ci	int error;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	if ((!vfsuid_eq_kuid(vfsuid, current_fsuid())) && !capable(CAP_LEASE))
187862306a36Sopenharmony_ci		return -EACCES;
187962306a36Sopenharmony_ci	if (!S_ISREG(inode->i_mode))
188062306a36Sopenharmony_ci		return -EINVAL;
188162306a36Sopenharmony_ci	error = security_file_lock(filp, arg);
188262306a36Sopenharmony_ci	if (error)
188362306a36Sopenharmony_ci		return error;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	switch (arg) {
188662306a36Sopenharmony_ci	case F_UNLCK:
188762306a36Sopenharmony_ci		return generic_delete_lease(filp, *priv);
188862306a36Sopenharmony_ci	case F_RDLCK:
188962306a36Sopenharmony_ci	case F_WRLCK:
189062306a36Sopenharmony_ci		if (!(*flp)->fl_lmops->lm_break) {
189162306a36Sopenharmony_ci			WARN_ON_ONCE(1);
189262306a36Sopenharmony_ci			return -ENOLCK;
189362306a36Sopenharmony_ci		}
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci		return generic_add_lease(filp, arg, flp, priv);
189662306a36Sopenharmony_ci	default:
189762306a36Sopenharmony_ci		return -EINVAL;
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ciEXPORT_SYMBOL(generic_setlease);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci/*
190362306a36Sopenharmony_ci * Kernel subsystems can register to be notified on any attempt to set
190462306a36Sopenharmony_ci * a new lease with the lease_notifier_chain. This is used by (e.g.) nfsd
190562306a36Sopenharmony_ci * to close files that it may have cached when there is an attempt to set a
190662306a36Sopenharmony_ci * conflicting lease.
190762306a36Sopenharmony_ci */
190862306a36Sopenharmony_cistatic struct srcu_notifier_head lease_notifier_chain;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_cistatic inline void
191162306a36Sopenharmony_cilease_notifier_chain_init(void)
191262306a36Sopenharmony_ci{
191362306a36Sopenharmony_ci	srcu_init_notifier_head(&lease_notifier_chain);
191462306a36Sopenharmony_ci}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_cistatic inline void
191762306a36Sopenharmony_cisetlease_notifier(int arg, struct file_lock *lease)
191862306a36Sopenharmony_ci{
191962306a36Sopenharmony_ci	if (arg != F_UNLCK)
192062306a36Sopenharmony_ci		srcu_notifier_call_chain(&lease_notifier_chain, arg, lease);
192162306a36Sopenharmony_ci}
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ciint lease_register_notifier(struct notifier_block *nb)
192462306a36Sopenharmony_ci{
192562306a36Sopenharmony_ci	return srcu_notifier_chain_register(&lease_notifier_chain, nb);
192662306a36Sopenharmony_ci}
192762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lease_register_notifier);
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_civoid lease_unregister_notifier(struct notifier_block *nb)
193062306a36Sopenharmony_ci{
193162306a36Sopenharmony_ci	srcu_notifier_chain_unregister(&lease_notifier_chain, nb);
193262306a36Sopenharmony_ci}
193362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lease_unregister_notifier);
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci/**
193662306a36Sopenharmony_ci * vfs_setlease        -       sets a lease on an open file
193762306a36Sopenharmony_ci * @filp:	file pointer
193862306a36Sopenharmony_ci * @arg:	type of lease to obtain
193962306a36Sopenharmony_ci * @lease:	file_lock to use when adding a lease
194062306a36Sopenharmony_ci * @priv:	private info for lm_setup when adding a lease (may be
194162306a36Sopenharmony_ci *		NULL if lm_setup doesn't require it)
194262306a36Sopenharmony_ci *
194362306a36Sopenharmony_ci * Call this to establish a lease on the file. The "lease" argument is not
194462306a36Sopenharmony_ci * used for F_UNLCK requests and may be NULL. For commands that set or alter
194562306a36Sopenharmony_ci * an existing lease, the ``(*lease)->fl_lmops->lm_break`` operation must be
194662306a36Sopenharmony_ci * set; if not, this function will return -ENOLCK (and generate a scary-looking
194762306a36Sopenharmony_ci * stack trace).
194862306a36Sopenharmony_ci *
194962306a36Sopenharmony_ci * The "priv" pointer is passed directly to the lm_setup function as-is. It
195062306a36Sopenharmony_ci * may be NULL if the lm_setup operation doesn't require it.
195162306a36Sopenharmony_ci */
195262306a36Sopenharmony_ciint
195362306a36Sopenharmony_civfs_setlease(struct file *filp, int arg, struct file_lock **lease, void **priv)
195462306a36Sopenharmony_ci{
195562306a36Sopenharmony_ci	if (lease)
195662306a36Sopenharmony_ci		setlease_notifier(arg, *lease);
195762306a36Sopenharmony_ci	if (filp->f_op->setlease)
195862306a36Sopenharmony_ci		return filp->f_op->setlease(filp, arg, lease, priv);
195962306a36Sopenharmony_ci	else
196062306a36Sopenharmony_ci		return generic_setlease(filp, arg, lease, priv);
196162306a36Sopenharmony_ci}
196262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_setlease);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_cistatic int do_fcntl_add_lease(unsigned int fd, struct file *filp, int arg)
196562306a36Sopenharmony_ci{
196662306a36Sopenharmony_ci	struct file_lock *fl;
196762306a36Sopenharmony_ci	struct fasync_struct *new;
196862306a36Sopenharmony_ci	int error;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	fl = lease_alloc(filp, arg);
197162306a36Sopenharmony_ci	if (IS_ERR(fl))
197262306a36Sopenharmony_ci		return PTR_ERR(fl);
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	new = fasync_alloc();
197562306a36Sopenharmony_ci	if (!new) {
197662306a36Sopenharmony_ci		locks_free_lock(fl);
197762306a36Sopenharmony_ci		return -ENOMEM;
197862306a36Sopenharmony_ci	}
197962306a36Sopenharmony_ci	new->fa_fd = fd;
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	error = vfs_setlease(filp, arg, &fl, (void **)&new);
198262306a36Sopenharmony_ci	if (fl)
198362306a36Sopenharmony_ci		locks_free_lock(fl);
198462306a36Sopenharmony_ci	if (new)
198562306a36Sopenharmony_ci		fasync_free(new);
198662306a36Sopenharmony_ci	return error;
198762306a36Sopenharmony_ci}
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci/**
199062306a36Sopenharmony_ci *	fcntl_setlease	-	sets a lease on an open file
199162306a36Sopenharmony_ci *	@fd: open file descriptor
199262306a36Sopenharmony_ci *	@filp: file pointer
199362306a36Sopenharmony_ci *	@arg: type of lease to obtain
199462306a36Sopenharmony_ci *
199562306a36Sopenharmony_ci *	Call this fcntl to establish a lease on the file.
199662306a36Sopenharmony_ci *	Note that you also need to call %F_SETSIG to
199762306a36Sopenharmony_ci *	receive a signal when the lease is broken.
199862306a36Sopenharmony_ci */
199962306a36Sopenharmony_ciint fcntl_setlease(unsigned int fd, struct file *filp, int arg)
200062306a36Sopenharmony_ci{
200162306a36Sopenharmony_ci	if (arg == F_UNLCK)
200262306a36Sopenharmony_ci		return vfs_setlease(filp, F_UNLCK, NULL, (void **)&filp);
200362306a36Sopenharmony_ci	return do_fcntl_add_lease(fd, filp, arg);
200462306a36Sopenharmony_ci}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci/**
200762306a36Sopenharmony_ci * flock_lock_inode_wait - Apply a FLOCK-style lock to a file
200862306a36Sopenharmony_ci * @inode: inode of the file to apply to
200962306a36Sopenharmony_ci * @fl: The lock to be applied
201062306a36Sopenharmony_ci *
201162306a36Sopenharmony_ci * Apply a FLOCK style lock request to an inode.
201262306a36Sopenharmony_ci */
201362306a36Sopenharmony_cistatic int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
201462306a36Sopenharmony_ci{
201562306a36Sopenharmony_ci	int error;
201662306a36Sopenharmony_ci	might_sleep();
201762306a36Sopenharmony_ci	for (;;) {
201862306a36Sopenharmony_ci		error = flock_lock_inode(inode, fl);
201962306a36Sopenharmony_ci		if (error != FILE_LOCK_DEFERRED)
202062306a36Sopenharmony_ci			break;
202162306a36Sopenharmony_ci		error = wait_event_interruptible(fl->fl_wait,
202262306a36Sopenharmony_ci				list_empty(&fl->fl_blocked_member));
202362306a36Sopenharmony_ci		if (error)
202462306a36Sopenharmony_ci			break;
202562306a36Sopenharmony_ci	}
202662306a36Sopenharmony_ci	locks_delete_block(fl);
202762306a36Sopenharmony_ci	return error;
202862306a36Sopenharmony_ci}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci/**
203162306a36Sopenharmony_ci * locks_lock_inode_wait - Apply a lock to an inode
203262306a36Sopenharmony_ci * @inode: inode of the file to apply to
203362306a36Sopenharmony_ci * @fl: The lock to be applied
203462306a36Sopenharmony_ci *
203562306a36Sopenharmony_ci * Apply a POSIX or FLOCK style lock request to an inode.
203662306a36Sopenharmony_ci */
203762306a36Sopenharmony_ciint locks_lock_inode_wait(struct inode *inode, struct file_lock *fl)
203862306a36Sopenharmony_ci{
203962306a36Sopenharmony_ci	int res = 0;
204062306a36Sopenharmony_ci	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
204162306a36Sopenharmony_ci		case FL_POSIX:
204262306a36Sopenharmony_ci			res = posix_lock_inode_wait(inode, fl);
204362306a36Sopenharmony_ci			break;
204462306a36Sopenharmony_ci		case FL_FLOCK:
204562306a36Sopenharmony_ci			res = flock_lock_inode_wait(inode, fl);
204662306a36Sopenharmony_ci			break;
204762306a36Sopenharmony_ci		default:
204862306a36Sopenharmony_ci			BUG();
204962306a36Sopenharmony_ci	}
205062306a36Sopenharmony_ci	return res;
205162306a36Sopenharmony_ci}
205262306a36Sopenharmony_ciEXPORT_SYMBOL(locks_lock_inode_wait);
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci/**
205562306a36Sopenharmony_ci *	sys_flock: - flock() system call.
205662306a36Sopenharmony_ci *	@fd: the file descriptor to lock.
205762306a36Sopenharmony_ci *	@cmd: the type of lock to apply.
205862306a36Sopenharmony_ci *
205962306a36Sopenharmony_ci *	Apply a %FL_FLOCK style lock to an open file descriptor.
206062306a36Sopenharmony_ci *	The @cmd can be one of:
206162306a36Sopenharmony_ci *
206262306a36Sopenharmony_ci *	- %LOCK_SH -- a shared lock.
206362306a36Sopenharmony_ci *	- %LOCK_EX -- an exclusive lock.
206462306a36Sopenharmony_ci *	- %LOCK_UN -- remove an existing lock.
206562306a36Sopenharmony_ci *	- %LOCK_MAND -- a 'mandatory' flock. (DEPRECATED)
206662306a36Sopenharmony_ci *
206762306a36Sopenharmony_ci *	%LOCK_MAND support has been removed from the kernel.
206862306a36Sopenharmony_ci */
206962306a36Sopenharmony_ciSYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
207062306a36Sopenharmony_ci{
207162306a36Sopenharmony_ci	int can_sleep, error, type;
207262306a36Sopenharmony_ci	struct file_lock fl;
207362306a36Sopenharmony_ci	struct fd f;
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	/*
207662306a36Sopenharmony_ci	 * LOCK_MAND locks were broken for a long time in that they never
207762306a36Sopenharmony_ci	 * conflicted with one another and didn't prevent any sort of open,
207862306a36Sopenharmony_ci	 * read or write activity.
207962306a36Sopenharmony_ci	 *
208062306a36Sopenharmony_ci	 * Just ignore these requests now, to preserve legacy behavior, but
208162306a36Sopenharmony_ci	 * throw a warning to let people know that they don't actually work.
208262306a36Sopenharmony_ci	 */
208362306a36Sopenharmony_ci	if (cmd & LOCK_MAND) {
208462306a36Sopenharmony_ci		pr_warn_once("%s(%d): Attempt to set a LOCK_MAND lock via flock(2). This support has been removed and the request ignored.\n", current->comm, current->pid);
208562306a36Sopenharmony_ci		return 0;
208662306a36Sopenharmony_ci	}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	type = flock_translate_cmd(cmd & ~LOCK_NB);
208962306a36Sopenharmony_ci	if (type < 0)
209062306a36Sopenharmony_ci		return type;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	error = -EBADF;
209362306a36Sopenharmony_ci	f = fdget(fd);
209462306a36Sopenharmony_ci	if (!f.file)
209562306a36Sopenharmony_ci		return error;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	if (type != F_UNLCK && !(f.file->f_mode & (FMODE_READ | FMODE_WRITE)))
209862306a36Sopenharmony_ci		goto out_putf;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	flock_make_lock(f.file, &fl, type);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	error = security_file_lock(f.file, fl.fl_type);
210362306a36Sopenharmony_ci	if (error)
210462306a36Sopenharmony_ci		goto out_putf;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	can_sleep = !(cmd & LOCK_NB);
210762306a36Sopenharmony_ci	if (can_sleep)
210862306a36Sopenharmony_ci		fl.fl_flags |= FL_SLEEP;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	if (f.file->f_op->flock)
211162306a36Sopenharmony_ci		error = f.file->f_op->flock(f.file,
211262306a36Sopenharmony_ci					    (can_sleep) ? F_SETLKW : F_SETLK,
211362306a36Sopenharmony_ci					    &fl);
211462306a36Sopenharmony_ci	else
211562306a36Sopenharmony_ci		error = locks_lock_file_wait(f.file, &fl);
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	locks_release_private(&fl);
211862306a36Sopenharmony_ci out_putf:
211962306a36Sopenharmony_ci	fdput(f);
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	return error;
212262306a36Sopenharmony_ci}
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci/**
212562306a36Sopenharmony_ci * vfs_test_lock - test file byte range lock
212662306a36Sopenharmony_ci * @filp: The file to test lock for
212762306a36Sopenharmony_ci * @fl: The lock to test; also used to hold result
212862306a36Sopenharmony_ci *
212962306a36Sopenharmony_ci * Returns -ERRNO on failure.  Indicates presence of conflicting lock by
213062306a36Sopenharmony_ci * setting conf->fl_type to something other than F_UNLCK.
213162306a36Sopenharmony_ci */
213262306a36Sopenharmony_ciint vfs_test_lock(struct file *filp, struct file_lock *fl)
213362306a36Sopenharmony_ci{
213462306a36Sopenharmony_ci	WARN_ON_ONCE(filp != fl->fl_file);
213562306a36Sopenharmony_ci	if (filp->f_op->lock)
213662306a36Sopenharmony_ci		return filp->f_op->lock(filp, F_GETLK, fl);
213762306a36Sopenharmony_ci	posix_test_lock(filp, fl);
213862306a36Sopenharmony_ci	return 0;
213962306a36Sopenharmony_ci}
214062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_test_lock);
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci/**
214362306a36Sopenharmony_ci * locks_translate_pid - translate a file_lock's fl_pid number into a namespace
214462306a36Sopenharmony_ci * @fl: The file_lock who's fl_pid should be translated
214562306a36Sopenharmony_ci * @ns: The namespace into which the pid should be translated
214662306a36Sopenharmony_ci *
214762306a36Sopenharmony_ci * Used to translate a fl_pid into a namespace virtual pid number
214862306a36Sopenharmony_ci */
214962306a36Sopenharmony_cistatic pid_t locks_translate_pid(struct file_lock *fl, struct pid_namespace *ns)
215062306a36Sopenharmony_ci{
215162306a36Sopenharmony_ci	pid_t vnr;
215262306a36Sopenharmony_ci	struct pid *pid;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	if (IS_OFDLCK(fl))
215562306a36Sopenharmony_ci		return -1;
215662306a36Sopenharmony_ci	if (IS_REMOTELCK(fl))
215762306a36Sopenharmony_ci		return fl->fl_pid;
215862306a36Sopenharmony_ci	/*
215962306a36Sopenharmony_ci	 * If the flock owner process is dead and its pid has been already
216062306a36Sopenharmony_ci	 * freed, the translation below won't work, but we still want to show
216162306a36Sopenharmony_ci	 * flock owner pid number in init pidns.
216262306a36Sopenharmony_ci	 */
216362306a36Sopenharmony_ci	if (ns == &init_pid_ns)
216462306a36Sopenharmony_ci		return (pid_t)fl->fl_pid;
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	rcu_read_lock();
216762306a36Sopenharmony_ci	pid = find_pid_ns(fl->fl_pid, &init_pid_ns);
216862306a36Sopenharmony_ci	vnr = pid_nr_ns(pid, ns);
216962306a36Sopenharmony_ci	rcu_read_unlock();
217062306a36Sopenharmony_ci	return vnr;
217162306a36Sopenharmony_ci}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_cistatic int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
217462306a36Sopenharmony_ci{
217562306a36Sopenharmony_ci	flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current));
217662306a36Sopenharmony_ci#if BITS_PER_LONG == 32
217762306a36Sopenharmony_ci	/*
217862306a36Sopenharmony_ci	 * Make sure we can represent the posix lock via
217962306a36Sopenharmony_ci	 * legacy 32bit flock.
218062306a36Sopenharmony_ci	 */
218162306a36Sopenharmony_ci	if (fl->fl_start > OFFT_OFFSET_MAX)
218262306a36Sopenharmony_ci		return -EOVERFLOW;
218362306a36Sopenharmony_ci	if (fl->fl_end != OFFSET_MAX && fl->fl_end > OFFT_OFFSET_MAX)
218462306a36Sopenharmony_ci		return -EOVERFLOW;
218562306a36Sopenharmony_ci#endif
218662306a36Sopenharmony_ci	flock->l_start = fl->fl_start;
218762306a36Sopenharmony_ci	flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
218862306a36Sopenharmony_ci		fl->fl_end - fl->fl_start + 1;
218962306a36Sopenharmony_ci	flock->l_whence = 0;
219062306a36Sopenharmony_ci	flock->l_type = fl->fl_type;
219162306a36Sopenharmony_ci	return 0;
219262306a36Sopenharmony_ci}
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci#if BITS_PER_LONG == 32
219562306a36Sopenharmony_cistatic void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
219662306a36Sopenharmony_ci{
219762306a36Sopenharmony_ci	flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current));
219862306a36Sopenharmony_ci	flock->l_start = fl->fl_start;
219962306a36Sopenharmony_ci	flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
220062306a36Sopenharmony_ci		fl->fl_end - fl->fl_start + 1;
220162306a36Sopenharmony_ci	flock->l_whence = 0;
220262306a36Sopenharmony_ci	flock->l_type = fl->fl_type;
220362306a36Sopenharmony_ci}
220462306a36Sopenharmony_ci#endif
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci/* Report the first existing lock that would conflict with l.
220762306a36Sopenharmony_ci * This implements the F_GETLK command of fcntl().
220862306a36Sopenharmony_ci */
220962306a36Sopenharmony_ciint fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock)
221062306a36Sopenharmony_ci{
221162306a36Sopenharmony_ci	struct file_lock *fl;
221262306a36Sopenharmony_ci	int error;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	fl = locks_alloc_lock();
221562306a36Sopenharmony_ci	if (fl == NULL)
221662306a36Sopenharmony_ci		return -ENOMEM;
221762306a36Sopenharmony_ci	error = -EINVAL;
221862306a36Sopenharmony_ci	if (cmd != F_OFD_GETLK && flock->l_type != F_RDLCK
221962306a36Sopenharmony_ci			&& flock->l_type != F_WRLCK)
222062306a36Sopenharmony_ci		goto out;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	error = flock_to_posix_lock(filp, fl, flock);
222362306a36Sopenharmony_ci	if (error)
222462306a36Sopenharmony_ci		goto out;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	if (cmd == F_OFD_GETLK) {
222762306a36Sopenharmony_ci		error = -EINVAL;
222862306a36Sopenharmony_ci		if (flock->l_pid != 0)
222962306a36Sopenharmony_ci			goto out;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci		fl->fl_flags |= FL_OFDLCK;
223262306a36Sopenharmony_ci		fl->fl_owner = filp;
223362306a36Sopenharmony_ci	}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	error = vfs_test_lock(filp, fl);
223662306a36Sopenharmony_ci	if (error)
223762306a36Sopenharmony_ci		goto out;
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	flock->l_type = fl->fl_type;
224062306a36Sopenharmony_ci	if (fl->fl_type != F_UNLCK) {
224162306a36Sopenharmony_ci		error = posix_lock_to_flock(flock, fl);
224262306a36Sopenharmony_ci		if (error)
224362306a36Sopenharmony_ci			goto out;
224462306a36Sopenharmony_ci	}
224562306a36Sopenharmony_ciout:
224662306a36Sopenharmony_ci	locks_free_lock(fl);
224762306a36Sopenharmony_ci	return error;
224862306a36Sopenharmony_ci}
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci/**
225162306a36Sopenharmony_ci * vfs_lock_file - file byte range lock
225262306a36Sopenharmony_ci * @filp: The file to apply the lock to
225362306a36Sopenharmony_ci * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.)
225462306a36Sopenharmony_ci * @fl: The lock to be applied
225562306a36Sopenharmony_ci * @conf: Place to return a copy of the conflicting lock, if found.
225662306a36Sopenharmony_ci *
225762306a36Sopenharmony_ci * A caller that doesn't care about the conflicting lock may pass NULL
225862306a36Sopenharmony_ci * as the final argument.
225962306a36Sopenharmony_ci *
226062306a36Sopenharmony_ci * If the filesystem defines a private ->lock() method, then @conf will
226162306a36Sopenharmony_ci * be left unchanged; so a caller that cares should initialize it to
226262306a36Sopenharmony_ci * some acceptable default.
226362306a36Sopenharmony_ci *
226462306a36Sopenharmony_ci * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX
226562306a36Sopenharmony_ci * locks, the ->lock() interface may return asynchronously, before the lock has
226662306a36Sopenharmony_ci * been granted or denied by the underlying filesystem, if (and only if)
226762306a36Sopenharmony_ci * lm_grant is set. Callers expecting ->lock() to return asynchronously
226862306a36Sopenharmony_ci * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if)
226962306a36Sopenharmony_ci * the request is for a blocking lock. When ->lock() does return asynchronously,
227062306a36Sopenharmony_ci * it must return FILE_LOCK_DEFERRED, and call ->lm_grant() when the lock
227162306a36Sopenharmony_ci * request completes.
227262306a36Sopenharmony_ci * If the request is for non-blocking lock the file system should return
227362306a36Sopenharmony_ci * FILE_LOCK_DEFERRED then try to get the lock and call the callback routine
227462306a36Sopenharmony_ci * with the result. If the request timed out the callback routine will return a
227562306a36Sopenharmony_ci * nonzero return code and the file system should release the lock. The file
227662306a36Sopenharmony_ci * system is also responsible to keep a corresponding posix lock when it
227762306a36Sopenharmony_ci * grants a lock so the VFS can find out which locks are locally held and do
227862306a36Sopenharmony_ci * the correct lock cleanup when required.
227962306a36Sopenharmony_ci * The underlying filesystem must not drop the kernel lock or call
228062306a36Sopenharmony_ci * ->lm_grant() before returning to the caller with a FILE_LOCK_DEFERRED
228162306a36Sopenharmony_ci * return code.
228262306a36Sopenharmony_ci */
228362306a36Sopenharmony_ciint vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
228462306a36Sopenharmony_ci{
228562306a36Sopenharmony_ci	WARN_ON_ONCE(filp != fl->fl_file);
228662306a36Sopenharmony_ci	if (filp->f_op->lock)
228762306a36Sopenharmony_ci		return filp->f_op->lock(filp, cmd, fl);
228862306a36Sopenharmony_ci	else
228962306a36Sopenharmony_ci		return posix_lock_file(filp, fl, conf);
229062306a36Sopenharmony_ci}
229162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_lock_file);
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_cistatic int do_lock_file_wait(struct file *filp, unsigned int cmd,
229462306a36Sopenharmony_ci			     struct file_lock *fl)
229562306a36Sopenharmony_ci{
229662306a36Sopenharmony_ci	int error;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	error = security_file_lock(filp, fl->fl_type);
229962306a36Sopenharmony_ci	if (error)
230062306a36Sopenharmony_ci		return error;
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	for (;;) {
230362306a36Sopenharmony_ci		error = vfs_lock_file(filp, cmd, fl, NULL);
230462306a36Sopenharmony_ci		if (error != FILE_LOCK_DEFERRED)
230562306a36Sopenharmony_ci			break;
230662306a36Sopenharmony_ci		error = wait_event_interruptible(fl->fl_wait,
230762306a36Sopenharmony_ci					list_empty(&fl->fl_blocked_member));
230862306a36Sopenharmony_ci		if (error)
230962306a36Sopenharmony_ci			break;
231062306a36Sopenharmony_ci	}
231162306a36Sopenharmony_ci	locks_delete_block(fl);
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	return error;
231462306a36Sopenharmony_ci}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci/* Ensure that fl->fl_file has compatible f_mode for F_SETLK calls */
231762306a36Sopenharmony_cistatic int
231862306a36Sopenharmony_cicheck_fmode_for_setlk(struct file_lock *fl)
231962306a36Sopenharmony_ci{
232062306a36Sopenharmony_ci	switch (fl->fl_type) {
232162306a36Sopenharmony_ci	case F_RDLCK:
232262306a36Sopenharmony_ci		if (!(fl->fl_file->f_mode & FMODE_READ))
232362306a36Sopenharmony_ci			return -EBADF;
232462306a36Sopenharmony_ci		break;
232562306a36Sopenharmony_ci	case F_WRLCK:
232662306a36Sopenharmony_ci		if (!(fl->fl_file->f_mode & FMODE_WRITE))
232762306a36Sopenharmony_ci			return -EBADF;
232862306a36Sopenharmony_ci	}
232962306a36Sopenharmony_ci	return 0;
233062306a36Sopenharmony_ci}
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci/* Apply the lock described by l to an open file descriptor.
233362306a36Sopenharmony_ci * This implements both the F_SETLK and F_SETLKW commands of fcntl().
233462306a36Sopenharmony_ci */
233562306a36Sopenharmony_ciint fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
233662306a36Sopenharmony_ci		struct flock *flock)
233762306a36Sopenharmony_ci{
233862306a36Sopenharmony_ci	struct file_lock *file_lock = locks_alloc_lock();
233962306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
234062306a36Sopenharmony_ci	struct file *f;
234162306a36Sopenharmony_ci	int error;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	if (file_lock == NULL)
234462306a36Sopenharmony_ci		return -ENOLCK;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	error = flock_to_posix_lock(filp, file_lock, flock);
234762306a36Sopenharmony_ci	if (error)
234862306a36Sopenharmony_ci		goto out;
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	error = check_fmode_for_setlk(file_lock);
235162306a36Sopenharmony_ci	if (error)
235262306a36Sopenharmony_ci		goto out;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	/*
235562306a36Sopenharmony_ci	 * If the cmd is requesting file-private locks, then set the
235662306a36Sopenharmony_ci	 * FL_OFDLCK flag and override the owner.
235762306a36Sopenharmony_ci	 */
235862306a36Sopenharmony_ci	switch (cmd) {
235962306a36Sopenharmony_ci	case F_OFD_SETLK:
236062306a36Sopenharmony_ci		error = -EINVAL;
236162306a36Sopenharmony_ci		if (flock->l_pid != 0)
236262306a36Sopenharmony_ci			goto out;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci		cmd = F_SETLK;
236562306a36Sopenharmony_ci		file_lock->fl_flags |= FL_OFDLCK;
236662306a36Sopenharmony_ci		file_lock->fl_owner = filp;
236762306a36Sopenharmony_ci		break;
236862306a36Sopenharmony_ci	case F_OFD_SETLKW:
236962306a36Sopenharmony_ci		error = -EINVAL;
237062306a36Sopenharmony_ci		if (flock->l_pid != 0)
237162306a36Sopenharmony_ci			goto out;
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci		cmd = F_SETLKW;
237462306a36Sopenharmony_ci		file_lock->fl_flags |= FL_OFDLCK;
237562306a36Sopenharmony_ci		file_lock->fl_owner = filp;
237662306a36Sopenharmony_ci		fallthrough;
237762306a36Sopenharmony_ci	case F_SETLKW:
237862306a36Sopenharmony_ci		file_lock->fl_flags |= FL_SLEEP;
237962306a36Sopenharmony_ci	}
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	error = do_lock_file_wait(filp, cmd, file_lock);
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	/*
238462306a36Sopenharmony_ci	 * Attempt to detect a close/fcntl race and recover by releasing the
238562306a36Sopenharmony_ci	 * lock that was just acquired. There is no need to do that when we're
238662306a36Sopenharmony_ci	 * unlocking though, or for OFD locks.
238762306a36Sopenharmony_ci	 */
238862306a36Sopenharmony_ci	if (!error && file_lock->fl_type != F_UNLCK &&
238962306a36Sopenharmony_ci	    !(file_lock->fl_flags & FL_OFDLCK)) {
239062306a36Sopenharmony_ci		struct files_struct *files = current->files;
239162306a36Sopenharmony_ci		/*
239262306a36Sopenharmony_ci		 * We need that spin_lock here - it prevents reordering between
239362306a36Sopenharmony_ci		 * update of i_flctx->flc_posix and check for it done in
239462306a36Sopenharmony_ci		 * close(). rcu_read_lock() wouldn't do.
239562306a36Sopenharmony_ci		 */
239662306a36Sopenharmony_ci		spin_lock(&files->file_lock);
239762306a36Sopenharmony_ci		f = files_lookup_fd_locked(files, fd);
239862306a36Sopenharmony_ci		spin_unlock(&files->file_lock);
239962306a36Sopenharmony_ci		if (f != filp) {
240062306a36Sopenharmony_ci			file_lock->fl_type = F_UNLCK;
240162306a36Sopenharmony_ci			error = do_lock_file_wait(filp, cmd, file_lock);
240262306a36Sopenharmony_ci			WARN_ON_ONCE(error);
240362306a36Sopenharmony_ci			error = -EBADF;
240462306a36Sopenharmony_ci		}
240562306a36Sopenharmony_ci	}
240662306a36Sopenharmony_ciout:
240762306a36Sopenharmony_ci	trace_fcntl_setlk(inode, file_lock, error);
240862306a36Sopenharmony_ci	locks_free_lock(file_lock);
240962306a36Sopenharmony_ci	return error;
241062306a36Sopenharmony_ci}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci#if BITS_PER_LONG == 32
241362306a36Sopenharmony_ci/* Report the first existing lock that would conflict with l.
241462306a36Sopenharmony_ci * This implements the F_GETLK command of fcntl().
241562306a36Sopenharmony_ci */
241662306a36Sopenharmony_ciint fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
241762306a36Sopenharmony_ci{
241862306a36Sopenharmony_ci	struct file_lock *fl;
241962306a36Sopenharmony_ci	int error;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	fl = locks_alloc_lock();
242262306a36Sopenharmony_ci	if (fl == NULL)
242362306a36Sopenharmony_ci		return -ENOMEM;
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	error = -EINVAL;
242662306a36Sopenharmony_ci	if (cmd != F_OFD_GETLK && flock->l_type != F_RDLCK
242762306a36Sopenharmony_ci			&& flock->l_type != F_WRLCK)
242862306a36Sopenharmony_ci		goto out;
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	error = flock64_to_posix_lock(filp, fl, flock);
243162306a36Sopenharmony_ci	if (error)
243262306a36Sopenharmony_ci		goto out;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	if (cmd == F_OFD_GETLK) {
243562306a36Sopenharmony_ci		error = -EINVAL;
243662306a36Sopenharmony_ci		if (flock->l_pid != 0)
243762306a36Sopenharmony_ci			goto out;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci		fl->fl_flags |= FL_OFDLCK;
244062306a36Sopenharmony_ci		fl->fl_owner = filp;
244162306a36Sopenharmony_ci	}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	error = vfs_test_lock(filp, fl);
244462306a36Sopenharmony_ci	if (error)
244562306a36Sopenharmony_ci		goto out;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	flock->l_type = fl->fl_type;
244862306a36Sopenharmony_ci	if (fl->fl_type != F_UNLCK)
244962306a36Sopenharmony_ci		posix_lock_to_flock64(flock, fl);
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ciout:
245262306a36Sopenharmony_ci	locks_free_lock(fl);
245362306a36Sopenharmony_ci	return error;
245462306a36Sopenharmony_ci}
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci/* Apply the lock described by l to an open file descriptor.
245762306a36Sopenharmony_ci * This implements both the F_SETLK and F_SETLKW commands of fcntl().
245862306a36Sopenharmony_ci */
245962306a36Sopenharmony_ciint fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
246062306a36Sopenharmony_ci		struct flock64 *flock)
246162306a36Sopenharmony_ci{
246262306a36Sopenharmony_ci	struct file_lock *file_lock = locks_alloc_lock();
246362306a36Sopenharmony_ci	struct file *f;
246462306a36Sopenharmony_ci	int error;
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci	if (file_lock == NULL)
246762306a36Sopenharmony_ci		return -ENOLCK;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	error = flock64_to_posix_lock(filp, file_lock, flock);
247062306a36Sopenharmony_ci	if (error)
247162306a36Sopenharmony_ci		goto out;
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	error = check_fmode_for_setlk(file_lock);
247462306a36Sopenharmony_ci	if (error)
247562306a36Sopenharmony_ci		goto out;
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	/*
247862306a36Sopenharmony_ci	 * If the cmd is requesting file-private locks, then set the
247962306a36Sopenharmony_ci	 * FL_OFDLCK flag and override the owner.
248062306a36Sopenharmony_ci	 */
248162306a36Sopenharmony_ci	switch (cmd) {
248262306a36Sopenharmony_ci	case F_OFD_SETLK:
248362306a36Sopenharmony_ci		error = -EINVAL;
248462306a36Sopenharmony_ci		if (flock->l_pid != 0)
248562306a36Sopenharmony_ci			goto out;
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci		cmd = F_SETLK64;
248862306a36Sopenharmony_ci		file_lock->fl_flags |= FL_OFDLCK;
248962306a36Sopenharmony_ci		file_lock->fl_owner = filp;
249062306a36Sopenharmony_ci		break;
249162306a36Sopenharmony_ci	case F_OFD_SETLKW:
249262306a36Sopenharmony_ci		error = -EINVAL;
249362306a36Sopenharmony_ci		if (flock->l_pid != 0)
249462306a36Sopenharmony_ci			goto out;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci		cmd = F_SETLKW64;
249762306a36Sopenharmony_ci		file_lock->fl_flags |= FL_OFDLCK;
249862306a36Sopenharmony_ci		file_lock->fl_owner = filp;
249962306a36Sopenharmony_ci		fallthrough;
250062306a36Sopenharmony_ci	case F_SETLKW64:
250162306a36Sopenharmony_ci		file_lock->fl_flags |= FL_SLEEP;
250262306a36Sopenharmony_ci	}
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	error = do_lock_file_wait(filp, cmd, file_lock);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	/*
250762306a36Sopenharmony_ci	 * Attempt to detect a close/fcntl race and recover by releasing the
250862306a36Sopenharmony_ci	 * lock that was just acquired. There is no need to do that when we're
250962306a36Sopenharmony_ci	 * unlocking though, or for OFD locks.
251062306a36Sopenharmony_ci	 */
251162306a36Sopenharmony_ci	if (!error && file_lock->fl_type != F_UNLCK &&
251262306a36Sopenharmony_ci	    !(file_lock->fl_flags & FL_OFDLCK)) {
251362306a36Sopenharmony_ci		struct files_struct *files = current->files;
251462306a36Sopenharmony_ci		/*
251562306a36Sopenharmony_ci		 * We need that spin_lock here - it prevents reordering between
251662306a36Sopenharmony_ci		 * update of i_flctx->flc_posix and check for it done in
251762306a36Sopenharmony_ci		 * close(). rcu_read_lock() wouldn't do.
251862306a36Sopenharmony_ci		 */
251962306a36Sopenharmony_ci		spin_lock(&files->file_lock);
252062306a36Sopenharmony_ci		f = files_lookup_fd_locked(files, fd);
252162306a36Sopenharmony_ci		spin_unlock(&files->file_lock);
252262306a36Sopenharmony_ci		if (f != filp) {
252362306a36Sopenharmony_ci			file_lock->fl_type = F_UNLCK;
252462306a36Sopenharmony_ci			error = do_lock_file_wait(filp, cmd, file_lock);
252562306a36Sopenharmony_ci			WARN_ON_ONCE(error);
252662306a36Sopenharmony_ci			error = -EBADF;
252762306a36Sopenharmony_ci		}
252862306a36Sopenharmony_ci	}
252962306a36Sopenharmony_ciout:
253062306a36Sopenharmony_ci	locks_free_lock(file_lock);
253162306a36Sopenharmony_ci	return error;
253262306a36Sopenharmony_ci}
253362306a36Sopenharmony_ci#endif /* BITS_PER_LONG == 32 */
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci/*
253662306a36Sopenharmony_ci * This function is called when the file is being removed
253762306a36Sopenharmony_ci * from the task's fd array.  POSIX locks belonging to this task
253862306a36Sopenharmony_ci * are deleted at this time.
253962306a36Sopenharmony_ci */
254062306a36Sopenharmony_civoid locks_remove_posix(struct file *filp, fl_owner_t owner)
254162306a36Sopenharmony_ci{
254262306a36Sopenharmony_ci	int error;
254362306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
254462306a36Sopenharmony_ci	struct file_lock lock;
254562306a36Sopenharmony_ci	struct file_lock_context *ctx;
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	/*
254862306a36Sopenharmony_ci	 * If there are no locks held on this file, we don't need to call
254962306a36Sopenharmony_ci	 * posix_lock_file().  Another process could be setting a lock on this
255062306a36Sopenharmony_ci	 * file at the same time, but we wouldn't remove that lock anyway.
255162306a36Sopenharmony_ci	 */
255262306a36Sopenharmony_ci	ctx = locks_inode_context(inode);
255362306a36Sopenharmony_ci	if (!ctx || list_empty(&ctx->flc_posix))
255462306a36Sopenharmony_ci		return;
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	locks_init_lock(&lock);
255762306a36Sopenharmony_ci	lock.fl_type = F_UNLCK;
255862306a36Sopenharmony_ci	lock.fl_flags = FL_POSIX | FL_CLOSE;
255962306a36Sopenharmony_ci	lock.fl_start = 0;
256062306a36Sopenharmony_ci	lock.fl_end = OFFSET_MAX;
256162306a36Sopenharmony_ci	lock.fl_owner = owner;
256262306a36Sopenharmony_ci	lock.fl_pid = current->tgid;
256362306a36Sopenharmony_ci	lock.fl_file = filp;
256462306a36Sopenharmony_ci	lock.fl_ops = NULL;
256562306a36Sopenharmony_ci	lock.fl_lmops = NULL;
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	error = vfs_lock_file(filp, F_SETLK, &lock, NULL);
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	if (lock.fl_ops && lock.fl_ops->fl_release_private)
257062306a36Sopenharmony_ci		lock.fl_ops->fl_release_private(&lock);
257162306a36Sopenharmony_ci	trace_locks_remove_posix(inode, &lock, error);
257262306a36Sopenharmony_ci}
257362306a36Sopenharmony_ciEXPORT_SYMBOL(locks_remove_posix);
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci/* The i_flctx must be valid when calling into here */
257662306a36Sopenharmony_cistatic void
257762306a36Sopenharmony_cilocks_remove_flock(struct file *filp, struct file_lock_context *flctx)
257862306a36Sopenharmony_ci{
257962306a36Sopenharmony_ci	struct file_lock fl;
258062306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	if (list_empty(&flctx->flc_flock))
258362306a36Sopenharmony_ci		return;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	flock_make_lock(filp, &fl, F_UNLCK);
258662306a36Sopenharmony_ci	fl.fl_flags |= FL_CLOSE;
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	if (filp->f_op->flock)
258962306a36Sopenharmony_ci		filp->f_op->flock(filp, F_SETLKW, &fl);
259062306a36Sopenharmony_ci	else
259162306a36Sopenharmony_ci		flock_lock_inode(inode, &fl);
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	if (fl.fl_ops && fl.fl_ops->fl_release_private)
259462306a36Sopenharmony_ci		fl.fl_ops->fl_release_private(&fl);
259562306a36Sopenharmony_ci}
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci/* The i_flctx must be valid when calling into here */
259862306a36Sopenharmony_cistatic void
259962306a36Sopenharmony_cilocks_remove_lease(struct file *filp, struct file_lock_context *ctx)
260062306a36Sopenharmony_ci{
260162306a36Sopenharmony_ci	struct file_lock *fl, *tmp;
260262306a36Sopenharmony_ci	LIST_HEAD(dispose);
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	if (list_empty(&ctx->flc_lease))
260562306a36Sopenharmony_ci		return;
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	percpu_down_read(&file_rwsem);
260862306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
260962306a36Sopenharmony_ci	list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list)
261062306a36Sopenharmony_ci		if (filp == fl->fl_file)
261162306a36Sopenharmony_ci			lease_modify(fl, F_UNLCK, &dispose);
261262306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
261362306a36Sopenharmony_ci	percpu_up_read(&file_rwsem);
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	locks_dispose_list(&dispose);
261662306a36Sopenharmony_ci}
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci/*
261962306a36Sopenharmony_ci * This function is called on the last close of an open file.
262062306a36Sopenharmony_ci */
262162306a36Sopenharmony_civoid locks_remove_file(struct file *filp)
262262306a36Sopenharmony_ci{
262362306a36Sopenharmony_ci	struct file_lock_context *ctx;
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	ctx = locks_inode_context(file_inode(filp));
262662306a36Sopenharmony_ci	if (!ctx)
262762306a36Sopenharmony_ci		return;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	/* remove any OFD locks */
263062306a36Sopenharmony_ci	locks_remove_posix(filp, filp);
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci	/* remove flock locks */
263362306a36Sopenharmony_ci	locks_remove_flock(filp, ctx);
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci	/* remove any leases */
263662306a36Sopenharmony_ci	locks_remove_lease(filp, ctx);
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
263962306a36Sopenharmony_ci	locks_check_ctx_file_list(filp, &ctx->flc_posix, "POSIX");
264062306a36Sopenharmony_ci	locks_check_ctx_file_list(filp, &ctx->flc_flock, "FLOCK");
264162306a36Sopenharmony_ci	locks_check_ctx_file_list(filp, &ctx->flc_lease, "LEASE");
264262306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
264362306a36Sopenharmony_ci}
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci/**
264662306a36Sopenharmony_ci * vfs_cancel_lock - file byte range unblock lock
264762306a36Sopenharmony_ci * @filp: The file to apply the unblock to
264862306a36Sopenharmony_ci * @fl: The lock to be unblocked
264962306a36Sopenharmony_ci *
265062306a36Sopenharmony_ci * Used by lock managers to cancel blocked requests
265162306a36Sopenharmony_ci */
265262306a36Sopenharmony_ciint vfs_cancel_lock(struct file *filp, struct file_lock *fl)
265362306a36Sopenharmony_ci{
265462306a36Sopenharmony_ci	WARN_ON_ONCE(filp != fl->fl_file);
265562306a36Sopenharmony_ci	if (filp->f_op->lock)
265662306a36Sopenharmony_ci		return filp->f_op->lock(filp, F_CANCELLK, fl);
265762306a36Sopenharmony_ci	return 0;
265862306a36Sopenharmony_ci}
265962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_cancel_lock);
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci/**
266262306a36Sopenharmony_ci * vfs_inode_has_locks - are any file locks held on @inode?
266362306a36Sopenharmony_ci * @inode: inode to check for locks
266462306a36Sopenharmony_ci *
266562306a36Sopenharmony_ci * Return true if there are any FL_POSIX or FL_FLOCK locks currently
266662306a36Sopenharmony_ci * set on @inode.
266762306a36Sopenharmony_ci */
266862306a36Sopenharmony_cibool vfs_inode_has_locks(struct inode *inode)
266962306a36Sopenharmony_ci{
267062306a36Sopenharmony_ci	struct file_lock_context *ctx;
267162306a36Sopenharmony_ci	bool ret;
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	ctx = locks_inode_context(inode);
267462306a36Sopenharmony_ci	if (!ctx)
267562306a36Sopenharmony_ci		return false;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
267862306a36Sopenharmony_ci	ret = !list_empty(&ctx->flc_posix) || !list_empty(&ctx->flc_flock);
267962306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
268062306a36Sopenharmony_ci	return ret;
268162306a36Sopenharmony_ci}
268262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_inode_has_locks);
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
268562306a36Sopenharmony_ci#include <linux/proc_fs.h>
268662306a36Sopenharmony_ci#include <linux/seq_file.h>
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_cistruct locks_iterator {
268962306a36Sopenharmony_ci	int	li_cpu;
269062306a36Sopenharmony_ci	loff_t	li_pos;
269162306a36Sopenharmony_ci};
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_cistatic void lock_get_status(struct seq_file *f, struct file_lock *fl,
269462306a36Sopenharmony_ci			    loff_t id, char *pfx, int repeat)
269562306a36Sopenharmony_ci{
269662306a36Sopenharmony_ci	struct inode *inode = NULL;
269762306a36Sopenharmony_ci	unsigned int fl_pid;
269862306a36Sopenharmony_ci	struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb);
269962306a36Sopenharmony_ci	int type;
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	fl_pid = locks_translate_pid(fl, proc_pidns);
270262306a36Sopenharmony_ci	/*
270362306a36Sopenharmony_ci	 * If lock owner is dead (and pid is freed) or not visible in current
270462306a36Sopenharmony_ci	 * pidns, zero is shown as a pid value. Check lock info from
270562306a36Sopenharmony_ci	 * init_pid_ns to get saved lock pid value.
270662306a36Sopenharmony_ci	 */
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	if (fl->fl_file != NULL)
270962306a36Sopenharmony_ci		inode = file_inode(fl->fl_file);
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci	seq_printf(f, "%lld: ", id);
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	if (repeat)
271462306a36Sopenharmony_ci		seq_printf(f, "%*s", repeat - 1 + (int)strlen(pfx), pfx);
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	if (IS_POSIX(fl)) {
271762306a36Sopenharmony_ci		if (fl->fl_flags & FL_ACCESS)
271862306a36Sopenharmony_ci			seq_puts(f, "ACCESS");
271962306a36Sopenharmony_ci		else if (IS_OFDLCK(fl))
272062306a36Sopenharmony_ci			seq_puts(f, "OFDLCK");
272162306a36Sopenharmony_ci		else
272262306a36Sopenharmony_ci			seq_puts(f, "POSIX ");
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci		seq_printf(f, " %s ",
272562306a36Sopenharmony_ci			     (inode == NULL) ? "*NOINODE*" : "ADVISORY ");
272662306a36Sopenharmony_ci	} else if (IS_FLOCK(fl)) {
272762306a36Sopenharmony_ci		seq_puts(f, "FLOCK  ADVISORY  ");
272862306a36Sopenharmony_ci	} else if (IS_LEASE(fl)) {
272962306a36Sopenharmony_ci		if (fl->fl_flags & FL_DELEG)
273062306a36Sopenharmony_ci			seq_puts(f, "DELEG  ");
273162306a36Sopenharmony_ci		else
273262306a36Sopenharmony_ci			seq_puts(f, "LEASE  ");
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci		if (lease_breaking(fl))
273562306a36Sopenharmony_ci			seq_puts(f, "BREAKING  ");
273662306a36Sopenharmony_ci		else if (fl->fl_file)
273762306a36Sopenharmony_ci			seq_puts(f, "ACTIVE    ");
273862306a36Sopenharmony_ci		else
273962306a36Sopenharmony_ci			seq_puts(f, "BREAKER   ");
274062306a36Sopenharmony_ci	} else {
274162306a36Sopenharmony_ci		seq_puts(f, "UNKNOWN UNKNOWN  ");
274262306a36Sopenharmony_ci	}
274362306a36Sopenharmony_ci	type = IS_LEASE(fl) ? target_leasetype(fl) : fl->fl_type;
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	seq_printf(f, "%s ", (type == F_WRLCK) ? "WRITE" :
274662306a36Sopenharmony_ci			     (type == F_RDLCK) ? "READ" : "UNLCK");
274762306a36Sopenharmony_ci	if (inode) {
274862306a36Sopenharmony_ci		/* userspace relies on this representation of dev_t */
274962306a36Sopenharmony_ci		seq_printf(f, "%d %02x:%02x:%lu ", fl_pid,
275062306a36Sopenharmony_ci				MAJOR(inode->i_sb->s_dev),
275162306a36Sopenharmony_ci				MINOR(inode->i_sb->s_dev), inode->i_ino);
275262306a36Sopenharmony_ci	} else {
275362306a36Sopenharmony_ci		seq_printf(f, "%d <none>:0 ", fl_pid);
275462306a36Sopenharmony_ci	}
275562306a36Sopenharmony_ci	if (IS_POSIX(fl)) {
275662306a36Sopenharmony_ci		if (fl->fl_end == OFFSET_MAX)
275762306a36Sopenharmony_ci			seq_printf(f, "%Ld EOF\n", fl->fl_start);
275862306a36Sopenharmony_ci		else
275962306a36Sopenharmony_ci			seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end);
276062306a36Sopenharmony_ci	} else {
276162306a36Sopenharmony_ci		seq_puts(f, "0 EOF\n");
276262306a36Sopenharmony_ci	}
276362306a36Sopenharmony_ci}
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_cistatic struct file_lock *get_next_blocked_member(struct file_lock *node)
276662306a36Sopenharmony_ci{
276762306a36Sopenharmony_ci	struct file_lock *tmp;
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci	/* NULL node or root node */
277062306a36Sopenharmony_ci	if (node == NULL || node->fl_blocker == NULL)
277162306a36Sopenharmony_ci		return NULL;
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	/* Next member in the linked list could be itself */
277462306a36Sopenharmony_ci	tmp = list_next_entry(node, fl_blocked_member);
277562306a36Sopenharmony_ci	if (list_entry_is_head(tmp, &node->fl_blocker->fl_blocked_requests, fl_blocked_member)
277662306a36Sopenharmony_ci		|| tmp == node) {
277762306a36Sopenharmony_ci		return NULL;
277862306a36Sopenharmony_ci	}
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	return tmp;
278162306a36Sopenharmony_ci}
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_cistatic int locks_show(struct seq_file *f, void *v)
278462306a36Sopenharmony_ci{
278562306a36Sopenharmony_ci	struct locks_iterator *iter = f->private;
278662306a36Sopenharmony_ci	struct file_lock *cur, *tmp;
278762306a36Sopenharmony_ci	struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb);
278862306a36Sopenharmony_ci	int level = 0;
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	cur = hlist_entry(v, struct file_lock, fl_link);
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci	if (locks_translate_pid(cur, proc_pidns) == 0)
279362306a36Sopenharmony_ci		return 0;
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	/* View this crossed linked list as a binary tree, the first member of fl_blocked_requests
279662306a36Sopenharmony_ci	 * is the left child of current node, the next silibing in fl_blocked_member is the
279762306a36Sopenharmony_ci	 * right child, we can alse get the parent of current node from fl_blocker, so this
279862306a36Sopenharmony_ci	 * question becomes traversal of a binary tree
279962306a36Sopenharmony_ci	 */
280062306a36Sopenharmony_ci	while (cur != NULL) {
280162306a36Sopenharmony_ci		if (level)
280262306a36Sopenharmony_ci			lock_get_status(f, cur, iter->li_pos, "-> ", level);
280362306a36Sopenharmony_ci		else
280462306a36Sopenharmony_ci			lock_get_status(f, cur, iter->li_pos, "", level);
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci		if (!list_empty(&cur->fl_blocked_requests)) {
280762306a36Sopenharmony_ci			/* Turn left */
280862306a36Sopenharmony_ci			cur = list_first_entry_or_null(&cur->fl_blocked_requests,
280962306a36Sopenharmony_ci				struct file_lock, fl_blocked_member);
281062306a36Sopenharmony_ci			level++;
281162306a36Sopenharmony_ci		} else {
281262306a36Sopenharmony_ci			/* Turn right */
281362306a36Sopenharmony_ci			tmp = get_next_blocked_member(cur);
281462306a36Sopenharmony_ci			/* Fall back to parent node */
281562306a36Sopenharmony_ci			while (tmp == NULL && cur->fl_blocker != NULL) {
281662306a36Sopenharmony_ci				cur = cur->fl_blocker;
281762306a36Sopenharmony_ci				level--;
281862306a36Sopenharmony_ci				tmp = get_next_blocked_member(cur);
281962306a36Sopenharmony_ci			}
282062306a36Sopenharmony_ci			cur = tmp;
282162306a36Sopenharmony_ci		}
282262306a36Sopenharmony_ci	}
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	return 0;
282562306a36Sopenharmony_ci}
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_cistatic void __show_fd_locks(struct seq_file *f,
282862306a36Sopenharmony_ci			struct list_head *head, int *id,
282962306a36Sopenharmony_ci			struct file *filp, struct files_struct *files)
283062306a36Sopenharmony_ci{
283162306a36Sopenharmony_ci	struct file_lock *fl;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	list_for_each_entry(fl, head, fl_list) {
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci		if (filp != fl->fl_file)
283662306a36Sopenharmony_ci			continue;
283762306a36Sopenharmony_ci		if (fl->fl_owner != files &&
283862306a36Sopenharmony_ci		    fl->fl_owner != filp)
283962306a36Sopenharmony_ci			continue;
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci		(*id)++;
284262306a36Sopenharmony_ci		seq_puts(f, "lock:\t");
284362306a36Sopenharmony_ci		lock_get_status(f, fl, *id, "", 0);
284462306a36Sopenharmony_ci	}
284562306a36Sopenharmony_ci}
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_civoid show_fd_locks(struct seq_file *f,
284862306a36Sopenharmony_ci		  struct file *filp, struct files_struct *files)
284962306a36Sopenharmony_ci{
285062306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
285162306a36Sopenharmony_ci	struct file_lock_context *ctx;
285262306a36Sopenharmony_ci	int id = 0;
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	ctx = locks_inode_context(inode);
285562306a36Sopenharmony_ci	if (!ctx)
285662306a36Sopenharmony_ci		return;
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	spin_lock(&ctx->flc_lock);
285962306a36Sopenharmony_ci	__show_fd_locks(f, &ctx->flc_flock, &id, filp, files);
286062306a36Sopenharmony_ci	__show_fd_locks(f, &ctx->flc_posix, &id, filp, files);
286162306a36Sopenharmony_ci	__show_fd_locks(f, &ctx->flc_lease, &id, filp, files);
286262306a36Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
286362306a36Sopenharmony_ci}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_cistatic void *locks_start(struct seq_file *f, loff_t *pos)
286662306a36Sopenharmony_ci	__acquires(&blocked_lock_lock)
286762306a36Sopenharmony_ci{
286862306a36Sopenharmony_ci	struct locks_iterator *iter = f->private;
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	iter->li_pos = *pos + 1;
287162306a36Sopenharmony_ci	percpu_down_write(&file_rwsem);
287262306a36Sopenharmony_ci	spin_lock(&blocked_lock_lock);
287362306a36Sopenharmony_ci	return seq_hlist_start_percpu(&file_lock_list.hlist, &iter->li_cpu, *pos);
287462306a36Sopenharmony_ci}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_cistatic void *locks_next(struct seq_file *f, void *v, loff_t *pos)
287762306a36Sopenharmony_ci{
287862306a36Sopenharmony_ci	struct locks_iterator *iter = f->private;
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_ci	++iter->li_pos;
288162306a36Sopenharmony_ci	return seq_hlist_next_percpu(v, &file_lock_list.hlist, &iter->li_cpu, pos);
288262306a36Sopenharmony_ci}
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_cistatic void locks_stop(struct seq_file *f, void *v)
288562306a36Sopenharmony_ci	__releases(&blocked_lock_lock)
288662306a36Sopenharmony_ci{
288762306a36Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
288862306a36Sopenharmony_ci	percpu_up_write(&file_rwsem);
288962306a36Sopenharmony_ci}
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_cistatic const struct seq_operations locks_seq_operations = {
289262306a36Sopenharmony_ci	.start	= locks_start,
289362306a36Sopenharmony_ci	.next	= locks_next,
289462306a36Sopenharmony_ci	.stop	= locks_stop,
289562306a36Sopenharmony_ci	.show	= locks_show,
289662306a36Sopenharmony_ci};
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_cistatic int __init proc_locks_init(void)
289962306a36Sopenharmony_ci{
290062306a36Sopenharmony_ci	proc_create_seq_private("locks", 0, NULL, &locks_seq_operations,
290162306a36Sopenharmony_ci			sizeof(struct locks_iterator), NULL);
290262306a36Sopenharmony_ci	return 0;
290362306a36Sopenharmony_ci}
290462306a36Sopenharmony_cifs_initcall(proc_locks_init);
290562306a36Sopenharmony_ci#endif
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_cistatic int __init filelock_init(void)
290862306a36Sopenharmony_ci{
290962306a36Sopenharmony_ci	int i;
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ci	flctx_cache = kmem_cache_create("file_lock_ctx",
291262306a36Sopenharmony_ci			sizeof(struct file_lock_context), 0, SLAB_PANIC, NULL);
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	filelock_cache = kmem_cache_create("file_lock_cache",
291562306a36Sopenharmony_ci			sizeof(struct file_lock), 0, SLAB_PANIC, NULL);
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	for_each_possible_cpu(i) {
291862306a36Sopenharmony_ci		struct file_lock_list_struct *fll = per_cpu_ptr(&file_lock_list, i);
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci		spin_lock_init(&fll->lock);
292162306a36Sopenharmony_ci		INIT_HLIST_HEAD(&fll->hlist);
292262306a36Sopenharmony_ci	}
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	lease_notifier_chain_init();
292562306a36Sopenharmony_ci	return 0;
292662306a36Sopenharmony_ci}
292762306a36Sopenharmony_cicore_initcall(filelock_init);
2928