Skip to content

Commit

Permalink
tmpfs: optimize clearing when writing
Browse files Browse the repository at this point in the history
Nick proposed years ago that tmpfs should avoid clearing its pages where
write will overwrite them with new data, as ramfs has long done.  But I
messed it up and just got bad data.  Tried again recently, it works
fine.

Here's time output for writing 4GiB 16 times on this Core i5 laptop:

before: real	0m21.169s user	0m0.028s sys	0m21.057s
        real	0m21.382s user	0m0.016s sys	0m21.289s
        real	0m21.311s user	0m0.020s sys	0m21.217s

after:  real	0m18.273s user	0m0.032s sys	0m18.165s
        real	0m18.354s user	0m0.020s sys	0m18.265s
        real	0m18.440s user	0m0.032s sys	0m18.337s

ramfs:  real	0m16.860s user	0m0.028s sys	0m16.765s
        real	0m17.382s user	0m0.040s sys	0m17.273s
        real	0m17.133s user	0m0.044s sys	0m17.021s

Yes, I have done perf reports, but they need more explanation than they
deserve: in summary, clear_page vanishes, its cache loading shifts into
copy_user_generic_unrolled; shmem_getpage_gfp goes down, and
surprisingly mark_page_accessed goes way up - I think because they are
respectively where the cache gets to be reloaded after being purged by
clear or copy.

Suggested-by: Nick Piggin <npiggin@gmail.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Hugh Dickins authored and Linus Torvalds committed May 29, 2012
1 parent 2f6e38f commit ec9516f
Showing 1 changed file with 17 additions and 3 deletions.
20 changes: 17 additions & 3 deletions mm/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1095,9 +1095,14 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
shmem_recalc_inode(inode);
spin_unlock(&info->lock);

clear_highpage(page);
flush_dcache_page(page);
SetPageUptodate(page);
/*
* Let SGP_WRITE caller clear ends if write does not fill page
*/
if (sgp != SGP_WRITE) {
clear_highpage(page);
flush_dcache_page(page);
SetPageUptodate(page);
}
if (sgp == SGP_DIRTY)
set_page_dirty(page);
}
Expand Down Expand Up @@ -1307,6 +1312,14 @@ shmem_write_end(struct file *file, struct address_space *mapping,
if (pos + copied > inode->i_size)
i_size_write(inode, pos + copied);

if (!PageUptodate(page)) {
if (copied < PAGE_CACHE_SIZE) {
unsigned from = pos & (PAGE_CACHE_SIZE - 1);
zero_user_segments(page, 0, from,
from + copied, PAGE_CACHE_SIZE);
}
SetPageUptodate(page);
}
set_page_dirty(page);
unlock_page(page);
page_cache_release(page);
Expand Down Expand Up @@ -1768,6 +1781,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
kaddr = kmap_atomic(page);
memcpy(kaddr, symname, len);
kunmap_atomic(kaddr);
SetPageUptodate(page);
set_page_dirty(page);
unlock_page(page);
page_cache_release(page);
Expand Down

0 comments on commit ec9516f

Please sign in to comment.