aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <nickpiggin@yahoo.com.au>2005-07-07 20:56:56 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:23:45 -0400
commita39722034ae37f80a1803bf781fe3fe1b03e20bc (patch)
treefb7ef719d745e28678d73f884108f4cb2ef79171
parentd6afe27bfff30fbec2cca6ad5626c22f4094d770 (diff)
[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>
-rw-r--r--fs/buffer.c25
-rw-r--r--include/linux/buffer_head.h3
2 files changed, 20 insertions, 8 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 561e63a14966..6a25d7df89b1 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -513,8 +513,8 @@ static void free_more_memory(void)
513 */ 513 */
514static void end_buffer_async_read(struct buffer_head *bh, int uptodate) 514static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
515{ 515{
516 static DEFINE_SPINLOCK(page_uptodate_lock);
517 unsigned long flags; 516 unsigned long flags;
517 struct buffer_head *first;
518 struct buffer_head *tmp; 518 struct buffer_head *tmp;
519 struct page *page; 519 struct page *page;
520 int page_uptodate = 1; 520 int page_uptodate = 1;
@@ -536,7 +536,9 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
536 * two buffer heads end IO at almost the same time and both 536 * two buffer heads end IO at almost the same time and both
537 * decide that the page is now completely done. 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 clear_buffer_async_read(bh); 542 clear_buffer_async_read(bh);
541 unlock_buffer(bh); 543 unlock_buffer(bh);
542 tmp = bh; 544 tmp = bh;
@@ -549,7 +551,8 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
549 } 551 }
550 tmp = tmp->b_this_page; 552 tmp = tmp->b_this_page;
551 } while (tmp != bh); 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 * If none of the buffers had errors and they are all 558 * If none of the buffers had errors and they are all
@@ -561,7 +564,8 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
561 return; 564 return;
562 565
563still_busy: 566still_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 return; 569 return;
566} 570}
567 571
@@ -572,8 +576,8 @@ still_busy:
572void end_buffer_async_write(struct buffer_head *bh, int uptodate) 576void end_buffer_async_write(struct buffer_head *bh, int uptodate)
573{ 577{
574 char b[BDEVNAME_SIZE]; 578 char b[BDEVNAME_SIZE];
575 static DEFINE_SPINLOCK(page_uptodate_lock);
576 unsigned long flags; 579 unsigned long flags;
580 struct buffer_head *first;
577 struct buffer_head *tmp; 581 struct buffer_head *tmp;
578 struct page *page; 582 struct page *page;
579 583
@@ -594,7 +598,10 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
594 SetPageError(page); 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 clear_buffer_async_write(bh); 605 clear_buffer_async_write(bh);
599 unlock_buffer(bh); 606 unlock_buffer(bh);
600 tmp = bh->b_this_page; 607 tmp = bh->b_this_page;
@@ -605,12 +612,14 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
605 } 612 }
606 tmp = tmp->b_this_page; 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 end_page_writeback(page); 617 end_page_writeback(page);
610 return; 618 return;
611 619
612still_busy: 620still_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 return; 623 return;
615} 624}
616 625
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 802c91e9b3da..90828493791f 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -19,6 +19,9 @@ enum bh_state_bits {
19 BH_Dirty, /* Is dirty */ 19 BH_Dirty, /* Is dirty */
20 BH_Lock, /* Is locked */ 20 BH_Lock, /* Is locked */
21 BH_Req, /* Has been submitted for I/O */ 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 BH_Mapped, /* Has a disk mapping */ 26 BH_Mapped, /* Has a disk mapping */
24 BH_New, /* Disk mapping was newly created by get_block */ 27 BH_New, /* Disk mapping was newly created by get_block */