diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2007-05-11 01:22:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-11 11:29:35 -0400 |
commit | 0ea971801625184a91a6d80ea85e53875caa0bf5 (patch) | |
tree | 6f4144b7ba809fccfe6d75314df8c348596c9a01 /fs/mpage.c | |
parent | e10cc1df1d2014f68a4bdcf73f6dd122c4561f94 (diff) |
consolidate generic_writepages and mpage_writepages
Clean up massive code duplication between mpage_writepages() and
generic_writepages().
The new generic function, write_cache_pages() takes a function pointer
argument, which will be called for each page to be written.
Maybe cifs_writepages() too can use this infrastructure, but I'm not
touching that with a ten-foot pole.
The upcoming page writeback support in fuse will also want this.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Acked-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/mpage.c')
-rw-r--r-- | fs/mpage.c | 174 |
1 files changed, 45 insertions, 129 deletions
diff --git a/fs/mpage.c b/fs/mpage.c index 0fb914fc2ee0..c1698f2291aa 100644 --- a/fs/mpage.c +++ b/fs/mpage.c | |||
@@ -454,11 +454,18 @@ EXPORT_SYMBOL(mpage_readpage); | |||
454 | * written, so it can intelligently allocate a suitably-sized BIO. For now, | 454 | * written, so it can intelligently allocate a suitably-sized BIO. For now, |
455 | * just allocate full-size (16-page) BIOs. | 455 | * just allocate full-size (16-page) BIOs. |
456 | */ | 456 | */ |
457 | static struct bio * | 457 | struct mpage_data { |
458 | __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block, | 458 | struct bio *bio; |
459 | sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc, | 459 | sector_t last_block_in_bio; |
460 | writepage_t writepage_fn) | 460 | get_block_t *get_block; |
461 | unsigned use_writepage; | ||
462 | }; | ||
463 | |||
464 | static int __mpage_writepage(struct page *page, struct writeback_control *wbc, | ||
465 | void *data) | ||
461 | { | 466 | { |
467 | struct mpage_data *mpd = data; | ||
468 | struct bio *bio = mpd->bio; | ||
462 | struct address_space *mapping = page->mapping; | 469 | struct address_space *mapping = page->mapping; |
463 | struct inode *inode = page->mapping->host; | 470 | struct inode *inode = page->mapping->host; |
464 | const unsigned blkbits = inode->i_blkbits; | 471 | const unsigned blkbits = inode->i_blkbits; |
@@ -476,6 +483,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block, | |||
476 | int length; | 483 | int length; |
477 | struct buffer_head map_bh; | 484 | struct buffer_head map_bh; |
478 | loff_t i_size = i_size_read(inode); | 485 | loff_t i_size = i_size_read(inode); |
486 | int ret = 0; | ||
479 | 487 | ||
480 | if (page_has_buffers(page)) { | 488 | if (page_has_buffers(page)) { |
481 | struct buffer_head *head = page_buffers(page); | 489 | struct buffer_head *head = page_buffers(page); |
@@ -538,7 +546,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block, | |||
538 | 546 | ||
539 | map_bh.b_state = 0; | 547 | map_bh.b_state = 0; |
540 | map_bh.b_size = 1 << blkbits; | 548 | map_bh.b_size = 1 << blkbits; |
541 | if (get_block(inode, block_in_file, &map_bh, 1)) | 549 | if (mpd->get_block(inode, block_in_file, &map_bh, 1)) |
542 | goto confused; | 550 | goto confused; |
543 | if (buffer_new(&map_bh)) | 551 | if (buffer_new(&map_bh)) |
544 | unmap_underlying_metadata(map_bh.b_bdev, | 552 | unmap_underlying_metadata(map_bh.b_bdev, |
@@ -584,7 +592,7 @@ page_is_mapped: | |||
584 | /* | 592 | /* |
585 | * This page will go to BIO. Do we need to send this BIO off first? | 593 | * This page will go to BIO. Do we need to send this BIO off first? |
586 | */ | 594 | */ |
587 | if (bio && *last_block_in_bio != blocks[0] - 1) | 595 | if (bio && mpd->last_block_in_bio != blocks[0] - 1) |
588 | bio = mpage_bio_submit(WRITE, bio); | 596 | bio = mpage_bio_submit(WRITE, bio); |
589 | 597 | ||
590 | alloc_new: | 598 | alloc_new: |
@@ -641,7 +649,7 @@ alloc_new: | |||
641 | boundary_block, 1 << blkbits); | 649 | boundary_block, 1 << blkbits); |
642 | } | 650 | } |
643 | } else { | 651 | } else { |
644 | *last_block_in_bio = blocks[blocks_per_page - 1]; | 652 | mpd->last_block_in_bio = blocks[blocks_per_page - 1]; |
645 | } | 653 | } |
646 | goto out; | 654 | goto out; |
647 | 655 | ||
@@ -649,18 +657,19 @@ confused: | |||
649 | if (bio) | 657 | if (bio) |
650 | bio = mpage_bio_submit(WRITE, bio); | 658 | bio = mpage_bio_submit(WRITE, bio); |
651 | 659 | ||
652 | if (writepage_fn) { | 660 | if (mpd->use_writepage) { |
653 | *ret = (*writepage_fn)(page, wbc); | 661 | ret = mapping->a_ops->writepage(page, wbc); |
654 | } else { | 662 | } else { |
655 | *ret = -EAGAIN; | 663 | ret = -EAGAIN; |
656 | goto out; | 664 | goto out; |
657 | } | 665 | } |
658 | /* | 666 | /* |
659 | * The caller has a ref on the inode, so *mapping is stable | 667 | * The caller has a ref on the inode, so *mapping is stable |
660 | */ | 668 | */ |
661 | mapping_set_error(mapping, *ret); | 669 | mapping_set_error(mapping, ret); |
662 | out: | 670 | out: |
663 | return bio; | 671 | mpd->bio = bio; |
672 | return ret; | ||
664 | } | 673 | } |
665 | 674 | ||
666 | /** | 675 | /** |
@@ -683,120 +692,27 @@ out: | |||
683 | * the call was made get new I/O started against them. If wbc->sync_mode is | 692 | * the call was made get new I/O started against them. If wbc->sync_mode is |
684 | * WB_SYNC_ALL then we were called for data integrity and we must wait for | 693 | * WB_SYNC_ALL then we were called for data integrity and we must wait for |
685 | * existing IO to complete. | 694 | * existing IO to complete. |
686 | * | ||
687 | * If you fix this you should check generic_writepages() also! | ||
688 | */ | 695 | */ |
689 | int | 696 | int |
690 | mpage_writepages(struct address_space *mapping, | 697 | mpage_writepages(struct address_space *mapping, |
691 | struct writeback_control *wbc, get_block_t get_block) | 698 | struct writeback_control *wbc, get_block_t get_block) |
692 | { | 699 | { |
693 | struct backing_dev_info *bdi = mapping->backing_dev_info; | 700 | int ret; |
694 | struct bio *bio = NULL; | 701 | |
695 | sector_t last_block_in_bio = 0; | 702 | if (!get_block) |
696 | int ret = 0; | 703 | ret = generic_writepages(mapping, wbc); |
697 | int done = 0; | 704 | else { |
698 | int (*writepage)(struct page *page, struct writeback_control *wbc); | 705 | struct mpage_data mpd = { |
699 | struct pagevec pvec; | 706 | .bio = NULL, |
700 | int nr_pages; | 707 | .last_block_in_bio = 0, |
701 | pgoff_t index; | 708 | .get_block = get_block, |
702 | pgoff_t end; /* Inclusive */ | 709 | .use_writepage = 1, |
703 | int scanned = 0; | 710 | }; |
704 | int range_whole = 0; | 711 | |
705 | 712 | ret = write_cache_pages(mapping, wbc, __mpage_writepage, &mpd); | |
706 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | 713 | if (mpd.bio) |
707 | wbc->encountered_congestion = 1; | 714 | mpage_bio_submit(WRITE, mpd.bio); |
708 | return 0; | ||
709 | } | ||
710 | |||
711 | writepage = NULL; | ||
712 | if (get_block == NULL) | ||
713 | writepage = mapping->a_ops->writepage; | ||
714 | |||
715 | pagevec_init(&pvec, 0); | ||
716 | if (wbc->range_cyclic) { | ||
717 | index = mapping->writeback_index; /* Start from prev offset */ | ||
718 | end = -1; | ||
719 | } else { | ||
720 | index = wbc->range_start >> PAGE_CACHE_SHIFT; | ||
721 | end = wbc->range_end >> PAGE_CACHE_SHIFT; | ||
722 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) | ||
723 | range_whole = 1; | ||
724 | scanned = 1; | ||
725 | } | 715 | } |
726 | retry: | ||
727 | while (!done && (index <= end) && | ||
728 | (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, | ||
729 | PAGECACHE_TAG_DIRTY, | ||
730 | min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { | ||
731 | unsigned i; | ||
732 | |||
733 | scanned = 1; | ||
734 | for (i = 0; i < nr_pages; i++) { | ||
735 | struct page *page = pvec.pages[i]; | ||
736 | |||
737 | /* | ||
738 | * At this point we hold neither mapping->tree_lock nor | ||
739 | * lock on the page itself: the page may be truncated or | ||
740 | * invalidated (changing page->mapping to NULL), or even | ||
741 | * swizzled back from swapper_space to tmpfs file | ||
742 | * mapping | ||
743 | */ | ||
744 | |||
745 | lock_page(page); | ||
746 | |||
747 | if (unlikely(page->mapping != mapping)) { | ||
748 | unlock_page(page); | ||
749 | continue; | ||
750 | } | ||
751 | |||
752 | if (!wbc->range_cyclic && page->index > end) { | ||
753 | done = 1; | ||
754 | unlock_page(page); | ||
755 | continue; | ||
756 | } | ||
757 | |||
758 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
759 | wait_on_page_writeback(page); | ||
760 | |||
761 | if (PageWriteback(page) || | ||
762 | !clear_page_dirty_for_io(page)) { | ||
763 | unlock_page(page); | ||
764 | continue; | ||
765 | } | ||
766 | |||
767 | if (writepage) { | ||
768 | ret = (*writepage)(page, wbc); | ||
769 | mapping_set_error(mapping, ret); | ||
770 | } else { | ||
771 | bio = __mpage_writepage(bio, page, get_block, | ||
772 | &last_block_in_bio, &ret, wbc, | ||
773 | page->mapping->a_ops->writepage); | ||
774 | } | ||
775 | if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) | ||
776 | unlock_page(page); | ||
777 | if (ret || (--(wbc->nr_to_write) <= 0)) | ||
778 | done = 1; | ||
779 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
780 | wbc->encountered_congestion = 1; | ||
781 | done = 1; | ||
782 | } | ||
783 | } | ||
784 | pagevec_release(&pvec); | ||
785 | cond_resched(); | ||
786 | } | ||
787 | if (!scanned && !done) { | ||
788 | /* | ||
789 | * We hit the last page and there is more work to be done: wrap | ||
790 | * back to the start of the file | ||
791 | */ | ||
792 | scanned = 1; | ||
793 | index = 0; | ||
794 | goto retry; | ||
795 | } | ||
796 | if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) | ||
797 | mapping->writeback_index = index; | ||
798 | if (bio) | ||
799 | mpage_bio_submit(WRITE, bio); | ||
800 | return ret; | 716 | return ret; |
801 | } | 717 | } |
802 | EXPORT_SYMBOL(mpage_writepages); | 718 | EXPORT_SYMBOL(mpage_writepages); |
@@ -804,15 +720,15 @@ EXPORT_SYMBOL(mpage_writepages); | |||
804 | int mpage_writepage(struct page *page, get_block_t get_block, | 720 | int mpage_writepage(struct page *page, get_block_t get_block, |
805 | struct writeback_control *wbc) | 721 | struct writeback_control *wbc) |
806 | { | 722 | { |
807 | int ret = 0; | 723 | struct mpage_data mpd = { |
808 | struct bio *bio; | 724 | .bio = NULL, |
809 | sector_t last_block_in_bio = 0; | 725 | .last_block_in_bio = 0, |
810 | 726 | .get_block = get_block, | |
811 | bio = __mpage_writepage(NULL, page, get_block, | 727 | .use_writepage = 0, |
812 | &last_block_in_bio, &ret, wbc, NULL); | 728 | }; |
813 | if (bio) | 729 | int ret = __mpage_writepage(page, wbc, &mpd); |
814 | mpage_bio_submit(WRITE, bio); | 730 | if (mpd.bio) |
815 | 731 | mpage_bio_submit(WRITE, mpd.bio); | |
816 | return ret; | 732 | return ret; |
817 | } | 733 | } |
818 | EXPORT_SYMBOL(mpage_writepage); | 734 | EXPORT_SYMBOL(mpage_writepage); |