aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
parentb390c2b55c830eb3b64633fa8d8b8837e073e458 (diff)
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')
-rw-r--r--fs/nfs/file.c20
-rw-r--r--fs/nfs/write.c12
2 files changed, 23 insertions, 9 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,
344 unsigned offset = pos & (PAGE_CACHE_SIZE - 1); 344 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
345 int status; 345 int status;
346 346
347 /*
348 * Zero any uninitialised parts of the page, and then mark the page
349 * as up to date if it turns out that we're extending the file.
350 */
351 if (!PageUptodate(page)) {
352 unsigned pglen = nfs_page_length(page);
353 unsigned end = offset + len;
354
355 if (pglen == 0) {
356 zero_user_segments(page, 0, offset,
357 end, PAGE_CACHE_SIZE);
358 SetPageUptodate(page);
359 } else if (end >= pglen) {
360 zero_user_segment(page, end, PAGE_CACHE_SIZE);
361 if (offset == 0)
362 SetPageUptodate(page);
363 } else
364 zero_user_segment(page, pglen, PAGE_CACHE_SIZE);
365 }
366
347 lock_kernel(); 367 lock_kernel();
348 status = nfs_updatepage(file, page, offset, copied); 368 status = nfs_updatepage(file, page, offset, copied);
349 unlock_kernel(); 369 unlock_kernel();
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index dc62bc504693..eea2d2b5278c 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -616,7 +616,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
616 spin_unlock(&inode->i_lock); 616 spin_unlock(&inode->i_lock);
617 radix_tree_preload_end(); 617 radix_tree_preload_end();
618 req = new; 618 req = new;
619 goto zero_page; 619 goto out;
620 } 620 }
621 spin_unlock(&inode->i_lock); 621 spin_unlock(&inode->i_lock);
622 622
@@ -649,19 +649,13 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
649 req->wb_offset = offset; 649 req->wb_offset = offset;
650 req->wb_pgbase = offset; 650 req->wb_pgbase = offset;
651 req->wb_bytes = max(end, rqend) - req->wb_offset; 651 req->wb_bytes = max(end, rqend) - req->wb_offset;
652 goto zero_page; 652 goto out;
653 } 653 }
654 654
655 if (end > rqend) 655 if (end > rqend)
656 req->wb_bytes = end - req->wb_offset; 656 req->wb_bytes = end - req->wb_offset;
657 657
658 return req; 658out:
659zero_page:
660 /* If this page might potentially be marked as up to date,
661 * then we need to zero any uninitalised data. */
662 if (req->wb_pgbase == 0 && req->wb_bytes != PAGE_CACHE_SIZE
663 && !PageUptodate(req->wb_page))
664 zero_user_segment(req->wb_page, req->wb_bytes, PAGE_CACHE_SIZE);
665 return req; 659 return req;
666} 660}
667 661