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