diff options
Diffstat (limited to 'fs/locks.c')
| -rw-r--r-- | fs/locks.c | 56 |
1 files changed, 27 insertions, 29 deletions
diff --git a/fs/locks.c b/fs/locks.c index 40bc384728c0..52b780fb5258 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -203,11 +203,11 @@ static struct kmem_cache *flctx_cache __read_mostly; | |||
| 203 | static struct kmem_cache *filelock_cache __read_mostly; | 203 | static struct kmem_cache *filelock_cache __read_mostly; |
| 204 | 204 | ||
| 205 | static struct file_lock_context * | 205 | static struct file_lock_context * |
| 206 | locks_get_lock_context(struct inode *inode) | 206 | locks_get_lock_context(struct inode *inode, int type) |
| 207 | { | 207 | { |
| 208 | struct file_lock_context *new; | 208 | struct file_lock_context *new; |
| 209 | 209 | ||
| 210 | if (likely(inode->i_flctx)) | 210 | if (likely(inode->i_flctx) || type == F_UNLCK) |
| 211 | goto out; | 211 | goto out; |
| 212 | 212 | ||
| 213 | new = kmem_cache_alloc(flctx_cache, GFP_KERNEL); | 213 | new = kmem_cache_alloc(flctx_cache, GFP_KERNEL); |
| @@ -223,14 +223,7 @@ locks_get_lock_context(struct inode *inode) | |||
| 223 | * Assign the pointer if it's not already assigned. If it is, then | 223 | * Assign the pointer if it's not already assigned. If it is, then |
| 224 | * free the context we just allocated. | 224 | * free the context we just allocated. |
| 225 | */ | 225 | */ |
| 226 | spin_lock(&inode->i_lock); | 226 | if (cmpxchg(&inode->i_flctx, NULL, new)) |
| 227 | if (likely(!inode->i_flctx)) { | ||
| 228 | inode->i_flctx = new; | ||
| 229 | new = NULL; | ||
| 230 | } | ||
| 231 | spin_unlock(&inode->i_lock); | ||
| 232 | |||
| 233 | if (new) | ||
| 234 | kmem_cache_free(flctx_cache, new); | 227 | kmem_cache_free(flctx_cache, new); |
| 235 | out: | 228 | out: |
| 236 | return inode->i_flctx; | 229 | return inode->i_flctx; |
| @@ -276,8 +269,10 @@ void locks_release_private(struct file_lock *fl) | |||
| 276 | } | 269 | } |
| 277 | 270 | ||
| 278 | if (fl->fl_lmops) { | 271 | if (fl->fl_lmops) { |
| 279 | if (fl->fl_lmops->lm_put_owner) | 272 | if (fl->fl_lmops->lm_put_owner) { |
| 280 | fl->fl_lmops->lm_put_owner(fl); | 273 | fl->fl_lmops->lm_put_owner(fl->fl_owner); |
| 274 | fl->fl_owner = NULL; | ||
| 275 | } | ||
| 281 | fl->fl_lmops = NULL; | 276 | fl->fl_lmops = NULL; |
| 282 | } | 277 | } |
| 283 | } | 278 | } |
| @@ -333,7 +328,7 @@ void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) | |||
| 333 | 328 | ||
| 334 | if (fl->fl_lmops) { | 329 | if (fl->fl_lmops) { |
| 335 | if (fl->fl_lmops->lm_get_owner) | 330 | if (fl->fl_lmops->lm_get_owner) |
| 336 | fl->fl_lmops->lm_get_owner(new, fl); | 331 | fl->fl_lmops->lm_get_owner(fl->fl_owner); |
| 337 | } | 332 | } |
| 338 | } | 333 | } |
| 339 | EXPORT_SYMBOL(locks_copy_conflock); | 334 | EXPORT_SYMBOL(locks_copy_conflock); |
| @@ -592,11 +587,15 @@ posix_owner_key(struct file_lock *fl) | |||
| 592 | 587 | ||
| 593 | static void locks_insert_global_blocked(struct file_lock *waiter) | 588 | static void locks_insert_global_blocked(struct file_lock *waiter) |
| 594 | { | 589 | { |
| 590 | lockdep_assert_held(&blocked_lock_lock); | ||
| 591 | |||
| 595 | hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter)); | 592 | hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter)); |
| 596 | } | 593 | } |
| 597 | 594 | ||
| 598 | static void locks_delete_global_blocked(struct file_lock *waiter) | 595 | static void locks_delete_global_blocked(struct file_lock *waiter) |
| 599 | { | 596 | { |
| 597 | lockdep_assert_held(&blocked_lock_lock); | ||
| 598 | |||
| 600 | hash_del(&waiter->fl_link); | 599 | hash_del(&waiter->fl_link); |
| 601 | } | 600 | } |
| 602 | 601 | ||
| @@ -730,7 +729,7 @@ static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *s | |||
| 730 | /* POSIX locks owned by the same process do not conflict with | 729 | /* POSIX locks owned by the same process do not conflict with |
| 731 | * each other. | 730 | * each other. |
| 732 | */ | 731 | */ |
| 733 | if (!IS_POSIX(sys_fl) || posix_same_owner(caller_fl, sys_fl)) | 732 | if (posix_same_owner(caller_fl, sys_fl)) |
| 734 | return (0); | 733 | return (0); |
| 735 | 734 | ||
| 736 | /* Check whether they overlap */ | 735 | /* Check whether they overlap */ |
| @@ -748,7 +747,7 @@ static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *s | |||
| 748 | /* FLOCK locks referring to the same filp do not conflict with | 747 | /* FLOCK locks referring to the same filp do not conflict with |
| 749 | * each other. | 748 | * each other. |
| 750 | */ | 749 | */ |
| 751 | if (!IS_FLOCK(sys_fl) || (caller_fl->fl_file == sys_fl->fl_file)) | 750 | if (caller_fl->fl_file == sys_fl->fl_file) |
| 752 | return (0); | 751 | return (0); |
| 753 | if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND)) | 752 | if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND)) |
| 754 | return 0; | 753 | return 0; |
| @@ -838,6 +837,8 @@ static int posix_locks_deadlock(struct file_lock *caller_fl, | |||
| 838 | { | 837 | { |
| 839 | int i = 0; | 838 | int i = 0; |
| 840 | 839 | ||
| 840 | lockdep_assert_held(&blocked_lock_lock); | ||
| 841 | |||
| 841 | /* | 842 | /* |
| 842 | * This deadlock detector can't reasonably detect deadlocks with | 843 | * This deadlock detector can't reasonably detect deadlocks with |
| 843 | * FL_OFDLCK locks, since they aren't owned by a process, per-se. | 844 | * 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) | |||
| 871 | bool found = false; | 872 | bool found = false; |
| 872 | LIST_HEAD(dispose); | 873 | LIST_HEAD(dispose); |
| 873 | 874 | ||
| 874 | ctx = locks_get_lock_context(inode); | 875 | ctx = locks_get_lock_context(inode, request->fl_type); |
| 875 | if (!ctx) | 876 | if (!ctx) { |
| 876 | return -ENOMEM; | 877 | if (request->fl_type != F_UNLCK) |
| 878 | return -ENOMEM; | ||
| 879 | return (request->fl_flags & FL_EXISTS) ? -ENOENT : 0; | ||
| 880 | } | ||
| 877 | 881 | ||
| 878 | if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { | 882 | if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { |
| 879 | new_fl = locks_alloc_lock(); | 883 | new_fl = locks_alloc_lock(); |
| @@ -939,9 +943,9 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
| 939 | bool added = false; | 943 | bool added = false; |
| 940 | LIST_HEAD(dispose); | 944 | LIST_HEAD(dispose); |
| 941 | 945 | ||
| 942 | ctx = locks_get_lock_context(inode); | 946 | ctx = locks_get_lock_context(inode, request->fl_type); |
| 943 | if (!ctx) | 947 | if (!ctx) |
| 944 | return -ENOMEM; | 948 | return (request->fl_type == F_UNLCK) ? 0 : -ENOMEM; |
| 945 | 949 | ||
| 946 | /* | 950 | /* |
| 947 | * We may need two file_lock structures for this operation, | 951 | * 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 | |||
| 964 | */ | 968 | */ |
| 965 | if (request->fl_type != F_UNLCK) { | 969 | if (request->fl_type != F_UNLCK) { |
| 966 | list_for_each_entry(fl, &ctx->flc_posix, fl_list) { | 970 | list_for_each_entry(fl, &ctx->flc_posix, fl_list) { |
| 967 | if (!IS_POSIX(fl)) | ||
| 968 | continue; | ||
| 969 | if (!posix_locks_conflict(request, fl)) | 971 | if (!posix_locks_conflict(request, fl)) |
| 970 | continue; | 972 | continue; |
| 971 | if (conflock) | 973 | if (conflock) |
| @@ -1605,7 +1607,8 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
| 1605 | lease = *flp; | 1607 | lease = *flp; |
| 1606 | trace_generic_add_lease(inode, lease); | 1608 | trace_generic_add_lease(inode, lease); |
| 1607 | 1609 | ||
| 1608 | ctx = locks_get_lock_context(inode); | 1610 | /* Note that arg is never F_UNLCK here */ |
| 1611 | ctx = locks_get_lock_context(inode, arg); | ||
| 1609 | if (!ctx) | 1612 | if (!ctx) |
| 1610 | return -ENOMEM; | 1613 | return -ENOMEM; |
| 1611 | 1614 | ||
| @@ -2555,15 +2558,10 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, | |||
| 2555 | : (fl->fl_type == F_WRLCK) ? "WRITE" : "READ "); | 2558 | : (fl->fl_type == F_WRLCK) ? "WRITE" : "READ "); |
| 2556 | } | 2559 | } |
| 2557 | if (inode) { | 2560 | if (inode) { |
| 2558 | #ifdef WE_CAN_BREAK_LSLK_NOW | 2561 | /* userspace relies on this representation of dev_t */ |
| 2559 | seq_printf(f, "%d %s:%ld ", fl_pid, | ||
| 2560 | inode->i_sb->s_id, inode->i_ino); | ||
| 2561 | #else | ||
| 2562 | /* userspace relies on this representation of dev_t ;-( */ | ||
| 2563 | seq_printf(f, "%d %02x:%02x:%ld ", fl_pid, | 2562 | seq_printf(f, "%d %02x:%02x:%ld ", fl_pid, |
| 2564 | MAJOR(inode->i_sb->s_dev), | 2563 | MAJOR(inode->i_sb->s_dev), |
| 2565 | MINOR(inode->i_sb->s_dev), inode->i_ino); | 2564 | MINOR(inode->i_sb->s_dev), inode->i_ino); |
| 2566 | #endif | ||
| 2567 | } else { | 2565 | } else { |
| 2568 | seq_printf(f, "%d <none>:0 ", fl_pid); | 2566 | seq_printf(f, "%d <none>:0 ", fl_pid); |
| 2569 | } | 2567 | } |
