diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2009-09-24 09:25:11 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-09-25 12:08:26 -0400 |
commit | 9ecc2738ac2371f88dff5d48914b4e35c45203cd (patch) | |
tree | 12cd500172561fb43e5cbe1ee1993945a4ac2c5c /fs | |
parent | cf137307cd9827495b65e7d74ea2b610daa9898b (diff) |
writeback: make the super_block pinning more efficient
Currently we pin the inode->i_sb for every single inode. This
increases cache traffic on sb->s_umount sem. Lets instead
cache the inode sb pin state and keep the super_block pinned
for as long as keep writing out inodes from the same
super_block.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fs-writeback.c | 46 |
1 files changed, 29 insertions, 17 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 225c7316344e..c6bf775e641a 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -540,6 +540,17 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
540 | return ret; | 540 | return ret; |
541 | } | 541 | } |
542 | 542 | ||
543 | static void unpin_sb_for_writeback(struct super_block **psb) | ||
544 | { | ||
545 | struct super_block *sb = *psb; | ||
546 | |||
547 | if (sb) { | ||
548 | up_read(&sb->s_umount); | ||
549 | put_super(sb); | ||
550 | *psb = NULL; | ||
551 | } | ||
552 | } | ||
553 | |||
543 | /* | 554 | /* |
544 | * For WB_SYNC_NONE writeback, the caller does not have the sb pinned | 555 | * For WB_SYNC_NONE writeback, the caller does not have the sb pinned |
545 | * before calling writeback. So make sure that we do pin it, so it doesn't | 556 | * before calling writeback. So make sure that we do pin it, so it doesn't |
@@ -549,11 +560,20 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
549 | * 1 if we failed. | 560 | * 1 if we failed. |
550 | */ | 561 | */ |
551 | static int pin_sb_for_writeback(struct writeback_control *wbc, | 562 | static int pin_sb_for_writeback(struct writeback_control *wbc, |
552 | struct inode *inode) | 563 | struct inode *inode, struct super_block **psb) |
553 | { | 564 | { |
554 | struct super_block *sb = inode->i_sb; | 565 | struct super_block *sb = inode->i_sb; |
555 | 566 | ||
556 | /* | 567 | /* |
568 | * If this sb is already pinned, nothing more to do. If not and | ||
569 | * *psb is non-NULL, unpin the old one first | ||
570 | */ | ||
571 | if (sb == *psb) | ||
572 | return 0; | ||
573 | else if (*psb) | ||
574 | unpin_sb_for_writeback(psb); | ||
575 | |||
576 | /* | ||
557 | * Caller must already hold the ref for this | 577 | * Caller must already hold the ref for this |
558 | */ | 578 | */ |
559 | if (wbc->sync_mode == WB_SYNC_ALL) { | 579 | if (wbc->sync_mode == WB_SYNC_ALL) { |
@@ -566,7 +586,7 @@ static int pin_sb_for_writeback(struct writeback_control *wbc, | |||
566 | if (down_read_trylock(&sb->s_umount)) { | 586 | if (down_read_trylock(&sb->s_umount)) { |
567 | if (sb->s_root) { | 587 | if (sb->s_root) { |
568 | spin_unlock(&sb_lock); | 588 | spin_unlock(&sb_lock); |
569 | return 0; | 589 | goto pinned; |
570 | } | 590 | } |
571 | /* | 591 | /* |
572 | * umounted, drop rwsem again and fall through to failure | 592 | * umounted, drop rwsem again and fall through to failure |
@@ -577,24 +597,15 @@ static int pin_sb_for_writeback(struct writeback_control *wbc, | |||
577 | sb->s_count--; | 597 | sb->s_count--; |
578 | spin_unlock(&sb_lock); | 598 | spin_unlock(&sb_lock); |
579 | return 1; | 599 | return 1; |
580 | } | 600 | pinned: |
581 | 601 | *psb = sb; | |
582 | static void unpin_sb_for_writeback(struct writeback_control *wbc, | 602 | return 0; |
583 | struct inode *inode) | ||
584 | { | ||
585 | struct super_block *sb = inode->i_sb; | ||
586 | |||
587 | if (wbc->sync_mode == WB_SYNC_ALL) | ||
588 | return; | ||
589 | |||
590 | up_read(&sb->s_umount); | ||
591 | put_super(sb); | ||
592 | } | 603 | } |
593 | 604 | ||
594 | static void writeback_inodes_wb(struct bdi_writeback *wb, | 605 | static void writeback_inodes_wb(struct bdi_writeback *wb, |
595 | struct writeback_control *wbc) | 606 | struct writeback_control *wbc) |
596 | { | 607 | { |
597 | struct super_block *sb = wbc->sb; | 608 | struct super_block *sb = wbc->sb, *pin_sb = NULL; |
598 | const int is_blkdev_sb = sb_is_blkdev_sb(sb); | 609 | const int is_blkdev_sb = sb_is_blkdev_sb(sb); |
599 | const unsigned long start = jiffies; /* livelock avoidance */ | 610 | const unsigned long start = jiffies; /* livelock avoidance */ |
600 | 611 | ||
@@ -653,7 +664,7 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
653 | if (inode_dirtied_after(inode, start)) | 664 | if (inode_dirtied_after(inode, start)) |
654 | break; | 665 | break; |
655 | 666 | ||
656 | if (pin_sb_for_writeback(wbc, inode)) { | 667 | if (pin_sb_for_writeback(wbc, inode, &pin_sb)) { |
657 | requeue_io(inode); | 668 | requeue_io(inode); |
658 | continue; | 669 | continue; |
659 | } | 670 | } |
@@ -662,7 +673,6 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
662 | __iget(inode); | 673 | __iget(inode); |
663 | pages_skipped = wbc->pages_skipped; | 674 | pages_skipped = wbc->pages_skipped; |
664 | writeback_single_inode(inode, wbc); | 675 | writeback_single_inode(inode, wbc); |
665 | unpin_sb_for_writeback(wbc, inode); | ||
666 | if (wbc->pages_skipped != pages_skipped) { | 676 | if (wbc->pages_skipped != pages_skipped) { |
667 | /* | 677 | /* |
668 | * writeback is not making progress due to locked | 678 | * writeback is not making progress due to locked |
@@ -682,6 +692,8 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
682 | wbc->more_io = 1; | 692 | wbc->more_io = 1; |
683 | } | 693 | } |
684 | 694 | ||
695 | unpin_sb_for_writeback(&pin_sb); | ||
696 | |||
685 | spin_unlock(&inode_lock); | 697 | spin_unlock(&inode_lock); |
686 | /* Leave any unwritten inodes on b_io */ | 698 | /* Leave any unwritten inodes on b_io */ |
687 | } | 699 | } |