diff options
author | Nick Piggin <nickpiggin@yahoo.com.au> | 2005-07-07 20:56:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-07 21:23:45 -0400 |
commit | a39722034ae37f80a1803bf781fe3fe1b03e20bc (patch) | |
tree | fb7ef719d745e28678d73f884108f4cb2ef79171 | |
parent | d6afe27bfff30fbec2cca6ad5626c22f4094d770 (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.c | 25 | ||||
-rw-r--r-- | include/linux/buffer_head.h | 3 |
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 | */ |
514 | static void end_buffer_async_read(struct buffer_head *bh, int uptodate) | 514 | static 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 | ||
563 | still_busy: | 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 | return; | 569 | return; |
566 | } | 570 | } |
567 | 571 | ||
@@ -572,8 +576,8 @@ still_busy: | |||
572 | void end_buffer_async_write(struct buffer_head *bh, int uptodate) | 576 | void 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 | ||
612 | still_busy: | 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 | 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 */ |