diff options
author | Suparna Bhattacharya <suparna@in.ibm.com> | 2004-11-10 21:29:50 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-11-10 21:29:50 -0800 |
commit | c62ba94c38516675f02007826a4aab325125aa8d (patch) | |
tree | 961458223b471431a9c81edf71317c44bf70f8ab /mm | |
parent | a370025d1ed83b2b8202c4fefe4ea465bf22f10a (diff) | |
download | history-c62ba94c38516675f02007826a4aab325125aa8d.tar.gz |
[PATCH] Fix O_SYNC speedup for generic_file_write_nolock
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 <suparna@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 73 |
1 files changed, 62 insertions, 11 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 3f169349c10f4c..bf87992991fbae 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -283,6 +283,29 @@ int sync_page_range(struct inode *inode, struct address_space *mapping, } 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 file *file, loff_t *pos, size_t *count, i } return 0; } - EXPORT_SYMBOL(generic_write_checks); ssize_t @@ -1864,7 +1886,6 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, written = -EIOCBQUEUED; return written; } - EXPORT_SYMBOL(generic_file_direct_write); ssize_t @@ -1986,11 +2007,10 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, 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 *file, const struct iovec *iov, 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 *file, const char __user *buf, .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 *filp, const struct iovec *iov, 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 *file, const struct iovec *iov, 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 *file, const struct iovec *iov, } return ret; } - EXPORT_SYMBOL(generic_file_writev); /* @@ -2192,5 +2244,4 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, } return retval; } - EXPORT_SYMBOL_GPL(generic_file_direct_IO); |