--- fs/proc/task_mmu.c | 12 +++++-- include/linux/mm.h | 3 + mm/filemap.c | 6 +-- mm/fremap.c | 11 +++---- mm/memory.c | 82 +++++++++++++++++++++++------------------------------ mm/mempolicy.c | 7 ++-- mm/migrate.c | 2 - mm/rmap.c | 15 +++++---- 8 files changed, 68 insertions(+), 70 deletions(-) Index: linux-2.6/include/linux/mm.h =================================================================== --- linux-2.6.orig/include/linux/mm.h 2007-09-12 08:50:48.000000000 -0700 +++ linux-2.6/include/linux/mm.h 2007-09-12 08:50:48.000000000 -0700 @@ -781,7 +781,8 @@ struct zap_details { unsigned long truncate_count; /* Compare vm_truncate_count */ }; -struct page *vm_normal_page(struct vm_area_struct *, unsigned long, pte_t); +struct page *vm_normal_page(struct vm_area_struct *, unsigned long, pte_t, + int *); unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size, struct zap_details *); unsigned long unmap_vmas(struct mmu_gather **tlb, Index: linux-2.6/mm/filemap.c =================================================================== --- linux-2.6.orig/mm/filemap.c 2007-09-12 08:50:48.000000000 -0700 +++ linux-2.6/mm/filemap.c 2007-09-12 08:50:48.000000000 -0700 @@ -1322,7 +1322,7 @@ int filemap_fault(struct vm_area_struct int ret = 0; size = page_cache_next(mapping, i_size_read(inode)); - if (pgoff >= size) + if (vmf->pgoff >= size) goto outside_data_content; /* If we don't want any read-ahead, don't bother */ @@ -1377,7 +1377,7 @@ retry_find: pgoff_t start = 0; if (vmf->pgoff > ra_pages / 2) - start = pgoff - ra_pages / 2; + start = vmf->pgoff - ra_pages / 2; do_page_cache_readahead(mapping, file, start, ra_pages); } page = find_lock_page(mapping, vmf->pgoff); @@ -1479,7 +1479,7 @@ int generic_file_mmap(struct file * file { struct address_space *mapping = file->f_mapping; - if (!mapping->a_ops->readpage)` + if (!mapping->a_ops->readpage) return -ENOEXEC; file_accessed(file); vma->vm_ops = &generic_file_vm_ops; Index: linux-2.6/mm/fremap.c =================================================================== --- linux-2.6.orig/mm/fremap.c 2007-09-12 08:50:48.000000000 -0700 +++ linux-2.6/mm/fremap.c 2007-09-12 08:50:48.000000000 -0700 @@ -27,17 +27,16 @@ static void zap_pte(struct mm_struct *mm if (pte_present(pte)) { struct page *page; + int page_index; flush_cache_page(vma, addr, pte_pfn(pte)); pte = ptep_clear_flush(vma, addr, ptep); - page = vm_normal_page(vma, addr, pte); + page = vm_normal_page(vma, addr, pte, &page_index); if (page) { - struct page *head = page_cache_head(page); - if (pte_dirty(pte)) - set_page_dirty(head); - page_remove_rmap(head, vma); - page_cache_release(head); + set_page_dirty(page); + page_remove_rmap(page, vma); + page_cache_release(page); update_hiwater_rss(mm); dec_mm_counter(mm, file_rss); } Index: linux-2.6/mm/memory.c =================================================================== --- linux-2.6.orig/mm/memory.c 2007-09-12 08:50:48.000000000 -0700 +++ linux-2.6/mm/memory.c 2007-09-12 08:50:48.000000000 -0700 @@ -382,15 +382,12 @@ static inline int is_cow_mapping(unsigne * and if that isn't true, the page has been COW'ed (in which case it * _does_ have a "struct page" associated with it even if it is in a * VM_PFNMAP range). - * - * vm_normal_page may return a tail page of a compound page. The tail - * page pointer allows the determination of the PAGE_SIZE slice - * intended to be operated upon on. The page head can be determined - * from the tail page. */ -struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, + pte_t pte, int *page_index) { unsigned long pfn = pte_pfn(pte); + struct page *page, *head; if (unlikely(vma->vm_flags & VM_PFNMAP)) { unsigned long off = (addr - vma->vm_start) >> PAGE_SHIFT; @@ -418,7 +415,11 @@ struct page *vm_normal_page(struct vm_ar * The PAGE_ZERO() pages and various VDSO mappings can * cause them to exist. */ - return pfn_to_page(pfn); + page = pfn_to_page(pfn); + head = page_cache_head(page); + if (page_index) + *page_index = page - head; + return head; } /* @@ -435,6 +436,7 @@ copy_one_pte(struct mm_struct *dst_mm, s unsigned long vm_flags = vma->vm_flags; pte_t pte = *src_pte; struct page *page; + int page_index; /* pte contains position in swap or file, so copy. */ if (unlikely(!pte_present(pte))) { @@ -481,13 +483,11 @@ copy_one_pte(struct mm_struct *dst_mm, s pte = pte_mkclean(pte); pte = pte_mkold(pte); - page = vm_normal_page(vma, addr, pte); + page = vm_normal_page(vma, addr, pte, &page_index); if (page) { - struct page *head = page_cache_head(page); - - get_page(head); - page_dup_rmap(head, vma, addr); - rss[!!PageAnon(head)]++; + get_page(page); + page_dup_rmap(page, vma, addr); + rss[!!PageAnon(page)]++; } out_set_pte: @@ -646,19 +646,16 @@ static unsigned long zap_pte_range(struc (*zap_work) -= PAGE_SIZE; if (pte_present(ptent)) { - int page_index = 0; + int page_index; int index = 0; - struct page *page = vm_normal_page(vma, addr, ptent); + struct page *page; - if (page) { - struct page *head = page_cache_head(page); + page = vm_normal_page(vma, addr, ptent, &page_index); - page_index = page - head; - page = head; + if (page) index = (page->index << page_cache_page_order(page)) + page_index; - } if (unlikely(details) && page) { /* @@ -915,10 +912,6 @@ unsigned long zap_page_range(struct vm_a /* * Do a quick page-table lookup for a single page. - * - * follow_page() may return a tail page. However, the reference count - * is taken on the head page. The head page must be determined - * to drop the refcount again. */ struct page *follow_page(struct vm_area_struct *vma, unsigned long address, unsigned int flags) @@ -928,8 +921,9 @@ struct page *follow_page(struct vm_area_ pmd_t *pmd; pte_t *ptep, pte; spinlock_t *ptl; - struct page *page, *head; + struct page *page; struct mm_struct *mm = vma->vm_mm; + int page_index; page = follow_huge_addr(mm, address, flags & FOLL_WRITE); if (!IS_ERR(page)) { @@ -965,23 +959,22 @@ struct page *follow_page(struct vm_area_ goto unlock; if ((flags & FOLL_WRITE) && !pte_write(pte)) goto unlock; - page = vm_normal_page(vma, address, pte); + page = vm_normal_page(vma, address, pte, &page_index); if (unlikely(!page)) goto unlock; - head = page_cache_head(page); if (flags & FOLL_GET) - get_page(head); + get_page(page); if (flags & FOLL_TOUCH) { if ((flags & FOLL_WRITE) && - !pte_dirty(pte) && !PageDirty(head)) - set_page_dirty(head); - mark_page_accessed(head); + !pte_dirty(pte) && !PageDirty(page)) + set_page_dirty(page); + mark_page_accessed(page); } unlock: pte_unmap_unlock(ptep, ptl); out: - return page; + return page + page_index; no_page_table: /* @@ -1042,10 +1035,15 @@ int get_user_pages(struct task_struct *t return i ? : -EFAULT; } if (pages) { - struct page *page = vm_normal_page(gate_vma, start, *pte); - pages[i] = page; - if (page) - get_page(page_cache_head(page)); + int page_index; + struct page *page = vm_normal_page(gate_vma, + start, *pte, &page_index); + + if (page) { + pages[i] = page + page_index; + get_page(page); + } else + pages[i] = NULL; } pte_unmap(pte); if (vmas) @@ -1661,20 +1659,14 @@ static int do_wp_page(struct mm_struct * { struct page *old_page, *new_page; pte_t entry; - int reuse = 0, ret = 0, page_index = 0; + int reuse = 0, ret = 0; + int page_index; struct page *dirty_page = NULL; - old_page = vm_normal_page(vma, address, orig_pte); + old_page = vm_normal_page(vma, address, orig_pte, &page_index); if (!old_page) goto gotten; - if (PageTail(old_page)) { - struct page *head = page_cache_head(old_page); - - page_index = old_page - head; - old_page = head; - } - /* * Take out anonymous pages first, anonymous shared vmas are * not dirty accountable. Index: linux-2.6/mm/mempolicy.c =================================================================== --- linux-2.6.orig/mm/mempolicy.c 2007-09-12 08:50:48.000000000 -0700 +++ linux-2.6/mm/mempolicy.c 2007-09-12 08:50:48.000000000 -0700 @@ -228,11 +228,12 @@ static int check_pte_range(struct vm_are struct page *page; int nid; int pages = 1; + int page_index; if (!pte_present(*pte)) goto next; - page = vm_normal_page(vma, addr, *pte); - if (!page || PageTail(page)) + page = vm_normal_page(vma, addr, *pte, &page_index); + if (!page) goto next; pages = page_cache_base_pages(page); @@ -262,7 +263,7 @@ static int check_pte_range(struct vm_are break; next: pte += pages; - addr += PAGE_SIZE * pages; + addr += pages << PAGE_SHIFT; } while (addr != end); pte_unmap_unlock(orig_pte, ptl); Index: linux-2.6/mm/migrate.c =================================================================== --- linux-2.6.orig/mm/migrate.c 2007-09-12 08:50:48.000000000 -0700 +++ linux-2.6/mm/migrate.c 2007-09-12 08:50:48.000000000 -0700 @@ -832,10 +832,10 @@ static int do_move_pages(struct mm_struc if (!page) goto set_status; - page = page_cache_head(page); if (PageReserved(page)) /* Check for zero page */ goto put_and_set; + page = page_cache_head(page); pp->page = page; err = page_to_nid(page); Index: linux-2.6/mm/rmap.c =================================================================== --- linux-2.6.orig/mm/rmap.c 2007-09-12 08:50:48.000000000 -0700 +++ linux-2.6/mm/rmap.c 2007-09-12 08:50:48.000000000 -0700 @@ -817,9 +817,10 @@ static void try_to_unmap_cluster(unsigne pte_t *pte; pte_t pteval; spinlock_t *ptl; - struct page *page, *head; + struct page *page; unsigned long address; unsigned long end; + int page_index; address = (vma->vm_start + cursor) & CLUSTER_MASK; end = address + CLUSTER_SIZE; @@ -848,27 +849,27 @@ static void try_to_unmap_cluster(unsigne for (; address < end; pte++, address += PAGE_SIZE) { if (!pte_present(*pte)) continue; - page = vm_normal_page(vma, address, *pte); + page = vm_normal_page(vma, address, *pte, &page_index); BUG_ON(!page || PageAnon(page)); if (ptep_clear_flush_young(vma, address, pte)) continue; - head = page_cache_head(page); /* Nuke the page table entry. */ flush_cache_page(vma, address, pte_pfn(*pte)); pteval = ptep_clear_flush(vma, address, pte); /* If nonlinear, store the file page offset in the pte. */ if (page->index != linear_page_index(vma, address)) - set_pte_at(mm, address, pte, pgoff_to_pte(page->index)); + set_pte_at(mm, address, pte, + pgoff_to_pte(page->index + page_index)); /* Move the dirty bit to the physical page now the pte is gone. */ if (pte_dirty(pteval)) - set_page_dirty(head); + set_page_dirty(page); - page_remove_rmap(head, vma); - page_cache_release(head); + page_remove_rmap(page, vma); + page_cache_release(page); dec_mm_counter(mm, file_rss); (*mapcount)--; } Index: linux-2.6/fs/proc/task_mmu.c =================================================================== --- linux-2.6.orig/fs/proc/task_mmu.c 2007-09-12 08:50:44.000000000 -0700 +++ linux-2.6/fs/proc/task_mmu.c 2007-09-12 08:50:50.000000000 -0700 @@ -230,17 +230,19 @@ static void smaps_pte_range(struct vm_ar pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); for (; addr != end; pte++, addr += PAGE_SIZE) { ptent = *pte; + int page_index; + if (!pte_present(ptent)) continue; mss->resident += PAGE_SIZE; - page = vm_normal_page(vma, addr, ptent); + page = vm_normal_page(vma, addr, ptent, &page_index); if (!page) continue; /* Accumulate the size in pages that have been accessed. */ - if (pte_young(ptent) || PageReferenced(page)) + if (pte_young(ptent) || PageReferenced(page + page_index)) mss->referenced += PAGE_SIZE; if (page_mapcount(page) >= 2) { if (pte_dirty(ptent)) @@ -269,16 +271,18 @@ static void clear_refs_pte_range(struct pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); for (; addr != end; pte++, addr += PAGE_SIZE) { ptent = *pte; + int page_index; + if (!pte_present(ptent)) continue; - page = vm_normal_page(vma, addr, ptent); + page = vm_normal_page(vma, addr, ptent, &page_index); if (!page) continue; /* Clear accessed and referenced bits. */ ptep_test_and_clear_young(vma, addr, pte); - ClearPageReferenced(page); + ClearPageReferenced(page + page_index); } pte_unmap_unlock(pte - 1, ptl); cond_resched();