summaryrefslogtreecommitdiffstats
path: root/fs/nfs/file.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-06-10 18:31:00 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-07-09 12:08:45 -0400
commitefc91ed0191e3fc62bb1c556ac93fc4e661214d2 (patch)
tree291dba382da5d609c5bd35b5e369324ecbb95c00 /fs/nfs/file.c
parentb390c2b55c830eb3b64633fa8d8b8837e073e458 (diff)
downloadlinux-efc91ed0191e3fc62bb1c556ac93fc4e661214d2.tar.bz2
NFS: Optimise append writes with holes
If a file is being extended, and we're creating a hole, we might as well declare the entire page to be up to date. This patch significantly improves the write performance for sparse files in the case where lseek(SEEK_END) is used to append several non-contiguous writes at intervals of < PAGE_SIZE. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/file.c')
-rw-r--r--fs/nfs/file.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 7c73f06692b6..7ac89a845a5e 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -344,6 +344,26 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
int status;
+ /*
+ * Zero any uninitialised parts of the page, and then mark the page
+ * as up to date if it turns out that we're extending the file.
+ */
+ if (!PageUptodate(page)) {
+ unsigned pglen = nfs_page_length(page);
+ unsigned end = offset + len;
+
+ if (pglen == 0) {
+ zero_user_segments(page, 0, offset,
+ end, PAGE_CACHE_SIZE);
+ SetPageUptodate(page);
+ } else if (end >= pglen) {
+ zero_user_segment(page, end, PAGE_CACHE_SIZE);
+ if (offset == 0)
+ SetPageUptodate(page);
+ } else
+ zero_user_segment(page, pglen, PAGE_CACHE_SIZE);
+ }
+
lock_kernel();
status = nfs_updatepage(file, page, offset, copied);
unlock_kernel();