From: Suparna Bhattacharya <suparna@in.ibm.com>

The current implementation of O_SYNC support for AIO calls sync_page_range
explicitly in the high level aio write handlers after invoking the fops
aio_write method.  This a duplication of logic across sync i/o and aio (not
good from a maintenance perspective, and more error prone, e.g.  forgets to
check for O_DIRECT).

More importantly, it doesn't take into account the possibility that different
filesystems may have their own O_SYNC implementations in their corresponding
aio methods.  This is a problem for example in the case of ext3 which may
commit the journal after data and meta-data are written out.

This patch fixes the above problems by moving the call to sync_page_range out
of the high level aio_pwrite handler, and back into generic_file_aio_write
for both aio and sync i/o.  It takes care to make sure that sync_page_range
is called only after all the data is copied in the AIO case, rather than on
every retry.



 include/linux/writeback.h |    0 
 mm/filemap.c              |   16 ++++++++++++++++
 mm/page-writeback.c       |    0 
 3 files changed, 16 insertions(+)

diff -puN include/linux/writeback.h~aio-O_SYNC-fix include/linux/writeback.h
diff -puN mm/filemap.c~aio-O_SYNC-fix mm/filemap.c
--- 25/mm/filemap.c~aio-O_SYNC-fix	2003-08-30 15:42:32.000000000 -0700
+++ 25-akpm/mm/filemap.c	2003-08-30 15:42:32.000000000 -0700
@@ -1928,17 +1928,33 @@ ssize_t generic_file_aio_write(struct ki
 
 	BUG_ON(iocb->ki_pos != pos);
 
+	if (!buf && !is_sync_kiocb(iocb)) {
+		/* nothing to transfer, may just need to sync data */
+		ret = count;
+		goto osync;
+	}
+
 	down(&inode->i_sem);
 	ret = generic_file_aio_write_nolock(iocb, &local_iov, 1,
 						&iocb->ki_pos);
 	up(&inode->i_sem);
 
+	/*
+	 * Avoid doing a sync in parts for aio - its more efficient to
+	 * call in again after all the data has been copied
+	 */
+	if (!is_sync_kiocb(iocb))
+		return ret;
+
+osync:
 	if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
 		ssize_t err;
 
 		err = sync_page_range(inode, mapping, pos, ret);
 		if (err < 0)
 			ret = err;
+		else
+			iocb->ki_pos = pos + err;
 	}
 	return ret;
 }
diff -puN mm/page-writeback.c~aio-O_SYNC-fix mm/page-writeback.c

_