18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/fs/locks.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Provide support for fcntl()'s F_GETLK, F_SETLK, and F_SETLKW calls.
68c2ecf20Sopenharmony_ci *  Doug Evans (dje@spiff.uucp), August 07, 1992
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  Deadlock detection added.
98c2ecf20Sopenharmony_ci *  FIXME: one thing isn't handled yet:
108c2ecf20Sopenharmony_ci *	- mandatory locks (requires lots of changes elsewhere)
118c2ecf20Sopenharmony_ci *  Kelly Carmichael (kelly@[142.24.8.65]), September 17, 1994.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *  Miscellaneous edits, and a total rewrite of posix_lock_file() code.
148c2ecf20Sopenharmony_ci *  Kai Petzke (wpp@marie.physik.tu-berlin.de), 1994
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *  Converted file_lock_table to a linked list from an array, which eliminates
178c2ecf20Sopenharmony_ci *  the limits on how many active file locks are open.
188c2ecf20Sopenharmony_ci *  Chad Page (pageone@netcom.com), November 27, 1994
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci *  Removed dependency on file descriptors. dup()'ed file descriptors now
218c2ecf20Sopenharmony_ci *  get the same locks as the original file descriptors, and a close() on
228c2ecf20Sopenharmony_ci *  any file descriptor removes ALL the locks on the file for the current
238c2ecf20Sopenharmony_ci *  process. Since locks still depend on the process id, locks are inherited
248c2ecf20Sopenharmony_ci *  after an exec() but not after a fork(). This agrees with POSIX, and both
258c2ecf20Sopenharmony_ci *  BSD and SVR4 practice.
268c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), February 14, 1995
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci *  Scrapped free list which is redundant now that we allocate locks
298c2ecf20Sopenharmony_ci *  dynamically with kmalloc()/kfree().
308c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), February 21, 1995
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci *  Implemented two lock personalities - FL_FLOCK and FL_POSIX.
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci *  FL_POSIX locks are created with calls to fcntl() and lockf() through the
358c2ecf20Sopenharmony_ci *  fcntl() system call. They have the semantics described above.
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci *  FL_FLOCK locks are created with calls to flock(), through the flock()
388c2ecf20Sopenharmony_ci *  system call, which is new. Old C libraries implement flock() via fcntl()
398c2ecf20Sopenharmony_ci *  and will continue to use the old, broken implementation.
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci *  FL_FLOCK locks follow the 4.4 BSD flock() semantics. They are associated
428c2ecf20Sopenharmony_ci *  with a file pointer (filp). As a result they can be shared by a parent
438c2ecf20Sopenharmony_ci *  process and its children after a fork(). They are removed when the last
448c2ecf20Sopenharmony_ci *  file descriptor referring to the file pointer is closed (unless explicitly
458c2ecf20Sopenharmony_ci *  unlocked).
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci *  FL_FLOCK locks never deadlock, an existing lock is always removed before
488c2ecf20Sopenharmony_ci *  upgrading from shared to exclusive (or vice versa). When this happens
498c2ecf20Sopenharmony_ci *  any processes blocked by the current lock are woken up and allowed to
508c2ecf20Sopenharmony_ci *  run before the new lock is applied.
518c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), June 09, 1995
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci *  Removed some race conditions in flock_lock_file(), marked other possible
548c2ecf20Sopenharmony_ci *  races. Just grep for FIXME to see them.
558c2ecf20Sopenharmony_ci *  Dmitry Gorodchanin (pgmdsg@ibi.com), February 09, 1996.
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci *  Addressed Dmitry's concerns. Deadlock checking no longer recursive.
588c2ecf20Sopenharmony_ci *  Lock allocation changed to GFP_ATOMIC as we can't afford to sleep
598c2ecf20Sopenharmony_ci *  once we've checked for blocking and deadlocking.
608c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), April 03, 1996.
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci *  Initial implementation of mandatory locks. SunOS turned out to be
638c2ecf20Sopenharmony_ci *  a rotten model, so I implemented the "obvious" semantics.
648c2ecf20Sopenharmony_ci *  See 'Documentation/filesystems/mandatory-locking.rst' for details.
658c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), April 06, 1996.
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci *  Don't allow mandatory locks on mmap()'ed files. Added simple functions to
688c2ecf20Sopenharmony_ci *  check if a file has mandatory locks, used by mmap(), open() and creat() to
698c2ecf20Sopenharmony_ci *  see if system call should be rejected. Ref. HP-UX/SunOS/Solaris Reference
708c2ecf20Sopenharmony_ci *  Manual, Section 2.
718c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), April 09, 1996.
728c2ecf20Sopenharmony_ci *
738c2ecf20Sopenharmony_ci *  Tidied up block list handling. Added '/proc/locks' interface.
748c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), April 24, 1996.
758c2ecf20Sopenharmony_ci *
768c2ecf20Sopenharmony_ci *  Fixed deadlock condition for pathological code that mixes calls to
778c2ecf20Sopenharmony_ci *  flock() and fcntl().
788c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), April 29, 1996.
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci *  Allow only one type of locking scheme (FL_POSIX or FL_FLOCK) to be in use
818c2ecf20Sopenharmony_ci *  for a given file at a time. Changed the CONFIG_LOCK_MANDATORY scheme to
828c2ecf20Sopenharmony_ci *  guarantee sensible behaviour in the case where file system modules might
838c2ecf20Sopenharmony_ci *  be compiled with different options than the kernel itself.
848c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996.
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci *  Added a couple of missing wake_up() calls. Thanks to Thomas Meckel
878c2ecf20Sopenharmony_ci *  (Thomas.Meckel@mni.fh-giessen.de) for spotting this.
888c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996.
898c2ecf20Sopenharmony_ci *
908c2ecf20Sopenharmony_ci *  Changed FL_POSIX locks to use the block list in the same way as FL_FLOCK
918c2ecf20Sopenharmony_ci *  locks. Changed process synchronisation to avoid dereferencing locks that
928c2ecf20Sopenharmony_ci *  have already been freed.
938c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), Sep 21, 1996.
948c2ecf20Sopenharmony_ci *
958c2ecf20Sopenharmony_ci *  Made the block list a circular list to minimise searching in the list.
968c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), Sep 25, 1996.
978c2ecf20Sopenharmony_ci *
988c2ecf20Sopenharmony_ci *  Made mandatory locking a mount option. Default is not to allow mandatory
998c2ecf20Sopenharmony_ci *  locking.
1008c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), Oct 04, 1996.
1018c2ecf20Sopenharmony_ci *
1028c2ecf20Sopenharmony_ci *  Some adaptations for NFS support.
1038c2ecf20Sopenharmony_ci *  Olaf Kirch (okir@monad.swb.de), Dec 1996,
1048c2ecf20Sopenharmony_ci *
1058c2ecf20Sopenharmony_ci *  Fixed /proc/locks interface so that we can't overrun the buffer we are handed.
1068c2ecf20Sopenharmony_ci *  Andy Walker (andy@lysaker.kvaerner.no), May 12, 1997.
1078c2ecf20Sopenharmony_ci *
1088c2ecf20Sopenharmony_ci *  Use slab allocator instead of kmalloc/kfree.
1098c2ecf20Sopenharmony_ci *  Use generic list implementation from <linux/list.h>.
1108c2ecf20Sopenharmony_ci *  Sped up posix_locks_deadlock by only considering blocked locks.
1118c2ecf20Sopenharmony_ci *  Matthew Wilcox <willy@debian.org>, March, 2000.
1128c2ecf20Sopenharmony_ci *
1138c2ecf20Sopenharmony_ci *  Leases and LOCK_MAND
1148c2ecf20Sopenharmony_ci *  Matthew Wilcox <willy@debian.org>, June, 2000.
1158c2ecf20Sopenharmony_ci *  Stephen Rothwell <sfr@canb.auug.org.au>, June, 2000.
1168c2ecf20Sopenharmony_ci *
1178c2ecf20Sopenharmony_ci * Locking conflicts and dependencies:
1188c2ecf20Sopenharmony_ci * If multiple threads attempt to lock the same byte (or flock the same file)
1198c2ecf20Sopenharmony_ci * only one can be granted the lock, and other must wait their turn.
1208c2ecf20Sopenharmony_ci * The first lock has been "applied" or "granted", the others are "waiting"
1218c2ecf20Sopenharmony_ci * and are "blocked" by the "applied" lock..
1228c2ecf20Sopenharmony_ci *
1238c2ecf20Sopenharmony_ci * Waiting and applied locks are all kept in trees whose properties are:
1248c2ecf20Sopenharmony_ci *
1258c2ecf20Sopenharmony_ci *	- the root of a tree may be an applied or waiting lock.
1268c2ecf20Sopenharmony_ci *	- every other node in the tree is a waiting lock that
1278c2ecf20Sopenharmony_ci *	  conflicts with every ancestor of that node.
1288c2ecf20Sopenharmony_ci *
1298c2ecf20Sopenharmony_ci * Every such tree begins life as a waiting singleton which obviously
1308c2ecf20Sopenharmony_ci * satisfies the above properties.
1318c2ecf20Sopenharmony_ci *
1328c2ecf20Sopenharmony_ci * The only ways we modify trees preserve these properties:
1338c2ecf20Sopenharmony_ci *
1348c2ecf20Sopenharmony_ci *	1. We may add a new leaf node, but only after first verifying that it
1358c2ecf20Sopenharmony_ci *	   conflicts with all of its ancestors.
1368c2ecf20Sopenharmony_ci *	2. We may remove the root of a tree, creating a new singleton
1378c2ecf20Sopenharmony_ci *	   tree from the root and N new trees rooted in the immediate
1388c2ecf20Sopenharmony_ci *	   children.
1398c2ecf20Sopenharmony_ci *	3. If the root of a tree is not currently an applied lock, we may
1408c2ecf20Sopenharmony_ci *	   apply it (if possible).
1418c2ecf20Sopenharmony_ci *	4. We may upgrade the root of the tree (either extend its range,
1428c2ecf20Sopenharmony_ci *	   or upgrade its entire range from read to write).
1438c2ecf20Sopenharmony_ci *
1448c2ecf20Sopenharmony_ci * When an applied lock is modified in a way that reduces or downgrades any
1458c2ecf20Sopenharmony_ci * part of its range, we remove all its children (2 above).  This particularly
1468c2ecf20Sopenharmony_ci * happens when a lock is unlocked.
1478c2ecf20Sopenharmony_ci *
1488c2ecf20Sopenharmony_ci * For each of those child trees we "wake up" the thread which is
1498c2ecf20Sopenharmony_ci * waiting for the lock so it can continue handling as follows: if the
1508c2ecf20Sopenharmony_ci * root of the tree applies, we do so (3).  If it doesn't, it must
1518c2ecf20Sopenharmony_ci * conflict with some applied lock.  We remove (wake up) all of its children
1528c2ecf20Sopenharmony_ci * (2), and add it is a new leaf to the tree rooted in the applied
1538c2ecf20Sopenharmony_ci * lock (1).  We then repeat the process recursively with those
1548c2ecf20Sopenharmony_ci * children.
1558c2ecf20Sopenharmony_ci *
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci#include <linux/capability.h>
1598c2ecf20Sopenharmony_ci#include <linux/file.h>
1608c2ecf20Sopenharmony_ci#include <linux/fdtable.h>
1618c2ecf20Sopenharmony_ci#include <linux/fs.h>
1628c2ecf20Sopenharmony_ci#include <linux/init.h>
1638c2ecf20Sopenharmony_ci#include <linux/security.h>
1648c2ecf20Sopenharmony_ci#include <linux/slab.h>
1658c2ecf20Sopenharmony_ci#include <linux/syscalls.h>
1668c2ecf20Sopenharmony_ci#include <linux/time.h>
1678c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
1688c2ecf20Sopenharmony_ci#include <linux/pid_namespace.h>
1698c2ecf20Sopenharmony_ci#include <linux/hashtable.h>
1708c2ecf20Sopenharmony_ci#include <linux/percpu.h>
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS
1738c2ecf20Sopenharmony_ci#include <trace/events/filelock.h>
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci#define IS_POSIX(fl)	(fl->fl_flags & FL_POSIX)
1788c2ecf20Sopenharmony_ci#define IS_FLOCK(fl)	(fl->fl_flags & FL_FLOCK)
1798c2ecf20Sopenharmony_ci#define IS_LEASE(fl)	(fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
1808c2ecf20Sopenharmony_ci#define IS_OFDLCK(fl)	(fl->fl_flags & FL_OFDLCK)
1818c2ecf20Sopenharmony_ci#define IS_REMOTELCK(fl)	(fl->fl_pid <= 0)
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic bool lease_breaking(struct file_lock *fl)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int target_leasetype(struct file_lock *fl)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	if (fl->fl_flags & FL_UNLOCK_PENDING)
1918c2ecf20Sopenharmony_ci		return F_UNLCK;
1928c2ecf20Sopenharmony_ci	if (fl->fl_flags & FL_DOWNGRADE_PENDING)
1938c2ecf20Sopenharmony_ci		return F_RDLCK;
1948c2ecf20Sopenharmony_ci	return fl->fl_type;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ciint leases_enable = 1;
1988c2ecf20Sopenharmony_ciint lease_break_time = 45;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci/*
2018c2ecf20Sopenharmony_ci * The global file_lock_list is only used for displaying /proc/locks, so we
2028c2ecf20Sopenharmony_ci * keep a list on each CPU, with each list protected by its own spinlock.
2038c2ecf20Sopenharmony_ci * Global serialization is done using file_rwsem.
2048c2ecf20Sopenharmony_ci *
2058c2ecf20Sopenharmony_ci * Note that alterations to the list also require that the relevant flc_lock is
2068c2ecf20Sopenharmony_ci * held.
2078c2ecf20Sopenharmony_ci */
2088c2ecf20Sopenharmony_cistruct file_lock_list_struct {
2098c2ecf20Sopenharmony_ci	spinlock_t		lock;
2108c2ecf20Sopenharmony_ci	struct hlist_head	hlist;
2118c2ecf20Sopenharmony_ci};
2128c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct file_lock_list_struct, file_lock_list);
2138c2ecf20Sopenharmony_ciDEFINE_STATIC_PERCPU_RWSEM(file_rwsem);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci/*
2178c2ecf20Sopenharmony_ci * The blocked_hash is used to find POSIX lock loops for deadlock detection.
2188c2ecf20Sopenharmony_ci * It is protected by blocked_lock_lock.
2198c2ecf20Sopenharmony_ci *
2208c2ecf20Sopenharmony_ci * We hash locks by lockowner in order to optimize searching for the lock a
2218c2ecf20Sopenharmony_ci * particular lockowner is waiting on.
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * FIXME: make this value scale via some heuristic? We generally will want more
2248c2ecf20Sopenharmony_ci * buckets when we have more lockowners holding locks, but that's a little
2258c2ecf20Sopenharmony_ci * difficult to determine without knowing what the workload will look like.
2268c2ecf20Sopenharmony_ci */
2278c2ecf20Sopenharmony_ci#define BLOCKED_HASH_BITS	7
2288c2ecf20Sopenharmony_cistatic DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/*
2318c2ecf20Sopenharmony_ci * This lock protects the blocked_hash. Generally, if you're accessing it, you
2328c2ecf20Sopenharmony_ci * want to be holding this lock.
2338c2ecf20Sopenharmony_ci *
2348c2ecf20Sopenharmony_ci * In addition, it also protects the fl->fl_blocked_requests list, and the
2358c2ecf20Sopenharmony_ci * fl->fl_blocker pointer for file_lock structures that are acting as lock
2368c2ecf20Sopenharmony_ci * requests (in contrast to those that are acting as records of acquired locks).
2378c2ecf20Sopenharmony_ci *
2388c2ecf20Sopenharmony_ci * Note that when we acquire this lock in order to change the above fields,
2398c2ecf20Sopenharmony_ci * we often hold the flc_lock as well. In certain cases, when reading the fields
2408c2ecf20Sopenharmony_ci * protected by this lock, we can skip acquiring it iff we already hold the
2418c2ecf20Sopenharmony_ci * flc_lock.
2428c2ecf20Sopenharmony_ci */
2438c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(blocked_lock_lock);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic struct kmem_cache *flctx_cache __read_mostly;
2468c2ecf20Sopenharmony_cistatic struct kmem_cache *filelock_cache __read_mostly;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic struct file_lock_context *
2498c2ecf20Sopenharmony_cilocks_get_lock_context(struct inode *inode, int type)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* paired with cmpxchg() below */
2548c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&inode->i_flctx);
2558c2ecf20Sopenharmony_ci	if (likely(ctx) || type == F_UNLCK)
2568c2ecf20Sopenharmony_ci		goto out;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	ctx = kmem_cache_alloc(flctx_cache, GFP_KERNEL);
2598c2ecf20Sopenharmony_ci	if (!ctx)
2608c2ecf20Sopenharmony_ci		goto out;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	spin_lock_init(&ctx->flc_lock);
2638c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctx->flc_flock);
2648c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctx->flc_posix);
2658c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctx->flc_lease);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/*
2688c2ecf20Sopenharmony_ci	 * Assign the pointer if it's not already assigned. If it is, then
2698c2ecf20Sopenharmony_ci	 * free the context we just allocated.
2708c2ecf20Sopenharmony_ci	 */
2718c2ecf20Sopenharmony_ci	if (cmpxchg(&inode->i_flctx, NULL, ctx)) {
2728c2ecf20Sopenharmony_ci		kmem_cache_free(flctx_cache, ctx);
2738c2ecf20Sopenharmony_ci		ctx = smp_load_acquire(&inode->i_flctx);
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ciout:
2768c2ecf20Sopenharmony_ci	trace_locks_get_lock_context(inode, type, ctx);
2778c2ecf20Sopenharmony_ci	return ctx;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic void
2818c2ecf20Sopenharmony_cilocks_dump_ctx_list(struct list_head *list, char *list_type)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct file_lock *fl;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	list_for_each_entry(fl, list, fl_list) {
2868c2ecf20Sopenharmony_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);
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic void
2918c2ecf20Sopenharmony_cilocks_check_ctx_lists(struct inode *inode)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct file_lock_context *ctx = inode->i_flctx;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (unlikely(!list_empty(&ctx->flc_flock) ||
2968c2ecf20Sopenharmony_ci		     !list_empty(&ctx->flc_posix) ||
2978c2ecf20Sopenharmony_ci		     !list_empty(&ctx->flc_lease))) {
2988c2ecf20Sopenharmony_ci		pr_warn("Leaked locks on dev=0x%x:0x%x ino=0x%lx:\n",
2998c2ecf20Sopenharmony_ci			MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev),
3008c2ecf20Sopenharmony_ci			inode->i_ino);
3018c2ecf20Sopenharmony_ci		locks_dump_ctx_list(&ctx->flc_flock, "FLOCK");
3028c2ecf20Sopenharmony_ci		locks_dump_ctx_list(&ctx->flc_posix, "POSIX");
3038c2ecf20Sopenharmony_ci		locks_dump_ctx_list(&ctx->flc_lease, "LEASE");
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic void
3088c2ecf20Sopenharmony_cilocks_check_ctx_file_list(struct file *filp, struct list_head *list,
3098c2ecf20Sopenharmony_ci				char *list_type)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct file_lock *fl;
3128c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	list_for_each_entry(fl, list, fl_list)
3158c2ecf20Sopenharmony_ci		if (fl->fl_file == filp)
3168c2ecf20Sopenharmony_ci			pr_warn("Leaked %s lock on dev=0x%x:0x%x ino=0x%lx "
3178c2ecf20Sopenharmony_ci				" fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u\n",
3188c2ecf20Sopenharmony_ci				list_type, MAJOR(inode->i_sb->s_dev),
3198c2ecf20Sopenharmony_ci				MINOR(inode->i_sb->s_dev), inode->i_ino,
3208c2ecf20Sopenharmony_ci				fl->fl_owner, fl->fl_flags, fl->fl_type, fl->fl_pid);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_civoid
3248c2ecf20Sopenharmony_cilocks_free_lock_context(struct inode *inode)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct file_lock_context *ctx = inode->i_flctx;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (unlikely(ctx)) {
3298c2ecf20Sopenharmony_ci		locks_check_ctx_lists(inode);
3308c2ecf20Sopenharmony_ci		kmem_cache_free(flctx_cache, ctx);
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic void locks_init_lock_heads(struct file_lock *fl)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	INIT_HLIST_NODE(&fl->fl_link);
3378c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fl->fl_list);
3388c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fl->fl_blocked_requests);
3398c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fl->fl_blocked_member);
3408c2ecf20Sopenharmony_ci	init_waitqueue_head(&fl->fl_wait);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci/* Allocate an empty lock structure. */
3448c2ecf20Sopenharmony_cistruct file_lock *locks_alloc_lock(void)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct file_lock *fl = kmem_cache_zalloc(filelock_cache, GFP_KERNEL);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (fl)
3498c2ecf20Sopenharmony_ci		locks_init_lock_heads(fl);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return fl;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_alloc_lock);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_civoid locks_release_private(struct file_lock *fl)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	BUG_ON(waitqueue_active(&fl->fl_wait));
3588c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&fl->fl_list));
3598c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&fl->fl_blocked_requests));
3608c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&fl->fl_blocked_member));
3618c2ecf20Sopenharmony_ci	BUG_ON(!hlist_unhashed(&fl->fl_link));
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (fl->fl_ops) {
3648c2ecf20Sopenharmony_ci		if (fl->fl_ops->fl_release_private)
3658c2ecf20Sopenharmony_ci			fl->fl_ops->fl_release_private(fl);
3668c2ecf20Sopenharmony_ci		fl->fl_ops = NULL;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (fl->fl_lmops) {
3708c2ecf20Sopenharmony_ci		if (fl->fl_lmops->lm_put_owner) {
3718c2ecf20Sopenharmony_ci			fl->fl_lmops->lm_put_owner(fl->fl_owner);
3728c2ecf20Sopenharmony_ci			fl->fl_owner = NULL;
3738c2ecf20Sopenharmony_ci		}
3748c2ecf20Sopenharmony_ci		fl->fl_lmops = NULL;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_release_private);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci/* Free a lock which is not in use. */
3808c2ecf20Sopenharmony_civoid locks_free_lock(struct file_lock *fl)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	locks_release_private(fl);
3838c2ecf20Sopenharmony_ci	kmem_cache_free(filelock_cache, fl);
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locks_free_lock);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic void
3888c2ecf20Sopenharmony_cilocks_dispose_list(struct list_head *dispose)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct file_lock *fl;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	while (!list_empty(dispose)) {
3938c2ecf20Sopenharmony_ci		fl = list_first_entry(dispose, struct file_lock, fl_list);
3948c2ecf20Sopenharmony_ci		list_del_init(&fl->fl_list);
3958c2ecf20Sopenharmony_ci		locks_free_lock(fl);
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_civoid locks_init_lock(struct file_lock *fl)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	memset(fl, 0, sizeof(struct file_lock));
4028c2ecf20Sopenharmony_ci	locks_init_lock_heads(fl);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locks_init_lock);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/*
4078c2ecf20Sopenharmony_ci * Initialize a new lock from an existing file_lock structure.
4088c2ecf20Sopenharmony_ci */
4098c2ecf20Sopenharmony_civoid locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	new->fl_owner = fl->fl_owner;
4128c2ecf20Sopenharmony_ci	new->fl_pid = fl->fl_pid;
4138c2ecf20Sopenharmony_ci	new->fl_file = NULL;
4148c2ecf20Sopenharmony_ci	new->fl_flags = fl->fl_flags;
4158c2ecf20Sopenharmony_ci	new->fl_type = fl->fl_type;
4168c2ecf20Sopenharmony_ci	new->fl_start = fl->fl_start;
4178c2ecf20Sopenharmony_ci	new->fl_end = fl->fl_end;
4188c2ecf20Sopenharmony_ci	new->fl_lmops = fl->fl_lmops;
4198c2ecf20Sopenharmony_ci	new->fl_ops = NULL;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (fl->fl_lmops) {
4228c2ecf20Sopenharmony_ci		if (fl->fl_lmops->lm_get_owner)
4238c2ecf20Sopenharmony_ci			fl->fl_lmops->lm_get_owner(fl->fl_owner);
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locks_copy_conflock);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_civoid locks_copy_lock(struct file_lock *new, struct file_lock *fl)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	/* "new" must be a freshly-initialized lock */
4318c2ecf20Sopenharmony_ci	WARN_ON_ONCE(new->fl_ops);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	locks_copy_conflock(new, fl);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	new->fl_file = fl->fl_file;
4368c2ecf20Sopenharmony_ci	new->fl_ops = fl->fl_ops;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	if (fl->fl_ops) {
4398c2ecf20Sopenharmony_ci		if (fl->fl_ops->fl_copy_lock)
4408c2ecf20Sopenharmony_ci			fl->fl_ops->fl_copy_lock(new, fl);
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locks_copy_lock);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistatic void locks_move_blocks(struct file_lock *new, struct file_lock *fl)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct file_lock *f;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/*
4508c2ecf20Sopenharmony_ci	 * As ctx->flc_lock is held, new requests cannot be added to
4518c2ecf20Sopenharmony_ci	 * ->fl_blocked_requests, so we don't need a lock to check if it
4528c2ecf20Sopenharmony_ci	 * is empty.
4538c2ecf20Sopenharmony_ci	 */
4548c2ecf20Sopenharmony_ci	if (list_empty(&fl->fl_blocked_requests))
4558c2ecf20Sopenharmony_ci		return;
4568c2ecf20Sopenharmony_ci	spin_lock(&blocked_lock_lock);
4578c2ecf20Sopenharmony_ci	list_splice_init(&fl->fl_blocked_requests, &new->fl_blocked_requests);
4588c2ecf20Sopenharmony_ci	list_for_each_entry(f, &new->fl_blocked_requests, fl_blocked_member)
4598c2ecf20Sopenharmony_ci		f->fl_blocker = new;
4608c2ecf20Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic inline int flock_translate_cmd(int cmd) {
4648c2ecf20Sopenharmony_ci	if (cmd & LOCK_MAND)
4658c2ecf20Sopenharmony_ci		return cmd & (LOCK_MAND | LOCK_RW);
4668c2ecf20Sopenharmony_ci	switch (cmd) {
4678c2ecf20Sopenharmony_ci	case LOCK_SH:
4688c2ecf20Sopenharmony_ci		return F_RDLCK;
4698c2ecf20Sopenharmony_ci	case LOCK_EX:
4708c2ecf20Sopenharmony_ci		return F_WRLCK;
4718c2ecf20Sopenharmony_ci	case LOCK_UN:
4728c2ecf20Sopenharmony_ci		return F_UNLCK;
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci	return -EINVAL;
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci/* Fill in a file_lock structure with an appropriate FLOCK lock. */
4788c2ecf20Sopenharmony_cistatic struct file_lock *
4798c2ecf20Sopenharmony_ciflock_make_lock(struct file *filp, unsigned int cmd, struct file_lock *fl)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	int type = flock_translate_cmd(cmd);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (type < 0)
4848c2ecf20Sopenharmony_ci		return ERR_PTR(type);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (fl == NULL) {
4878c2ecf20Sopenharmony_ci		fl = locks_alloc_lock();
4888c2ecf20Sopenharmony_ci		if (fl == NULL)
4898c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOMEM);
4908c2ecf20Sopenharmony_ci	} else {
4918c2ecf20Sopenharmony_ci		locks_init_lock(fl);
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	fl->fl_file = filp;
4958c2ecf20Sopenharmony_ci	fl->fl_owner = filp;
4968c2ecf20Sopenharmony_ci	fl->fl_pid = current->tgid;
4978c2ecf20Sopenharmony_ci	fl->fl_flags = FL_FLOCK;
4988c2ecf20Sopenharmony_ci	fl->fl_type = type;
4998c2ecf20Sopenharmony_ci	fl->fl_end = OFFSET_MAX;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	return fl;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic int assign_type(struct file_lock *fl, long type)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	switch (type) {
5078c2ecf20Sopenharmony_ci	case F_RDLCK:
5088c2ecf20Sopenharmony_ci	case F_WRLCK:
5098c2ecf20Sopenharmony_ci	case F_UNLCK:
5108c2ecf20Sopenharmony_ci		fl->fl_type = type;
5118c2ecf20Sopenharmony_ci		break;
5128c2ecf20Sopenharmony_ci	default:
5138c2ecf20Sopenharmony_ci		return -EINVAL;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci	return 0;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
5198c2ecf20Sopenharmony_ci				 struct flock64 *l)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	switch (l->l_whence) {
5228c2ecf20Sopenharmony_ci	case SEEK_SET:
5238c2ecf20Sopenharmony_ci		fl->fl_start = 0;
5248c2ecf20Sopenharmony_ci		break;
5258c2ecf20Sopenharmony_ci	case SEEK_CUR:
5268c2ecf20Sopenharmony_ci		fl->fl_start = filp->f_pos;
5278c2ecf20Sopenharmony_ci		break;
5288c2ecf20Sopenharmony_ci	case SEEK_END:
5298c2ecf20Sopenharmony_ci		fl->fl_start = i_size_read(file_inode(filp));
5308c2ecf20Sopenharmony_ci		break;
5318c2ecf20Sopenharmony_ci	default:
5328c2ecf20Sopenharmony_ci		return -EINVAL;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci	if (l->l_start > OFFSET_MAX - fl->fl_start)
5358c2ecf20Sopenharmony_ci		return -EOVERFLOW;
5368c2ecf20Sopenharmony_ci	fl->fl_start += l->l_start;
5378c2ecf20Sopenharmony_ci	if (fl->fl_start < 0)
5388c2ecf20Sopenharmony_ci		return -EINVAL;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	/* POSIX-1996 leaves the case l->l_len < 0 undefined;
5418c2ecf20Sopenharmony_ci	   POSIX-2001 defines it. */
5428c2ecf20Sopenharmony_ci	if (l->l_len > 0) {
5438c2ecf20Sopenharmony_ci		if (l->l_len - 1 > OFFSET_MAX - fl->fl_start)
5448c2ecf20Sopenharmony_ci			return -EOVERFLOW;
5458c2ecf20Sopenharmony_ci		fl->fl_end = fl->fl_start + (l->l_len - 1);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	} else if (l->l_len < 0) {
5488c2ecf20Sopenharmony_ci		if (fl->fl_start + l->l_len < 0)
5498c2ecf20Sopenharmony_ci			return -EINVAL;
5508c2ecf20Sopenharmony_ci		fl->fl_end = fl->fl_start - 1;
5518c2ecf20Sopenharmony_ci		fl->fl_start += l->l_len;
5528c2ecf20Sopenharmony_ci	} else
5538c2ecf20Sopenharmony_ci		fl->fl_end = OFFSET_MAX;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	fl->fl_owner = current->files;
5568c2ecf20Sopenharmony_ci	fl->fl_pid = current->tgid;
5578c2ecf20Sopenharmony_ci	fl->fl_file = filp;
5588c2ecf20Sopenharmony_ci	fl->fl_flags = FL_POSIX;
5598c2ecf20Sopenharmony_ci	fl->fl_ops = NULL;
5608c2ecf20Sopenharmony_ci	fl->fl_lmops = NULL;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	return assign_type(fl, l->l_type);
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
5668c2ecf20Sopenharmony_ci * style lock.
5678c2ecf20Sopenharmony_ci */
5688c2ecf20Sopenharmony_cistatic int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
5698c2ecf20Sopenharmony_ci			       struct flock *l)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	struct flock64 ll = {
5728c2ecf20Sopenharmony_ci		.l_type = l->l_type,
5738c2ecf20Sopenharmony_ci		.l_whence = l->l_whence,
5748c2ecf20Sopenharmony_ci		.l_start = l->l_start,
5758c2ecf20Sopenharmony_ci		.l_len = l->l_len,
5768c2ecf20Sopenharmony_ci	};
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	return flock64_to_posix_lock(filp, fl, &ll);
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci/* default lease lock manager operations */
5828c2ecf20Sopenharmony_cistatic bool
5838c2ecf20Sopenharmony_cilease_break_callback(struct file_lock *fl)
5848c2ecf20Sopenharmony_ci{
5858c2ecf20Sopenharmony_ci	kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
5868c2ecf20Sopenharmony_ci	return false;
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_cistatic void
5908c2ecf20Sopenharmony_cilease_setup(struct file_lock *fl, void **priv)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	struct file *filp = fl->fl_file;
5938c2ecf20Sopenharmony_ci	struct fasync_struct *fa = *priv;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	/*
5968c2ecf20Sopenharmony_ci	 * fasync_insert_entry() returns the old entry if any. If there was no
5978c2ecf20Sopenharmony_ci	 * old entry, then it used "priv" and inserted it into the fasync list.
5988c2ecf20Sopenharmony_ci	 * Clear the pointer to indicate that it shouldn't be freed.
5998c2ecf20Sopenharmony_ci	 */
6008c2ecf20Sopenharmony_ci	if (!fasync_insert_entry(fa->fa_fd, filp, &fl->fl_fasync, fa))
6018c2ecf20Sopenharmony_ci		*priv = NULL;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	__f_setown(filp, task_pid(current), PIDTYPE_TGID, 0);
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_cistatic const struct lock_manager_operations lease_manager_ops = {
6078c2ecf20Sopenharmony_ci	.lm_break = lease_break_callback,
6088c2ecf20Sopenharmony_ci	.lm_change = lease_modify,
6098c2ecf20Sopenharmony_ci	.lm_setup = lease_setup,
6108c2ecf20Sopenharmony_ci};
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci/*
6138c2ecf20Sopenharmony_ci * Initialize a lease, use the default lock manager operations
6148c2ecf20Sopenharmony_ci */
6158c2ecf20Sopenharmony_cistatic int lease_init(struct file *filp, long type, struct file_lock *fl)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	if (assign_type(fl, type) != 0)
6188c2ecf20Sopenharmony_ci		return -EINVAL;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	fl->fl_owner = filp;
6218c2ecf20Sopenharmony_ci	fl->fl_pid = current->tgid;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	fl->fl_file = filp;
6248c2ecf20Sopenharmony_ci	fl->fl_flags = FL_LEASE;
6258c2ecf20Sopenharmony_ci	fl->fl_start = 0;
6268c2ecf20Sopenharmony_ci	fl->fl_end = OFFSET_MAX;
6278c2ecf20Sopenharmony_ci	fl->fl_ops = NULL;
6288c2ecf20Sopenharmony_ci	fl->fl_lmops = &lease_manager_ops;
6298c2ecf20Sopenharmony_ci	return 0;
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci/* Allocate a file_lock initialised to this type of lease */
6338c2ecf20Sopenharmony_cistatic struct file_lock *lease_alloc(struct file *filp, long type)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct file_lock *fl = locks_alloc_lock();
6368c2ecf20Sopenharmony_ci	int error = -ENOMEM;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	if (fl == NULL)
6398c2ecf20Sopenharmony_ci		return ERR_PTR(error);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	error = lease_init(filp, type, fl);
6428c2ecf20Sopenharmony_ci	if (error) {
6438c2ecf20Sopenharmony_ci		locks_free_lock(fl);
6448c2ecf20Sopenharmony_ci		return ERR_PTR(error);
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci	return fl;
6478c2ecf20Sopenharmony_ci}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci/* Check if two locks overlap each other.
6508c2ecf20Sopenharmony_ci */
6518c2ecf20Sopenharmony_cistatic inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	return ((fl1->fl_end >= fl2->fl_start) &&
6548c2ecf20Sopenharmony_ci		(fl2->fl_end >= fl1->fl_start));
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci/*
6588c2ecf20Sopenharmony_ci * Check whether two locks have the same owner.
6598c2ecf20Sopenharmony_ci */
6608c2ecf20Sopenharmony_cistatic int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	return fl1->fl_owner == fl2->fl_owner;
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci/* Must be called with the flc_lock held! */
6668c2ecf20Sopenharmony_cistatic void locks_insert_global_locks(struct file_lock *fl)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	struct file_lock_list_struct *fll = this_cpu_ptr(&file_lock_list);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	percpu_rwsem_assert_held(&file_rwsem);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	spin_lock(&fll->lock);
6738c2ecf20Sopenharmony_ci	fl->fl_link_cpu = smp_processor_id();
6748c2ecf20Sopenharmony_ci	hlist_add_head(&fl->fl_link, &fll->hlist);
6758c2ecf20Sopenharmony_ci	spin_unlock(&fll->lock);
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci/* Must be called with the flc_lock held! */
6798c2ecf20Sopenharmony_cistatic void locks_delete_global_locks(struct file_lock *fl)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct file_lock_list_struct *fll;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	percpu_rwsem_assert_held(&file_rwsem);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	/*
6868c2ecf20Sopenharmony_ci	 * Avoid taking lock if already unhashed. This is safe since this check
6878c2ecf20Sopenharmony_ci	 * is done while holding the flc_lock, and new insertions into the list
6888c2ecf20Sopenharmony_ci	 * also require that it be held.
6898c2ecf20Sopenharmony_ci	 */
6908c2ecf20Sopenharmony_ci	if (hlist_unhashed(&fl->fl_link))
6918c2ecf20Sopenharmony_ci		return;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	fll = per_cpu_ptr(&file_lock_list, fl->fl_link_cpu);
6948c2ecf20Sopenharmony_ci	spin_lock(&fll->lock);
6958c2ecf20Sopenharmony_ci	hlist_del_init(&fl->fl_link);
6968c2ecf20Sopenharmony_ci	spin_unlock(&fll->lock);
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cistatic unsigned long
7008c2ecf20Sopenharmony_ciposix_owner_key(struct file_lock *fl)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	return (unsigned long)fl->fl_owner;
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_cistatic void locks_insert_global_blocked(struct file_lock *waiter)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	lockdep_assert_held(&blocked_lock_lock);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter));
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic void locks_delete_global_blocked(struct file_lock *waiter)
7138c2ecf20Sopenharmony_ci{
7148c2ecf20Sopenharmony_ci	lockdep_assert_held(&blocked_lock_lock);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	hash_del(&waiter->fl_link);
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci/* Remove waiter from blocker's block list.
7208c2ecf20Sopenharmony_ci * When blocker ends up pointing to itself then the list is empty.
7218c2ecf20Sopenharmony_ci *
7228c2ecf20Sopenharmony_ci * Must be called with blocked_lock_lock held.
7238c2ecf20Sopenharmony_ci */
7248c2ecf20Sopenharmony_cistatic void __locks_delete_block(struct file_lock *waiter)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	locks_delete_global_blocked(waiter);
7278c2ecf20Sopenharmony_ci	list_del_init(&waiter->fl_blocked_member);
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cistatic void __locks_wake_up_blocks(struct file_lock *blocker)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	while (!list_empty(&blocker->fl_blocked_requests)) {
7338c2ecf20Sopenharmony_ci		struct file_lock *waiter;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		waiter = list_first_entry(&blocker->fl_blocked_requests,
7368c2ecf20Sopenharmony_ci					  struct file_lock, fl_blocked_member);
7378c2ecf20Sopenharmony_ci		__locks_delete_block(waiter);
7388c2ecf20Sopenharmony_ci		if (waiter->fl_lmops && waiter->fl_lmops->lm_notify)
7398c2ecf20Sopenharmony_ci			waiter->fl_lmops->lm_notify(waiter);
7408c2ecf20Sopenharmony_ci		else
7418c2ecf20Sopenharmony_ci			wake_up(&waiter->fl_wait);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci		/*
7448c2ecf20Sopenharmony_ci		 * The setting of fl_blocker to NULL marks the "done"
7458c2ecf20Sopenharmony_ci		 * point in deleting a block. Paired with acquire at the top
7468c2ecf20Sopenharmony_ci		 * of locks_delete_block().
7478c2ecf20Sopenharmony_ci		 */
7488c2ecf20Sopenharmony_ci		smp_store_release(&waiter->fl_blocker, NULL);
7498c2ecf20Sopenharmony_ci	}
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci/**
7538c2ecf20Sopenharmony_ci *	locks_delete_lock - stop waiting for a file lock
7548c2ecf20Sopenharmony_ci *	@waiter: the lock which was waiting
7558c2ecf20Sopenharmony_ci *
7568c2ecf20Sopenharmony_ci *	lockd/nfsd need to disconnect the lock while working on it.
7578c2ecf20Sopenharmony_ci */
7588c2ecf20Sopenharmony_ciint locks_delete_block(struct file_lock *waiter)
7598c2ecf20Sopenharmony_ci{
7608c2ecf20Sopenharmony_ci	int status = -ENOENT;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/*
7638c2ecf20Sopenharmony_ci	 * If fl_blocker is NULL, it won't be set again as this thread "owns"
7648c2ecf20Sopenharmony_ci	 * the lock and is the only one that might try to claim the lock.
7658c2ecf20Sopenharmony_ci	 *
7668c2ecf20Sopenharmony_ci	 * We use acquire/release to manage fl_blocker so that we can
7678c2ecf20Sopenharmony_ci	 * optimize away taking the blocked_lock_lock in many cases.
7688c2ecf20Sopenharmony_ci	 *
7698c2ecf20Sopenharmony_ci	 * The smp_load_acquire guarantees two things:
7708c2ecf20Sopenharmony_ci	 *
7718c2ecf20Sopenharmony_ci	 * 1/ that fl_blocked_requests can be tested locklessly. If something
7728c2ecf20Sopenharmony_ci	 * was recently added to that list it must have been in a locked region
7738c2ecf20Sopenharmony_ci	 * *before* the locked region when fl_blocker was set to NULL.
7748c2ecf20Sopenharmony_ci	 *
7758c2ecf20Sopenharmony_ci	 * 2/ that no other thread is accessing 'waiter', so it is safe to free
7768c2ecf20Sopenharmony_ci	 * it.  __locks_wake_up_blocks is careful not to touch waiter after
7778c2ecf20Sopenharmony_ci	 * fl_blocker is released.
7788c2ecf20Sopenharmony_ci	 *
7798c2ecf20Sopenharmony_ci	 * If a lockless check of fl_blocker shows it to be NULL, we know that
7808c2ecf20Sopenharmony_ci	 * no new locks can be inserted into its fl_blocked_requests list, and
7818c2ecf20Sopenharmony_ci	 * can avoid doing anything further if the list is empty.
7828c2ecf20Sopenharmony_ci	 */
7838c2ecf20Sopenharmony_ci	if (!smp_load_acquire(&waiter->fl_blocker) &&
7848c2ecf20Sopenharmony_ci	    list_empty(&waiter->fl_blocked_requests))
7858c2ecf20Sopenharmony_ci		return status;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	spin_lock(&blocked_lock_lock);
7888c2ecf20Sopenharmony_ci	if (waiter->fl_blocker)
7898c2ecf20Sopenharmony_ci		status = 0;
7908c2ecf20Sopenharmony_ci	__locks_wake_up_blocks(waiter);
7918c2ecf20Sopenharmony_ci	__locks_delete_block(waiter);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	/*
7948c2ecf20Sopenharmony_ci	 * The setting of fl_blocker to NULL marks the "done" point in deleting
7958c2ecf20Sopenharmony_ci	 * a block. Paired with acquire at the top of this function.
7968c2ecf20Sopenharmony_ci	 */
7978c2ecf20Sopenharmony_ci	smp_store_release(&waiter->fl_blocker, NULL);
7988c2ecf20Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
7998c2ecf20Sopenharmony_ci	return status;
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locks_delete_block);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci/* Insert waiter into blocker's block list.
8048c2ecf20Sopenharmony_ci * We use a circular list so that processes can be easily woken up in
8058c2ecf20Sopenharmony_ci * the order they blocked. The documentation doesn't require this but
8068c2ecf20Sopenharmony_ci * it seems like the reasonable thing to do.
8078c2ecf20Sopenharmony_ci *
8088c2ecf20Sopenharmony_ci * Must be called with both the flc_lock and blocked_lock_lock held. The
8098c2ecf20Sopenharmony_ci * fl_blocked_requests list itself is protected by the blocked_lock_lock,
8108c2ecf20Sopenharmony_ci * but by ensuring that the flc_lock is also held on insertions we can avoid
8118c2ecf20Sopenharmony_ci * taking the blocked_lock_lock in some cases when we see that the
8128c2ecf20Sopenharmony_ci * fl_blocked_requests list is empty.
8138c2ecf20Sopenharmony_ci *
8148c2ecf20Sopenharmony_ci * Rather than just adding to the list, we check for conflicts with any existing
8158c2ecf20Sopenharmony_ci * waiters, and add beneath any waiter that blocks the new waiter.
8168c2ecf20Sopenharmony_ci * Thus wakeups don't happen until needed.
8178c2ecf20Sopenharmony_ci */
8188c2ecf20Sopenharmony_cistatic void __locks_insert_block(struct file_lock *blocker,
8198c2ecf20Sopenharmony_ci				 struct file_lock *waiter,
8208c2ecf20Sopenharmony_ci				 bool conflict(struct file_lock *,
8218c2ecf20Sopenharmony_ci					       struct file_lock *))
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	struct file_lock *fl;
8248c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&waiter->fl_blocked_member));
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_cinew_blocker:
8278c2ecf20Sopenharmony_ci	list_for_each_entry(fl, &blocker->fl_blocked_requests, fl_blocked_member)
8288c2ecf20Sopenharmony_ci		if (conflict(fl, waiter)) {
8298c2ecf20Sopenharmony_ci			blocker =  fl;
8308c2ecf20Sopenharmony_ci			goto new_blocker;
8318c2ecf20Sopenharmony_ci		}
8328c2ecf20Sopenharmony_ci	waiter->fl_blocker = blocker;
8338c2ecf20Sopenharmony_ci	list_add_tail(&waiter->fl_blocked_member, &blocker->fl_blocked_requests);
8348c2ecf20Sopenharmony_ci	if (IS_POSIX(blocker) && !IS_OFDLCK(blocker))
8358c2ecf20Sopenharmony_ci		locks_insert_global_blocked(waiter);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	/* The requests in waiter->fl_blocked are known to conflict with
8388c2ecf20Sopenharmony_ci	 * waiter, but might not conflict with blocker, or the requests
8398c2ecf20Sopenharmony_ci	 * and lock which block it.  So they all need to be woken.
8408c2ecf20Sopenharmony_ci	 */
8418c2ecf20Sopenharmony_ci	__locks_wake_up_blocks(waiter);
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci/* Must be called with flc_lock held. */
8458c2ecf20Sopenharmony_cistatic void locks_insert_block(struct file_lock *blocker,
8468c2ecf20Sopenharmony_ci			       struct file_lock *waiter,
8478c2ecf20Sopenharmony_ci			       bool conflict(struct file_lock *,
8488c2ecf20Sopenharmony_ci					     struct file_lock *))
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	spin_lock(&blocked_lock_lock);
8518c2ecf20Sopenharmony_ci	__locks_insert_block(blocker, waiter, conflict);
8528c2ecf20Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci/*
8568c2ecf20Sopenharmony_ci * Wake up processes blocked waiting for blocker.
8578c2ecf20Sopenharmony_ci *
8588c2ecf20Sopenharmony_ci * Must be called with the inode->flc_lock held!
8598c2ecf20Sopenharmony_ci */
8608c2ecf20Sopenharmony_cistatic void locks_wake_up_blocks(struct file_lock *blocker)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	/*
8638c2ecf20Sopenharmony_ci	 * Avoid taking global lock if list is empty. This is safe since new
8648c2ecf20Sopenharmony_ci	 * blocked requests are only added to the list under the flc_lock, and
8658c2ecf20Sopenharmony_ci	 * the flc_lock is always held here. Note that removal from the
8668c2ecf20Sopenharmony_ci	 * fl_blocked_requests list does not require the flc_lock, so we must
8678c2ecf20Sopenharmony_ci	 * recheck list_empty() after acquiring the blocked_lock_lock.
8688c2ecf20Sopenharmony_ci	 */
8698c2ecf20Sopenharmony_ci	if (list_empty(&blocker->fl_blocked_requests))
8708c2ecf20Sopenharmony_ci		return;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	spin_lock(&blocked_lock_lock);
8738c2ecf20Sopenharmony_ci	__locks_wake_up_blocks(blocker);
8748c2ecf20Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic void
8788c2ecf20Sopenharmony_cilocks_insert_lock_ctx(struct file_lock *fl, struct list_head *before)
8798c2ecf20Sopenharmony_ci{
8808c2ecf20Sopenharmony_ci	list_add_tail(&fl->fl_list, before);
8818c2ecf20Sopenharmony_ci	locks_insert_global_locks(fl);
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic void
8858c2ecf20Sopenharmony_cilocks_unlink_lock_ctx(struct file_lock *fl)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	locks_delete_global_locks(fl);
8888c2ecf20Sopenharmony_ci	list_del_init(&fl->fl_list);
8898c2ecf20Sopenharmony_ci	locks_wake_up_blocks(fl);
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic void
8938c2ecf20Sopenharmony_cilocks_delete_lock_ctx(struct file_lock *fl, struct list_head *dispose)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	locks_unlink_lock_ctx(fl);
8968c2ecf20Sopenharmony_ci	if (dispose)
8978c2ecf20Sopenharmony_ci		list_add(&fl->fl_list, dispose);
8988c2ecf20Sopenharmony_ci	else
8998c2ecf20Sopenharmony_ci		locks_free_lock(fl);
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci/* Determine if lock sys_fl blocks lock caller_fl. Common functionality
9038c2ecf20Sopenharmony_ci * checks for shared/exclusive status of overlapping locks.
9048c2ecf20Sopenharmony_ci */
9058c2ecf20Sopenharmony_cistatic bool locks_conflict(struct file_lock *caller_fl,
9068c2ecf20Sopenharmony_ci			   struct file_lock *sys_fl)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	if (sys_fl->fl_type == F_WRLCK)
9098c2ecf20Sopenharmony_ci		return true;
9108c2ecf20Sopenharmony_ci	if (caller_fl->fl_type == F_WRLCK)
9118c2ecf20Sopenharmony_ci		return true;
9128c2ecf20Sopenharmony_ci	return false;
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci/* Determine if lock sys_fl blocks lock caller_fl. POSIX specific
9168c2ecf20Sopenharmony_ci * checking before calling the locks_conflict().
9178c2ecf20Sopenharmony_ci */
9188c2ecf20Sopenharmony_cistatic bool posix_locks_conflict(struct file_lock *caller_fl,
9198c2ecf20Sopenharmony_ci				 struct file_lock *sys_fl)
9208c2ecf20Sopenharmony_ci{
9218c2ecf20Sopenharmony_ci	/* POSIX locks owned by the same process do not conflict with
9228c2ecf20Sopenharmony_ci	 * each other.
9238c2ecf20Sopenharmony_ci	 */
9248c2ecf20Sopenharmony_ci	if (posix_same_owner(caller_fl, sys_fl))
9258c2ecf20Sopenharmony_ci		return false;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	/* Check whether they overlap */
9288c2ecf20Sopenharmony_ci	if (!locks_overlap(caller_fl, sys_fl))
9298c2ecf20Sopenharmony_ci		return false;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	return locks_conflict(caller_fl, sys_fl);
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific
9358c2ecf20Sopenharmony_ci * checking before calling the locks_conflict().
9368c2ecf20Sopenharmony_ci */
9378c2ecf20Sopenharmony_cistatic bool flock_locks_conflict(struct file_lock *caller_fl,
9388c2ecf20Sopenharmony_ci				 struct file_lock *sys_fl)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	/* FLOCK locks referring to the same filp do not conflict with
9418c2ecf20Sopenharmony_ci	 * each other.
9428c2ecf20Sopenharmony_ci	 */
9438c2ecf20Sopenharmony_ci	if (caller_fl->fl_file == sys_fl->fl_file)
9448c2ecf20Sopenharmony_ci		return false;
9458c2ecf20Sopenharmony_ci	if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND))
9468c2ecf20Sopenharmony_ci		return false;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	return locks_conflict(caller_fl, sys_fl);
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_civoid
9528c2ecf20Sopenharmony_ciposix_test_lock(struct file *filp, struct file_lock *fl)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	struct file_lock *cfl;
9558c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
9568c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&inode->i_flctx);
9598c2ecf20Sopenharmony_ci	if (!ctx || list_empty_careful(&ctx->flc_posix)) {
9608c2ecf20Sopenharmony_ci		fl->fl_type = F_UNLCK;
9618c2ecf20Sopenharmony_ci		return;
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
9658c2ecf20Sopenharmony_ci	list_for_each_entry(cfl, &ctx->flc_posix, fl_list) {
9668c2ecf20Sopenharmony_ci		if (posix_locks_conflict(fl, cfl)) {
9678c2ecf20Sopenharmony_ci			locks_copy_conflock(fl, cfl);
9688c2ecf20Sopenharmony_ci			goto out;
9698c2ecf20Sopenharmony_ci		}
9708c2ecf20Sopenharmony_ci	}
9718c2ecf20Sopenharmony_ci	fl->fl_type = F_UNLCK;
9728c2ecf20Sopenharmony_ciout:
9738c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
9748c2ecf20Sopenharmony_ci	return;
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(posix_test_lock);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci/*
9798c2ecf20Sopenharmony_ci * Deadlock detection:
9808c2ecf20Sopenharmony_ci *
9818c2ecf20Sopenharmony_ci * We attempt to detect deadlocks that are due purely to posix file
9828c2ecf20Sopenharmony_ci * locks.
9838c2ecf20Sopenharmony_ci *
9848c2ecf20Sopenharmony_ci * We assume that a task can be waiting for at most one lock at a time.
9858c2ecf20Sopenharmony_ci * So for any acquired lock, the process holding that lock may be
9868c2ecf20Sopenharmony_ci * waiting on at most one other lock.  That lock in turns may be held by
9878c2ecf20Sopenharmony_ci * someone waiting for at most one other lock.  Given a requested lock
9888c2ecf20Sopenharmony_ci * caller_fl which is about to wait for a conflicting lock block_fl, we
9898c2ecf20Sopenharmony_ci * follow this chain of waiters to ensure we are not about to create a
9908c2ecf20Sopenharmony_ci * cycle.
9918c2ecf20Sopenharmony_ci *
9928c2ecf20Sopenharmony_ci * Since we do this before we ever put a process to sleep on a lock, we
9938c2ecf20Sopenharmony_ci * are ensured that there is never a cycle; that is what guarantees that
9948c2ecf20Sopenharmony_ci * the while() loop in posix_locks_deadlock() eventually completes.
9958c2ecf20Sopenharmony_ci *
9968c2ecf20Sopenharmony_ci * Note: the above assumption may not be true when handling lock
9978c2ecf20Sopenharmony_ci * requests from a broken NFS client. It may also fail in the presence
9988c2ecf20Sopenharmony_ci * of tasks (such as posix threads) sharing the same open file table.
9998c2ecf20Sopenharmony_ci * To handle those cases, we just bail out after a few iterations.
10008c2ecf20Sopenharmony_ci *
10018c2ecf20Sopenharmony_ci * For FL_OFDLCK locks, the owner is the filp, not the files_struct.
10028c2ecf20Sopenharmony_ci * Because the owner is not even nominally tied to a thread of
10038c2ecf20Sopenharmony_ci * execution, the deadlock detection below can't reasonably work well. Just
10048c2ecf20Sopenharmony_ci * skip it for those.
10058c2ecf20Sopenharmony_ci *
10068c2ecf20Sopenharmony_ci * In principle, we could do a more limited deadlock detection on FL_OFDLCK
10078c2ecf20Sopenharmony_ci * locks that just checks for the case where two tasks are attempting to
10088c2ecf20Sopenharmony_ci * upgrade from read to write locks on the same inode.
10098c2ecf20Sopenharmony_ci */
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci#define MAX_DEADLK_ITERATIONS 10
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci/* Find a lock that the owner of the given block_fl is blocking on. */
10148c2ecf20Sopenharmony_cistatic struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
10158c2ecf20Sopenharmony_ci{
10168c2ecf20Sopenharmony_ci	struct file_lock *fl;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) {
10198c2ecf20Sopenharmony_ci		if (posix_same_owner(fl, block_fl)) {
10208c2ecf20Sopenharmony_ci			while (fl->fl_blocker)
10218c2ecf20Sopenharmony_ci				fl = fl->fl_blocker;
10228c2ecf20Sopenharmony_ci			return fl;
10238c2ecf20Sopenharmony_ci		}
10248c2ecf20Sopenharmony_ci	}
10258c2ecf20Sopenharmony_ci	return NULL;
10268c2ecf20Sopenharmony_ci}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci/* Must be called with the blocked_lock_lock held! */
10298c2ecf20Sopenharmony_cistatic int posix_locks_deadlock(struct file_lock *caller_fl,
10308c2ecf20Sopenharmony_ci				struct file_lock *block_fl)
10318c2ecf20Sopenharmony_ci{
10328c2ecf20Sopenharmony_ci	int i = 0;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	lockdep_assert_held(&blocked_lock_lock);
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	/*
10378c2ecf20Sopenharmony_ci	 * This deadlock detector can't reasonably detect deadlocks with
10388c2ecf20Sopenharmony_ci	 * FL_OFDLCK locks, since they aren't owned by a process, per-se.
10398c2ecf20Sopenharmony_ci	 */
10408c2ecf20Sopenharmony_ci	if (IS_OFDLCK(caller_fl))
10418c2ecf20Sopenharmony_ci		return 0;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	while ((block_fl = what_owner_is_waiting_for(block_fl))) {
10448c2ecf20Sopenharmony_ci		if (i++ > MAX_DEADLK_ITERATIONS)
10458c2ecf20Sopenharmony_ci			return 0;
10468c2ecf20Sopenharmony_ci		if (posix_same_owner(caller_fl, block_fl))
10478c2ecf20Sopenharmony_ci			return 1;
10488c2ecf20Sopenharmony_ci	}
10498c2ecf20Sopenharmony_ci	return 0;
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
10538c2ecf20Sopenharmony_ci * after any leases, but before any posix locks.
10548c2ecf20Sopenharmony_ci *
10558c2ecf20Sopenharmony_ci * Note that if called with an FL_EXISTS argument, the caller may determine
10568c2ecf20Sopenharmony_ci * whether or not a lock was successfully freed by testing the return
10578c2ecf20Sopenharmony_ci * value for -ENOENT.
10588c2ecf20Sopenharmony_ci */
10598c2ecf20Sopenharmony_cistatic int flock_lock_inode(struct inode *inode, struct file_lock *request)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	struct file_lock *new_fl = NULL;
10628c2ecf20Sopenharmony_ci	struct file_lock *fl;
10638c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
10648c2ecf20Sopenharmony_ci	int error = 0;
10658c2ecf20Sopenharmony_ci	bool found = false;
10668c2ecf20Sopenharmony_ci	LIST_HEAD(dispose);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	ctx = locks_get_lock_context(inode, request->fl_type);
10698c2ecf20Sopenharmony_ci	if (!ctx) {
10708c2ecf20Sopenharmony_ci		if (request->fl_type != F_UNLCK)
10718c2ecf20Sopenharmony_ci			return -ENOMEM;
10728c2ecf20Sopenharmony_ci		return (request->fl_flags & FL_EXISTS) ? -ENOENT : 0;
10738c2ecf20Sopenharmony_ci	}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {
10768c2ecf20Sopenharmony_ci		new_fl = locks_alloc_lock();
10778c2ecf20Sopenharmony_ci		if (!new_fl)
10788c2ecf20Sopenharmony_ci			return -ENOMEM;
10798c2ecf20Sopenharmony_ci	}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	percpu_down_read(&file_rwsem);
10828c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
10838c2ecf20Sopenharmony_ci	if (request->fl_flags & FL_ACCESS)
10848c2ecf20Sopenharmony_ci		goto find_conflict;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
10878c2ecf20Sopenharmony_ci		if (request->fl_file != fl->fl_file)
10888c2ecf20Sopenharmony_ci			continue;
10898c2ecf20Sopenharmony_ci		if (request->fl_type == fl->fl_type)
10908c2ecf20Sopenharmony_ci			goto out;
10918c2ecf20Sopenharmony_ci		found = true;
10928c2ecf20Sopenharmony_ci		locks_delete_lock_ctx(fl, &dispose);
10938c2ecf20Sopenharmony_ci		break;
10948c2ecf20Sopenharmony_ci	}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	if (request->fl_type == F_UNLCK) {
10978c2ecf20Sopenharmony_ci		if ((request->fl_flags & FL_EXISTS) && !found)
10988c2ecf20Sopenharmony_ci			error = -ENOENT;
10998c2ecf20Sopenharmony_ci		goto out;
11008c2ecf20Sopenharmony_ci	}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_cifind_conflict:
11038c2ecf20Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
11048c2ecf20Sopenharmony_ci		if (!flock_locks_conflict(request, fl))
11058c2ecf20Sopenharmony_ci			continue;
11068c2ecf20Sopenharmony_ci		error = -EAGAIN;
11078c2ecf20Sopenharmony_ci		if (!(request->fl_flags & FL_SLEEP))
11088c2ecf20Sopenharmony_ci			goto out;
11098c2ecf20Sopenharmony_ci		error = FILE_LOCK_DEFERRED;
11108c2ecf20Sopenharmony_ci		locks_insert_block(fl, request, flock_locks_conflict);
11118c2ecf20Sopenharmony_ci		goto out;
11128c2ecf20Sopenharmony_ci	}
11138c2ecf20Sopenharmony_ci	if (request->fl_flags & FL_ACCESS)
11148c2ecf20Sopenharmony_ci		goto out;
11158c2ecf20Sopenharmony_ci	locks_copy_lock(new_fl, request);
11168c2ecf20Sopenharmony_ci	locks_move_blocks(new_fl, request);
11178c2ecf20Sopenharmony_ci	locks_insert_lock_ctx(new_fl, &ctx->flc_flock);
11188c2ecf20Sopenharmony_ci	new_fl = NULL;
11198c2ecf20Sopenharmony_ci	error = 0;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ciout:
11228c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
11238c2ecf20Sopenharmony_ci	percpu_up_read(&file_rwsem);
11248c2ecf20Sopenharmony_ci	if (new_fl)
11258c2ecf20Sopenharmony_ci		locks_free_lock(new_fl);
11268c2ecf20Sopenharmony_ci	locks_dispose_list(&dispose);
11278c2ecf20Sopenharmony_ci	trace_flock_lock_inode(inode, request, error);
11288c2ecf20Sopenharmony_ci	return error;
11298c2ecf20Sopenharmony_ci}
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_cistatic int posix_lock_inode(struct inode *inode, struct file_lock *request,
11328c2ecf20Sopenharmony_ci			    struct file_lock *conflock)
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	struct file_lock *fl, *tmp;
11358c2ecf20Sopenharmony_ci	struct file_lock *new_fl = NULL;
11368c2ecf20Sopenharmony_ci	struct file_lock *new_fl2 = NULL;
11378c2ecf20Sopenharmony_ci	struct file_lock *left = NULL;
11388c2ecf20Sopenharmony_ci	struct file_lock *right = NULL;
11398c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
11408c2ecf20Sopenharmony_ci	int error;
11418c2ecf20Sopenharmony_ci	bool added = false;
11428c2ecf20Sopenharmony_ci	LIST_HEAD(dispose);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	ctx = locks_get_lock_context(inode, request->fl_type);
11458c2ecf20Sopenharmony_ci	if (!ctx)
11468c2ecf20Sopenharmony_ci		return (request->fl_type == F_UNLCK) ? 0 : -ENOMEM;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	/*
11498c2ecf20Sopenharmony_ci	 * We may need two file_lock structures for this operation,
11508c2ecf20Sopenharmony_ci	 * so we get them in advance to avoid races.
11518c2ecf20Sopenharmony_ci	 *
11528c2ecf20Sopenharmony_ci	 * In some cases we can be sure, that no new locks will be needed
11538c2ecf20Sopenharmony_ci	 */
11548c2ecf20Sopenharmony_ci	if (!(request->fl_flags & FL_ACCESS) &&
11558c2ecf20Sopenharmony_ci	    (request->fl_type != F_UNLCK ||
11568c2ecf20Sopenharmony_ci	     request->fl_start != 0 || request->fl_end != OFFSET_MAX)) {
11578c2ecf20Sopenharmony_ci		new_fl = locks_alloc_lock();
11588c2ecf20Sopenharmony_ci		new_fl2 = locks_alloc_lock();
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	percpu_down_read(&file_rwsem);
11628c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
11638c2ecf20Sopenharmony_ci	/*
11648c2ecf20Sopenharmony_ci	 * New lock request. Walk all POSIX locks and look for conflicts. If
11658c2ecf20Sopenharmony_ci	 * there are any, either return error or put the request on the
11668c2ecf20Sopenharmony_ci	 * blocker's list of waiters and the global blocked_hash.
11678c2ecf20Sopenharmony_ci	 */
11688c2ecf20Sopenharmony_ci	if (request->fl_type != F_UNLCK) {
11698c2ecf20Sopenharmony_ci		list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
11708c2ecf20Sopenharmony_ci			if (!posix_locks_conflict(request, fl))
11718c2ecf20Sopenharmony_ci				continue;
11728c2ecf20Sopenharmony_ci			if (conflock)
11738c2ecf20Sopenharmony_ci				locks_copy_conflock(conflock, fl);
11748c2ecf20Sopenharmony_ci			error = -EAGAIN;
11758c2ecf20Sopenharmony_ci			if (!(request->fl_flags & FL_SLEEP))
11768c2ecf20Sopenharmony_ci				goto out;
11778c2ecf20Sopenharmony_ci			/*
11788c2ecf20Sopenharmony_ci			 * Deadlock detection and insertion into the blocked
11798c2ecf20Sopenharmony_ci			 * locks list must be done while holding the same lock!
11808c2ecf20Sopenharmony_ci			 */
11818c2ecf20Sopenharmony_ci			error = -EDEADLK;
11828c2ecf20Sopenharmony_ci			spin_lock(&blocked_lock_lock);
11838c2ecf20Sopenharmony_ci			/*
11848c2ecf20Sopenharmony_ci			 * Ensure that we don't find any locks blocked on this
11858c2ecf20Sopenharmony_ci			 * request during deadlock detection.
11868c2ecf20Sopenharmony_ci			 */
11878c2ecf20Sopenharmony_ci			__locks_wake_up_blocks(request);
11888c2ecf20Sopenharmony_ci			if (likely(!posix_locks_deadlock(request, fl))) {
11898c2ecf20Sopenharmony_ci				error = FILE_LOCK_DEFERRED;
11908c2ecf20Sopenharmony_ci				__locks_insert_block(fl, request,
11918c2ecf20Sopenharmony_ci						     posix_locks_conflict);
11928c2ecf20Sopenharmony_ci			}
11938c2ecf20Sopenharmony_ci			spin_unlock(&blocked_lock_lock);
11948c2ecf20Sopenharmony_ci			goto out;
11958c2ecf20Sopenharmony_ci		}
11968c2ecf20Sopenharmony_ci	}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	/* If we're just looking for a conflict, we're done. */
11998c2ecf20Sopenharmony_ci	error = 0;
12008c2ecf20Sopenharmony_ci	if (request->fl_flags & FL_ACCESS)
12018c2ecf20Sopenharmony_ci		goto out;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	/* Find the first old lock with the same owner as the new lock */
12048c2ecf20Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
12058c2ecf20Sopenharmony_ci		if (posix_same_owner(request, fl))
12068c2ecf20Sopenharmony_ci			break;
12078c2ecf20Sopenharmony_ci	}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	/* Process locks with this owner. */
12108c2ecf20Sopenharmony_ci	list_for_each_entry_safe_from(fl, tmp, &ctx->flc_posix, fl_list) {
12118c2ecf20Sopenharmony_ci		if (!posix_same_owner(request, fl))
12128c2ecf20Sopenharmony_ci			break;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci		/* Detect adjacent or overlapping regions (if same lock type) */
12158c2ecf20Sopenharmony_ci		if (request->fl_type == fl->fl_type) {
12168c2ecf20Sopenharmony_ci			/* In all comparisons of start vs end, use
12178c2ecf20Sopenharmony_ci			 * "start - 1" rather than "end + 1". If end
12188c2ecf20Sopenharmony_ci			 * is OFFSET_MAX, end + 1 will become negative.
12198c2ecf20Sopenharmony_ci			 */
12208c2ecf20Sopenharmony_ci			if (fl->fl_end < request->fl_start - 1)
12218c2ecf20Sopenharmony_ci				continue;
12228c2ecf20Sopenharmony_ci			/* If the next lock in the list has entirely bigger
12238c2ecf20Sopenharmony_ci			 * addresses than the new one, insert the lock here.
12248c2ecf20Sopenharmony_ci			 */
12258c2ecf20Sopenharmony_ci			if (fl->fl_start - 1 > request->fl_end)
12268c2ecf20Sopenharmony_ci				break;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci			/* If we come here, the new and old lock are of the
12298c2ecf20Sopenharmony_ci			 * same type and adjacent or overlapping. Make one
12308c2ecf20Sopenharmony_ci			 * lock yielding from the lower start address of both
12318c2ecf20Sopenharmony_ci			 * locks to the higher end address.
12328c2ecf20Sopenharmony_ci			 */
12338c2ecf20Sopenharmony_ci			if (fl->fl_start > request->fl_start)
12348c2ecf20Sopenharmony_ci				fl->fl_start = request->fl_start;
12358c2ecf20Sopenharmony_ci			else
12368c2ecf20Sopenharmony_ci				request->fl_start = fl->fl_start;
12378c2ecf20Sopenharmony_ci			if (fl->fl_end < request->fl_end)
12388c2ecf20Sopenharmony_ci				fl->fl_end = request->fl_end;
12398c2ecf20Sopenharmony_ci			else
12408c2ecf20Sopenharmony_ci				request->fl_end = fl->fl_end;
12418c2ecf20Sopenharmony_ci			if (added) {
12428c2ecf20Sopenharmony_ci				locks_delete_lock_ctx(fl, &dispose);
12438c2ecf20Sopenharmony_ci				continue;
12448c2ecf20Sopenharmony_ci			}
12458c2ecf20Sopenharmony_ci			request = fl;
12468c2ecf20Sopenharmony_ci			added = true;
12478c2ecf20Sopenharmony_ci		} else {
12488c2ecf20Sopenharmony_ci			/* Processing for different lock types is a bit
12498c2ecf20Sopenharmony_ci			 * more complex.
12508c2ecf20Sopenharmony_ci			 */
12518c2ecf20Sopenharmony_ci			if (fl->fl_end < request->fl_start)
12528c2ecf20Sopenharmony_ci				continue;
12538c2ecf20Sopenharmony_ci			if (fl->fl_start > request->fl_end)
12548c2ecf20Sopenharmony_ci				break;
12558c2ecf20Sopenharmony_ci			if (request->fl_type == F_UNLCK)
12568c2ecf20Sopenharmony_ci				added = true;
12578c2ecf20Sopenharmony_ci			if (fl->fl_start < request->fl_start)
12588c2ecf20Sopenharmony_ci				left = fl;
12598c2ecf20Sopenharmony_ci			/* If the next lock in the list has a higher end
12608c2ecf20Sopenharmony_ci			 * address than the new one, insert the new one here.
12618c2ecf20Sopenharmony_ci			 */
12628c2ecf20Sopenharmony_ci			if (fl->fl_end > request->fl_end) {
12638c2ecf20Sopenharmony_ci				right = fl;
12648c2ecf20Sopenharmony_ci				break;
12658c2ecf20Sopenharmony_ci			}
12668c2ecf20Sopenharmony_ci			if (fl->fl_start >= request->fl_start) {
12678c2ecf20Sopenharmony_ci				/* The new lock completely replaces an old
12688c2ecf20Sopenharmony_ci				 * one (This may happen several times).
12698c2ecf20Sopenharmony_ci				 */
12708c2ecf20Sopenharmony_ci				if (added) {
12718c2ecf20Sopenharmony_ci					locks_delete_lock_ctx(fl, &dispose);
12728c2ecf20Sopenharmony_ci					continue;
12738c2ecf20Sopenharmony_ci				}
12748c2ecf20Sopenharmony_ci				/*
12758c2ecf20Sopenharmony_ci				 * Replace the old lock with new_fl, and
12768c2ecf20Sopenharmony_ci				 * remove the old one. It's safe to do the
12778c2ecf20Sopenharmony_ci				 * insert here since we know that we won't be
12788c2ecf20Sopenharmony_ci				 * using new_fl later, and that the lock is
12798c2ecf20Sopenharmony_ci				 * just replacing an existing lock.
12808c2ecf20Sopenharmony_ci				 */
12818c2ecf20Sopenharmony_ci				error = -ENOLCK;
12828c2ecf20Sopenharmony_ci				if (!new_fl)
12838c2ecf20Sopenharmony_ci					goto out;
12848c2ecf20Sopenharmony_ci				locks_copy_lock(new_fl, request);
12858c2ecf20Sopenharmony_ci				locks_move_blocks(new_fl, request);
12868c2ecf20Sopenharmony_ci				request = new_fl;
12878c2ecf20Sopenharmony_ci				new_fl = NULL;
12888c2ecf20Sopenharmony_ci				locks_insert_lock_ctx(request, &fl->fl_list);
12898c2ecf20Sopenharmony_ci				locks_delete_lock_ctx(fl, &dispose);
12908c2ecf20Sopenharmony_ci				added = true;
12918c2ecf20Sopenharmony_ci			}
12928c2ecf20Sopenharmony_ci		}
12938c2ecf20Sopenharmony_ci	}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	/*
12968c2ecf20Sopenharmony_ci	 * The above code only modifies existing locks in case of merging or
12978c2ecf20Sopenharmony_ci	 * replacing. If new lock(s) need to be inserted all modifications are
12988c2ecf20Sopenharmony_ci	 * done below this, so it's safe yet to bail out.
12998c2ecf20Sopenharmony_ci	 */
13008c2ecf20Sopenharmony_ci	error = -ENOLCK; /* "no luck" */
13018c2ecf20Sopenharmony_ci	if (right && left == right && !new_fl2)
13028c2ecf20Sopenharmony_ci		goto out;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	error = 0;
13058c2ecf20Sopenharmony_ci	if (!added) {
13068c2ecf20Sopenharmony_ci		if (request->fl_type == F_UNLCK) {
13078c2ecf20Sopenharmony_ci			if (request->fl_flags & FL_EXISTS)
13088c2ecf20Sopenharmony_ci				error = -ENOENT;
13098c2ecf20Sopenharmony_ci			goto out;
13108c2ecf20Sopenharmony_ci		}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		if (!new_fl) {
13138c2ecf20Sopenharmony_ci			error = -ENOLCK;
13148c2ecf20Sopenharmony_ci			goto out;
13158c2ecf20Sopenharmony_ci		}
13168c2ecf20Sopenharmony_ci		locks_copy_lock(new_fl, request);
13178c2ecf20Sopenharmony_ci		locks_move_blocks(new_fl, request);
13188c2ecf20Sopenharmony_ci		locks_insert_lock_ctx(new_fl, &fl->fl_list);
13198c2ecf20Sopenharmony_ci		fl = new_fl;
13208c2ecf20Sopenharmony_ci		new_fl = NULL;
13218c2ecf20Sopenharmony_ci	}
13228c2ecf20Sopenharmony_ci	if (right) {
13238c2ecf20Sopenharmony_ci		if (left == right) {
13248c2ecf20Sopenharmony_ci			/* The new lock breaks the old one in two pieces,
13258c2ecf20Sopenharmony_ci			 * so we have to use the second new lock.
13268c2ecf20Sopenharmony_ci			 */
13278c2ecf20Sopenharmony_ci			left = new_fl2;
13288c2ecf20Sopenharmony_ci			new_fl2 = NULL;
13298c2ecf20Sopenharmony_ci			locks_copy_lock(left, right);
13308c2ecf20Sopenharmony_ci			locks_insert_lock_ctx(left, &fl->fl_list);
13318c2ecf20Sopenharmony_ci		}
13328c2ecf20Sopenharmony_ci		right->fl_start = request->fl_end + 1;
13338c2ecf20Sopenharmony_ci		locks_wake_up_blocks(right);
13348c2ecf20Sopenharmony_ci	}
13358c2ecf20Sopenharmony_ci	if (left) {
13368c2ecf20Sopenharmony_ci		left->fl_end = request->fl_start - 1;
13378c2ecf20Sopenharmony_ci		locks_wake_up_blocks(left);
13388c2ecf20Sopenharmony_ci	}
13398c2ecf20Sopenharmony_ci out:
13408c2ecf20Sopenharmony_ci	trace_posix_lock_inode(inode, request, error);
13418c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
13428c2ecf20Sopenharmony_ci	percpu_up_read(&file_rwsem);
13438c2ecf20Sopenharmony_ci	/*
13448c2ecf20Sopenharmony_ci	 * Free any unused locks.
13458c2ecf20Sopenharmony_ci	 */
13468c2ecf20Sopenharmony_ci	if (new_fl)
13478c2ecf20Sopenharmony_ci		locks_free_lock(new_fl);
13488c2ecf20Sopenharmony_ci	if (new_fl2)
13498c2ecf20Sopenharmony_ci		locks_free_lock(new_fl2);
13508c2ecf20Sopenharmony_ci	locks_dispose_list(&dispose);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	return error;
13538c2ecf20Sopenharmony_ci}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci/**
13568c2ecf20Sopenharmony_ci * posix_lock_file - Apply a POSIX-style lock to a file
13578c2ecf20Sopenharmony_ci * @filp: The file to apply the lock to
13588c2ecf20Sopenharmony_ci * @fl: The lock to be applied
13598c2ecf20Sopenharmony_ci * @conflock: Place to return a copy of the conflicting lock, if found.
13608c2ecf20Sopenharmony_ci *
13618c2ecf20Sopenharmony_ci * Add a POSIX style lock to a file.
13628c2ecf20Sopenharmony_ci * We merge adjacent & overlapping locks whenever possible.
13638c2ecf20Sopenharmony_ci * POSIX locks are sorted by owner task, then by starting address
13648c2ecf20Sopenharmony_ci *
13658c2ecf20Sopenharmony_ci * Note that if called with an FL_EXISTS argument, the caller may determine
13668c2ecf20Sopenharmony_ci * whether or not a lock was successfully freed by testing the return
13678c2ecf20Sopenharmony_ci * value for -ENOENT.
13688c2ecf20Sopenharmony_ci */
13698c2ecf20Sopenharmony_ciint posix_lock_file(struct file *filp, struct file_lock *fl,
13708c2ecf20Sopenharmony_ci			struct file_lock *conflock)
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci	return posix_lock_inode(locks_inode(filp), fl, conflock);
13738c2ecf20Sopenharmony_ci}
13748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(posix_lock_file);
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci/**
13778c2ecf20Sopenharmony_ci * posix_lock_inode_wait - Apply a POSIX-style lock to a file
13788c2ecf20Sopenharmony_ci * @inode: inode of file to which lock request should be applied
13798c2ecf20Sopenharmony_ci * @fl: The lock to be applied
13808c2ecf20Sopenharmony_ci *
13818c2ecf20Sopenharmony_ci * Apply a POSIX style lock request to an inode.
13828c2ecf20Sopenharmony_ci */
13838c2ecf20Sopenharmony_cistatic int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
13848c2ecf20Sopenharmony_ci{
13858c2ecf20Sopenharmony_ci	int error;
13868c2ecf20Sopenharmony_ci	might_sleep ();
13878c2ecf20Sopenharmony_ci	for (;;) {
13888c2ecf20Sopenharmony_ci		error = posix_lock_inode(inode, fl, NULL);
13898c2ecf20Sopenharmony_ci		if (error != FILE_LOCK_DEFERRED)
13908c2ecf20Sopenharmony_ci			break;
13918c2ecf20Sopenharmony_ci		error = wait_event_interruptible(fl->fl_wait,
13928c2ecf20Sopenharmony_ci					list_empty(&fl->fl_blocked_member));
13938c2ecf20Sopenharmony_ci		if (error)
13948c2ecf20Sopenharmony_ci			break;
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci	locks_delete_block(fl);
13978c2ecf20Sopenharmony_ci	return error;
13988c2ecf20Sopenharmony_ci}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci#ifdef CONFIG_MANDATORY_FILE_LOCKING
14018c2ecf20Sopenharmony_ci/**
14028c2ecf20Sopenharmony_ci * locks_mandatory_locked - Check for an active lock
14038c2ecf20Sopenharmony_ci * @file: the file to check
14048c2ecf20Sopenharmony_ci *
14058c2ecf20Sopenharmony_ci * Searches the inode's list of locks to find any POSIX locks which conflict.
14068c2ecf20Sopenharmony_ci * This function is called from locks_verify_locked() only.
14078c2ecf20Sopenharmony_ci */
14088c2ecf20Sopenharmony_ciint locks_mandatory_locked(struct file *file)
14098c2ecf20Sopenharmony_ci{
14108c2ecf20Sopenharmony_ci	int ret;
14118c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(file);
14128c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
14138c2ecf20Sopenharmony_ci	struct file_lock *fl;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&inode->i_flctx);
14168c2ecf20Sopenharmony_ci	if (!ctx || list_empty_careful(&ctx->flc_posix))
14178c2ecf20Sopenharmony_ci		return 0;
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	/*
14208c2ecf20Sopenharmony_ci	 * Search the lock list for this inode for any POSIX locks.
14218c2ecf20Sopenharmony_ci	 */
14228c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
14238c2ecf20Sopenharmony_ci	ret = 0;
14248c2ecf20Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
14258c2ecf20Sopenharmony_ci		if (fl->fl_owner != current->files &&
14268c2ecf20Sopenharmony_ci		    fl->fl_owner != file) {
14278c2ecf20Sopenharmony_ci			ret = -EAGAIN;
14288c2ecf20Sopenharmony_ci			break;
14298c2ecf20Sopenharmony_ci		}
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
14328c2ecf20Sopenharmony_ci	return ret;
14338c2ecf20Sopenharmony_ci}
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci/**
14368c2ecf20Sopenharmony_ci * locks_mandatory_area - Check for a conflicting lock
14378c2ecf20Sopenharmony_ci * @inode:	the file to check
14388c2ecf20Sopenharmony_ci * @filp:       how the file was opened (if it was)
14398c2ecf20Sopenharmony_ci * @start:	first byte in the file to check
14408c2ecf20Sopenharmony_ci * @end:	lastbyte in the file to check
14418c2ecf20Sopenharmony_ci * @type:	%F_WRLCK for a write lock, else %F_RDLCK
14428c2ecf20Sopenharmony_ci *
14438c2ecf20Sopenharmony_ci * Searches the inode's list of locks to find any POSIX locks which conflict.
14448c2ecf20Sopenharmony_ci */
14458c2ecf20Sopenharmony_ciint locks_mandatory_area(struct inode *inode, struct file *filp, loff_t start,
14468c2ecf20Sopenharmony_ci			 loff_t end, unsigned char type)
14478c2ecf20Sopenharmony_ci{
14488c2ecf20Sopenharmony_ci	struct file_lock fl;
14498c2ecf20Sopenharmony_ci	int error;
14508c2ecf20Sopenharmony_ci	bool sleep = false;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	locks_init_lock(&fl);
14538c2ecf20Sopenharmony_ci	fl.fl_pid = current->tgid;
14548c2ecf20Sopenharmony_ci	fl.fl_file = filp;
14558c2ecf20Sopenharmony_ci	fl.fl_flags = FL_POSIX | FL_ACCESS;
14568c2ecf20Sopenharmony_ci	if (filp && !(filp->f_flags & O_NONBLOCK))
14578c2ecf20Sopenharmony_ci		sleep = true;
14588c2ecf20Sopenharmony_ci	fl.fl_type = type;
14598c2ecf20Sopenharmony_ci	fl.fl_start = start;
14608c2ecf20Sopenharmony_ci	fl.fl_end = end;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	for (;;) {
14638c2ecf20Sopenharmony_ci		if (filp) {
14648c2ecf20Sopenharmony_ci			fl.fl_owner = filp;
14658c2ecf20Sopenharmony_ci			fl.fl_flags &= ~FL_SLEEP;
14668c2ecf20Sopenharmony_ci			error = posix_lock_inode(inode, &fl, NULL);
14678c2ecf20Sopenharmony_ci			if (!error)
14688c2ecf20Sopenharmony_ci				break;
14698c2ecf20Sopenharmony_ci		}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci		if (sleep)
14728c2ecf20Sopenharmony_ci			fl.fl_flags |= FL_SLEEP;
14738c2ecf20Sopenharmony_ci		fl.fl_owner = current->files;
14748c2ecf20Sopenharmony_ci		error = posix_lock_inode(inode, &fl, NULL);
14758c2ecf20Sopenharmony_ci		if (error != FILE_LOCK_DEFERRED)
14768c2ecf20Sopenharmony_ci			break;
14778c2ecf20Sopenharmony_ci		error = wait_event_interruptible(fl.fl_wait,
14788c2ecf20Sopenharmony_ci					list_empty(&fl.fl_blocked_member));
14798c2ecf20Sopenharmony_ci		if (!error) {
14808c2ecf20Sopenharmony_ci			/*
14818c2ecf20Sopenharmony_ci			 * If we've been sleeping someone might have
14828c2ecf20Sopenharmony_ci			 * changed the permissions behind our back.
14838c2ecf20Sopenharmony_ci			 */
14848c2ecf20Sopenharmony_ci			if (__mandatory_lock(inode))
14858c2ecf20Sopenharmony_ci				continue;
14868c2ecf20Sopenharmony_ci		}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci		break;
14898c2ecf20Sopenharmony_ci	}
14908c2ecf20Sopenharmony_ci	locks_delete_block(&fl);
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	return error;
14938c2ecf20Sopenharmony_ci}
14948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locks_mandatory_area);
14958c2ecf20Sopenharmony_ci#endif /* CONFIG_MANDATORY_FILE_LOCKING */
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_cistatic void lease_clear_pending(struct file_lock *fl, int arg)
14988c2ecf20Sopenharmony_ci{
14998c2ecf20Sopenharmony_ci	switch (arg) {
15008c2ecf20Sopenharmony_ci	case F_UNLCK:
15018c2ecf20Sopenharmony_ci		fl->fl_flags &= ~FL_UNLOCK_PENDING;
15028c2ecf20Sopenharmony_ci		fallthrough;
15038c2ecf20Sopenharmony_ci	case F_RDLCK:
15048c2ecf20Sopenharmony_ci		fl->fl_flags &= ~FL_DOWNGRADE_PENDING;
15058c2ecf20Sopenharmony_ci	}
15068c2ecf20Sopenharmony_ci}
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci/* We already had a lease on this file; just change its type */
15098c2ecf20Sopenharmony_ciint lease_modify(struct file_lock *fl, int arg, struct list_head *dispose)
15108c2ecf20Sopenharmony_ci{
15118c2ecf20Sopenharmony_ci	int error = assign_type(fl, arg);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	if (error)
15148c2ecf20Sopenharmony_ci		return error;
15158c2ecf20Sopenharmony_ci	lease_clear_pending(fl, arg);
15168c2ecf20Sopenharmony_ci	locks_wake_up_blocks(fl);
15178c2ecf20Sopenharmony_ci	if (arg == F_UNLCK) {
15188c2ecf20Sopenharmony_ci		struct file *filp = fl->fl_file;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci		f_delown(filp);
15218c2ecf20Sopenharmony_ci		filp->f_owner.signum = 0;
15228c2ecf20Sopenharmony_ci		fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
15238c2ecf20Sopenharmony_ci		if (fl->fl_fasync != NULL) {
15248c2ecf20Sopenharmony_ci			printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
15258c2ecf20Sopenharmony_ci			fl->fl_fasync = NULL;
15268c2ecf20Sopenharmony_ci		}
15278c2ecf20Sopenharmony_ci		locks_delete_lock_ctx(fl, dispose);
15288c2ecf20Sopenharmony_ci	}
15298c2ecf20Sopenharmony_ci	return 0;
15308c2ecf20Sopenharmony_ci}
15318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lease_modify);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_cistatic bool past_time(unsigned long then)
15348c2ecf20Sopenharmony_ci{
15358c2ecf20Sopenharmony_ci	if (!then)
15368c2ecf20Sopenharmony_ci		/* 0 is a special value meaning "this never expires": */
15378c2ecf20Sopenharmony_ci		return false;
15388c2ecf20Sopenharmony_ci	return time_after(jiffies, then);
15398c2ecf20Sopenharmony_ci}
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_cistatic void time_out_leases(struct inode *inode, struct list_head *dispose)
15428c2ecf20Sopenharmony_ci{
15438c2ecf20Sopenharmony_ci	struct file_lock_context *ctx = inode->i_flctx;
15448c2ecf20Sopenharmony_ci	struct file_lock *fl, *tmp;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	lockdep_assert_held(&ctx->flc_lock);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) {
15498c2ecf20Sopenharmony_ci		trace_time_out_leases(inode, fl);
15508c2ecf20Sopenharmony_ci		if (past_time(fl->fl_downgrade_time))
15518c2ecf20Sopenharmony_ci			lease_modify(fl, F_RDLCK, dispose);
15528c2ecf20Sopenharmony_ci		if (past_time(fl->fl_break_time))
15538c2ecf20Sopenharmony_ci			lease_modify(fl, F_UNLCK, dispose);
15548c2ecf20Sopenharmony_ci	}
15558c2ecf20Sopenharmony_ci}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_cistatic bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
15588c2ecf20Sopenharmony_ci{
15598c2ecf20Sopenharmony_ci	bool rc;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	if (lease->fl_lmops->lm_breaker_owns_lease
15628c2ecf20Sopenharmony_ci			&& lease->fl_lmops->lm_breaker_owns_lease(lease))
15638c2ecf20Sopenharmony_ci		return false;
15648c2ecf20Sopenharmony_ci	if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT)) {
15658c2ecf20Sopenharmony_ci		rc = false;
15668c2ecf20Sopenharmony_ci		goto trace;
15678c2ecf20Sopenharmony_ci	}
15688c2ecf20Sopenharmony_ci	if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) {
15698c2ecf20Sopenharmony_ci		rc = false;
15708c2ecf20Sopenharmony_ci		goto trace;
15718c2ecf20Sopenharmony_ci	}
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	rc = locks_conflict(breaker, lease);
15748c2ecf20Sopenharmony_citrace:
15758c2ecf20Sopenharmony_ci	trace_leases_conflict(rc, lease, breaker);
15768c2ecf20Sopenharmony_ci	return rc;
15778c2ecf20Sopenharmony_ci}
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_cistatic bool
15808c2ecf20Sopenharmony_ciany_leases_conflict(struct inode *inode, struct file_lock *breaker)
15818c2ecf20Sopenharmony_ci{
15828c2ecf20Sopenharmony_ci	struct file_lock_context *ctx = inode->i_flctx;
15838c2ecf20Sopenharmony_ci	struct file_lock *fl;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	lockdep_assert_held(&ctx->flc_lock);
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
15888c2ecf20Sopenharmony_ci		if (leases_conflict(fl, breaker))
15898c2ecf20Sopenharmony_ci			return true;
15908c2ecf20Sopenharmony_ci	}
15918c2ecf20Sopenharmony_ci	return false;
15928c2ecf20Sopenharmony_ci}
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci/**
15958c2ecf20Sopenharmony_ci *	__break_lease	-	revoke all outstanding leases on file
15968c2ecf20Sopenharmony_ci *	@inode: the inode of the file to return
15978c2ecf20Sopenharmony_ci *	@mode: O_RDONLY: break only write leases; O_WRONLY or O_RDWR:
15988c2ecf20Sopenharmony_ci *	    break all leases
15998c2ecf20Sopenharmony_ci *	@type: FL_LEASE: break leases and delegations; FL_DELEG: break
16008c2ecf20Sopenharmony_ci *	    only delegations
16018c2ecf20Sopenharmony_ci *
16028c2ecf20Sopenharmony_ci *	break_lease (inlined for speed) has checked there already is at least
16038c2ecf20Sopenharmony_ci *	some kind of lock (maybe a lease) on this file.  Leases are broken on
16048c2ecf20Sopenharmony_ci *	a call to open() or truncate().  This function can sleep unless you
16058c2ecf20Sopenharmony_ci *	specified %O_NONBLOCK to your open().
16068c2ecf20Sopenharmony_ci */
16078c2ecf20Sopenharmony_ciint __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	int error = 0;
16108c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
16118c2ecf20Sopenharmony_ci	struct file_lock *new_fl, *fl, *tmp;
16128c2ecf20Sopenharmony_ci	unsigned long break_time;
16138c2ecf20Sopenharmony_ci	int want_write = (mode & O_ACCMODE) != O_RDONLY;
16148c2ecf20Sopenharmony_ci	LIST_HEAD(dispose);
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK);
16178c2ecf20Sopenharmony_ci	if (IS_ERR(new_fl))
16188c2ecf20Sopenharmony_ci		return PTR_ERR(new_fl);
16198c2ecf20Sopenharmony_ci	new_fl->fl_flags = type;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	/* typically we will check that ctx is non-NULL before calling */
16228c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&inode->i_flctx);
16238c2ecf20Sopenharmony_ci	if (!ctx) {
16248c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
16258c2ecf20Sopenharmony_ci		goto free_lock;
16268c2ecf20Sopenharmony_ci	}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	percpu_down_read(&file_rwsem);
16298c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	time_out_leases(inode, &dispose);
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	if (!any_leases_conflict(inode, new_fl))
16348c2ecf20Sopenharmony_ci		goto out;
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	break_time = 0;
16378c2ecf20Sopenharmony_ci	if (lease_break_time > 0) {
16388c2ecf20Sopenharmony_ci		break_time = jiffies + lease_break_time * HZ;
16398c2ecf20Sopenharmony_ci		if (break_time == 0)
16408c2ecf20Sopenharmony_ci			break_time++;	/* so that 0 means no break time */
16418c2ecf20Sopenharmony_ci	}
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) {
16448c2ecf20Sopenharmony_ci		if (!leases_conflict(fl, new_fl))
16458c2ecf20Sopenharmony_ci			continue;
16468c2ecf20Sopenharmony_ci		if (want_write) {
16478c2ecf20Sopenharmony_ci			if (fl->fl_flags & FL_UNLOCK_PENDING)
16488c2ecf20Sopenharmony_ci				continue;
16498c2ecf20Sopenharmony_ci			fl->fl_flags |= FL_UNLOCK_PENDING;
16508c2ecf20Sopenharmony_ci			fl->fl_break_time = break_time;
16518c2ecf20Sopenharmony_ci		} else {
16528c2ecf20Sopenharmony_ci			if (lease_breaking(fl))
16538c2ecf20Sopenharmony_ci				continue;
16548c2ecf20Sopenharmony_ci			fl->fl_flags |= FL_DOWNGRADE_PENDING;
16558c2ecf20Sopenharmony_ci			fl->fl_downgrade_time = break_time;
16568c2ecf20Sopenharmony_ci		}
16578c2ecf20Sopenharmony_ci		if (fl->fl_lmops->lm_break(fl))
16588c2ecf20Sopenharmony_ci			locks_delete_lock_ctx(fl, &dispose);
16598c2ecf20Sopenharmony_ci	}
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	if (list_empty(&ctx->flc_lease))
16628c2ecf20Sopenharmony_ci		goto out;
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	if (mode & O_NONBLOCK) {
16658c2ecf20Sopenharmony_ci		trace_break_lease_noblock(inode, new_fl);
16668c2ecf20Sopenharmony_ci		error = -EWOULDBLOCK;
16678c2ecf20Sopenharmony_ci		goto out;
16688c2ecf20Sopenharmony_ci	}
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_cirestart:
16718c2ecf20Sopenharmony_ci	fl = list_first_entry(&ctx->flc_lease, struct file_lock, fl_list);
16728c2ecf20Sopenharmony_ci	break_time = fl->fl_break_time;
16738c2ecf20Sopenharmony_ci	if (break_time != 0)
16748c2ecf20Sopenharmony_ci		break_time -= jiffies;
16758c2ecf20Sopenharmony_ci	if (break_time == 0)
16768c2ecf20Sopenharmony_ci		break_time++;
16778c2ecf20Sopenharmony_ci	locks_insert_block(fl, new_fl, leases_conflict);
16788c2ecf20Sopenharmony_ci	trace_break_lease_block(inode, new_fl);
16798c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
16808c2ecf20Sopenharmony_ci	percpu_up_read(&file_rwsem);
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	locks_dispose_list(&dispose);
16838c2ecf20Sopenharmony_ci	error = wait_event_interruptible_timeout(new_fl->fl_wait,
16848c2ecf20Sopenharmony_ci					list_empty(&new_fl->fl_blocked_member),
16858c2ecf20Sopenharmony_ci					break_time);
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	percpu_down_read(&file_rwsem);
16888c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
16898c2ecf20Sopenharmony_ci	trace_break_lease_unblock(inode, new_fl);
16908c2ecf20Sopenharmony_ci	locks_delete_block(new_fl);
16918c2ecf20Sopenharmony_ci	if (error >= 0) {
16928c2ecf20Sopenharmony_ci		/*
16938c2ecf20Sopenharmony_ci		 * Wait for the next conflicting lease that has not been
16948c2ecf20Sopenharmony_ci		 * broken yet
16958c2ecf20Sopenharmony_ci		 */
16968c2ecf20Sopenharmony_ci		if (error == 0)
16978c2ecf20Sopenharmony_ci			time_out_leases(inode, &dispose);
16988c2ecf20Sopenharmony_ci		if (any_leases_conflict(inode, new_fl))
16998c2ecf20Sopenharmony_ci			goto restart;
17008c2ecf20Sopenharmony_ci		error = 0;
17018c2ecf20Sopenharmony_ci	}
17028c2ecf20Sopenharmony_ciout:
17038c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
17048c2ecf20Sopenharmony_ci	percpu_up_read(&file_rwsem);
17058c2ecf20Sopenharmony_ci	locks_dispose_list(&dispose);
17068c2ecf20Sopenharmony_cifree_lock:
17078c2ecf20Sopenharmony_ci	locks_free_lock(new_fl);
17088c2ecf20Sopenharmony_ci	return error;
17098c2ecf20Sopenharmony_ci}
17108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__break_lease);
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci/**
17138c2ecf20Sopenharmony_ci *	lease_get_mtime - update modified time of an inode with exclusive lease
17148c2ecf20Sopenharmony_ci *	@inode: the inode
17158c2ecf20Sopenharmony_ci *      @time:  pointer to a timespec which contains the last modified time
17168c2ecf20Sopenharmony_ci *
17178c2ecf20Sopenharmony_ci * This is to force NFS clients to flush their caches for files with
17188c2ecf20Sopenharmony_ci * exclusive leases.  The justification is that if someone has an
17198c2ecf20Sopenharmony_ci * exclusive lease, then they could be modifying it.
17208c2ecf20Sopenharmony_ci */
17218c2ecf20Sopenharmony_civoid lease_get_mtime(struct inode *inode, struct timespec64 *time)
17228c2ecf20Sopenharmony_ci{
17238c2ecf20Sopenharmony_ci	bool has_lease = false;
17248c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
17258c2ecf20Sopenharmony_ci	struct file_lock *fl;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&inode->i_flctx);
17288c2ecf20Sopenharmony_ci	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
17298c2ecf20Sopenharmony_ci		spin_lock(&ctx->flc_lock);
17308c2ecf20Sopenharmony_ci		fl = list_first_entry_or_null(&ctx->flc_lease,
17318c2ecf20Sopenharmony_ci					      struct file_lock, fl_list);
17328c2ecf20Sopenharmony_ci		if (fl && (fl->fl_type == F_WRLCK))
17338c2ecf20Sopenharmony_ci			has_lease = true;
17348c2ecf20Sopenharmony_ci		spin_unlock(&ctx->flc_lock);
17358c2ecf20Sopenharmony_ci	}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	if (has_lease)
17388c2ecf20Sopenharmony_ci		*time = current_time(inode);
17398c2ecf20Sopenharmony_ci}
17408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lease_get_mtime);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci/**
17438c2ecf20Sopenharmony_ci *	fcntl_getlease - Enquire what lease is currently active
17448c2ecf20Sopenharmony_ci *	@filp: the file
17458c2ecf20Sopenharmony_ci *
17468c2ecf20Sopenharmony_ci *	The value returned by this function will be one of
17478c2ecf20Sopenharmony_ci *	(if no lease break is pending):
17488c2ecf20Sopenharmony_ci *
17498c2ecf20Sopenharmony_ci *	%F_RDLCK to indicate a shared lease is held.
17508c2ecf20Sopenharmony_ci *
17518c2ecf20Sopenharmony_ci *	%F_WRLCK to indicate an exclusive lease is held.
17528c2ecf20Sopenharmony_ci *
17538c2ecf20Sopenharmony_ci *	%F_UNLCK to indicate no lease is held.
17548c2ecf20Sopenharmony_ci *
17558c2ecf20Sopenharmony_ci *	(if a lease break is pending):
17568c2ecf20Sopenharmony_ci *
17578c2ecf20Sopenharmony_ci *	%F_RDLCK to indicate an exclusive lease needs to be
17588c2ecf20Sopenharmony_ci *		changed to a shared lease (or removed).
17598c2ecf20Sopenharmony_ci *
17608c2ecf20Sopenharmony_ci *	%F_UNLCK to indicate the lease needs to be removed.
17618c2ecf20Sopenharmony_ci *
17628c2ecf20Sopenharmony_ci *	XXX: sfr & willy disagree over whether F_INPROGRESS
17638c2ecf20Sopenharmony_ci *	should be returned to userspace.
17648c2ecf20Sopenharmony_ci */
17658c2ecf20Sopenharmony_ciint fcntl_getlease(struct file *filp)
17668c2ecf20Sopenharmony_ci{
17678c2ecf20Sopenharmony_ci	struct file_lock *fl;
17688c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
17698c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
17708c2ecf20Sopenharmony_ci	int type = F_UNLCK;
17718c2ecf20Sopenharmony_ci	LIST_HEAD(dispose);
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&inode->i_flctx);
17748c2ecf20Sopenharmony_ci	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
17758c2ecf20Sopenharmony_ci		percpu_down_read(&file_rwsem);
17768c2ecf20Sopenharmony_ci		spin_lock(&ctx->flc_lock);
17778c2ecf20Sopenharmony_ci		time_out_leases(inode, &dispose);
17788c2ecf20Sopenharmony_ci		list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
17798c2ecf20Sopenharmony_ci			if (fl->fl_file != filp)
17808c2ecf20Sopenharmony_ci				continue;
17818c2ecf20Sopenharmony_ci			type = target_leasetype(fl);
17828c2ecf20Sopenharmony_ci			break;
17838c2ecf20Sopenharmony_ci		}
17848c2ecf20Sopenharmony_ci		spin_unlock(&ctx->flc_lock);
17858c2ecf20Sopenharmony_ci		percpu_up_read(&file_rwsem);
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci		locks_dispose_list(&dispose);
17888c2ecf20Sopenharmony_ci	}
17898c2ecf20Sopenharmony_ci	return type;
17908c2ecf20Sopenharmony_ci}
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci/**
17938c2ecf20Sopenharmony_ci * check_conflicting_open - see if the given file points to an inode that has
17948c2ecf20Sopenharmony_ci *			    an existing open that would conflict with the
17958c2ecf20Sopenharmony_ci *			    desired lease.
17968c2ecf20Sopenharmony_ci * @filp:	file to check
17978c2ecf20Sopenharmony_ci * @arg:	type of lease that we're trying to acquire
17988c2ecf20Sopenharmony_ci * @flags:	current lock flags
17998c2ecf20Sopenharmony_ci *
18008c2ecf20Sopenharmony_ci * Check to see if there's an existing open fd on this file that would
18018c2ecf20Sopenharmony_ci * conflict with the lease we're trying to set.
18028c2ecf20Sopenharmony_ci */
18038c2ecf20Sopenharmony_cistatic int
18048c2ecf20Sopenharmony_cicheck_conflicting_open(struct file *filp, const long arg, int flags)
18058c2ecf20Sopenharmony_ci{
18068c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
18078c2ecf20Sopenharmony_ci	int self_wcount = 0, self_rcount = 0;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	if (flags & FL_LAYOUT)
18108c2ecf20Sopenharmony_ci		return 0;
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	if (arg == F_RDLCK)
18138c2ecf20Sopenharmony_ci		return inode_is_open_for_write(inode) ? -EAGAIN : 0;
18148c2ecf20Sopenharmony_ci	else if (arg != F_WRLCK)
18158c2ecf20Sopenharmony_ci		return 0;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	/*
18188c2ecf20Sopenharmony_ci	 * Make sure that only read/write count is from lease requestor.
18198c2ecf20Sopenharmony_ci	 * Note that this will result in denying write leases when i_writecount
18208c2ecf20Sopenharmony_ci	 * is negative, which is what we want.  (We shouldn't grant write leases
18218c2ecf20Sopenharmony_ci	 * on files open for execution.)
18228c2ecf20Sopenharmony_ci	 */
18238c2ecf20Sopenharmony_ci	if (filp->f_mode & FMODE_WRITE)
18248c2ecf20Sopenharmony_ci		self_wcount = 1;
18258c2ecf20Sopenharmony_ci	else if (filp->f_mode & FMODE_READ)
18268c2ecf20Sopenharmony_ci		self_rcount = 1;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	if (atomic_read(&inode->i_writecount) != self_wcount ||
18298c2ecf20Sopenharmony_ci	    atomic_read(&inode->i_readcount) != self_rcount)
18308c2ecf20Sopenharmony_ci		return -EAGAIN;
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	return 0;
18338c2ecf20Sopenharmony_ci}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_cistatic int
18368c2ecf20Sopenharmony_cigeneric_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv)
18378c2ecf20Sopenharmony_ci{
18388c2ecf20Sopenharmony_ci	struct file_lock *fl, *my_fl = NULL, *lease;
18398c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
18408c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
18418c2ecf20Sopenharmony_ci	bool is_deleg = (*flp)->fl_flags & FL_DELEG;
18428c2ecf20Sopenharmony_ci	int error;
18438c2ecf20Sopenharmony_ci	LIST_HEAD(dispose);
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci	lease = *flp;
18468c2ecf20Sopenharmony_ci	trace_generic_add_lease(inode, lease);
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	/* Note that arg is never F_UNLCK here */
18498c2ecf20Sopenharmony_ci	ctx = locks_get_lock_context(inode, arg);
18508c2ecf20Sopenharmony_ci	if (!ctx)
18518c2ecf20Sopenharmony_ci		return -ENOMEM;
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	/*
18548c2ecf20Sopenharmony_ci	 * In the delegation case we need mutual exclusion with
18558c2ecf20Sopenharmony_ci	 * a number of operations that take the i_mutex.  We trylock
18568c2ecf20Sopenharmony_ci	 * because delegations are an optional optimization, and if
18578c2ecf20Sopenharmony_ci	 * there's some chance of a conflict--we'd rather not
18588c2ecf20Sopenharmony_ci	 * bother, maybe that's a sign this just isn't a good file to
18598c2ecf20Sopenharmony_ci	 * hand out a delegation on.
18608c2ecf20Sopenharmony_ci	 */
18618c2ecf20Sopenharmony_ci	if (is_deleg && !inode_trylock(inode))
18628c2ecf20Sopenharmony_ci		return -EAGAIN;
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	if (is_deleg && arg == F_WRLCK) {
18658c2ecf20Sopenharmony_ci		/* Write delegations are not currently supported: */
18668c2ecf20Sopenharmony_ci		inode_unlock(inode);
18678c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
18688c2ecf20Sopenharmony_ci		return -EINVAL;
18698c2ecf20Sopenharmony_ci	}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	percpu_down_read(&file_rwsem);
18728c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
18738c2ecf20Sopenharmony_ci	time_out_leases(inode, &dispose);
18748c2ecf20Sopenharmony_ci	error = check_conflicting_open(filp, arg, lease->fl_flags);
18758c2ecf20Sopenharmony_ci	if (error)
18768c2ecf20Sopenharmony_ci		goto out;
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	/*
18798c2ecf20Sopenharmony_ci	 * At this point, we know that if there is an exclusive
18808c2ecf20Sopenharmony_ci	 * lease on this file, then we hold it on this filp
18818c2ecf20Sopenharmony_ci	 * (otherwise our open of this file would have blocked).
18828c2ecf20Sopenharmony_ci	 * And if we are trying to acquire an exclusive lease,
18838c2ecf20Sopenharmony_ci	 * then the file is not open by anyone (including us)
18848c2ecf20Sopenharmony_ci	 * except for this filp.
18858c2ecf20Sopenharmony_ci	 */
18868c2ecf20Sopenharmony_ci	error = -EAGAIN;
18878c2ecf20Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
18888c2ecf20Sopenharmony_ci		if (fl->fl_file == filp &&
18898c2ecf20Sopenharmony_ci		    fl->fl_owner == lease->fl_owner) {
18908c2ecf20Sopenharmony_ci			my_fl = fl;
18918c2ecf20Sopenharmony_ci			continue;
18928c2ecf20Sopenharmony_ci		}
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci		/*
18958c2ecf20Sopenharmony_ci		 * No exclusive leases if someone else has a lease on
18968c2ecf20Sopenharmony_ci		 * this file:
18978c2ecf20Sopenharmony_ci		 */
18988c2ecf20Sopenharmony_ci		if (arg == F_WRLCK)
18998c2ecf20Sopenharmony_ci			goto out;
19008c2ecf20Sopenharmony_ci		/*
19018c2ecf20Sopenharmony_ci		 * Modifying our existing lease is OK, but no getting a
19028c2ecf20Sopenharmony_ci		 * new lease if someone else is opening for write:
19038c2ecf20Sopenharmony_ci		 */
19048c2ecf20Sopenharmony_ci		if (fl->fl_flags & FL_UNLOCK_PENDING)
19058c2ecf20Sopenharmony_ci			goto out;
19068c2ecf20Sopenharmony_ci	}
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci	if (my_fl != NULL) {
19098c2ecf20Sopenharmony_ci		lease = my_fl;
19108c2ecf20Sopenharmony_ci		error = lease->fl_lmops->lm_change(lease, arg, &dispose);
19118c2ecf20Sopenharmony_ci		if (error)
19128c2ecf20Sopenharmony_ci			goto out;
19138c2ecf20Sopenharmony_ci		goto out_setup;
19148c2ecf20Sopenharmony_ci	}
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	error = -EINVAL;
19178c2ecf20Sopenharmony_ci	if (!leases_enable)
19188c2ecf20Sopenharmony_ci		goto out;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	locks_insert_lock_ctx(lease, &ctx->flc_lease);
19218c2ecf20Sopenharmony_ci	/*
19228c2ecf20Sopenharmony_ci	 * The check in break_lease() is lockless. It's possible for another
19238c2ecf20Sopenharmony_ci	 * open to race in after we did the earlier check for a conflicting
19248c2ecf20Sopenharmony_ci	 * open but before the lease was inserted. Check again for a
19258c2ecf20Sopenharmony_ci	 * conflicting open and cancel the lease if there is one.
19268c2ecf20Sopenharmony_ci	 *
19278c2ecf20Sopenharmony_ci	 * We also add a barrier here to ensure that the insertion of the lock
19288c2ecf20Sopenharmony_ci	 * precedes these checks.
19298c2ecf20Sopenharmony_ci	 */
19308c2ecf20Sopenharmony_ci	smp_mb();
19318c2ecf20Sopenharmony_ci	error = check_conflicting_open(filp, arg, lease->fl_flags);
19328c2ecf20Sopenharmony_ci	if (error) {
19338c2ecf20Sopenharmony_ci		locks_unlink_lock_ctx(lease);
19348c2ecf20Sopenharmony_ci		goto out;
19358c2ecf20Sopenharmony_ci	}
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ciout_setup:
19388c2ecf20Sopenharmony_ci	if (lease->fl_lmops->lm_setup)
19398c2ecf20Sopenharmony_ci		lease->fl_lmops->lm_setup(lease, priv);
19408c2ecf20Sopenharmony_ciout:
19418c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
19428c2ecf20Sopenharmony_ci	percpu_up_read(&file_rwsem);
19438c2ecf20Sopenharmony_ci	locks_dispose_list(&dispose);
19448c2ecf20Sopenharmony_ci	if (is_deleg)
19458c2ecf20Sopenharmony_ci		inode_unlock(inode);
19468c2ecf20Sopenharmony_ci	if (!error && !my_fl)
19478c2ecf20Sopenharmony_ci		*flp = NULL;
19488c2ecf20Sopenharmony_ci	return error;
19498c2ecf20Sopenharmony_ci}
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_cistatic int generic_delete_lease(struct file *filp, void *owner)
19528c2ecf20Sopenharmony_ci{
19538c2ecf20Sopenharmony_ci	int error = -EAGAIN;
19548c2ecf20Sopenharmony_ci	struct file_lock *fl, *victim = NULL;
19558c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
19568c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
19578c2ecf20Sopenharmony_ci	LIST_HEAD(dispose);
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&inode->i_flctx);
19608c2ecf20Sopenharmony_ci	if (!ctx) {
19618c2ecf20Sopenharmony_ci		trace_generic_delete_lease(inode, NULL);
19628c2ecf20Sopenharmony_ci		return error;
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	percpu_down_read(&file_rwsem);
19668c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
19678c2ecf20Sopenharmony_ci	list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
19688c2ecf20Sopenharmony_ci		if (fl->fl_file == filp &&
19698c2ecf20Sopenharmony_ci		    fl->fl_owner == owner) {
19708c2ecf20Sopenharmony_ci			victim = fl;
19718c2ecf20Sopenharmony_ci			break;
19728c2ecf20Sopenharmony_ci		}
19738c2ecf20Sopenharmony_ci	}
19748c2ecf20Sopenharmony_ci	trace_generic_delete_lease(inode, victim);
19758c2ecf20Sopenharmony_ci	if (victim)
19768c2ecf20Sopenharmony_ci		error = fl->fl_lmops->lm_change(victim, F_UNLCK, &dispose);
19778c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
19788c2ecf20Sopenharmony_ci	percpu_up_read(&file_rwsem);
19798c2ecf20Sopenharmony_ci	locks_dispose_list(&dispose);
19808c2ecf20Sopenharmony_ci	return error;
19818c2ecf20Sopenharmony_ci}
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci/**
19848c2ecf20Sopenharmony_ci *	generic_setlease	-	sets a lease on an open file
19858c2ecf20Sopenharmony_ci *	@filp:	file pointer
19868c2ecf20Sopenharmony_ci *	@arg:	type of lease to obtain
19878c2ecf20Sopenharmony_ci *	@flp:	input - file_lock to use, output - file_lock inserted
19888c2ecf20Sopenharmony_ci *	@priv:	private data for lm_setup (may be NULL if lm_setup
19898c2ecf20Sopenharmony_ci *		doesn't require it)
19908c2ecf20Sopenharmony_ci *
19918c2ecf20Sopenharmony_ci *	The (input) flp->fl_lmops->lm_break function is required
19928c2ecf20Sopenharmony_ci *	by break_lease().
19938c2ecf20Sopenharmony_ci */
19948c2ecf20Sopenharmony_ciint generic_setlease(struct file *filp, long arg, struct file_lock **flp,
19958c2ecf20Sopenharmony_ci			void **priv)
19968c2ecf20Sopenharmony_ci{
19978c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
19988c2ecf20Sopenharmony_ci	int error;
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE))
20018c2ecf20Sopenharmony_ci		return -EACCES;
20028c2ecf20Sopenharmony_ci	if (!S_ISREG(inode->i_mode))
20038c2ecf20Sopenharmony_ci		return -EINVAL;
20048c2ecf20Sopenharmony_ci	error = security_file_lock(filp, arg);
20058c2ecf20Sopenharmony_ci	if (error)
20068c2ecf20Sopenharmony_ci		return error;
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	switch (arg) {
20098c2ecf20Sopenharmony_ci	case F_UNLCK:
20108c2ecf20Sopenharmony_ci		return generic_delete_lease(filp, *priv);
20118c2ecf20Sopenharmony_ci	case F_RDLCK:
20128c2ecf20Sopenharmony_ci	case F_WRLCK:
20138c2ecf20Sopenharmony_ci		if (!(*flp)->fl_lmops->lm_break) {
20148c2ecf20Sopenharmony_ci			WARN_ON_ONCE(1);
20158c2ecf20Sopenharmony_ci			return -ENOLCK;
20168c2ecf20Sopenharmony_ci		}
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci		return generic_add_lease(filp, arg, flp, priv);
20198c2ecf20Sopenharmony_ci	default:
20208c2ecf20Sopenharmony_ci		return -EINVAL;
20218c2ecf20Sopenharmony_ci	}
20228c2ecf20Sopenharmony_ci}
20238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(generic_setlease);
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SRCU)
20268c2ecf20Sopenharmony_ci/*
20278c2ecf20Sopenharmony_ci * Kernel subsystems can register to be notified on any attempt to set
20288c2ecf20Sopenharmony_ci * a new lease with the lease_notifier_chain. This is used by (e.g.) nfsd
20298c2ecf20Sopenharmony_ci * to close files that it may have cached when there is an attempt to set a
20308c2ecf20Sopenharmony_ci * conflicting lease.
20318c2ecf20Sopenharmony_ci */
20328c2ecf20Sopenharmony_cistatic struct srcu_notifier_head lease_notifier_chain;
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_cistatic inline void
20358c2ecf20Sopenharmony_cilease_notifier_chain_init(void)
20368c2ecf20Sopenharmony_ci{
20378c2ecf20Sopenharmony_ci	srcu_init_notifier_head(&lease_notifier_chain);
20388c2ecf20Sopenharmony_ci}
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_cistatic inline void
20418c2ecf20Sopenharmony_cisetlease_notifier(long arg, struct file_lock *lease)
20428c2ecf20Sopenharmony_ci{
20438c2ecf20Sopenharmony_ci	if (arg != F_UNLCK)
20448c2ecf20Sopenharmony_ci		srcu_notifier_call_chain(&lease_notifier_chain, arg, lease);
20458c2ecf20Sopenharmony_ci}
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ciint lease_register_notifier(struct notifier_block *nb)
20488c2ecf20Sopenharmony_ci{
20498c2ecf20Sopenharmony_ci	return srcu_notifier_chain_register(&lease_notifier_chain, nb);
20508c2ecf20Sopenharmony_ci}
20518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lease_register_notifier);
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_civoid lease_unregister_notifier(struct notifier_block *nb)
20548c2ecf20Sopenharmony_ci{
20558c2ecf20Sopenharmony_ci	srcu_notifier_chain_unregister(&lease_notifier_chain, nb);
20568c2ecf20Sopenharmony_ci}
20578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lease_unregister_notifier);
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci#else /* !IS_ENABLED(CONFIG_SRCU) */
20608c2ecf20Sopenharmony_cistatic inline void
20618c2ecf20Sopenharmony_cilease_notifier_chain_init(void)
20628c2ecf20Sopenharmony_ci{
20638c2ecf20Sopenharmony_ci}
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_cistatic inline void
20668c2ecf20Sopenharmony_cisetlease_notifier(long arg, struct file_lock *lease)
20678c2ecf20Sopenharmony_ci{
20688c2ecf20Sopenharmony_ci}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ciint lease_register_notifier(struct notifier_block *nb)
20718c2ecf20Sopenharmony_ci{
20728c2ecf20Sopenharmony_ci	return 0;
20738c2ecf20Sopenharmony_ci}
20748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lease_register_notifier);
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_civoid lease_unregister_notifier(struct notifier_block *nb)
20778c2ecf20Sopenharmony_ci{
20788c2ecf20Sopenharmony_ci}
20798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lease_unregister_notifier);
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_SRCU) */
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci/**
20848c2ecf20Sopenharmony_ci * vfs_setlease        -       sets a lease on an open file
20858c2ecf20Sopenharmony_ci * @filp:	file pointer
20868c2ecf20Sopenharmony_ci * @arg:	type of lease to obtain
20878c2ecf20Sopenharmony_ci * @lease:	file_lock to use when adding a lease
20888c2ecf20Sopenharmony_ci * @priv:	private info for lm_setup when adding a lease (may be
20898c2ecf20Sopenharmony_ci *		NULL if lm_setup doesn't require it)
20908c2ecf20Sopenharmony_ci *
20918c2ecf20Sopenharmony_ci * Call this to establish a lease on the file. The "lease" argument is not
20928c2ecf20Sopenharmony_ci * used for F_UNLCK requests and may be NULL. For commands that set or alter
20938c2ecf20Sopenharmony_ci * an existing lease, the ``(*lease)->fl_lmops->lm_break`` operation must be
20948c2ecf20Sopenharmony_ci * set; if not, this function will return -ENOLCK (and generate a scary-looking
20958c2ecf20Sopenharmony_ci * stack trace).
20968c2ecf20Sopenharmony_ci *
20978c2ecf20Sopenharmony_ci * The "priv" pointer is passed directly to the lm_setup function as-is. It
20988c2ecf20Sopenharmony_ci * may be NULL if the lm_setup operation doesn't require it.
20998c2ecf20Sopenharmony_ci */
21008c2ecf20Sopenharmony_ciint
21018c2ecf20Sopenharmony_civfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
21028c2ecf20Sopenharmony_ci{
21038c2ecf20Sopenharmony_ci	if (lease)
21048c2ecf20Sopenharmony_ci		setlease_notifier(arg, *lease);
21058c2ecf20Sopenharmony_ci	if (filp->f_op->setlease)
21068c2ecf20Sopenharmony_ci		return filp->f_op->setlease(filp, arg, lease, priv);
21078c2ecf20Sopenharmony_ci	else
21088c2ecf20Sopenharmony_ci		return generic_setlease(filp, arg, lease, priv);
21098c2ecf20Sopenharmony_ci}
21108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_setlease);
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_cistatic int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
21138c2ecf20Sopenharmony_ci{
21148c2ecf20Sopenharmony_ci	struct file_lock *fl;
21158c2ecf20Sopenharmony_ci	struct fasync_struct *new;
21168c2ecf20Sopenharmony_ci	int error;
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	fl = lease_alloc(filp, arg);
21198c2ecf20Sopenharmony_ci	if (IS_ERR(fl))
21208c2ecf20Sopenharmony_ci		return PTR_ERR(fl);
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	new = fasync_alloc();
21238c2ecf20Sopenharmony_ci	if (!new) {
21248c2ecf20Sopenharmony_ci		locks_free_lock(fl);
21258c2ecf20Sopenharmony_ci		return -ENOMEM;
21268c2ecf20Sopenharmony_ci	}
21278c2ecf20Sopenharmony_ci	new->fa_fd = fd;
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	error = vfs_setlease(filp, arg, &fl, (void **)&new);
21308c2ecf20Sopenharmony_ci	if (fl)
21318c2ecf20Sopenharmony_ci		locks_free_lock(fl);
21328c2ecf20Sopenharmony_ci	if (new)
21338c2ecf20Sopenharmony_ci		fasync_free(new);
21348c2ecf20Sopenharmony_ci	return error;
21358c2ecf20Sopenharmony_ci}
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci/**
21388c2ecf20Sopenharmony_ci *	fcntl_setlease	-	sets a lease on an open file
21398c2ecf20Sopenharmony_ci *	@fd: open file descriptor
21408c2ecf20Sopenharmony_ci *	@filp: file pointer
21418c2ecf20Sopenharmony_ci *	@arg: type of lease to obtain
21428c2ecf20Sopenharmony_ci *
21438c2ecf20Sopenharmony_ci *	Call this fcntl to establish a lease on the file.
21448c2ecf20Sopenharmony_ci *	Note that you also need to call %F_SETSIG to
21458c2ecf20Sopenharmony_ci *	receive a signal when the lease is broken.
21468c2ecf20Sopenharmony_ci */
21478c2ecf20Sopenharmony_ciint fcntl_setlease(unsigned int fd, struct file *filp, long arg)
21488c2ecf20Sopenharmony_ci{
21498c2ecf20Sopenharmony_ci	if (arg == F_UNLCK)
21508c2ecf20Sopenharmony_ci		return vfs_setlease(filp, F_UNLCK, NULL, (void **)&filp);
21518c2ecf20Sopenharmony_ci	return do_fcntl_add_lease(fd, filp, arg);
21528c2ecf20Sopenharmony_ci}
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci/**
21558c2ecf20Sopenharmony_ci * flock_lock_inode_wait - Apply a FLOCK-style lock to a file
21568c2ecf20Sopenharmony_ci * @inode: inode of the file to apply to
21578c2ecf20Sopenharmony_ci * @fl: The lock to be applied
21588c2ecf20Sopenharmony_ci *
21598c2ecf20Sopenharmony_ci * Apply a FLOCK style lock request to an inode.
21608c2ecf20Sopenharmony_ci */
21618c2ecf20Sopenharmony_cistatic int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
21628c2ecf20Sopenharmony_ci{
21638c2ecf20Sopenharmony_ci	int error;
21648c2ecf20Sopenharmony_ci	might_sleep();
21658c2ecf20Sopenharmony_ci	for (;;) {
21668c2ecf20Sopenharmony_ci		error = flock_lock_inode(inode, fl);
21678c2ecf20Sopenharmony_ci		if (error != FILE_LOCK_DEFERRED)
21688c2ecf20Sopenharmony_ci			break;
21698c2ecf20Sopenharmony_ci		error = wait_event_interruptible(fl->fl_wait,
21708c2ecf20Sopenharmony_ci				list_empty(&fl->fl_blocked_member));
21718c2ecf20Sopenharmony_ci		if (error)
21728c2ecf20Sopenharmony_ci			break;
21738c2ecf20Sopenharmony_ci	}
21748c2ecf20Sopenharmony_ci	locks_delete_block(fl);
21758c2ecf20Sopenharmony_ci	return error;
21768c2ecf20Sopenharmony_ci}
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci/**
21798c2ecf20Sopenharmony_ci * locks_lock_inode_wait - Apply a lock to an inode
21808c2ecf20Sopenharmony_ci * @inode: inode of the file to apply to
21818c2ecf20Sopenharmony_ci * @fl: The lock to be applied
21828c2ecf20Sopenharmony_ci *
21838c2ecf20Sopenharmony_ci * Apply a POSIX or FLOCK style lock request to an inode.
21848c2ecf20Sopenharmony_ci */
21858c2ecf20Sopenharmony_ciint locks_lock_inode_wait(struct inode *inode, struct file_lock *fl)
21868c2ecf20Sopenharmony_ci{
21878c2ecf20Sopenharmony_ci	int res = 0;
21888c2ecf20Sopenharmony_ci	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
21898c2ecf20Sopenharmony_ci		case FL_POSIX:
21908c2ecf20Sopenharmony_ci			res = posix_lock_inode_wait(inode, fl);
21918c2ecf20Sopenharmony_ci			break;
21928c2ecf20Sopenharmony_ci		case FL_FLOCK:
21938c2ecf20Sopenharmony_ci			res = flock_lock_inode_wait(inode, fl);
21948c2ecf20Sopenharmony_ci			break;
21958c2ecf20Sopenharmony_ci		default:
21968c2ecf20Sopenharmony_ci			BUG();
21978c2ecf20Sopenharmony_ci	}
21988c2ecf20Sopenharmony_ci	return res;
21998c2ecf20Sopenharmony_ci}
22008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locks_lock_inode_wait);
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci/**
22038c2ecf20Sopenharmony_ci *	sys_flock: - flock() system call.
22048c2ecf20Sopenharmony_ci *	@fd: the file descriptor to lock.
22058c2ecf20Sopenharmony_ci *	@cmd: the type of lock to apply.
22068c2ecf20Sopenharmony_ci *
22078c2ecf20Sopenharmony_ci *	Apply a %FL_FLOCK style lock to an open file descriptor.
22088c2ecf20Sopenharmony_ci *	The @cmd can be one of:
22098c2ecf20Sopenharmony_ci *
22108c2ecf20Sopenharmony_ci *	- %LOCK_SH -- a shared lock.
22118c2ecf20Sopenharmony_ci *	- %LOCK_EX -- an exclusive lock.
22128c2ecf20Sopenharmony_ci *	- %LOCK_UN -- remove an existing lock.
22138c2ecf20Sopenharmony_ci *	- %LOCK_MAND -- a 'mandatory' flock.
22148c2ecf20Sopenharmony_ci *	  This exists to emulate Windows Share Modes.
22158c2ecf20Sopenharmony_ci *
22168c2ecf20Sopenharmony_ci *	%LOCK_MAND can be combined with %LOCK_READ or %LOCK_WRITE to allow other
22178c2ecf20Sopenharmony_ci *	processes read and write access respectively.
22188c2ecf20Sopenharmony_ci */
22198c2ecf20Sopenharmony_ciSYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
22208c2ecf20Sopenharmony_ci{
22218c2ecf20Sopenharmony_ci	struct fd f = fdget(fd);
22228c2ecf20Sopenharmony_ci	struct file_lock *lock;
22238c2ecf20Sopenharmony_ci	int can_sleep, unlock;
22248c2ecf20Sopenharmony_ci	int error;
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci	error = -EBADF;
22278c2ecf20Sopenharmony_ci	if (!f.file)
22288c2ecf20Sopenharmony_ci		goto out;
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	can_sleep = !(cmd & LOCK_NB);
22318c2ecf20Sopenharmony_ci	cmd &= ~LOCK_NB;
22328c2ecf20Sopenharmony_ci	unlock = (cmd == LOCK_UN);
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	if (!unlock && !(cmd & LOCK_MAND) &&
22358c2ecf20Sopenharmony_ci	    !(f.file->f_mode & (FMODE_READ|FMODE_WRITE)))
22368c2ecf20Sopenharmony_ci		goto out_putf;
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	lock = flock_make_lock(f.file, cmd, NULL);
22398c2ecf20Sopenharmony_ci	if (IS_ERR(lock)) {
22408c2ecf20Sopenharmony_ci		error = PTR_ERR(lock);
22418c2ecf20Sopenharmony_ci		goto out_putf;
22428c2ecf20Sopenharmony_ci	}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	if (can_sleep)
22458c2ecf20Sopenharmony_ci		lock->fl_flags |= FL_SLEEP;
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	error = security_file_lock(f.file, lock->fl_type);
22488c2ecf20Sopenharmony_ci	if (error)
22498c2ecf20Sopenharmony_ci		goto out_free;
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	if (f.file->f_op->flock)
22528c2ecf20Sopenharmony_ci		error = f.file->f_op->flock(f.file,
22538c2ecf20Sopenharmony_ci					  (can_sleep) ? F_SETLKW : F_SETLK,
22548c2ecf20Sopenharmony_ci					  lock);
22558c2ecf20Sopenharmony_ci	else
22568c2ecf20Sopenharmony_ci		error = locks_lock_file_wait(f.file, lock);
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_ci out_free:
22598c2ecf20Sopenharmony_ci	locks_free_lock(lock);
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci out_putf:
22628c2ecf20Sopenharmony_ci	fdput(f);
22638c2ecf20Sopenharmony_ci out:
22648c2ecf20Sopenharmony_ci	return error;
22658c2ecf20Sopenharmony_ci}
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci/**
22688c2ecf20Sopenharmony_ci * vfs_test_lock - test file byte range lock
22698c2ecf20Sopenharmony_ci * @filp: The file to test lock for
22708c2ecf20Sopenharmony_ci * @fl: The lock to test; also used to hold result
22718c2ecf20Sopenharmony_ci *
22728c2ecf20Sopenharmony_ci * Returns -ERRNO on failure.  Indicates presence of conflicting lock by
22738c2ecf20Sopenharmony_ci * setting conf->fl_type to something other than F_UNLCK.
22748c2ecf20Sopenharmony_ci */
22758c2ecf20Sopenharmony_ciint vfs_test_lock(struct file *filp, struct file_lock *fl)
22768c2ecf20Sopenharmony_ci{
22778c2ecf20Sopenharmony_ci	if (filp->f_op->lock)
22788c2ecf20Sopenharmony_ci		return filp->f_op->lock(filp, F_GETLK, fl);
22798c2ecf20Sopenharmony_ci	posix_test_lock(filp, fl);
22808c2ecf20Sopenharmony_ci	return 0;
22818c2ecf20Sopenharmony_ci}
22828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_test_lock);
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci/**
22858c2ecf20Sopenharmony_ci * locks_translate_pid - translate a file_lock's fl_pid number into a namespace
22868c2ecf20Sopenharmony_ci * @fl: The file_lock who's fl_pid should be translated
22878c2ecf20Sopenharmony_ci * @ns: The namespace into which the pid should be translated
22888c2ecf20Sopenharmony_ci *
22898c2ecf20Sopenharmony_ci * Used to tranlate a fl_pid into a namespace virtual pid number
22908c2ecf20Sopenharmony_ci */
22918c2ecf20Sopenharmony_cistatic pid_t locks_translate_pid(struct file_lock *fl, struct pid_namespace *ns)
22928c2ecf20Sopenharmony_ci{
22938c2ecf20Sopenharmony_ci	pid_t vnr;
22948c2ecf20Sopenharmony_ci	struct pid *pid;
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	if (IS_OFDLCK(fl))
22978c2ecf20Sopenharmony_ci		return -1;
22988c2ecf20Sopenharmony_ci	if (IS_REMOTELCK(fl))
22998c2ecf20Sopenharmony_ci		return fl->fl_pid;
23008c2ecf20Sopenharmony_ci	/*
23018c2ecf20Sopenharmony_ci	 * If the flock owner process is dead and its pid has been already
23028c2ecf20Sopenharmony_ci	 * freed, the translation below won't work, but we still want to show
23038c2ecf20Sopenharmony_ci	 * flock owner pid number in init pidns.
23048c2ecf20Sopenharmony_ci	 */
23058c2ecf20Sopenharmony_ci	if (ns == &init_pid_ns)
23068c2ecf20Sopenharmony_ci		return (pid_t)fl->fl_pid;
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci	rcu_read_lock();
23098c2ecf20Sopenharmony_ci	pid = find_pid_ns(fl->fl_pid, &init_pid_ns);
23108c2ecf20Sopenharmony_ci	vnr = pid_nr_ns(pid, ns);
23118c2ecf20Sopenharmony_ci	rcu_read_unlock();
23128c2ecf20Sopenharmony_ci	return vnr;
23138c2ecf20Sopenharmony_ci}
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_cistatic int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
23168c2ecf20Sopenharmony_ci{
23178c2ecf20Sopenharmony_ci	flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current));
23188c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 32
23198c2ecf20Sopenharmony_ci	/*
23208c2ecf20Sopenharmony_ci	 * Make sure we can represent the posix lock via
23218c2ecf20Sopenharmony_ci	 * legacy 32bit flock.
23228c2ecf20Sopenharmony_ci	 */
23238c2ecf20Sopenharmony_ci	if (fl->fl_start > OFFT_OFFSET_MAX)
23248c2ecf20Sopenharmony_ci		return -EOVERFLOW;
23258c2ecf20Sopenharmony_ci	if (fl->fl_end != OFFSET_MAX && fl->fl_end > OFFT_OFFSET_MAX)
23268c2ecf20Sopenharmony_ci		return -EOVERFLOW;
23278c2ecf20Sopenharmony_ci#endif
23288c2ecf20Sopenharmony_ci	flock->l_start = fl->fl_start;
23298c2ecf20Sopenharmony_ci	flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
23308c2ecf20Sopenharmony_ci		fl->fl_end - fl->fl_start + 1;
23318c2ecf20Sopenharmony_ci	flock->l_whence = 0;
23328c2ecf20Sopenharmony_ci	flock->l_type = fl->fl_type;
23338c2ecf20Sopenharmony_ci	return 0;
23348c2ecf20Sopenharmony_ci}
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 32
23378c2ecf20Sopenharmony_cistatic void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
23388c2ecf20Sopenharmony_ci{
23398c2ecf20Sopenharmony_ci	flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current));
23408c2ecf20Sopenharmony_ci	flock->l_start = fl->fl_start;
23418c2ecf20Sopenharmony_ci	flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
23428c2ecf20Sopenharmony_ci		fl->fl_end - fl->fl_start + 1;
23438c2ecf20Sopenharmony_ci	flock->l_whence = 0;
23448c2ecf20Sopenharmony_ci	flock->l_type = fl->fl_type;
23458c2ecf20Sopenharmony_ci}
23468c2ecf20Sopenharmony_ci#endif
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci/* Report the first existing lock that would conflict with l.
23498c2ecf20Sopenharmony_ci * This implements the F_GETLK command of fcntl().
23508c2ecf20Sopenharmony_ci */
23518c2ecf20Sopenharmony_ciint fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock)
23528c2ecf20Sopenharmony_ci{
23538c2ecf20Sopenharmony_ci	struct file_lock *fl;
23548c2ecf20Sopenharmony_ci	int error;
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci	fl = locks_alloc_lock();
23578c2ecf20Sopenharmony_ci	if (fl == NULL)
23588c2ecf20Sopenharmony_ci		return -ENOMEM;
23598c2ecf20Sopenharmony_ci	error = -EINVAL;
23608c2ecf20Sopenharmony_ci	if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
23618c2ecf20Sopenharmony_ci		goto out;
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	error = flock_to_posix_lock(filp, fl, flock);
23648c2ecf20Sopenharmony_ci	if (error)
23658c2ecf20Sopenharmony_ci		goto out;
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	if (cmd == F_OFD_GETLK) {
23688c2ecf20Sopenharmony_ci		error = -EINVAL;
23698c2ecf20Sopenharmony_ci		if (flock->l_pid != 0)
23708c2ecf20Sopenharmony_ci			goto out;
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci		cmd = F_GETLK;
23738c2ecf20Sopenharmony_ci		fl->fl_flags |= FL_OFDLCK;
23748c2ecf20Sopenharmony_ci		fl->fl_owner = filp;
23758c2ecf20Sopenharmony_ci	}
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci	error = vfs_test_lock(filp, fl);
23788c2ecf20Sopenharmony_ci	if (error)
23798c2ecf20Sopenharmony_ci		goto out;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	flock->l_type = fl->fl_type;
23828c2ecf20Sopenharmony_ci	if (fl->fl_type != F_UNLCK) {
23838c2ecf20Sopenharmony_ci		error = posix_lock_to_flock(flock, fl);
23848c2ecf20Sopenharmony_ci		if (error)
23858c2ecf20Sopenharmony_ci			goto out;
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ciout:
23888c2ecf20Sopenharmony_ci	locks_free_lock(fl);
23898c2ecf20Sopenharmony_ci	return error;
23908c2ecf20Sopenharmony_ci}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci/**
23938c2ecf20Sopenharmony_ci * vfs_lock_file - file byte range lock
23948c2ecf20Sopenharmony_ci * @filp: The file to apply the lock to
23958c2ecf20Sopenharmony_ci * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.)
23968c2ecf20Sopenharmony_ci * @fl: The lock to be applied
23978c2ecf20Sopenharmony_ci * @conf: Place to return a copy of the conflicting lock, if found.
23988c2ecf20Sopenharmony_ci *
23998c2ecf20Sopenharmony_ci * A caller that doesn't care about the conflicting lock may pass NULL
24008c2ecf20Sopenharmony_ci * as the final argument.
24018c2ecf20Sopenharmony_ci *
24028c2ecf20Sopenharmony_ci * If the filesystem defines a private ->lock() method, then @conf will
24038c2ecf20Sopenharmony_ci * be left unchanged; so a caller that cares should initialize it to
24048c2ecf20Sopenharmony_ci * some acceptable default.
24058c2ecf20Sopenharmony_ci *
24068c2ecf20Sopenharmony_ci * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX
24078c2ecf20Sopenharmony_ci * locks, the ->lock() interface may return asynchronously, before the lock has
24088c2ecf20Sopenharmony_ci * been granted or denied by the underlying filesystem, if (and only if)
24098c2ecf20Sopenharmony_ci * lm_grant is set. Callers expecting ->lock() to return asynchronously
24108c2ecf20Sopenharmony_ci * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if)
24118c2ecf20Sopenharmony_ci * the request is for a blocking lock. When ->lock() does return asynchronously,
24128c2ecf20Sopenharmony_ci * it must return FILE_LOCK_DEFERRED, and call ->lm_grant() when the lock
24138c2ecf20Sopenharmony_ci * request completes.
24148c2ecf20Sopenharmony_ci * If the request is for non-blocking lock the file system should return
24158c2ecf20Sopenharmony_ci * FILE_LOCK_DEFERRED then try to get the lock and call the callback routine
24168c2ecf20Sopenharmony_ci * with the result. If the request timed out the callback routine will return a
24178c2ecf20Sopenharmony_ci * nonzero return code and the file system should release the lock. The file
24188c2ecf20Sopenharmony_ci * system is also responsible to keep a corresponding posix lock when it
24198c2ecf20Sopenharmony_ci * grants a lock so the VFS can find out which locks are locally held and do
24208c2ecf20Sopenharmony_ci * the correct lock cleanup when required.
24218c2ecf20Sopenharmony_ci * The underlying filesystem must not drop the kernel lock or call
24228c2ecf20Sopenharmony_ci * ->lm_grant() before returning to the caller with a FILE_LOCK_DEFERRED
24238c2ecf20Sopenharmony_ci * return code.
24248c2ecf20Sopenharmony_ci */
24258c2ecf20Sopenharmony_ciint vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
24268c2ecf20Sopenharmony_ci{
24278c2ecf20Sopenharmony_ci	if (filp->f_op->lock)
24288c2ecf20Sopenharmony_ci		return filp->f_op->lock(filp, cmd, fl);
24298c2ecf20Sopenharmony_ci	else
24308c2ecf20Sopenharmony_ci		return posix_lock_file(filp, fl, conf);
24318c2ecf20Sopenharmony_ci}
24328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_lock_file);
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_cistatic int do_lock_file_wait(struct file *filp, unsigned int cmd,
24358c2ecf20Sopenharmony_ci			     struct file_lock *fl)
24368c2ecf20Sopenharmony_ci{
24378c2ecf20Sopenharmony_ci	int error;
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	error = security_file_lock(filp, fl->fl_type);
24408c2ecf20Sopenharmony_ci	if (error)
24418c2ecf20Sopenharmony_ci		return error;
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	for (;;) {
24448c2ecf20Sopenharmony_ci		error = vfs_lock_file(filp, cmd, fl, NULL);
24458c2ecf20Sopenharmony_ci		if (error != FILE_LOCK_DEFERRED)
24468c2ecf20Sopenharmony_ci			break;
24478c2ecf20Sopenharmony_ci		error = wait_event_interruptible(fl->fl_wait,
24488c2ecf20Sopenharmony_ci					list_empty(&fl->fl_blocked_member));
24498c2ecf20Sopenharmony_ci		if (error)
24508c2ecf20Sopenharmony_ci			break;
24518c2ecf20Sopenharmony_ci	}
24528c2ecf20Sopenharmony_ci	locks_delete_block(fl);
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci	return error;
24558c2ecf20Sopenharmony_ci}
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci/* Ensure that fl->fl_file has compatible f_mode for F_SETLK calls */
24588c2ecf20Sopenharmony_cistatic int
24598c2ecf20Sopenharmony_cicheck_fmode_for_setlk(struct file_lock *fl)
24608c2ecf20Sopenharmony_ci{
24618c2ecf20Sopenharmony_ci	switch (fl->fl_type) {
24628c2ecf20Sopenharmony_ci	case F_RDLCK:
24638c2ecf20Sopenharmony_ci		if (!(fl->fl_file->f_mode & FMODE_READ))
24648c2ecf20Sopenharmony_ci			return -EBADF;
24658c2ecf20Sopenharmony_ci		break;
24668c2ecf20Sopenharmony_ci	case F_WRLCK:
24678c2ecf20Sopenharmony_ci		if (!(fl->fl_file->f_mode & FMODE_WRITE))
24688c2ecf20Sopenharmony_ci			return -EBADF;
24698c2ecf20Sopenharmony_ci	}
24708c2ecf20Sopenharmony_ci	return 0;
24718c2ecf20Sopenharmony_ci}
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci/* Apply the lock described by l to an open file descriptor.
24748c2ecf20Sopenharmony_ci * This implements both the F_SETLK and F_SETLKW commands of fcntl().
24758c2ecf20Sopenharmony_ci */
24768c2ecf20Sopenharmony_ciint fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
24778c2ecf20Sopenharmony_ci		struct flock *flock)
24788c2ecf20Sopenharmony_ci{
24798c2ecf20Sopenharmony_ci	struct file_lock *file_lock = locks_alloc_lock();
24808c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
24818c2ecf20Sopenharmony_ci	struct file *f;
24828c2ecf20Sopenharmony_ci	int error;
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	if (file_lock == NULL)
24858c2ecf20Sopenharmony_ci		return -ENOLCK;
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci	/* Don't allow mandatory locks on files that may be memory mapped
24888c2ecf20Sopenharmony_ci	 * and shared.
24898c2ecf20Sopenharmony_ci	 */
24908c2ecf20Sopenharmony_ci	if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) {
24918c2ecf20Sopenharmony_ci		error = -EAGAIN;
24928c2ecf20Sopenharmony_ci		goto out;
24938c2ecf20Sopenharmony_ci	}
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci	error = flock_to_posix_lock(filp, file_lock, flock);
24968c2ecf20Sopenharmony_ci	if (error)
24978c2ecf20Sopenharmony_ci		goto out;
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci	error = check_fmode_for_setlk(file_lock);
25008c2ecf20Sopenharmony_ci	if (error)
25018c2ecf20Sopenharmony_ci		goto out;
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci	/*
25048c2ecf20Sopenharmony_ci	 * If the cmd is requesting file-private locks, then set the
25058c2ecf20Sopenharmony_ci	 * FL_OFDLCK flag and override the owner.
25068c2ecf20Sopenharmony_ci	 */
25078c2ecf20Sopenharmony_ci	switch (cmd) {
25088c2ecf20Sopenharmony_ci	case F_OFD_SETLK:
25098c2ecf20Sopenharmony_ci		error = -EINVAL;
25108c2ecf20Sopenharmony_ci		if (flock->l_pid != 0)
25118c2ecf20Sopenharmony_ci			goto out;
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_ci		cmd = F_SETLK;
25148c2ecf20Sopenharmony_ci		file_lock->fl_flags |= FL_OFDLCK;
25158c2ecf20Sopenharmony_ci		file_lock->fl_owner = filp;
25168c2ecf20Sopenharmony_ci		break;
25178c2ecf20Sopenharmony_ci	case F_OFD_SETLKW:
25188c2ecf20Sopenharmony_ci		error = -EINVAL;
25198c2ecf20Sopenharmony_ci		if (flock->l_pid != 0)
25208c2ecf20Sopenharmony_ci			goto out;
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci		cmd = F_SETLKW;
25238c2ecf20Sopenharmony_ci		file_lock->fl_flags |= FL_OFDLCK;
25248c2ecf20Sopenharmony_ci		file_lock->fl_owner = filp;
25258c2ecf20Sopenharmony_ci		fallthrough;
25268c2ecf20Sopenharmony_ci	case F_SETLKW:
25278c2ecf20Sopenharmony_ci		file_lock->fl_flags |= FL_SLEEP;
25288c2ecf20Sopenharmony_ci	}
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci	error = do_lock_file_wait(filp, cmd, file_lock);
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci	/*
25338c2ecf20Sopenharmony_ci	 * Detect close/fcntl races and recover by zapping all POSIX locks
25348c2ecf20Sopenharmony_ci	 * associated with this file and our files_struct, just like on
25358c2ecf20Sopenharmony_ci	 * filp_flush(). There is no need to do that when we're
25368c2ecf20Sopenharmony_ci	 * unlocking though, or for OFD locks.
25378c2ecf20Sopenharmony_ci	 */
25388c2ecf20Sopenharmony_ci	if (!error && file_lock->fl_type != F_UNLCK &&
25398c2ecf20Sopenharmony_ci	    !(file_lock->fl_flags & FL_OFDLCK)) {
25408c2ecf20Sopenharmony_ci		struct files_struct *files = current->files;
25418c2ecf20Sopenharmony_ci		/*
25428c2ecf20Sopenharmony_ci		 * We need that spin_lock here - it prevents reordering between
25438c2ecf20Sopenharmony_ci		 * update of i_flctx->flc_posix and check for it done in
25448c2ecf20Sopenharmony_ci		 * close(). rcu_read_lock() wouldn't do.
25458c2ecf20Sopenharmony_ci		 */
25468c2ecf20Sopenharmony_ci		spin_lock(&files->file_lock);
25478c2ecf20Sopenharmony_ci		f = files_lookup_fd_locked(files, fd);
25488c2ecf20Sopenharmony_ci		spin_unlock(&files->file_lock);
25498c2ecf20Sopenharmony_ci		if (f != filp) {
25508c2ecf20Sopenharmony_ci			locks_remove_posix(filp, files);
25518c2ecf20Sopenharmony_ci			error = -EBADF;
25528c2ecf20Sopenharmony_ci		}
25538c2ecf20Sopenharmony_ci	}
25548c2ecf20Sopenharmony_ciout:
25558c2ecf20Sopenharmony_ci	trace_fcntl_setlk(inode, file_lock, error);
25568c2ecf20Sopenharmony_ci	locks_free_lock(file_lock);
25578c2ecf20Sopenharmony_ci	return error;
25588c2ecf20Sopenharmony_ci}
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 32
25618c2ecf20Sopenharmony_ci/* Report the first existing lock that would conflict with l.
25628c2ecf20Sopenharmony_ci * This implements the F_GETLK command of fcntl().
25638c2ecf20Sopenharmony_ci */
25648c2ecf20Sopenharmony_ciint fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
25658c2ecf20Sopenharmony_ci{
25668c2ecf20Sopenharmony_ci	struct file_lock *fl;
25678c2ecf20Sopenharmony_ci	int error;
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	fl = locks_alloc_lock();
25708c2ecf20Sopenharmony_ci	if (fl == NULL)
25718c2ecf20Sopenharmony_ci		return -ENOMEM;
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	error = -EINVAL;
25748c2ecf20Sopenharmony_ci	if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
25758c2ecf20Sopenharmony_ci		goto out;
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci	error = flock64_to_posix_lock(filp, fl, flock);
25788c2ecf20Sopenharmony_ci	if (error)
25798c2ecf20Sopenharmony_ci		goto out;
25808c2ecf20Sopenharmony_ci
25818c2ecf20Sopenharmony_ci	if (cmd == F_OFD_GETLK) {
25828c2ecf20Sopenharmony_ci		error = -EINVAL;
25838c2ecf20Sopenharmony_ci		if (flock->l_pid != 0)
25848c2ecf20Sopenharmony_ci			goto out;
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci		cmd = F_GETLK64;
25878c2ecf20Sopenharmony_ci		fl->fl_flags |= FL_OFDLCK;
25888c2ecf20Sopenharmony_ci		fl->fl_owner = filp;
25898c2ecf20Sopenharmony_ci	}
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	error = vfs_test_lock(filp, fl);
25928c2ecf20Sopenharmony_ci	if (error)
25938c2ecf20Sopenharmony_ci		goto out;
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	flock->l_type = fl->fl_type;
25968c2ecf20Sopenharmony_ci	if (fl->fl_type != F_UNLCK)
25978c2ecf20Sopenharmony_ci		posix_lock_to_flock64(flock, fl);
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ciout:
26008c2ecf20Sopenharmony_ci	locks_free_lock(fl);
26018c2ecf20Sopenharmony_ci	return error;
26028c2ecf20Sopenharmony_ci}
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci/* Apply the lock described by l to an open file descriptor.
26058c2ecf20Sopenharmony_ci * This implements both the F_SETLK and F_SETLKW commands of fcntl().
26068c2ecf20Sopenharmony_ci */
26078c2ecf20Sopenharmony_ciint fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
26088c2ecf20Sopenharmony_ci		struct flock64 *flock)
26098c2ecf20Sopenharmony_ci{
26108c2ecf20Sopenharmony_ci	struct file_lock *file_lock = locks_alloc_lock();
26118c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
26128c2ecf20Sopenharmony_ci	struct file *f;
26138c2ecf20Sopenharmony_ci	int error;
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	if (file_lock == NULL)
26168c2ecf20Sopenharmony_ci		return -ENOLCK;
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	/* Don't allow mandatory locks on files that may be memory mapped
26198c2ecf20Sopenharmony_ci	 * and shared.
26208c2ecf20Sopenharmony_ci	 */
26218c2ecf20Sopenharmony_ci	if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) {
26228c2ecf20Sopenharmony_ci		error = -EAGAIN;
26238c2ecf20Sopenharmony_ci		goto out;
26248c2ecf20Sopenharmony_ci	}
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	error = flock64_to_posix_lock(filp, file_lock, flock);
26278c2ecf20Sopenharmony_ci	if (error)
26288c2ecf20Sopenharmony_ci		goto out;
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	error = check_fmode_for_setlk(file_lock);
26318c2ecf20Sopenharmony_ci	if (error)
26328c2ecf20Sopenharmony_ci		goto out;
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci	/*
26358c2ecf20Sopenharmony_ci	 * If the cmd is requesting file-private locks, then set the
26368c2ecf20Sopenharmony_ci	 * FL_OFDLCK flag and override the owner.
26378c2ecf20Sopenharmony_ci	 */
26388c2ecf20Sopenharmony_ci	switch (cmd) {
26398c2ecf20Sopenharmony_ci	case F_OFD_SETLK:
26408c2ecf20Sopenharmony_ci		error = -EINVAL;
26418c2ecf20Sopenharmony_ci		if (flock->l_pid != 0)
26428c2ecf20Sopenharmony_ci			goto out;
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci		cmd = F_SETLK64;
26458c2ecf20Sopenharmony_ci		file_lock->fl_flags |= FL_OFDLCK;
26468c2ecf20Sopenharmony_ci		file_lock->fl_owner = filp;
26478c2ecf20Sopenharmony_ci		break;
26488c2ecf20Sopenharmony_ci	case F_OFD_SETLKW:
26498c2ecf20Sopenharmony_ci		error = -EINVAL;
26508c2ecf20Sopenharmony_ci		if (flock->l_pid != 0)
26518c2ecf20Sopenharmony_ci			goto out;
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci		cmd = F_SETLKW64;
26548c2ecf20Sopenharmony_ci		file_lock->fl_flags |= FL_OFDLCK;
26558c2ecf20Sopenharmony_ci		file_lock->fl_owner = filp;
26568c2ecf20Sopenharmony_ci		fallthrough;
26578c2ecf20Sopenharmony_ci	case F_SETLKW64:
26588c2ecf20Sopenharmony_ci		file_lock->fl_flags |= FL_SLEEP;
26598c2ecf20Sopenharmony_ci	}
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_ci	error = do_lock_file_wait(filp, cmd, file_lock);
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	/*
26648c2ecf20Sopenharmony_ci	 * Detect close/fcntl races and recover by zapping all POSIX locks
26658c2ecf20Sopenharmony_ci	 * associated with this file and our files_struct, just like on
26668c2ecf20Sopenharmony_ci	 * filp_flush(). There is no need to do that when we're
26678c2ecf20Sopenharmony_ci	 * unlocking though, or for OFD locks.
26688c2ecf20Sopenharmony_ci	 */
26698c2ecf20Sopenharmony_ci	if (!error && file_lock->fl_type != F_UNLCK &&
26708c2ecf20Sopenharmony_ci	    !(file_lock->fl_flags & FL_OFDLCK)) {
26718c2ecf20Sopenharmony_ci		struct files_struct *files = current->files;
26728c2ecf20Sopenharmony_ci		/*
26738c2ecf20Sopenharmony_ci		 * We need that spin_lock here - it prevents reordering between
26748c2ecf20Sopenharmony_ci		 * update of i_flctx->flc_posix and check for it done in
26758c2ecf20Sopenharmony_ci		 * close(). rcu_read_lock() wouldn't do.
26768c2ecf20Sopenharmony_ci		 */
26778c2ecf20Sopenharmony_ci		spin_lock(&files->file_lock);
26788c2ecf20Sopenharmony_ci		f = files_lookup_fd_locked(files, fd);
26798c2ecf20Sopenharmony_ci		spin_unlock(&files->file_lock);
26808c2ecf20Sopenharmony_ci		if (f != filp) {
26818c2ecf20Sopenharmony_ci			locks_remove_posix(filp, files);
26828c2ecf20Sopenharmony_ci			error = -EBADF;
26838c2ecf20Sopenharmony_ci		}
26848c2ecf20Sopenharmony_ci	}
26858c2ecf20Sopenharmony_ciout:
26868c2ecf20Sopenharmony_ci	locks_free_lock(file_lock);
26878c2ecf20Sopenharmony_ci	return error;
26888c2ecf20Sopenharmony_ci}
26898c2ecf20Sopenharmony_ci#endif /* BITS_PER_LONG == 32 */
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci/*
26928c2ecf20Sopenharmony_ci * This function is called when the file is being removed
26938c2ecf20Sopenharmony_ci * from the task's fd array.  POSIX locks belonging to this task
26948c2ecf20Sopenharmony_ci * are deleted at this time.
26958c2ecf20Sopenharmony_ci */
26968c2ecf20Sopenharmony_civoid locks_remove_posix(struct file *filp, fl_owner_t owner)
26978c2ecf20Sopenharmony_ci{
26988c2ecf20Sopenharmony_ci	int error;
26998c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
27008c2ecf20Sopenharmony_ci	struct file_lock lock;
27018c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_ci	/*
27048c2ecf20Sopenharmony_ci	 * If there are no locks held on this file, we don't need to call
27058c2ecf20Sopenharmony_ci	 * posix_lock_file().  Another process could be setting a lock on this
27068c2ecf20Sopenharmony_ci	 * file at the same time, but we wouldn't remove that lock anyway.
27078c2ecf20Sopenharmony_ci	 */
27088c2ecf20Sopenharmony_ci	ctx =  smp_load_acquire(&inode->i_flctx);
27098c2ecf20Sopenharmony_ci	if (!ctx || list_empty(&ctx->flc_posix))
27108c2ecf20Sopenharmony_ci		return;
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci	locks_init_lock(&lock);
27138c2ecf20Sopenharmony_ci	lock.fl_type = F_UNLCK;
27148c2ecf20Sopenharmony_ci	lock.fl_flags = FL_POSIX | FL_CLOSE;
27158c2ecf20Sopenharmony_ci	lock.fl_start = 0;
27168c2ecf20Sopenharmony_ci	lock.fl_end = OFFSET_MAX;
27178c2ecf20Sopenharmony_ci	lock.fl_owner = owner;
27188c2ecf20Sopenharmony_ci	lock.fl_pid = current->tgid;
27198c2ecf20Sopenharmony_ci	lock.fl_file = filp;
27208c2ecf20Sopenharmony_ci	lock.fl_ops = NULL;
27218c2ecf20Sopenharmony_ci	lock.fl_lmops = NULL;
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ci	error = vfs_lock_file(filp, F_SETLK, &lock, NULL);
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci	if (lock.fl_ops && lock.fl_ops->fl_release_private)
27268c2ecf20Sopenharmony_ci		lock.fl_ops->fl_release_private(&lock);
27278c2ecf20Sopenharmony_ci	trace_locks_remove_posix(inode, &lock, error);
27288c2ecf20Sopenharmony_ci}
27298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locks_remove_posix);
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci/* The i_flctx must be valid when calling into here */
27328c2ecf20Sopenharmony_cistatic void
27338c2ecf20Sopenharmony_cilocks_remove_flock(struct file *filp, struct file_lock_context *flctx)
27348c2ecf20Sopenharmony_ci{
27358c2ecf20Sopenharmony_ci	struct file_lock fl;
27368c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci	if (list_empty(&flctx->flc_flock))
27398c2ecf20Sopenharmony_ci		return;
27408c2ecf20Sopenharmony_ci
27418c2ecf20Sopenharmony_ci	flock_make_lock(filp, LOCK_UN, &fl);
27428c2ecf20Sopenharmony_ci	fl.fl_flags |= FL_CLOSE;
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	if (filp->f_op->flock)
27458c2ecf20Sopenharmony_ci		filp->f_op->flock(filp, F_SETLKW, &fl);
27468c2ecf20Sopenharmony_ci	else
27478c2ecf20Sopenharmony_ci		flock_lock_inode(inode, &fl);
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci	if (fl.fl_ops && fl.fl_ops->fl_release_private)
27508c2ecf20Sopenharmony_ci		fl.fl_ops->fl_release_private(&fl);
27518c2ecf20Sopenharmony_ci}
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci/* The i_flctx must be valid when calling into here */
27548c2ecf20Sopenharmony_cistatic void
27558c2ecf20Sopenharmony_cilocks_remove_lease(struct file *filp, struct file_lock_context *ctx)
27568c2ecf20Sopenharmony_ci{
27578c2ecf20Sopenharmony_ci	struct file_lock *fl, *tmp;
27588c2ecf20Sopenharmony_ci	LIST_HEAD(dispose);
27598c2ecf20Sopenharmony_ci
27608c2ecf20Sopenharmony_ci	if (list_empty(&ctx->flc_lease))
27618c2ecf20Sopenharmony_ci		return;
27628c2ecf20Sopenharmony_ci
27638c2ecf20Sopenharmony_ci	percpu_down_read(&file_rwsem);
27648c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
27658c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list)
27668c2ecf20Sopenharmony_ci		if (filp == fl->fl_file)
27678c2ecf20Sopenharmony_ci			lease_modify(fl, F_UNLCK, &dispose);
27688c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
27698c2ecf20Sopenharmony_ci	percpu_up_read(&file_rwsem);
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci	locks_dispose_list(&dispose);
27728c2ecf20Sopenharmony_ci}
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_ci/*
27758c2ecf20Sopenharmony_ci * This function is called on the last close of an open file.
27768c2ecf20Sopenharmony_ci */
27778c2ecf20Sopenharmony_civoid locks_remove_file(struct file *filp)
27788c2ecf20Sopenharmony_ci{
27798c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&locks_inode(filp)->i_flctx);
27828c2ecf20Sopenharmony_ci	if (!ctx)
27838c2ecf20Sopenharmony_ci		return;
27848c2ecf20Sopenharmony_ci
27858c2ecf20Sopenharmony_ci	/* remove any OFD locks */
27868c2ecf20Sopenharmony_ci	locks_remove_posix(filp, filp);
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	/* remove flock locks */
27898c2ecf20Sopenharmony_ci	locks_remove_flock(filp, ctx);
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	/* remove any leases */
27928c2ecf20Sopenharmony_ci	locks_remove_lease(filp, ctx);
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
27958c2ecf20Sopenharmony_ci	locks_check_ctx_file_list(filp, &ctx->flc_posix, "POSIX");
27968c2ecf20Sopenharmony_ci	locks_check_ctx_file_list(filp, &ctx->flc_flock, "FLOCK");
27978c2ecf20Sopenharmony_ci	locks_check_ctx_file_list(filp, &ctx->flc_lease, "LEASE");
27988c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
27998c2ecf20Sopenharmony_ci}
28008c2ecf20Sopenharmony_ci
28018c2ecf20Sopenharmony_ci/**
28028c2ecf20Sopenharmony_ci * vfs_cancel_lock - file byte range unblock lock
28038c2ecf20Sopenharmony_ci * @filp: The file to apply the unblock to
28048c2ecf20Sopenharmony_ci * @fl: The lock to be unblocked
28058c2ecf20Sopenharmony_ci *
28068c2ecf20Sopenharmony_ci * Used by lock managers to cancel blocked requests
28078c2ecf20Sopenharmony_ci */
28088c2ecf20Sopenharmony_ciint vfs_cancel_lock(struct file *filp, struct file_lock *fl)
28098c2ecf20Sopenharmony_ci{
28108c2ecf20Sopenharmony_ci	if (filp->f_op->lock)
28118c2ecf20Sopenharmony_ci		return filp->f_op->lock(filp, F_CANCELLK, fl);
28128c2ecf20Sopenharmony_ci	return 0;
28138c2ecf20Sopenharmony_ci}
28148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_cancel_lock);
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci/**
28178c2ecf20Sopenharmony_ci * vfs_inode_has_locks - are any file locks held on @inode?
28188c2ecf20Sopenharmony_ci * @inode: inode to check for locks
28198c2ecf20Sopenharmony_ci *
28208c2ecf20Sopenharmony_ci * Return true if there are any FL_POSIX or FL_FLOCK locks currently
28218c2ecf20Sopenharmony_ci * set on @inode.
28228c2ecf20Sopenharmony_ci */
28238c2ecf20Sopenharmony_cibool vfs_inode_has_locks(struct inode *inode)
28248c2ecf20Sopenharmony_ci{
28258c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
28268c2ecf20Sopenharmony_ci	bool ret;
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&inode->i_flctx);
28298c2ecf20Sopenharmony_ci	if (!ctx)
28308c2ecf20Sopenharmony_ci		return false;
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
28338c2ecf20Sopenharmony_ci	ret = !list_empty(&ctx->flc_posix) || !list_empty(&ctx->flc_flock);
28348c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
28358c2ecf20Sopenharmony_ci	return ret;
28368c2ecf20Sopenharmony_ci}
28378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_inode_has_locks);
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
28408c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
28418c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_cistruct locks_iterator {
28448c2ecf20Sopenharmony_ci	int	li_cpu;
28458c2ecf20Sopenharmony_ci	loff_t	li_pos;
28468c2ecf20Sopenharmony_ci};
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_cistatic void lock_get_status(struct seq_file *f, struct file_lock *fl,
28498c2ecf20Sopenharmony_ci			    loff_t id, char *pfx)
28508c2ecf20Sopenharmony_ci{
28518c2ecf20Sopenharmony_ci	struct inode *inode = NULL;
28528c2ecf20Sopenharmony_ci	unsigned int fl_pid;
28538c2ecf20Sopenharmony_ci	struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb);
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_ci	fl_pid = locks_translate_pid(fl, proc_pidns);
28568c2ecf20Sopenharmony_ci	/*
28578c2ecf20Sopenharmony_ci	 * If lock owner is dead (and pid is freed) or not visible in current
28588c2ecf20Sopenharmony_ci	 * pidns, zero is shown as a pid value. Check lock info from
28598c2ecf20Sopenharmony_ci	 * init_pid_ns to get saved lock pid value.
28608c2ecf20Sopenharmony_ci	 */
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	if (fl->fl_file != NULL)
28638c2ecf20Sopenharmony_ci		inode = locks_inode(fl->fl_file);
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	seq_printf(f, "%lld:%s ", id, pfx);
28668c2ecf20Sopenharmony_ci	if (IS_POSIX(fl)) {
28678c2ecf20Sopenharmony_ci		if (fl->fl_flags & FL_ACCESS)
28688c2ecf20Sopenharmony_ci			seq_puts(f, "ACCESS");
28698c2ecf20Sopenharmony_ci		else if (IS_OFDLCK(fl))
28708c2ecf20Sopenharmony_ci			seq_puts(f, "OFDLCK");
28718c2ecf20Sopenharmony_ci		else
28728c2ecf20Sopenharmony_ci			seq_puts(f, "POSIX ");
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci		seq_printf(f, " %s ",
28758c2ecf20Sopenharmony_ci			     (inode == NULL) ? "*NOINODE*" :
28768c2ecf20Sopenharmony_ci			     mandatory_lock(inode) ? "MANDATORY" : "ADVISORY ");
28778c2ecf20Sopenharmony_ci	} else if (IS_FLOCK(fl)) {
28788c2ecf20Sopenharmony_ci		if (fl->fl_type & LOCK_MAND) {
28798c2ecf20Sopenharmony_ci			seq_puts(f, "FLOCK  MSNFS     ");
28808c2ecf20Sopenharmony_ci		} else {
28818c2ecf20Sopenharmony_ci			seq_puts(f, "FLOCK  ADVISORY  ");
28828c2ecf20Sopenharmony_ci		}
28838c2ecf20Sopenharmony_ci	} else if (IS_LEASE(fl)) {
28848c2ecf20Sopenharmony_ci		if (fl->fl_flags & FL_DELEG)
28858c2ecf20Sopenharmony_ci			seq_puts(f, "DELEG  ");
28868c2ecf20Sopenharmony_ci		else
28878c2ecf20Sopenharmony_ci			seq_puts(f, "LEASE  ");
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci		if (lease_breaking(fl))
28908c2ecf20Sopenharmony_ci			seq_puts(f, "BREAKING  ");
28918c2ecf20Sopenharmony_ci		else if (fl->fl_file)
28928c2ecf20Sopenharmony_ci			seq_puts(f, "ACTIVE    ");
28938c2ecf20Sopenharmony_ci		else
28948c2ecf20Sopenharmony_ci			seq_puts(f, "BREAKER   ");
28958c2ecf20Sopenharmony_ci	} else {
28968c2ecf20Sopenharmony_ci		seq_puts(f, "UNKNOWN UNKNOWN  ");
28978c2ecf20Sopenharmony_ci	}
28988c2ecf20Sopenharmony_ci	if (fl->fl_type & LOCK_MAND) {
28998c2ecf20Sopenharmony_ci		seq_printf(f, "%s ",
29008c2ecf20Sopenharmony_ci			       (fl->fl_type & LOCK_READ)
29018c2ecf20Sopenharmony_ci			       ? (fl->fl_type & LOCK_WRITE) ? "RW   " : "READ "
29028c2ecf20Sopenharmony_ci			       : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
29038c2ecf20Sopenharmony_ci	} else {
29048c2ecf20Sopenharmony_ci		int type = IS_LEASE(fl) ? target_leasetype(fl) : fl->fl_type;
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci		seq_printf(f, "%s ", (type == F_WRLCK) ? "WRITE" :
29078c2ecf20Sopenharmony_ci				     (type == F_RDLCK) ? "READ" : "UNLCK");
29088c2ecf20Sopenharmony_ci	}
29098c2ecf20Sopenharmony_ci	if (inode) {
29108c2ecf20Sopenharmony_ci		/* userspace relies on this representation of dev_t */
29118c2ecf20Sopenharmony_ci		seq_printf(f, "%d %02x:%02x:%lu ", fl_pid,
29128c2ecf20Sopenharmony_ci				MAJOR(inode->i_sb->s_dev),
29138c2ecf20Sopenharmony_ci				MINOR(inode->i_sb->s_dev), inode->i_ino);
29148c2ecf20Sopenharmony_ci	} else {
29158c2ecf20Sopenharmony_ci		seq_printf(f, "%d <none>:0 ", fl_pid);
29168c2ecf20Sopenharmony_ci	}
29178c2ecf20Sopenharmony_ci	if (IS_POSIX(fl)) {
29188c2ecf20Sopenharmony_ci		if (fl->fl_end == OFFSET_MAX)
29198c2ecf20Sopenharmony_ci			seq_printf(f, "%Ld EOF\n", fl->fl_start);
29208c2ecf20Sopenharmony_ci		else
29218c2ecf20Sopenharmony_ci			seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end);
29228c2ecf20Sopenharmony_ci	} else {
29238c2ecf20Sopenharmony_ci		seq_puts(f, "0 EOF\n");
29248c2ecf20Sopenharmony_ci	}
29258c2ecf20Sopenharmony_ci}
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_cistatic int locks_show(struct seq_file *f, void *v)
29288c2ecf20Sopenharmony_ci{
29298c2ecf20Sopenharmony_ci	struct locks_iterator *iter = f->private;
29308c2ecf20Sopenharmony_ci	struct file_lock *fl, *bfl;
29318c2ecf20Sopenharmony_ci	struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb);
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci	fl = hlist_entry(v, struct file_lock, fl_link);
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	if (locks_translate_pid(fl, proc_pidns) == 0)
29368c2ecf20Sopenharmony_ci		return 0;
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci	lock_get_status(f, fl, iter->li_pos, "");
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci	list_for_each_entry(bfl, &fl->fl_blocked_requests, fl_blocked_member)
29418c2ecf20Sopenharmony_ci		lock_get_status(f, bfl, iter->li_pos, " ->");
29428c2ecf20Sopenharmony_ci
29438c2ecf20Sopenharmony_ci	return 0;
29448c2ecf20Sopenharmony_ci}
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_cistatic void __show_fd_locks(struct seq_file *f,
29478c2ecf20Sopenharmony_ci			struct list_head *head, int *id,
29488c2ecf20Sopenharmony_ci			struct file *filp, struct files_struct *files)
29498c2ecf20Sopenharmony_ci{
29508c2ecf20Sopenharmony_ci	struct file_lock *fl;
29518c2ecf20Sopenharmony_ci
29528c2ecf20Sopenharmony_ci	list_for_each_entry(fl, head, fl_list) {
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci		if (filp != fl->fl_file)
29558c2ecf20Sopenharmony_ci			continue;
29568c2ecf20Sopenharmony_ci		if (fl->fl_owner != files &&
29578c2ecf20Sopenharmony_ci		    fl->fl_owner != filp)
29588c2ecf20Sopenharmony_ci			continue;
29598c2ecf20Sopenharmony_ci
29608c2ecf20Sopenharmony_ci		(*id)++;
29618c2ecf20Sopenharmony_ci		seq_puts(f, "lock:\t");
29628c2ecf20Sopenharmony_ci		lock_get_status(f, fl, *id, "");
29638c2ecf20Sopenharmony_ci	}
29648c2ecf20Sopenharmony_ci}
29658c2ecf20Sopenharmony_ci
29668c2ecf20Sopenharmony_civoid show_fd_locks(struct seq_file *f,
29678c2ecf20Sopenharmony_ci		  struct file *filp, struct files_struct *files)
29688c2ecf20Sopenharmony_ci{
29698c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(filp);
29708c2ecf20Sopenharmony_ci	struct file_lock_context *ctx;
29718c2ecf20Sopenharmony_ci	int id = 0;
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci	ctx = smp_load_acquire(&inode->i_flctx);
29748c2ecf20Sopenharmony_ci	if (!ctx)
29758c2ecf20Sopenharmony_ci		return;
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_ci	spin_lock(&ctx->flc_lock);
29788c2ecf20Sopenharmony_ci	__show_fd_locks(f, &ctx->flc_flock, &id, filp, files);
29798c2ecf20Sopenharmony_ci	__show_fd_locks(f, &ctx->flc_posix, &id, filp, files);
29808c2ecf20Sopenharmony_ci	__show_fd_locks(f, &ctx->flc_lease, &id, filp, files);
29818c2ecf20Sopenharmony_ci	spin_unlock(&ctx->flc_lock);
29828c2ecf20Sopenharmony_ci}
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_cistatic void *locks_start(struct seq_file *f, loff_t *pos)
29858c2ecf20Sopenharmony_ci	__acquires(&blocked_lock_lock)
29868c2ecf20Sopenharmony_ci{
29878c2ecf20Sopenharmony_ci	struct locks_iterator *iter = f->private;
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci	iter->li_pos = *pos + 1;
29908c2ecf20Sopenharmony_ci	percpu_down_write(&file_rwsem);
29918c2ecf20Sopenharmony_ci	spin_lock(&blocked_lock_lock);
29928c2ecf20Sopenharmony_ci	return seq_hlist_start_percpu(&file_lock_list.hlist, &iter->li_cpu, *pos);
29938c2ecf20Sopenharmony_ci}
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_cistatic void *locks_next(struct seq_file *f, void *v, loff_t *pos)
29968c2ecf20Sopenharmony_ci{
29978c2ecf20Sopenharmony_ci	struct locks_iterator *iter = f->private;
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci	++iter->li_pos;
30008c2ecf20Sopenharmony_ci	return seq_hlist_next_percpu(v, &file_lock_list.hlist, &iter->li_cpu, pos);
30018c2ecf20Sopenharmony_ci}
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_cistatic void locks_stop(struct seq_file *f, void *v)
30048c2ecf20Sopenharmony_ci	__releases(&blocked_lock_lock)
30058c2ecf20Sopenharmony_ci{
30068c2ecf20Sopenharmony_ci	spin_unlock(&blocked_lock_lock);
30078c2ecf20Sopenharmony_ci	percpu_up_write(&file_rwsem);
30088c2ecf20Sopenharmony_ci}
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_cistatic const struct seq_operations locks_seq_operations = {
30118c2ecf20Sopenharmony_ci	.start	= locks_start,
30128c2ecf20Sopenharmony_ci	.next	= locks_next,
30138c2ecf20Sopenharmony_ci	.stop	= locks_stop,
30148c2ecf20Sopenharmony_ci	.show	= locks_show,
30158c2ecf20Sopenharmony_ci};
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_cistatic int __init proc_locks_init(void)
30188c2ecf20Sopenharmony_ci{
30198c2ecf20Sopenharmony_ci	proc_create_seq_private("locks", 0, NULL, &locks_seq_operations,
30208c2ecf20Sopenharmony_ci			sizeof(struct locks_iterator), NULL);
30218c2ecf20Sopenharmony_ci	return 0;
30228c2ecf20Sopenharmony_ci}
30238c2ecf20Sopenharmony_cifs_initcall(proc_locks_init);
30248c2ecf20Sopenharmony_ci#endif
30258c2ecf20Sopenharmony_ci
30268c2ecf20Sopenharmony_cistatic int __init filelock_init(void)
30278c2ecf20Sopenharmony_ci{
30288c2ecf20Sopenharmony_ci	int i;
30298c2ecf20Sopenharmony_ci
30308c2ecf20Sopenharmony_ci	flctx_cache = kmem_cache_create("file_lock_ctx",
30318c2ecf20Sopenharmony_ci			sizeof(struct file_lock_context), 0, SLAB_PANIC, NULL);
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_ci	filelock_cache = kmem_cache_create("file_lock_cache",
30348c2ecf20Sopenharmony_ci			sizeof(struct file_lock), 0, SLAB_PANIC, NULL);
30358c2ecf20Sopenharmony_ci
30368c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
30378c2ecf20Sopenharmony_ci		struct file_lock_list_struct *fll = per_cpu_ptr(&file_lock_list, i);
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_ci		spin_lock_init(&fll->lock);
30408c2ecf20Sopenharmony_ci		INIT_HLIST_HEAD(&fll->hlist);
30418c2ecf20Sopenharmony_ci	}
30428c2ecf20Sopenharmony_ci
30438c2ecf20Sopenharmony_ci	lease_notifier_chain_init();
30448c2ecf20Sopenharmony_ci	return 0;
30458c2ecf20Sopenharmony_ci}
30468c2ecf20Sopenharmony_cicore_initcall(filelock_init);
3047