Variable Order Page Cache: Add clearing and flushing function Add a flushing and clearing function for higher order pages. These are provisional and will likely have to be optimized. Signed-off-by: Christoph Lameter --- fs/libfs.c | 6 +++--- include/linux/highmem.h | 9 +++------ include/linux/pagemap.h | 25 +++++++++++++++++++++++++ mm/filemap.c | 4 ++-- 4 files changed, 33 insertions(+), 11 deletions(-) Index: linux-2.6.21-rc7-mm2/include/linux/pagemap.h =================================================================== --- linux-2.6.21-rc7-mm2.orig/include/linux/pagemap.h 2007-04-26 22:35:42.000000000 -0700 +++ linux-2.6.21-rc7-mm2/include/linux/pagemap.h 2007-04-26 22:35:47.000000000 -0700 @@ -325,6 +325,31 @@ static inline void wait_on_page_writebac extern void end_page_writeback(struct page *page); +/* Support for clearing higher order pages */ +static inline void clear_mapping_page(struct page *page) +{ + int nr_pages = compound_pages(page); + int i; + + for (i = 0; i < nr_pages; i++) + clear_highpage(page + i); +} + +/* + * Support for flushing higher order pages. + * + * A bit stupid: On many platforms flushing the first page + * will flush any TLB starting there + */ +static inline void flush_mapping_page(struct page *page) +{ + int nr_pages = compound_pages(page); + int i; + + for (i = 0; i < nr_pages; i++) + flush_dcache_page(page + i); +} + /* * Fault a userspace page into pagetables. Return non-zero on a fault. * Index: linux-2.6.21-rc7-mm2/fs/libfs.c =================================================================== --- linux-2.6.21-rc7-mm2.orig/fs/libfs.c 2007-04-26 22:35:45.000000000 -0700 +++ linux-2.6.21-rc7-mm2/fs/libfs.c 2007-04-26 22:35:47.000000000 -0700 @@ -326,8 +326,8 @@ int simple_rename(struct inode *old_dir, int simple_readpage(struct file *file, struct page *page) { - clear_highpage(page); - flush_dcache_page(page); + clear_mapping_page(page); + flush_mapping_page(page); SetPageUptodate(page); unlock_page(page); return 0; @@ -339,7 +339,7 @@ int simple_prepare_write(struct file *fi unsigned int page_size = page_cache_size(file->f_mapping); if (!PageUptodate(page)) { - if (to - from != page_size) + if (to - from != page_size) { if (from) zero_user_page(page, 0, from, KM_USER0); if (to < page_size) Index: linux-2.6.21-rc7-mm2/include/linux/highmem.h =================================================================== --- linux-2.6.21-rc7-mm2.orig/include/linux/highmem.h 2007-04-26 22:34:50.000000000 -0700 +++ linux-2.6.21-rc7-mm2/include/linux/highmem.h 2007-04-26 22:35:47.000000000 -0700 @@ -148,15 +148,12 @@ static inline void clear_highpage(struct \ kaddr = kmap_atomic(page, km_type); \ memset((char *)kaddr + (offset), 0, (size)); \ - flush_dcache_page(page); \ + flush_mapping_page(page); \ kunmap_atomic(kaddr, (km_type)); \ } while (0) -static inline void __deprecated memclear_highpage_flush(struct page *page, - unsigned int offset, unsigned int size) -{ - zero_user_page(page, offset, size, KM_USER0); -} +#define memclear_highpage_flush(__p, __o, __s) \ + zero_user_page(__p, __o, __s, KM_USER0) #ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE Index: linux-2.6.21-rc7-mm2/mm/filemap.c =================================================================== --- linux-2.6.21-rc7-mm2.orig/mm/filemap.c 2007-04-26 22:35:45.000000000 -0700 +++ linux-2.6.21-rc7-mm2/mm/filemap.c 2007-04-26 22:35:47.000000000 -0700 @@ -974,7 +974,7 @@ page_ok: * before reading the page on the kernel side. */ if (mapping_writably_mapped(mapping)) - flush_dcache_page(page); + flush_mapping_page(page); /* * When a sequential read accesses a page several times, @@ -2044,7 +2044,7 @@ generic_file_buffered_write(struct kiocb else copied = filemap_copy_from_user_iovec(page, offset, cur_iov, iov_base, bytes); - flush_dcache_page(page); + flush_mapping_page(page); status = a_ops->commit_write(file, page, offset, offset+bytes); if (status == AOP_TRUNCATED_PAGE) { page_cache_release(page);