aboutsummaryrefslogtreecommitdiffstats
path: root/fs/locks.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/locks.c')
-rw-r--r--fs/locks.c56
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;
203static struct kmem_cache *filelock_cache __read_mostly; 203static struct kmem_cache *filelock_cache __read_mostly;
204 204
205static struct file_lock_context * 205static struct file_lock_context *
206locks_get_lock_context(struct inode *inode) 206locks_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);
235out: 228out:
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}
339EXPORT_SYMBOL(locks_copy_conflock); 334EXPORT_SYMBOL(locks_copy_conflock);
@@ -592,11 +587,15 @@ posix_owner_key(struct file_lock *fl)
592 587
593static void locks_insert_global_blocked(struct file_lock *waiter) 588static 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
598static void locks_delete_global_blocked(struct file_lock *waiter) 595static 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 }