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 | 4 ++-- include/linux/highmem.h | 9 +++------ include/linux/pagemap.h | 41 +++++++++++++++++++++++++++++++++++++++-- mm/filemap.c | 4 ++-- 4 files changed, 46 insertions(+), 12 deletions(-) Index: linux-2.6.21-rc7-mm2/include/linux/pagemap.h =================================================================== --- linux-2.6.21-rc7-mm2.orig/include/linux/pagemap.h 2007-05-01 10:34:06.000000000 -0700 +++ linux-2.6.21-rc7-mm2/include/linux/pagemap.h 2007-05-01 16:15:14.000000000 -0700 @@ -72,11 +72,23 @@ static inline void mapping_set_gfp_mask( #ifdef CONFIG_LARGE_BLOCKSIZE static inline int page_cache_valid_blocksize(unsigned long size) { - return size >= 512; + extern int pagepool_order; + + return size >= 512 && size < (PAGE_SIZE << pagepool_order); } -static inline void set_mapping_order(struct address_space *a, int order) +static inline void set_mapping_bits(struct address_space *a, int bits) { + extern int pagepool_order; + int order; + + if (bits <= PAGE_SHIFT) + order = 0; + else if (bits <= pagepool_order + PAGE_SHIFT) + order = pagepool_order; + else + BUG(); + a->order = order; a->shift = order + PAGE_SHIFT; a->offset_mask = (1UL << a->shift) - 1; @@ -325,6 +337,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-05-01 15:46:40.000000000 -0700 +++ linux-2.6.21-rc7-mm2/fs/libfs.c 2007-05-01 15:47:35.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; Index: linux-2.6.21-rc7-mm2/include/linux/highmem.h =================================================================== --- linux-2.6.21-rc7-mm2.orig/include/linux/highmem.h 2007-04-27 22:51:28.000000000 -0700 +++ linux-2.6.21-rc7-mm2/include/linux/highmem.h 2007-05-01 15:47:35.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-05-01 15:46:40.000000000 -0700 +++ linux-2.6.21-rc7-mm2/mm/filemap.c 2007-05-02 10:51:33.000000000 -0700 @@ -979,7 +979,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, @@ -2049,7 +2049,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);