diff options
| author | Patrick McHardy <kaber@trash.net> | 2010-04-20 10:02:01 -0400 | 
|---|---|---|
| committer | Patrick McHardy <kaber@trash.net> | 2010-04-20 10:02:01 -0400 | 
| commit | 62910554656cdcd6b6f84a5154c4155aae4ca231 (patch) | |
| tree | dcf14004f6fd2ef7154362ff948bfeba0f3ea92d /fs/fs-writeback.c | |
| parent | 22265a5c3c103cf8c50be62e6c90d045eb649e6d (diff) | |
| parent | ab9304717f7624c41927f442e6b6d418b2d8b3e4 (diff) | |
Merge branch 'master' of /repos/git/net-next-2.6
Conflicts:
	Documentation/feature-removal-schedule.txt
	net/ipv6/netfilter/ip6t_REJECT.c
	net/netfilter/xt_limit.c
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'fs/fs-writeback.c')
| -rw-r--r-- | fs/fs-writeback.c | 134 | 
1 files changed, 74 insertions, 60 deletions
| diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 76fc4d594acb..4b37f7cea4dd 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> | 
| 17 | #include <linux/module.h> | 17 | #include <linux/module.h> | 
| 18 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> | 
| 19 | #include <linux/slab.h> | ||
| 19 | #include <linux/sched.h> | 20 | #include <linux/sched.h> | 
| 20 | #include <linux/fs.h> | 21 | #include <linux/fs.h> | 
| 21 | #include <linux/mm.h> | 22 | #include <linux/mm.h> | 
| @@ -553,108 +554,85 @@ select_queue: | |||
| 553 | return ret; | 554 | return ret; | 
| 554 | } | 555 | } | 
| 555 | 556 | ||
| 556 | static void unpin_sb_for_writeback(struct super_block **psb) | 557 | static void unpin_sb_for_writeback(struct super_block *sb) | 
| 557 | { | 558 | { | 
| 558 | struct super_block *sb = *psb; | 559 | up_read(&sb->s_umount); | 
| 559 | 560 | put_super(sb); | |
| 560 | if (sb) { | ||
| 561 | up_read(&sb->s_umount); | ||
| 562 | put_super(sb); | ||
| 563 | *psb = NULL; | ||
| 564 | } | ||
| 565 | } | 561 | } | 
| 566 | 562 | ||
| 563 | enum sb_pin_state { | ||
| 564 | SB_PINNED, | ||
| 565 | SB_NOT_PINNED, | ||
| 566 | SB_PIN_FAILED | ||
| 567 | }; | ||
| 568 | |||
| 567 | /* | 569 | /* | 
| 568 | * For WB_SYNC_NONE writeback, the caller does not have the sb pinned | 570 | * For WB_SYNC_NONE writeback, the caller does not have the sb pinned | 
| 569 | * before calling writeback. So make sure that we do pin it, so it doesn't | 571 | * before calling writeback. So make sure that we do pin it, so it doesn't | 
| 570 | * go away while we are writing inodes from it. | 572 | * go away while we are writing inodes from it. | 
| 571 | * | ||
| 572 | * Returns 0 if the super was successfully pinned (or pinning wasn't needed), | ||
| 573 | * 1 if we failed. | ||
| 574 | */ | 573 | */ | 
| 575 | static int pin_sb_for_writeback(struct writeback_control *wbc, | 574 | static enum sb_pin_state pin_sb_for_writeback(struct writeback_control *wbc, | 
| 576 | struct inode *inode, struct super_block **psb) | 575 | struct super_block *sb) | 
| 577 | { | 576 | { | 
| 578 | struct super_block *sb = inode->i_sb; | ||
| 579 | |||
| 580 | /* | ||
| 581 | * If this sb is already pinned, nothing more to do. If not and | ||
| 582 | * *psb is non-NULL, unpin the old one first | ||
| 583 | */ | ||
| 584 | if (sb == *psb) | ||
| 585 | return 0; | ||
| 586 | else if (*psb) | ||
| 587 | unpin_sb_for_writeback(psb); | ||
| 588 | |||
| 589 | /* | 577 | /* | 
| 590 | * Caller must already hold the ref for this | 578 | * Caller must already hold the ref for this | 
| 591 | */ | 579 | */ | 
| 592 | if (wbc->sync_mode == WB_SYNC_ALL) { | 580 | if (wbc->sync_mode == WB_SYNC_ALL) { | 
| 593 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 581 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 
| 594 | return 0; | 582 | return SB_NOT_PINNED; | 
| 595 | } | 583 | } | 
| 596 | |||
| 597 | spin_lock(&sb_lock); | 584 | spin_lock(&sb_lock); | 
| 598 | sb->s_count++; | 585 | sb->s_count++; | 
| 599 | if (down_read_trylock(&sb->s_umount)) { | 586 | if (down_read_trylock(&sb->s_umount)) { | 
| 600 | if (sb->s_root) { | 587 | if (sb->s_root) { | 
| 601 | spin_unlock(&sb_lock); | 588 | spin_unlock(&sb_lock); | 
| 602 | goto pinned; | 589 | return SB_PINNED; | 
| 603 | } | 590 | } | 
| 604 | /* | 591 | /* | 
| 605 | * umounted, drop rwsem again and fall through to failure | 592 | * umounted, drop rwsem again and fall through to failure | 
| 606 | */ | 593 | */ | 
| 607 | up_read(&sb->s_umount); | 594 | up_read(&sb->s_umount); | 
| 608 | } | 595 | } | 
| 609 | |||
| 610 | sb->s_count--; | 596 | sb->s_count--; | 
| 611 | spin_unlock(&sb_lock); | 597 | spin_unlock(&sb_lock); | 
| 612 | return 1; | 598 | return SB_PIN_FAILED; | 
| 613 | pinned: | ||
| 614 | *psb = sb; | ||
| 615 | return 0; | ||
| 616 | } | 599 | } | 
| 617 | 600 | ||
| 618 | static void writeback_inodes_wb(struct bdi_writeback *wb, | 601 | /* | 
| 619 | struct writeback_control *wbc) | 602 | * Write a portion of b_io inodes which belong to @sb. | 
| 603 | * If @wbc->sb != NULL, then find and write all such | ||
| 604 | * inodes. Otherwise write only ones which go sequentially | ||
| 605 | * in reverse order. | ||
| 606 | * Return 1, if the caller writeback routine should be | ||
| 607 | * interrupted. Otherwise return 0. | ||
| 608 | */ | ||
| 609 | static int writeback_sb_inodes(struct super_block *sb, | ||
| 610 | struct bdi_writeback *wb, | ||
| 611 | struct writeback_control *wbc) | ||
| 620 | { | 612 | { | 
| 621 | struct super_block *sb = wbc->sb, *pin_sb = NULL; | ||
| 622 | const unsigned long start = jiffies; /* livelock avoidance */ | ||
| 623 | |||
| 624 | spin_lock(&inode_lock); | ||
| 625 | |||
| 626 | if (!wbc->for_kupdate || list_empty(&wb->b_io)) | ||
| 627 | queue_io(wb, wbc->older_than_this); | ||
| 628 | |||
| 629 | while (!list_empty(&wb->b_io)) { | 613 | while (!list_empty(&wb->b_io)) { | 
| 630 | struct inode *inode = list_entry(wb->b_io.prev, | ||
| 631 | struct inode, i_list); | ||
| 632 | long pages_skipped; | 614 | long pages_skipped; | 
| 633 | 615 | struct inode *inode = list_entry(wb->b_io.prev, | |
| 634 | /* | 616 | struct inode, i_list); | 
| 635 | * super block given and doesn't match, skip this inode | 617 | if (wbc->sb && sb != inode->i_sb) { | 
| 636 | */ | 618 | /* super block given and doesn't | 
| 637 | if (sb && sb != inode->i_sb) { | 619 | match, skip this inode */ | 
| 638 | redirty_tail(inode); | 620 | redirty_tail(inode); | 
| 639 | continue; | 621 | continue; | 
| 640 | } | 622 | } | 
| 641 | 623 | if (sb != inode->i_sb) | |
| 624 | /* finish with this superblock */ | ||
| 625 | return 0; | ||
| 642 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { | 626 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { | 
| 643 | requeue_io(inode); | 627 | requeue_io(inode); | 
| 644 | continue; | 628 | continue; | 
| 645 | } | 629 | } | 
| 646 | |||
| 647 | /* | 630 | /* | 
| 648 | * Was this inode dirtied after sync_sb_inodes was called? | 631 | * Was this inode dirtied after sync_sb_inodes was called? | 
| 649 | * This keeps sync from extra jobs and livelock. | 632 | * This keeps sync from extra jobs and livelock. | 
| 650 | */ | 633 | */ | 
| 651 | if (inode_dirtied_after(inode, start)) | 634 | if (inode_dirtied_after(inode, wbc->wb_start)) | 
| 652 | break; | 635 | return 1; | 
| 653 | |||
| 654 | if (pin_sb_for_writeback(wbc, inode, &pin_sb)) { | ||
| 655 | requeue_io(inode); | ||
| 656 | continue; | ||
| 657 | } | ||
| 658 | 636 | ||
| 659 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); | 637 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); | 
| 660 | __iget(inode); | 638 | __iget(inode); | 
| @@ -673,14 +651,50 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
| 673 | spin_lock(&inode_lock); | 651 | spin_lock(&inode_lock); | 
| 674 | if (wbc->nr_to_write <= 0) { | 652 | if (wbc->nr_to_write <= 0) { | 
| 675 | wbc->more_io = 1; | 653 | wbc->more_io = 1; | 
| 676 | break; | 654 | return 1; | 
| 677 | } | 655 | } | 
| 678 | if (!list_empty(&wb->b_more_io)) | 656 | if (!list_empty(&wb->b_more_io)) | 
| 679 | wbc->more_io = 1; | 657 | wbc->more_io = 1; | 
| 680 | } | 658 | } | 
| 659 | /* b_io is empty */ | ||
| 660 | return 1; | ||
| 661 | } | ||
| 662 | |||
| 663 | static void writeback_inodes_wb(struct bdi_writeback *wb, | ||
| 664 | struct writeback_control *wbc) | ||
| 665 | { | ||
| 666 | int ret = 0; | ||
| 681 | 667 | ||
| 682 | unpin_sb_for_writeback(&pin_sb); | 668 | wbc->wb_start = jiffies; /* livelock avoidance */ | 
| 669 | spin_lock(&inode_lock); | ||
| 670 | if (!wbc->for_kupdate || list_empty(&wb->b_io)) | ||
| 671 | queue_io(wb, wbc->older_than_this); | ||
| 672 | |||
| 673 | while (!list_empty(&wb->b_io)) { | ||
| 674 | struct inode *inode = list_entry(wb->b_io.prev, | ||
| 675 | struct inode, i_list); | ||
| 676 | struct super_block *sb = inode->i_sb; | ||
| 677 | enum sb_pin_state state; | ||
| 678 | |||
| 679 | if (wbc->sb && sb != wbc->sb) { | ||
| 680 | /* super block given and doesn't | ||
| 681 | match, skip this inode */ | ||
| 682 | redirty_tail(inode); | ||
| 683 | continue; | ||
| 684 | } | ||
| 685 | state = pin_sb_for_writeback(wbc, sb); | ||
| 686 | |||
| 687 | if (state == SB_PIN_FAILED) { | ||
| 688 | requeue_io(inode); | ||
| 689 | continue; | ||
| 690 | } | ||
| 691 | ret = writeback_sb_inodes(sb, wb, wbc); | ||
| 683 | 692 | ||
| 693 | if (state == SB_PINNED) | ||
| 694 | unpin_sb_for_writeback(sb); | ||
| 695 | if (ret) | ||
| 696 | break; | ||
| 697 | } | ||
| 684 | spin_unlock(&inode_lock); | 698 | spin_unlock(&inode_lock); | 
| 685 | /* Leave any unwritten inodes on b_io */ | 699 | /* Leave any unwritten inodes on b_io */ | 
| 686 | } | 700 | } | 
