Commit c62ba94c authored by Suparna Bhattacharya's avatar Suparna Bhattacharya Committed by Linus Torvalds

[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: default avatarSuparna Bhattacharya <suparna@in.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a370025d
...@@ -106,6 +106,8 @@ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); ...@@ -106,6 +106,8 @@ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
int do_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, int sync_page_range(struct inode *inode, struct address_space *mapping,
loff_t pos, size_t count); 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 */ /* pdflush.c */
extern int nr_pdflush_threads; /* Global so it can be exported to sysctl extern int nr_pdflush_threads; /* Global so it can be exported to sysctl
......
...@@ -283,6 +283,29 @@ int sync_page_range(struct inode *inode, struct address_space *mapping, ...@@ -283,6 +283,29 @@ int sync_page_range(struct inode *inode, struct address_space *mapping,
} }
EXPORT_SYMBOL(sync_page_range); 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 * filemap_fdatawait - walk the list of under-writeback pages of the given
* address space and wait for all of them. * 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 ...@@ -1826,7 +1849,6 @@ inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, i
} }
return 0; return 0;
} }
EXPORT_SYMBOL(generic_write_checks); EXPORT_SYMBOL(generic_write_checks);
ssize_t ssize_t
...@@ -1864,7 +1886,6 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -1864,7 +1886,6 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
written = -EIOCBQUEUED; written = -EIOCBQUEUED;
return written; return written;
} }
EXPORT_SYMBOL(generic_file_direct_write); EXPORT_SYMBOL(generic_file_direct_write);
ssize_t ssize_t
...@@ -1986,11 +2007,10 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -1986,11 +2007,10 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
pagevec_lru_add(&lru_pvec); pagevec_lru_add(&lru_pvec);
return written ? written : status; return written ? written : status;
} }
EXPORT_SYMBOL(generic_file_buffered_write); EXPORT_SYMBOL(generic_file_buffered_write);
ssize_t 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) unsigned long nr_segs, loff_t *ppos)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
...@@ -2063,9 +2083,44 @@ generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, ...@@ -2063,9 +2083,44 @@ generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
current->backing_dev_info = NULL; current->backing_dev_info = NULL;
return written ? written : err; return written ? written : err;
} }
EXPORT_SYMBOL(generic_file_aio_write_nolock); 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 ssize_t
generic_file_write_nolock(struct file *file, const struct iovec *iov, generic_file_write_nolock(struct file *file, const struct iovec *iov,
unsigned long nr_segs, loff_t *ppos) unsigned long nr_segs, loff_t *ppos)
...@@ -2079,7 +2134,6 @@ generic_file_write_nolock(struct file *file, const struct iovec *iov, ...@@ -2079,7 +2134,6 @@ generic_file_write_nolock(struct file *file, const struct iovec *iov,
ret = wait_on_sync_kiocb(&kiocb); ret = wait_on_sync_kiocb(&kiocb);
return ret; return ret;
} }
EXPORT_SYMBOL(generic_file_write_nolock); EXPORT_SYMBOL(generic_file_write_nolock);
ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf, 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, ...@@ -2120,7 +2174,7 @@ ssize_t generic_file_write(struct file *file, const char __user *buf,
.iov_len = count }; .iov_len = count };
down(&inode->i_sem); 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); up(&inode->i_sem);
if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { 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, ...@@ -2146,7 +2200,6 @@ ssize_t generic_file_readv(struct file *filp, const struct iovec *iov,
ret = wait_on_sync_kiocb(&kiocb); ret = wait_on_sync_kiocb(&kiocb);
return ret; return ret;
} }
EXPORT_SYMBOL(generic_file_readv); EXPORT_SYMBOL(generic_file_readv);
ssize_t generic_file_writev(struct file *file, const struct iovec *iov, 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, ...@@ -2157,7 +2210,7 @@ ssize_t generic_file_writev(struct file *file, const struct iovec *iov,
ssize_t ret; ssize_t ret;
down(&inode->i_sem); 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); up(&inode->i_sem);
if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { 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, ...@@ -2169,7 +2222,6 @@ ssize_t generic_file_writev(struct file *file, const struct iovec *iov,
} }
return ret; return ret;
} }
EXPORT_SYMBOL(generic_file_writev); EXPORT_SYMBOL(generic_file_writev);
/* /*
...@@ -2192,5 +2244,4 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, ...@@ -2192,5 +2244,4 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
} }
return retval; return retval;
} }
EXPORT_SYMBOL_GPL(generic_file_direct_IO); EXPORT_SYMBOL_GPL(generic_file_direct_IO);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment