From: Suparna Bhattacharya The O_SYNC speedup patches missed the generic_file_xxx_nolock cases, which means that pages weren't actually getting sync'ed in those cases. This patch fixes that. Signed-off-by: Suparna Bhattacharya Signed-off-by: Andrew Morton --- 25-akpm/include/linux/writeback.h | 2 + 25-akpm/mm/filemap.c | 73 ++++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 11 deletions(-) diff -puN include/linux/writeback.h~fix-o_sync-speedup-for-generic_file_write_nolock include/linux/writeback.h --- 25/include/linux/writeback.h~fix-o_sync-speedup-for-generic_file_write_nolock 2004-11-08 09:50:50.341187576 -0800 +++ 25-akpm/include/linux/writeback.h 2004-11-08 09:50:50.347186664 -0800 @@ -106,6 +106,8 @@ int pdflush_operation(void (*fn)(unsigne 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, size_t count); +int sync_page_range_nolock(struct inode *inode, struct address_space + *mapping, loff_t pos, size_t count); /* pdflush.c */ extern int nr_pdflush_threads; /* Global so it can be exported to sysctl diff -puN mm/filemap.c~fix-o_sync-speedup-for-generic_file_write_nolock mm/filemap.c --- 25/mm/filemap.c~fix-o_sync-speedup-for-generic_file_write_nolock 2004-11-08 09:50:50.343187272 -0800 +++ 25-akpm/mm/filemap.c 2004-11-08 10:02:40.978154336 -0800 @@ -283,6 +283,29 @@ int sync_page_range(struct inode *inode, } EXPORT_SYMBOL(sync_page_range); +/* + * Note: Holding i_sem across sync_page_range_nolock is not a good idea + * as it forces O_SYNC writers to different parts of the same file + * to be serialised right until io completion. + */ +int sync_page_range_nolock(struct inode *inode, struct address_space *mapping, + loff_t pos, size_t count) +{ + pgoff_t start = pos >> PAGE_CACHE_SHIFT; + pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT; + int ret; + + if (mapping->backing_dev_info->memory_backed || !count) + return 0; + ret = filemap_fdatawrite_range(mapping, pos, pos + count - 1); + if (ret == 0) + ret = generic_osync_inode(inode, mapping, OSYNC_METADATA); + if (ret == 0) + ret = wait_on_page_writeback_range(mapping, start, end); + return ret; +} +EXPORT_SYMBOL(sync_page_range_nolock); + /** * filemap_fdatawait - walk the list of under-writeback pages of the given * address space and wait for all of them. @@ -1826,7 +1849,6 @@ inline int generic_write_checks(struct f } return 0; } - EXPORT_SYMBOL(generic_write_checks); ssize_t @@ -1864,7 +1886,6 @@ generic_file_direct_write(struct kiocb * written = -EIOCBQUEUED; return written; } - EXPORT_SYMBOL(generic_file_direct_write); ssize_t @@ -1986,11 +2007,10 @@ generic_file_buffered_write(struct kiocb pagevec_lru_add(&lru_pvec); return written ? written : status; } - EXPORT_SYMBOL(generic_file_buffered_write); ssize_t -generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, +__generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) { struct file *file = iocb->ki_filp; @@ -2063,10 +2083,45 @@ out: current->backing_dev_info = NULL; return written ? written : err; } - EXPORT_SYMBOL(generic_file_aio_write_nolock); ssize_t +generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret; + loff_t pos = *ppos; + + ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs, ppos); + + if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + int err; + + err = sync_page_range_nolock(inode, mapping, pos, ret); + if (err < 0) + ret = err; + } + return ret; +} + +ssize_t +__generic_file_write_nolock(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) +{ + struct kiocb kiocb; + ssize_t ret; + + init_sync_kiocb(&kiocb, file); + ret = __generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos); + if (ret == -EIOCBQUEUED) + ret = wait_on_sync_kiocb(&kiocb); + return ret; +} + +ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) { @@ -2079,7 +2134,6 @@ generic_file_write_nolock(struct file *f ret = wait_on_sync_kiocb(&kiocb); return ret; } - EXPORT_SYMBOL(generic_file_write_nolock); ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf, @@ -2120,7 +2174,7 @@ ssize_t generic_file_write(struct file * .iov_len = count }; down(&inode->i_sem); - ret = generic_file_write_nolock(file, &local_iov, 1, ppos); + ret = __generic_file_write_nolock(file, &local_iov, 1, ppos); up(&inode->i_sem); if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { @@ -2146,7 +2200,6 @@ ssize_t generic_file_readv(struct file * ret = wait_on_sync_kiocb(&kiocb); return ret; } - EXPORT_SYMBOL(generic_file_readv); ssize_t generic_file_writev(struct file *file, const struct iovec *iov, @@ -2157,7 +2210,7 @@ ssize_t generic_file_writev(struct file ssize_t ret; down(&inode->i_sem); - ret = generic_file_write_nolock(file, iov, nr_segs, ppos); + ret = __generic_file_write_nolock(file, iov, nr_segs, ppos); up(&inode->i_sem); if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { @@ -2169,7 +2222,6 @@ ssize_t generic_file_writev(struct file } return ret; } - EXPORT_SYMBOL(generic_file_writev); /* @@ -2192,5 +2244,4 @@ generic_file_direct_IO(int rw, struct ki } return retval; } - EXPORT_SYMBOL_GPL(generic_file_direct_IO); _