aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2007-05-11 01:22:51 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-11 11:29:35 -0400
commit0ea971801625184a91a6d80ea85e53875caa0bf5 (patch)
tree6f4144b7ba809fccfe6d75314df8c348596c9a01
parente10cc1df1d2014f68a4bdcf73f6dd122c4561f94 (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>
-rw-r--r--fs/mpage.c174
-rw-r--r--include/linux/mpage.h1
-rw-r--r--include/linux/writeback.h10
-rw-r--r--mm/page-writeback.c59
4 files changed, 93 insertions, 151 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 */
457static struct bio * 457struct 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
464static 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
590alloc_new: 598alloc_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);
662out: 670out:
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 */
689int 696int
690mpage_writepages(struct address_space *mapping, 697mpage_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 }
726retry:
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}
802EXPORT_SYMBOL(mpage_writepages); 718EXPORT_SYMBOL(mpage_writepages);
@@ -804,15 +720,15 @@ EXPORT_SYMBOL(mpage_writepages);
804int mpage_writepage(struct page *page, get_block_t get_block, 720int 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}
818EXPORT_SYMBOL(mpage_writepage); 734EXPORT_SYMBOL(mpage_writepage);
diff --git a/include/linux/mpage.h b/include/linux/mpage.h
index cc5fb75af78a..068a0c9946af 100644
--- a/include/linux/mpage.h
+++ b/include/linux/mpage.h
@@ -12,7 +12,6 @@
12#ifdef CONFIG_BLOCK 12#ifdef CONFIG_BLOCK
13 13
14struct writeback_control; 14struct writeback_control;
15typedef int (writepage_t)(struct page *page, struct writeback_control *wbc);
16 15
17int mpage_readpages(struct address_space *mapping, struct list_head *pages, 16int mpage_readpages(struct address_space *mapping, struct list_head *pages,
18 unsigned nr_pages, get_block_t get_block); 17 unsigned nr_pages, get_block_t get_block);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index daa6c125f66e..050915b59576 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -111,9 +111,15 @@ balance_dirty_pages_ratelimited(struct address_space *mapping)
111 balance_dirty_pages_ratelimited_nr(mapping, 1); 111 balance_dirty_pages_ratelimited_nr(mapping, 1);
112} 112}
113 113
114typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc,
115 void *data);
116
114int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); 117int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
115extern int generic_writepages(struct address_space *mapping, 118int generic_writepages(struct address_space *mapping,
116 struct writeback_control *wbc); 119 struct writeback_control *wbc);
120int write_cache_pages(struct address_space *mapping,
121 struct writeback_control *wbc, writepage_t writepage,
122 void *data);
117int do_writepages(struct address_space *mapping, struct writeback_control *wbc); 123int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
118int sync_page_range(struct inode *inode, struct address_space *mapping, 124int sync_page_range(struct inode *inode, struct address_space *mapping,
119 loff_t pos, loff_t count); 125 loff_t pos, loff_t count);
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 63cd88840eb2..eec1481ba44f 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -588,31 +588,27 @@ void __init page_writeback_init(void)
588} 588}
589 589
590/** 590/**
591 * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them. 591 * write_cache_pages - walk the list of dirty pages of the given address space and write all of them.
592 * @mapping: address space structure to write 592 * @mapping: address space structure to write
593 * @wbc: subtract the number of written pages from *@wbc->nr_to_write 593 * @wbc: subtract the number of written pages from *@wbc->nr_to_write
594 * @writepage: function called for each page
595 * @data: data passed to writepage function
594 * 596 *
595 * This is a library function, which implements the writepages() 597 * If a page is already under I/O, write_cache_pages() skips it, even
596 * address_space_operation.
597 *
598 * If a page is already under I/O, generic_writepages() skips it, even
599 * if it's dirty. This is desirable behaviour for memory-cleaning writeback, 598 * if it's dirty. This is desirable behaviour for memory-cleaning writeback,
600 * but it is INCORRECT for data-integrity system calls such as fsync(). fsync() 599 * but it is INCORRECT for data-integrity system calls such as fsync(). fsync()
601 * and msync() need to guarantee that all the data which was dirty at the time 600 * and msync() need to guarantee that all the data which was dirty at the time
602 * the call was made get new I/O started against them. If wbc->sync_mode is 601 * the call was made get new I/O started against them. If wbc->sync_mode is
603 * WB_SYNC_ALL then we were called for data integrity and we must wait for 602 * WB_SYNC_ALL then we were called for data integrity and we must wait for
604 * existing IO to complete. 603 * existing IO to complete.
605 *
606 * Derived from mpage_writepages() - if you fix this you should check that
607 * also!
608 */ 604 */
609int generic_writepages(struct address_space *mapping, 605int write_cache_pages(struct address_space *mapping,
610 struct writeback_control *wbc) 606 struct writeback_control *wbc, writepage_t writepage,
607 void *data)
611{ 608{
612 struct backing_dev_info *bdi = mapping->backing_dev_info; 609 struct backing_dev_info *bdi = mapping->backing_dev_info;
613 int ret = 0; 610 int ret = 0;
614 int done = 0; 611 int done = 0;
615 int (*writepage)(struct page *page, struct writeback_control *wbc);
616 struct pagevec pvec; 612 struct pagevec pvec;
617 int nr_pages; 613 int nr_pages;
618 pgoff_t index; 614 pgoff_t index;
@@ -625,12 +621,6 @@ int generic_writepages(struct address_space *mapping,
625 return 0; 621 return 0;
626 } 622 }
627 623
628 writepage = mapping->a_ops->writepage;
629
630 /* deal with chardevs and other special file */
631 if (!writepage)
632 return 0;
633
634 pagevec_init(&pvec, 0); 624 pagevec_init(&pvec, 0);
635 if (wbc->range_cyclic) { 625 if (wbc->range_cyclic) {
636 index = mapping->writeback_index; /* Start from prev offset */ 626 index = mapping->writeback_index; /* Start from prev offset */
@@ -682,8 +672,7 @@ retry:
682 continue; 672 continue;
683 } 673 }
684 674
685 ret = (*writepage)(page, wbc); 675 ret = (*writepage)(page, wbc, data);
686 mapping_set_error(mapping, ret);
687 676
688 if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) 677 if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
689 unlock_page(page); 678 unlock_page(page);
@@ -710,6 +699,38 @@ retry:
710 mapping->writeback_index = index; 699 mapping->writeback_index = index;
711 return ret; 700 return ret;
712} 701}
702EXPORT_SYMBOL(write_cache_pages);
703
704/*
705 * Function used by generic_writepages to call the real writepage
706 * function and set the mapping flags on error
707 */
708static int __writepage(struct page *page, struct writeback_control *wbc,
709 void *data)
710{
711 struct address_space *mapping = data;
712 int ret = mapping->a_ops->writepage(page, wbc);
713 mapping_set_error(mapping, ret);
714 return ret;
715}
716
717/**
718 * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them.
719 * @mapping: address space structure to write
720 * @wbc: subtract the number of written pages from *@wbc->nr_to_write
721 *
722 * This is a library function, which implements the writepages()
723 * address_space_operation.
724 */
725int generic_writepages(struct address_space *mapping,
726 struct writeback_control *wbc)
727{
728 /* deal with chardevs and other special file */
729 if (!mapping->a_ops->writepage)
730 return 0;
731
732 return write_cache_pages(mapping, wbc, __writepage, mapping);
733}
713 734
714EXPORT_SYMBOL(generic_writepages); 735EXPORT_SYMBOL(generic_writepages);
715 736