diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-09 14:50:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-09 14:50:29 -0400 |
commit | 2f4084209adc77f9a1c9f38db3019a509e167882 (patch) | |
tree | 775657114c885505ecc46605e29ea1470e986f76 /fs | |
parent | 2f10ffcfb28beb35137d9e86992c771b4a6c5f2a (diff) | |
parent | 3440c49f5c5ecb4f29b0544aa87da71888404f8f (diff) |
Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/linux-2.6-block: (34 commits)
cfq-iosched: Fix the incorrect timeslice accounting with forced_dispatch
loop: Update mtime when writing using aops
block: expose the statistics in blkio.time and blkio.sectors for the root cgroup
backing-dev: Handle class_create() failure
Block: Fix block/elevator.c elevator_get() off-by-one error
drbd: lc_element_by_index() never returns NULL
cciss: unlock on error path
cfq-iosched: Do not merge queues of BE and IDLE classes
cfq-iosched: Add additional blktrace log messages in CFQ for easier debugging
i2o: Remove the dangerous kobj_to_i2o_device macro
block: remove 16 bytes of padding from struct request on 64bits
cfq-iosched: fix a kbuild regression
block: make CONFIG_BLK_CGROUP visible
Remove GENHD_FL_DRIVERFS
block: Export max number of segments and max segment size in sysfs
block: Finalize conversion of block limits functions
block: Fix overrun in lcm() and move it to lib
vfs: improve writeback_inodes_wb()
paride: fix off-by-one test
drbd: fix al-to-on-disk-bitmap for 4k logical_block_size
...
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bio.c | 4 | ||||
-rw-r--r-- | fs/fs-writeback.c | 133 |
2 files changed, 75 insertions, 62 deletions
@@ -554,7 +554,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page | |||
554 | .bi_rw = bio->bi_rw, | 554 | .bi_rw = bio->bi_rw, |
555 | }; | 555 | }; |
556 | 556 | ||
557 | if (q->merge_bvec_fn(q, &bvm, prev) < len) { | 557 | if (q->merge_bvec_fn(q, &bvm, prev) < prev->bv_len) { |
558 | prev->bv_len -= len; | 558 | prev->bv_len -= len; |
559 | return 0; | 559 | return 0; |
560 | } | 560 | } |
@@ -607,7 +607,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page | |||
607 | * merge_bvec_fn() returns number of bytes it can accept | 607 | * merge_bvec_fn() returns number of bytes it can accept |
608 | * at this offset | 608 | * at this offset |
609 | */ | 609 | */ |
610 | if (q->merge_bvec_fn(q, &bvm, bvec) < len) { | 610 | if (q->merge_bvec_fn(q, &bvm, bvec) < bvec->bv_len) { |
611 | bvec->bv_page = NULL; | 611 | bvec->bv_page = NULL; |
612 | bvec->bv_len = 0; | 612 | bvec->bv_len = 0; |
613 | bvec->bv_offset = 0; | 613 | bvec->bv_offset = 0; |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 781a322ccb45..4b37f7cea4dd 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -554,108 +554,85 @@ select_queue: | |||
554 | return ret; | 554 | return ret; |
555 | } | 555 | } |
556 | 556 | ||
557 | static void unpin_sb_for_writeback(struct super_block **psb) | 557 | static void unpin_sb_for_writeback(struct super_block *sb) |
558 | { | 558 | { |
559 | struct super_block *sb = *psb; | 559 | up_read(&sb->s_umount); |
560 | 560 | put_super(sb); | |
561 | if (sb) { | ||
562 | up_read(&sb->s_umount); | ||
563 | put_super(sb); | ||
564 | *psb = NULL; | ||
565 | } | ||
566 | } | 561 | } |
567 | 562 | ||
563 | enum sb_pin_state { | ||
564 | SB_PINNED, | ||
565 | SB_NOT_PINNED, | ||
566 | SB_PIN_FAILED | ||
567 | }; | ||
568 | |||
568 | /* | 569 | /* |
569 | * 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 |
570 | * 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 |
571 | * go away while we are writing inodes from it. | 572 | * go away while we are writing inodes from it. |
572 | * | ||
573 | * Returns 0 if the super was successfully pinned (or pinning wasn't needed), | ||
574 | * 1 if we failed. | ||
575 | */ | 573 | */ |
576 | static int pin_sb_for_writeback(struct writeback_control *wbc, | 574 | static enum sb_pin_state pin_sb_for_writeback(struct writeback_control *wbc, |
577 | struct inode *inode, struct super_block **psb) | 575 | struct super_block *sb) |
578 | { | 576 | { |
579 | struct super_block *sb = inode->i_sb; | ||
580 | |||
581 | /* | ||
582 | * If this sb is already pinned, nothing more to do. If not and | ||
583 | * *psb is non-NULL, unpin the old one first | ||
584 | */ | ||
585 | if (sb == *psb) | ||
586 | return 0; | ||
587 | else if (*psb) | ||
588 | unpin_sb_for_writeback(psb); | ||
589 | |||
590 | /* | 577 | /* |
591 | * Caller must already hold the ref for this | 578 | * Caller must already hold the ref for this |
592 | */ | 579 | */ |
593 | if (wbc->sync_mode == WB_SYNC_ALL) { | 580 | if (wbc->sync_mode == WB_SYNC_ALL) { |
594 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 581 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); |
595 | return 0; | 582 | return SB_NOT_PINNED; |
596 | } | 583 | } |
597 | |||
598 | spin_lock(&sb_lock); | 584 | spin_lock(&sb_lock); |
599 | sb->s_count++; | 585 | sb->s_count++; |
600 | if (down_read_trylock(&sb->s_umount)) { | 586 | if (down_read_trylock(&sb->s_umount)) { |
601 | if (sb->s_root) { | 587 | if (sb->s_root) { |
602 | spin_unlock(&sb_lock); | 588 | spin_unlock(&sb_lock); |
603 | goto pinned; | 589 | return SB_PINNED; |
604 | } | 590 | } |
605 | /* | 591 | /* |
606 | * umounted, drop rwsem again and fall through to failure | 592 | * umounted, drop rwsem again and fall through to failure |
607 | */ | 593 | */ |
608 | up_read(&sb->s_umount); | 594 | up_read(&sb->s_umount); |
609 | } | 595 | } |
610 | |||
611 | sb->s_count--; | 596 | sb->s_count--; |
612 | spin_unlock(&sb_lock); | 597 | spin_unlock(&sb_lock); |
613 | return 1; | 598 | return SB_PIN_FAILED; |
614 | pinned: | ||
615 | *psb = sb; | ||
616 | return 0; | ||
617 | } | 599 | } |
618 | 600 | ||
619 | static void writeback_inodes_wb(struct bdi_writeback *wb, | 601 | /* |
620 | 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) | ||
621 | { | 612 | { |
622 | struct super_block *sb = wbc->sb, *pin_sb = NULL; | ||
623 | const unsigned long start = jiffies; /* livelock avoidance */ | ||
624 | |||
625 | spin_lock(&inode_lock); | ||
626 | |||
627 | if (!wbc->for_kupdate || list_empty(&wb->b_io)) | ||
628 | queue_io(wb, wbc->older_than_this); | ||
629 | |||
630 | while (!list_empty(&wb->b_io)) { | 613 | while (!list_empty(&wb->b_io)) { |
631 | struct inode *inode = list_entry(wb->b_io.prev, | ||
632 | struct inode, i_list); | ||
633 | long pages_skipped; | 614 | long pages_skipped; |
634 | 615 | struct inode *inode = list_entry(wb->b_io.prev, | |
635 | /* | 616 | struct inode, i_list); |
636 | * super block given and doesn't match, skip this inode | 617 | if (wbc->sb && sb != inode->i_sb) { |
637 | */ | 618 | /* super block given and doesn't |
638 | if (sb && sb != inode->i_sb) { | 619 | match, skip this inode */ |
639 | redirty_tail(inode); | 620 | redirty_tail(inode); |
640 | continue; | 621 | continue; |
641 | } | 622 | } |
642 | 623 | if (sb != inode->i_sb) | |
624 | /* finish with this superblock */ | ||
625 | return 0; | ||
643 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { | 626 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { |
644 | requeue_io(inode); | 627 | requeue_io(inode); |
645 | continue; | 628 | continue; |
646 | } | 629 | } |
647 | |||
648 | /* | 630 | /* |
649 | * Was this inode dirtied after sync_sb_inodes was called? | 631 | * Was this inode dirtied after sync_sb_inodes was called? |
650 | * This keeps sync from extra jobs and livelock. | 632 | * This keeps sync from extra jobs and livelock. |
651 | */ | 633 | */ |
652 | if (inode_dirtied_after(inode, start)) | 634 | if (inode_dirtied_after(inode, wbc->wb_start)) |
653 | break; | 635 | return 1; |
654 | |||
655 | if (pin_sb_for_writeback(wbc, inode, &pin_sb)) { | ||
656 | requeue_io(inode); | ||
657 | continue; | ||
658 | } | ||
659 | 636 | ||
660 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); | 637 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); |
661 | __iget(inode); | 638 | __iget(inode); |
@@ -674,14 +651,50 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
674 | spin_lock(&inode_lock); | 651 | spin_lock(&inode_lock); |
675 | if (wbc->nr_to_write <= 0) { | 652 | if (wbc->nr_to_write <= 0) { |
676 | wbc->more_io = 1; | 653 | wbc->more_io = 1; |
677 | break; | 654 | return 1; |
678 | } | 655 | } |
679 | if (!list_empty(&wb->b_more_io)) | 656 | if (!list_empty(&wb->b_more_io)) |
680 | wbc->more_io = 1; | 657 | wbc->more_io = 1; |
681 | } | 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; | ||
682 | 667 | ||
683 | 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); | ||
684 | 692 | ||
693 | if (state == SB_PINNED) | ||
694 | unpin_sb_for_writeback(sb); | ||
695 | if (ret) | ||
696 | break; | ||
697 | } | ||
685 | spin_unlock(&inode_lock); | 698 | spin_unlock(&inode_lock); |
686 | /* Leave any unwritten inodes on b_io */ | 699 | /* Leave any unwritten inodes on b_io */ |
687 | } | 700 | } |