NFS: Optimise append writes with holes
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 10 Jun 2008 22:31:00 +0000 (18:31 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 9 Jul 2008 16:08:45 +0000 (12:08 -0400)
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>
fs/nfs/file.c
fs/nfs/write.c

index 7c73f06692b6c9e34d39f184435a6c6f9448a739..7ac89a845a5eb454c109bd089b9a473be217c8e8 100644 (file)
@@ -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();
index dc62bc50469340a0872a166767b449f685c8801e..eea2d2b5278c0c7916c29a7a672a72d0be95cde3 100644 (file)
@@ -616,7 +616,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
                        spin_unlock(&inode->i_lock);
                        radix_tree_preload_end();
                        req = new;
-                       goto zero_page;
+                       goto out;
                }
                spin_unlock(&inode->i_lock);
 
@@ -649,19 +649,13 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
                req->wb_offset = offset;
                req->wb_pgbase = offset;
                req->wb_bytes = max(end, rqend) - req->wb_offset;
-               goto zero_page;
+               goto out;
        }
 
        if (end > rqend)
                req->wb_bytes = end - req->wb_offset;
 
-       return req;
-zero_page:
-       /* If this page might potentially be marked as up to date,
-        * then we need to zero any uninitalised data. */
-       if (req->wb_pgbase == 0 && req->wb_bytes != PAGE_CACHE_SIZE
-                       && !PageUptodate(req->wb_page))
-               zero_user_segment(req->wb_page, req->wb_bytes, PAGE_CACHE_SIZE);
+out:
        return req;
 }