--- mm/memory.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) Index: linux-2.6.21-rc7/mm/memory.c =================================================================== --- linux-2.6.21-rc7.orig/mm/memory.c 2007-04-20 10:55:16.000000000 -0700 +++ linux-2.6.21-rc7/mm/memory.c 2007-04-20 10:55:29.000000000 -0700 @@ -374,6 +374,12 @@ static inline int is_cow_mapping(unsigne * used to manipulate the page state. Use compound_head() if * operations (like getting a ref count) are necessary. * + * NOTE! For compound pages it may get to a tail page (maybe we + * only deal with a portion of a compound page after all). This + * means that the result of vm_normal_page may not directly be + * used to manipulate the page state. Use compound_head() if + * operations (like getting a ref count) are necessary. + * * NOTE! Some mappings do not have "struct pages". A raw PFN mapping * will have each page table entry just pointing to a raw page frame * number, and as far as the VM layer is concerned, those do not have @@ -998,6 +1004,14 @@ no_page_table: return page; } +/* + * Get user pages return a series of pointers to page struct. + * Note that these may contain compound head and tail pages (necessary + * to support direct I/O). Beware: It is not trivial to perform operations + * on tail pages. Dirtying etc should be performed on compound_head(page) + * and is performed by get_user_pages() (via follow_page) only on the head + * page alone. + */ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int len, int write, int force, struct page **pages, struct vm_area_struct **vmas) @@ -1628,6 +1642,7 @@ static int do_wp_page(struct mm_struct * goto unlock; } + head_page = compound_head(old_page); /* * Ok, we need to copy. Oh, well.. */ @@ -2220,7 +2235,7 @@ static int do_no_page(struct mm_struct * int write_access) { spinlock_t *ptl; - struct page *new_page; + struct page *new_page, *head_page; struct address_space *mapping = NULL; pte_t entry; unsigned int sequence = 0; @@ -2238,6 +2253,7 @@ static int do_no_page(struct mm_struct * } retry: new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret); + /* * No smp_rmb is needed here as long as there's a full * spin_lock/unlock sequence inside the ->nopage callback