diff options
author | Dave Airlie <airlied@redhat.com> | 2015-04-20 11:32:26 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-04-20 13:05:20 +1000 |
commit | 2c33ce009ca2389dbf0535d0672214d09738e35e (patch) | |
tree | 6186a6458c3c160385d794a23eaf07c786a9e61b /fs/locks.c | |
parent | cec32a47010647e8b0603726ebb75b990a4057a4 (diff) | |
parent | 09d51602cf84a1264946711dd4ea0dddbac599a1 (diff) | |
download | linux-stable-2c33ce009ca2389dbf0535d0672214d09738e35e.tar.gz linux-stable-2c33ce009ca2389dbf0535d0672214d09738e35e.tar.bz2 linux-stable-2c33ce009ca2389dbf0535d0672214d09738e35e.zip |
Merge Linus master into drm-next
The merge is clean, but the arm build fails afterwards,
due to API changes in the regulator tree.
I've included the patch into the merge to fix the build.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 94 |
1 files changed, 65 insertions, 29 deletions
diff --git a/fs/locks.c b/fs/locks.c index 40bc384728c0..653faabb07f4 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -203,11 +203,11 @@ static struct kmem_cache *flctx_cache __read_mostly; static struct kmem_cache *filelock_cache __read_mostly; static struct file_lock_context * -locks_get_lock_context(struct inode *inode) +locks_get_lock_context(struct inode *inode, int type) { struct file_lock_context *new; - if (likely(inode->i_flctx)) + if (likely(inode->i_flctx) || type == F_UNLCK) goto out; new = kmem_cache_alloc(flctx_cache, GFP_KERNEL); @@ -223,14 +223,7 @@ locks_get_lock_context(struct inode *inode) * Assign the pointer if it's not already assigned. If it is, then * free the context we just allocated. */ - spin_lock(&inode->i_lock); - if (likely(!inode->i_flctx)) { - inode->i_flctx = new; - new = NULL; - } - spin_unlock(&inode->i_lock); - - if (new) + if (cmpxchg(&inode->i_flctx, NULL, new)) kmem_cache_free(flctx_cache, new); out: return inode->i_flctx; @@ -276,8 +269,10 @@ void locks_release_private(struct file_lock *fl) } if (fl->fl_lmops) { - if (fl->fl_lmops->lm_put_owner) - fl->fl_lmops->lm_put_owner(fl); + if (fl->fl_lmops->lm_put_owner) { + fl->fl_lmops->lm_put_owner(fl->fl_owner); + fl->fl_owner = NULL; + } fl->fl_lmops = NULL; } } @@ -333,7 +328,7 @@ void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) if (fl->fl_lmops) { if (fl->fl_lmops->lm_get_owner) - fl->fl_lmops->lm_get_owner(new, fl); + fl->fl_lmops->lm_get_owner(fl->fl_owner); } } EXPORT_SYMBOL(locks_copy_conflock); @@ -592,11 +587,15 @@ posix_owner_key(struct file_lock *fl) static void locks_insert_global_blocked(struct file_lock *waiter) { + lockdep_assert_held(&blocked_lock_lock); + hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter)); } static void locks_delete_global_blocked(struct file_lock *waiter) { + lockdep_assert_held(&blocked_lock_lock); + hash_del(&waiter->fl_link); } @@ -730,7 +729,7 @@ static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *s /* POSIX locks owned by the same process do not conflict with * each other. */ - if (!IS_POSIX(sys_fl) || posix_same_owner(caller_fl, sys_fl)) + if (posix_same_owner(caller_fl, sys_fl)) return (0); /* Check whether they overlap */ @@ -748,7 +747,7 @@ static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *s /* FLOCK locks referring to the same filp do not conflict with * each other. */ - if (!IS_FLOCK(sys_fl) || (caller_fl->fl_file == sys_fl->fl_file)) + if (caller_fl->fl_file == sys_fl->fl_file) return (0); if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND)) return 0; @@ -838,6 +837,8 @@ static int posix_locks_deadlock(struct file_lock *caller_fl, { int i = 0; + lockdep_assert_held(&blocked_lock_lock); + /* * This deadlock detector can't reasonably detect deadlocks with * FL_OFDLCK locks, since they aren't owned by a process, per-se. @@ -871,9 +872,12 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) bool found = false; LIST_HEAD(dispose); - ctx = locks_get_lock_context(inode); - if (!ctx) - return -ENOMEM; + ctx = locks_get_lock_context(inode, request->fl_type); + if (!ctx) { + if (request->fl_type != F_UNLCK) + return -ENOMEM; + return (request->fl_flags & FL_EXISTS) ? -ENOENT : 0; + } if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { new_fl = locks_alloc_lock(); @@ -939,9 +943,9 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str bool added = false; LIST_HEAD(dispose); - ctx = locks_get_lock_context(inode); + ctx = locks_get_lock_context(inode, request->fl_type); if (!ctx) - return -ENOMEM; + return (request->fl_type == F_UNLCK) ? 0 : -ENOMEM; /* * We may need two file_lock structures for this operation, @@ -964,8 +968,6 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str */ if (request->fl_type != F_UNLCK) { list_for_each_entry(fl, &ctx->flc_posix, fl_list) { - if (!IS_POSIX(fl)) - continue; if (!posix_locks_conflict(request, fl)) continue; if (conflock) @@ -1605,7 +1607,8 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr lease = *flp; trace_generic_add_lease(inode, lease); - ctx = locks_get_lock_context(inode); + /* Note that arg is never F_UNLCK here */ + ctx = locks_get_lock_context(inode, arg); if (!ctx) return -ENOMEM; @@ -2555,15 +2558,10 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, : (fl->fl_type == F_WRLCK) ? "WRITE" : "READ "); } if (inode) { -#ifdef WE_CAN_BREAK_LSLK_NOW - seq_printf(f, "%d %s:%ld ", fl_pid, - inode->i_sb->s_id, inode->i_ino); -#else - /* userspace relies on this representation of dev_t ;-( */ + /* userspace relies on this representation of dev_t */ seq_printf(f, "%d %02x:%02x:%ld ", fl_pid, MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), inode->i_ino); -#endif } else { seq_printf(f, "%d <none>:0 ", fl_pid); } @@ -2592,6 +2590,44 @@ static int locks_show(struct seq_file *f, void *v) return 0; } +static void __show_fd_locks(struct seq_file *f, + struct list_head *head, int *id, + struct file *filp, struct files_struct *files) +{ + struct file_lock *fl; + + list_for_each_entry(fl, head, fl_list) { + + if (filp != fl->fl_file) + continue; + if (fl->fl_owner != files && + fl->fl_owner != filp) + continue; + + (*id)++; + seq_puts(f, "lock:\t"); + lock_get_status(f, fl, *id, ""); + } +} + +void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files) +{ + struct inode *inode = file_inode(filp); + struct file_lock_context *ctx; + int id = 0; + + ctx = inode->i_flctx; + if (!ctx) + return; + + spin_lock(&ctx->flc_lock); + __show_fd_locks(f, &ctx->flc_flock, &id, filp, files); + __show_fd_locks(f, &ctx->flc_posix, &id, filp, files); + __show_fd_locks(f, &ctx->flc_lease, &id, filp, files); + spin_unlock(&ctx->flc_lock); +} + static void *locks_start(struct seq_file *f, loff_t *pos) __acquires(&blocked_lock_lock) { |