From: Zach Brown <zach.brown@oracle.com>

This adds filemap_write_and_wait_range(mapping, lstart, lend) which starts
writeback and waits on a range of pages.  We call this from
__blkdev_direct_IO with just the range that is going to be read by the
direct_IO read.  It was lightly tested with fsx and ext3 and passed.

Signed-off-by: Zach Brown <zach.brown@oracle.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/direct-io.c     |    7 +++++--
 25-akpm/include/linux/fs.h |    2 ++
 25-akpm/mm/filemap.c       |   16 ++++++++++++++++
 3 files changed, 23 insertions(+), 2 deletions(-)

diff -puN fs/direct-io.c~write-and-wait-on-range-before-direct-io-read fs/direct-io.c
--- 25/fs/direct-io.c~write-and-wait-on-range-before-direct-io-read	2005-02-22 18:16:10.000000000 -0800
+++ 25-akpm/fs/direct-io.c	2005-02-22 18:16:10.000000000 -0800
@@ -1206,7 +1206,8 @@ __blockdev_direct_IO(int rw, struct kioc
 	 */
 	dio->lock_type = dio_lock_type;
 	if (dio_lock_type != DIO_NO_LOCKING) {
-		if (rw == READ) {
+		/* watch out for a 0 len io from a tricksy fs */
+		if (rw == READ && end > offset) {
 			struct address_space *mapping;
 
 			mapping = iocb->ki_filp->f_mapping;
@@ -1214,7 +1215,9 @@ __blockdev_direct_IO(int rw, struct kioc
 				down(&inode->i_sem);
 				reader_with_isem = 1;
 			}
-			retval = filemap_write_and_wait(mapping);
+
+			retval = filemap_write_and_wait_range(mapping, offset,
+							      end - 1);
 			if (retval) {
 				kfree(dio);
 				goto out;
diff -puN include/linux/fs.h~write-and-wait-on-range-before-direct-io-read include/linux/fs.h
--- 25/include/linux/fs.h~write-and-wait-on-range-before-direct-io-read	2005-02-22 18:16:10.000000000 -0800
+++ 25-akpm/include/linux/fs.h	2005-02-22 18:16:10.000000000 -0800
@@ -1360,6 +1360,8 @@ extern int filemap_fdatawrite(struct add
 extern int filemap_flush(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
 extern int filemap_write_and_wait(struct address_space *mapping);
+extern int filemap_write_and_wait_range(struct address_space *mapping,
+				        loff_t lstart, loff_t lend);
 extern void sync_supers(void);
 extern void sync_filesystems(int wait);
 extern void emergency_sync(void);
diff -puN mm/filemap.c~write-and-wait-on-range-before-direct-io-read mm/filemap.c
--- 25/mm/filemap.c~write-and-wait-on-range-before-direct-io-read	2005-02-22 18:16:10.000000000 -0800
+++ 25-akpm/mm/filemap.c	2005-02-22 18:16:10.000000000 -0800
@@ -336,6 +336,22 @@ int filemap_write_and_wait(struct addres
 	return retval;
 }
 
+int filemap_write_and_wait_range(struct address_space *mapping,
+				 loff_t lstart, loff_t lend)
+{
+	int retval = 0;
+
+	if (mapping->nrpages) {
+		retval = __filemap_fdatawrite_range(mapping, lstart, lend,
+						    WB_SYNC_ALL);
+		if (retval == 0)
+			retval = wait_on_page_writeback_range(mapping,
+						    lstart >> PAGE_CACHE_SHIFT,
+						    lend >> PAGE_CACHE_SHIFT);
+	}
+	return retval;
+}
+
 /*
  * This function is used to add newly allocated pagecache pages:
  * the page is new, so we can just run SetPageLocked() against it.
_