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