All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: axboe@kernel.dk
Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
	dhowells@redhat.com
Subject: [PATCH 08/19] BLOCK: Dissociate generic_writepages() from mpage stuff [try #6]
Date: Tue, 29 Aug 2006 19:06:09 +0100	[thread overview]
Message-ID: <20060829180609.32596.43663.stgit@warthog.cambridge.redhat.com> (raw)
In-Reply-To: <20060829180552.32596.15290.stgit@warthog.cambridge.redhat.com>

From: David Howells <dhowells@redhat.com>

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>
---

 fs/block_dev.c            |    1 
 fs/mpage.c                |    2 +
 include/linux/mpage.h     |    6 --
 include/linux/writeback.h |    2 +
 mm/page-writeback.c       |  134 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/fs/block_dev.c b/fs/block_dev.c
index 1c146a2..02acae1 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -17,6 +17,7 @@ #include <linux/blkdev.h>
 #include <linux/module.h>
 #include <linux/blkpg.h>
 #include <linux/buffer_head.h>
+#include <linux/writeback.h>
 #include <linux/mpage.h>
 #include <linux/mount.h>
 #include <linux/uio.h>
diff --git a/fs/mpage.c b/fs/mpage.c
index 1e45982..692a3e5 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -693,6 +693,8 @@ out:
  * the call was made get new I/O started against them.  If wbc->sync_mode is
  * WB_SYNC_ALL then we were called for data integrity and we must wait for
  * existing IO to complete.
+ *
+ * If you fix this you should check generic_writepages() also!
  */
 int
 mpage_writepages(struct address_space *mapping,
diff --git a/include/linux/mpage.h b/include/linux/mpage.h
index 3ca8804..517c098 100644
--- a/include/linux/mpage.h
+++ b/include/linux/mpage.h
@@ -20,9 +20,3 @@ int mpage_writepages(struct address_spac
 		struct writeback_control *wbc, get_block_t get_block);
 int mpage_writepage(struct page *page, get_block_t *get_block,
 		struct writeback_control *wbc);
-
-static inline int
-generic_writepages(struct address_space *mapping, struct writeback_control *wbc)
-{
-	return mpage_writepages(mapping, wbc, NULL);
-}
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 9e38b56..671c43b 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -110,6 +110,8 @@ balance_dirty_pages_ratelimited(struct a
 }
 
 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
+extern int generic_writepages(struct address_space *mapping,
+			      struct writeback_control *wbc);
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
 int sync_page_range(struct inode *inode, struct address_space *mapping,
 			loff_t pos, loff_t count);
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index f75d033..eeeaf43 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -30,6 +30,7 @@ #include <linux/sysctl.h>
 #include <linux/cpu.h>
 #include <linux/syscalls.h>
 #include <linux/buffer_head.h>
+#include <linux/pagevec.h>
 
 /*
  * The maximum number of pages to writeout in a single bdflush/kupdate
@@ -543,6 +544,139 @@ void __init page_writeback_init(void)
 	register_cpu_notifier(&ratelimit_nb);
 }
 
+/**
+ * generic_writepages - walk the list of dirty pages of the given
+ *                      address space and writepage() all of them.
+ *
+ * @mapping: address space structure to write
+ * @wbc: subtract the number of written pages from *@wbc->nr_to_write
+ *
+ * This is a library function, which implements the writepages()
+ * address_space_operation.
+ *
+ * If a page is already under I/O, generic_writepages() skips it, even
+ * if it's dirty.  This is desirable behaviour for memory-cleaning writeback,
+ * but it is INCORRECT for data-integrity system calls such as fsync().  fsync()
+ * and msync() need to guarantee that all the data which was dirty at the time
+ * the call was made get new I/O started against them.  If wbc->sync_mode is
+ * WB_SYNC_ALL then we were called for data integrity and we must wait for
+ * existing IO to complete.
+ *
+ * Derived from mpage_writepages() - if you fix this you should check that
+ * also!
+ */
+int generic_writepages(struct address_space *mapping,
+		       struct writeback_control *wbc)
+{
+	struct backing_dev_info *bdi = mapping->backing_dev_info;
+	int ret = 0;
+	int done = 0;
+	int (*writepage)(struct page *page, struct writeback_control *wbc);
+	struct pagevec pvec;
+	int nr_pages;
+	pgoff_t index;
+	pgoff_t end;		/* Inclusive */
+	int scanned = 0;
+	int range_whole = 0;
+
+	if (wbc->nonblocking && bdi_write_congested(bdi)) {
+		wbc->encountered_congestion = 1;
+		return 0;
+	}
+
+	writepage = mapping->a_ops->writepage;
+
+	/* deal with chardevs and other special file */
+	if (!writepage)
+		return 0;
+
+	pagevec_init(&pvec, 0);
+	if (wbc->range_cyclic) {
+		index = mapping->writeback_index; /* Start from prev offset */
+		end = -1;
+	} else {
+		index = wbc->range_start >> PAGE_CACHE_SHIFT;
+		end = wbc->range_end >> PAGE_CACHE_SHIFT;
+		if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+			range_whole = 1;
+		scanned = 1;
+	}
+retry:
+	while (!done && (index <= end) &&
+	       (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+					      PAGECACHE_TAG_DIRTY,
+					      min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
+		unsigned i;
+
+		scanned = 1;
+		for (i = 0; i < nr_pages; i++) {
+			struct page *page = pvec.pages[i];
+
+			/*
+			 * At this point we hold neither mapping->tree_lock nor
+			 * lock on the page itself: the page may be truncated or
+			 * invalidated (changing page->mapping to NULL), or even
+			 * swizzled back from swapper_space to tmpfs file
+			 * mapping
+			 */
+			lock_page(page);
+
+			if (unlikely(page->mapping != mapping)) {
+				unlock_page(page);
+				continue;
+			}
+
+			if (!wbc->range_cyclic && page->index > end) {
+				done = 1;
+				unlock_page(page);
+				continue;
+			}
+
+			if (wbc->sync_mode != WB_SYNC_NONE)
+				wait_on_page_writeback(page);
+
+			if (PageWriteback(page) ||
+			    !clear_page_dirty_for_io(page)) {
+				unlock_page(page);
+				continue;
+			}
+
+			ret = (*writepage)(page, wbc);
+			if (ret) {
+				if (ret == -ENOSPC)
+					set_bit(AS_ENOSPC, &mapping->flags);
+				else
+					set_bit(AS_EIO, &mapping->flags);
+			}
+
+			if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
+				unlock_page(page);
+			if (ret || (--(wbc->nr_to_write) <= 0))
+				done = 1;
+			if (wbc->nonblocking && bdi_write_congested(bdi)) {
+				wbc->encountered_congestion = 1;
+				done = 1;
+			}
+		}
+		pagevec_release(&pvec);
+		cond_resched();
+	}
+	if (!scanned && !done) {
+		/*
+		 * We hit the last page and there is more work to be done: wrap
+		 * back to the start of the file
+		 */
+		scanned = 1;
+		index = 0;
+		goto retry;
+	}
+	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
+		mapping->writeback_index = index;
+	return ret;
+}
+
+EXPORT_SYMBOL(generic_writepages);
+
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
 	int ret;

  parent reply	other threads:[~2006-08-29 18:08 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-08-29 18:05 [PATCH 00/19] BLOCK: Permit block layer to be disabled [try #6] David Howells
2006-08-29 18:05 ` [PATCH 01/19] BLOCK: Move functions out of buffer code " David Howells
2006-08-29 18:05 ` [PATCH 02/19] BLOCK: Remove duplicate declaration of exit_io_context() " David Howells
2006-08-29 18:05 ` [PATCH 03/19] BLOCK: Stop fallback_migrate_page() from using page_has_buffers() " David Howells
2006-08-29 18:06 ` [PATCH 04/19] BLOCK: Separate the bounce buffering code from the highmem code " David Howells
2006-08-29 18:06 ` [PATCH 05/19] BLOCK: Don't call block_sync_page() from AFS " David Howells
2006-08-29 18:06 ` [PATCH 06/19] BLOCK: Move extern declarations out of fs/*.c into header files " David Howells
2006-08-29 18:06 ` [PATCH 07/19] BLOCK: Remove dependence on existence of blockdev_superblock " David Howells
2006-08-29 18:06 ` David Howells [this message]
2006-08-29 18:06 ` [PATCH 09/19] BLOCK: Move __invalidate_device() to block_dev.c " David Howells
2006-08-29 18:06 ` [PATCH 10/19] BLOCK: Move the loop device ioctl compat stuff to the loop driver " David Howells
2006-08-29 18:06 ` [PATCH 11/19] BLOCK: Move common FS-specific ioctls to linux/fs.h " David Howells
2006-08-29 18:06 ` [PATCH 12/19] BLOCK: Move the ReiserFS device ioctl compat stuff to the ReiserFS driver " David Howells
2006-08-29 18:06 ` [PATCH 13/19] BLOCK: Move the Ext2 device ioctl compat stuff to the Ext2 " David Howells
2006-08-29 18:06 ` [PATCH 14/19] BLOCK: Move the Ext3 device ioctl compat stuff to the Ext3 " David Howells
2006-08-29 18:06 ` [PATCH 15/19] BLOCK: Move the msdos device ioctl compat stuff to the msdos " David Howells
2006-08-29 18:06 ` [PATCH 16/19] BLOCK: Remove no-longer necessary linux/mpage.h inclusions " David Howells
2006-08-29 18:06 ` [PATCH 17/19] BLOCK: Remove no-longer necessary linux/buffer_head.h " David Howells
2006-08-29 18:06 ` [PATCH 18/19] BLOCK: Make USB storage depend on SCSI rather than selecting it " David Howells
2006-08-29 18:53   ` Michael Buesch
2006-08-29 21:12   ` Stefan Richter
2006-08-30  8:25   ` David Howells
2006-08-30  8:43     ` Stefan Richter
2006-08-30 12:49       ` Dave Kleikamp
2006-08-30 13:02       ` David Howells
2006-08-30 13:10         ` Dave Kleikamp
2006-08-29 18:06 ` [PATCH 19/19] BLOCK: Make it possible to disable the block layer " David Howells
2006-08-30 19:44   ` Andrew Morton
2006-08-30 20:24     ` Jens Axboe
2006-08-30 21:06     ` Trond Myklebust
2006-08-30 21:20       ` Andrew Morton
2006-08-30 20:13   ` David Howells
2006-08-30 12:06 ` [PATCH 00/19] BLOCK: Permit block layer to be disabled " Jens Axboe
2006-08-30 20:07 ` David Howells

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060829180609.32596.43663.stgit@warthog.cambridge.redhat.com \
    --to=dhowells@redhat.com \
    --cc=axboe@kernel.dk \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.