aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorSuparna Bhattacharya <suparna@in.ibm.com>2004-11-10 21:29:50 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-11-10 21:29:50 -0800
commitc62ba94c38516675f02007826a4aab325125aa8d (patch)
tree961458223b471431a9c81edf71317c44bf70f8ab /mm
parenta370025d1ed83b2b8202c4fefe4ea465bf22f10a (diff)
downloadhistory-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.c73
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);