Commit a39722034ae37f80a1803bf781fe3fe1b03e20bc

Authored by Nick Piggin
Committed by Linus Torvalds
1 parent d6afe27bff

[PATCH] page_uptodate locking scalability

Use a bit spin lock in the first buffer of the page to synchronise asynch
IO buffer completions, instead of the global page_uptodate_lock, which is
showing some scalabilty problems.

Signed-off-by: Nick Piggin <nickpiggin@yahoo.com.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 2 changed files with 20 additions and 8 deletions Side-by-side Diff

... ... @@ -513,8 +513,8 @@
513 513 */
514 514 static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
515 515 {
516   - static DEFINE_SPINLOCK(page_uptodate_lock);
517 516 unsigned long flags;
  517 + struct buffer_head *first;
518 518 struct buffer_head *tmp;
519 519 struct page *page;
520 520 int page_uptodate = 1;
... ... @@ -536,7 +536,9 @@
536 536 * two buffer heads end IO at almost the same time and both
537 537 * decide that the page is now completely done.
538 538 */
539   - spin_lock_irqsave(&page_uptodate_lock, flags);
  539 + first = page_buffers(page);
  540 + local_irq_save(flags);
  541 + bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
540 542 clear_buffer_async_read(bh);
541 543 unlock_buffer(bh);
542 544 tmp = bh;
... ... @@ -549,7 +551,8 @@
549 551 }
550 552 tmp = tmp->b_this_page;
551 553 } while (tmp != bh);
552   - spin_unlock_irqrestore(&page_uptodate_lock, flags);
  554 + bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
  555 + local_irq_restore(flags);
553 556  
554 557 /*
555 558 * If none of the buffers had errors and they are all
... ... @@ -561,7 +564,8 @@
561 564 return;
562 565  
563 566 still_busy:
564   - spin_unlock_irqrestore(&page_uptodate_lock, flags);
  567 + bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
  568 + local_irq_restore(flags);
565 569 return;
566 570 }
567 571  
568 572  
... ... @@ -572,8 +576,8 @@
572 576 void end_buffer_async_write(struct buffer_head *bh, int uptodate)
573 577 {
574 578 char b[BDEVNAME_SIZE];
575   - static DEFINE_SPINLOCK(page_uptodate_lock);
576 579 unsigned long flags;
  580 + struct buffer_head *first;
577 581 struct buffer_head *tmp;
578 582 struct page *page;
579 583  
... ... @@ -594,7 +598,10 @@
594 598 SetPageError(page);
595 599 }
596 600  
597   - spin_lock_irqsave(&page_uptodate_lock, flags);
  601 + first = page_buffers(page);
  602 + local_irq_save(flags);
  603 + bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
  604 +
598 605 clear_buffer_async_write(bh);
599 606 unlock_buffer(bh);
600 607 tmp = bh->b_this_page;
601 608  
... ... @@ -605,12 +612,14 @@
605 612 }
606 613 tmp = tmp->b_this_page;
607 614 }
608   - spin_unlock_irqrestore(&page_uptodate_lock, flags);
  615 + bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
  616 + local_irq_restore(flags);
609 617 end_page_writeback(page);
610 618 return;
611 619  
612 620 still_busy:
613   - spin_unlock_irqrestore(&page_uptodate_lock, flags);
  621 + bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
  622 + local_irq_restore(flags);
614 623 return;
615 624 }
616 625  
include/linux/buffer_head.h
... ... @@ -19,6 +19,9 @@
19 19 BH_Dirty, /* Is dirty */
20 20 BH_Lock, /* Is locked */
21 21 BH_Req, /* Has been submitted for I/O */
  22 + BH_Uptodate_Lock,/* Used by the first bh in a page, to serialise
  23 + * IO completion of other buffers in the page
  24 + */
22 25  
23 26 BH_Mapped, /* Has a disk mapping */
24 27 BH_New, /* Disk mapping was newly created by get_block */