Commit 811d736f9e8013966e1a5a930c0db09508bdbb15

Authored by David Howells
Committed by Jens Axboe
1 parent 7b0de42d7c

[PATCH] BLOCK: Dissociate generic_writepages() from mpage stuff [try #6]

Dissociate the generic_writepages() function from the mpage stuff, moving its
declaration to linux/mm.h and actually emitting a full implementation into
mm/page-writeback.c.

The implementation is a partial duplicate of mpage_writepages() with all BIO
references removed.

It is used by NFS to do writeback.

Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

Showing 5 changed files with 139 additions and 6 deletions Side-by-side Diff

... ... @@ -17,6 +17,7 @@
17 17 #include <linux/module.h>
18 18 #include <linux/blkpg.h>
19 19 #include <linux/buffer_head.h>
  20 +#include <linux/writeback.h>
20 21 #include <linux/mpage.h>
21 22 #include <linux/mount.h>
22 23 #include <linux/uio.h>
... ... @@ -693,6 +693,8 @@
693 693 * the call was made get new I/O started against them. If wbc->sync_mode is
694 694 * WB_SYNC_ALL then we were called for data integrity and we must wait for
695 695 * existing IO to complete.
  696 + *
  697 + * If you fix this you should check generic_writepages() also!
696 698 */
697 699 int
698 700 mpage_writepages(struct address_space *mapping,
include/linux/mpage.h
... ... @@ -20,10 +20,4 @@
20 20 struct writeback_control *wbc, get_block_t get_block);
21 21 int mpage_writepage(struct page *page, get_block_t *get_block,
22 22 struct writeback_control *wbc);
23   -
24   -static inline int
25   -generic_writepages(struct address_space *mapping, struct writeback_control *wbc)
26   -{
27   - return mpage_writepages(mapping, wbc, NULL);
28   -}
include/linux/writeback.h
... ... @@ -111,6 +111,8 @@
111 111 }
112 112  
113 113 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
  114 +extern int generic_writepages(struct address_space *mapping,
  115 + struct writeback_control *wbc);
114 116 int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
115 117 int sync_page_range(struct inode *inode, struct address_space *mapping,
116 118 loff_t pos, loff_t count);
... ... @@ -31,6 +31,7 @@
31 31 #include <linux/cpu.h>
32 32 #include <linux/syscalls.h>
33 33 #include <linux/buffer_head.h>
  34 +#include <linux/pagevec.h>
34 35  
35 36 /*
36 37 * The maximum number of pages to writeout in a single bdflush/kupdate
... ... @@ -550,6 +551,139 @@
550 551 writeback_set_ratelimit();
551 552 register_cpu_notifier(&ratelimit_nb);
552 553 }
  554 +
  555 +/**
  556 + * generic_writepages - walk the list of dirty pages of the given
  557 + * address space and writepage() all of them.
  558 + *
  559 + * @mapping: address space structure to write
  560 + * @wbc: subtract the number of written pages from *@wbc->nr_to_write
  561 + *
  562 + * This is a library function, which implements the writepages()
  563 + * address_space_operation.
  564 + *
  565 + * If a page is already under I/O, generic_writepages() skips it, even
  566 + * if it's dirty. This is desirable behaviour for memory-cleaning writeback,
  567 + * but it is INCORRECT for data-integrity system calls such as fsync(). fsync()
  568 + * and msync() need to guarantee that all the data which was dirty at the time
  569 + * the call was made get new I/O started against them. If wbc->sync_mode is
  570 + * WB_SYNC_ALL then we were called for data integrity and we must wait for
  571 + * existing IO to complete.
  572 + *
  573 + * Derived from mpage_writepages() - if you fix this you should check that
  574 + * also!
  575 + */
  576 +int generic_writepages(struct address_space *mapping,
  577 + struct writeback_control *wbc)
  578 +{
  579 + struct backing_dev_info *bdi = mapping->backing_dev_info;
  580 + int ret = 0;
  581 + int done = 0;
  582 + int (*writepage)(struct page *page, struct writeback_control *wbc);
  583 + struct pagevec pvec;
  584 + int nr_pages;
  585 + pgoff_t index;
  586 + pgoff_t end; /* Inclusive */
  587 + int scanned = 0;
  588 + int range_whole = 0;
  589 +
  590 + if (wbc->nonblocking && bdi_write_congested(bdi)) {
  591 + wbc->encountered_congestion = 1;
  592 + return 0;
  593 + }
  594 +
  595 + writepage = mapping->a_ops->writepage;
  596 +
  597 + /* deal with chardevs and other special file */
  598 + if (!writepage)
  599 + return 0;
  600 +
  601 + pagevec_init(&pvec, 0);
  602 + if (wbc->range_cyclic) {
  603 + index = mapping->writeback_index; /* Start from prev offset */
  604 + end = -1;
  605 + } else {
  606 + index = wbc->range_start >> PAGE_CACHE_SHIFT;
  607 + end = wbc->range_end >> PAGE_CACHE_SHIFT;
  608 + if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
  609 + range_whole = 1;
  610 + scanned = 1;
  611 + }
  612 +retry:
  613 + while (!done && (index <= end) &&
  614 + (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
  615 + PAGECACHE_TAG_DIRTY,
  616 + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
  617 + unsigned i;
  618 +
  619 + scanned = 1;
  620 + for (i = 0; i < nr_pages; i++) {
  621 + struct page *page = pvec.pages[i];
  622 +
  623 + /*
  624 + * At this point we hold neither mapping->tree_lock nor
  625 + * lock on the page itself: the page may be truncated or
  626 + * invalidated (changing page->mapping to NULL), or even
  627 + * swizzled back from swapper_space to tmpfs file
  628 + * mapping
  629 + */
  630 + lock_page(page);
  631 +
  632 + if (unlikely(page->mapping != mapping)) {
  633 + unlock_page(page);
  634 + continue;
  635 + }
  636 +
  637 + if (!wbc->range_cyclic && page->index > end) {
  638 + done = 1;
  639 + unlock_page(page);
  640 + continue;
  641 + }
  642 +
  643 + if (wbc->sync_mode != WB_SYNC_NONE)
  644 + wait_on_page_writeback(page);
  645 +
  646 + if (PageWriteback(page) ||
  647 + !clear_page_dirty_for_io(page)) {
  648 + unlock_page(page);
  649 + continue;
  650 + }
  651 +
  652 + ret = (*writepage)(page, wbc);
  653 + if (ret) {
  654 + if (ret == -ENOSPC)
  655 + set_bit(AS_ENOSPC, &mapping->flags);
  656 + else
  657 + set_bit(AS_EIO, &mapping->flags);
  658 + }
  659 +
  660 + if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
  661 + unlock_page(page);
  662 + if (ret || (--(wbc->nr_to_write) <= 0))
  663 + done = 1;
  664 + if (wbc->nonblocking && bdi_write_congested(bdi)) {
  665 + wbc->encountered_congestion = 1;
  666 + done = 1;
  667 + }
  668 + }
  669 + pagevec_release(&pvec);
  670 + cond_resched();
  671 + }
  672 + if (!scanned && !done) {
  673 + /*
  674 + * We hit the last page and there is more work to be done: wrap
  675 + * back to the start of the file
  676 + */
  677 + scanned = 1;
  678 + index = 0;
  679 + goto retry;
  680 + }
  681 + if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
  682 + mapping->writeback_index = index;
  683 + return ret;
  684 +}
  685 +
  686 +EXPORT_SYMBOL(generic_writepages);
553 687  
554 688 int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
555 689 {