aboutsummaryrefslogtreecommitdiffstats
path: root/fs/locks.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2013-06-21 08:58:20 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-06-29 04:57:46 -0400
commit7b2296afb392bc21a50f42e7c7f4b19d3fea8c6d (patch)
tree360a8f35cf75f0bbcd1b984a6348f4c9e715e159 /fs/locks.c
parent3999e49364193f7dbbba66e2be655fe91ba1fced (diff)
locks: give the blocked_hash its own spinlock
There's no reason we have to protect the blocked_hash and file_lock_list with the same spinlock. With the tests I have, breaking it in two gives a barely measurable performance benefit, but it seems reasonable to make this locking as granular as possible. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/locks.c')
-rw-r--r--fs/locks.c41
1 files changed, 22 insertions, 19 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 6242e0b1c69c..04e2c1fdb157 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -159,10 +159,11 @@ int lease_break_time = 45;
159 * by the file_lock_lock. 159 * by the file_lock_lock.
160 */ 160 */
161static HLIST_HEAD(file_lock_list); 161static HLIST_HEAD(file_lock_list);
162static DEFINE_SPINLOCK(file_lock_lock);
162 163
163/* 164/*
164 * The blocked_hash is used to find POSIX lock loops for deadlock detection. 165 * The blocked_hash is used to find POSIX lock loops for deadlock detection.
165 * It is protected by file_lock_lock. 166 * It is protected by blocked_lock_lock.
166 * 167 *
167 * We hash locks by lockowner in order to optimize searching for the lock a 168 * We hash locks by lockowner in order to optimize searching for the lock a
168 * particular lockowner is waiting on. 169 * particular lockowner is waiting on.
@@ -175,8 +176,8 @@ static HLIST_HEAD(file_lock_list);
175static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS); 176static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS);
176 177
177/* 178/*
178 * This lock protects the blocked_hash and the file_lock_list. Generally, if 179 * This lock protects the blocked_hash. Generally, if you're accessing it, you
179 * you're accessing one of those lists, you want to be holding this lock. 180 * want to be holding this lock.
180 * 181 *
181 * In addition, it also protects the fl->fl_block list, and the fl->fl_next 182 * In addition, it also protects the fl->fl_block list, and the fl->fl_next
182 * pointer for file_lock structures that are acting as lock requests (in 183 * pointer for file_lock structures that are acting as lock requests (in
@@ -191,7 +192,7 @@ static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS);
191 * both the i_lock and the blocked_lock_lock (acquired in that order). Deleting 192 * both the i_lock and the blocked_lock_lock (acquired in that order). Deleting
192 * an entry from the list however only requires the file_lock_lock. 193 * an entry from the list however only requires the file_lock_lock.
193 */ 194 */
194static DEFINE_SPINLOCK(file_lock_lock); 195static DEFINE_SPINLOCK(blocked_lock_lock);
195 196
196static struct kmem_cache *filelock_cache __read_mostly; 197static struct kmem_cache *filelock_cache __read_mostly;
197 198
@@ -544,7 +545,7 @@ locks_delete_global_blocked(struct file_lock *waiter)
544/* Remove waiter from blocker's block list. 545/* Remove waiter from blocker's block list.
545 * When blocker ends up pointing to itself then the list is empty. 546 * When blocker ends up pointing to itself then the list is empty.
546 * 547 *
547 * Must be called with file_lock_lock held. 548 * Must be called with blocked_lock_lock held.
548 */ 549 */
549static void __locks_delete_block(struct file_lock *waiter) 550static void __locks_delete_block(struct file_lock *waiter)
550{ 551{
@@ -555,9 +556,9 @@ static void __locks_delete_block(struct file_lock *waiter)
555 556
556static void locks_delete_block(struct file_lock *waiter) 557static void locks_delete_block(struct file_lock *waiter)
557{ 558{
558 spin_lock(&file_lock_lock); 559 spin_lock(&blocked_lock_lock);
559 __locks_delete_block(waiter); 560 __locks_delete_block(waiter);
560 spin_unlock(&file_lock_lock); 561 spin_unlock(&blocked_lock_lock);
561} 562}
562 563
563/* Insert waiter into blocker's block list. 564/* Insert waiter into blocker's block list.
@@ -565,9 +566,9 @@ static void locks_delete_block(struct file_lock *waiter)
565 * the order they blocked. The documentation doesn't require this but 566 * the order they blocked. The documentation doesn't require this but
566 * it seems like the reasonable thing to do. 567 * it seems like the reasonable thing to do.
567 * 568 *
568 * Must be called with both the i_lock and file_lock_lock held. The fl_block 569 * Must be called with both the i_lock and blocked_lock_lock held. The fl_block
569 * list itself is protected by the file_lock_list, but by ensuring that the 570 * list itself is protected by the file_lock_list, but by ensuring that the
570 * i_lock is also held on insertions we can avoid taking the file_lock_lock 571 * i_lock is also held on insertions we can avoid taking the blocked_lock_lock
571 * in some cases when we see that the fl_block list is empty. 572 * in some cases when we see that the fl_block list is empty.
572 */ 573 */
573static void __locks_insert_block(struct file_lock *blocker, 574static void __locks_insert_block(struct file_lock *blocker,
@@ -584,9 +585,9 @@ static void __locks_insert_block(struct file_lock *blocker,
584static void locks_insert_block(struct file_lock *blocker, 585static void locks_insert_block(struct file_lock *blocker,
585 struct file_lock *waiter) 586 struct file_lock *waiter)
586{ 587{
587 spin_lock(&file_lock_lock); 588 spin_lock(&blocked_lock_lock);
588 __locks_insert_block(blocker, waiter); 589 __locks_insert_block(blocker, waiter);
589 spin_unlock(&file_lock_lock); 590 spin_unlock(&blocked_lock_lock);
590} 591}
591 592
592/* 593/*
@@ -601,12 +602,12 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
601 * blocked requests are only added to the list under the i_lock, and 602 * blocked requests are only added to the list under the i_lock, and
602 * the i_lock is always held here. Note that removal from the fl_block 603 * the i_lock is always held here. Note that removal from the fl_block
603 * list does not require the i_lock, so we must recheck list_empty() 604 * list does not require the i_lock, so we must recheck list_empty()
604 * after acquiring the file_lock_lock. 605 * after acquiring the blocked_lock_lock.
605 */ 606 */
606 if (list_empty(&blocker->fl_block)) 607 if (list_empty(&blocker->fl_block))
607 return; 608 return;
608 609
609 spin_lock(&file_lock_lock); 610 spin_lock(&blocked_lock_lock);
610 while (!list_empty(&blocker->fl_block)) { 611 while (!list_empty(&blocker->fl_block)) {
611 struct file_lock *waiter; 612 struct file_lock *waiter;
612 613
@@ -618,7 +619,7 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
618 else 619 else
619 wake_up(&waiter->fl_wait); 620 wake_up(&waiter->fl_wait);
620 } 621 }
621 spin_unlock(&file_lock_lock); 622 spin_unlock(&blocked_lock_lock);
622} 623}
623 624
624/* Insert file lock fl into an inode's lock list at the position indicated 625/* Insert file lock fl into an inode's lock list at the position indicated
@@ -772,7 +773,7 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
772 return NULL; 773 return NULL;
773} 774}
774 775
775/* Must be called with the file_lock_lock held! */ 776/* Must be called with the blocked_lock_lock held! */
776static int posix_locks_deadlock(struct file_lock *caller_fl, 777static int posix_locks_deadlock(struct file_lock *caller_fl,
777 struct file_lock *block_fl) 778 struct file_lock *block_fl)
778{ 779{
@@ -920,12 +921,12 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
920 * locks list must be done while holding the same lock! 921 * locks list must be done while holding the same lock!
921 */ 922 */
922 error = -EDEADLK; 923 error = -EDEADLK;
923 spin_lock(&file_lock_lock); 924 spin_lock(&blocked_lock_lock);
924 if (likely(!posix_locks_deadlock(request, fl))) { 925 if (likely(!posix_locks_deadlock(request, fl))) {
925 error = FILE_LOCK_DEFERRED; 926 error = FILE_LOCK_DEFERRED;
926 __locks_insert_block(fl, request); 927 __locks_insert_block(fl, request);
927 } 928 }
928 spin_unlock(&file_lock_lock); 929 spin_unlock(&blocked_lock_lock);
929 goto out; 930 goto out;
930 } 931 }
931 } 932 }
@@ -2212,12 +2213,12 @@ posix_unblock_lock(struct file_lock *waiter)
2212{ 2213{
2213 int status = 0; 2214 int status = 0;
2214 2215
2215 spin_lock(&file_lock_lock); 2216 spin_lock(&blocked_lock_lock);
2216 if (waiter->fl_next) 2217 if (waiter->fl_next)
2217 __locks_delete_block(waiter); 2218 __locks_delete_block(waiter);
2218 else 2219 else
2219 status = -ENOENT; 2220 status = -ENOENT;
2220 spin_unlock(&file_lock_lock); 2221 spin_unlock(&blocked_lock_lock);
2221 return status; 2222 return status;
2222} 2223}
2223EXPORT_SYMBOL(posix_unblock_lock); 2224EXPORT_SYMBOL(posix_unblock_lock);
@@ -2332,6 +2333,7 @@ static void *locks_start(struct seq_file *f, loff_t *pos)
2332 loff_t *p = f->private; 2333 loff_t *p = f->private;
2333 2334
2334 spin_lock(&file_lock_lock); 2335 spin_lock(&file_lock_lock);
2336 spin_lock(&blocked_lock_lock);
2335 *p = (*pos + 1); 2337 *p = (*pos + 1);
2336 return seq_hlist_start(&file_lock_list, *pos); 2338 return seq_hlist_start(&file_lock_list, *pos);
2337} 2339}
@@ -2345,6 +2347,7 @@ static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
2345 2347
2346static void locks_stop(struct seq_file *f, void *v) 2348static void locks_stop(struct seq_file *f, void *v)
2347{ 2349{
2350 spin_unlock(&blocked_lock_lock);
2348 spin_unlock(&file_lock_lock); 2351 spin_unlock(&file_lock_lock);
2349} 2352}
2350 2353