Index: linux-2.6.14-rc4-mm1/mm/mempolicy.c =================================================================== --- linux-2.6.14-rc4-mm1.orig/mm/mempolicy.c 2005-10-19 15:05:12.000000000 -0700 +++ linux-2.6.14-rc4-mm1/mm/mempolicy.c 2005-10-19 16:52:31.000000000 -0700 @@ -207,10 +207,10 @@ out: return rc; } -static void migrate_page_add(struct vm_area_struct *vma, +static int migrate_page_add(struct vm_area_struct *vma, struct page *page, struct list_head *pagelist, unsigned long flags) { - int rc; + int rc = 0; /* * Avoid migrating a page that is shared by others and not writable. @@ -228,13 +228,14 @@ static void migrate_page_add(struct vm_a */ WARN_ON(rc == 0); } + return rc; } /* Ensure all existing pages follow the policy. */ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr, unsigned long end, nodemask_t *nodes, unsigned long flags, - struct list_head *pagelist) + struct list_head *pagelist, struct list_head *destlist) { pte_t *orig_pte; pte_t *pte; @@ -257,7 +258,14 @@ static int check_pte_range(struct vm_are if (pagelist) { struct page *page = pfn_to_page(pfn); - migrate_page_add(vma, page, pagelist, flags); + if (migrate_page_add(vma, page, pagelist, flags) == 1) { + struct page *n; + + n = alloc_page_vma(page->mapping->flags, vma, addr); + if (n) + list_add(&n->lru, destlist); + /* Silently ignoring ENOMEM condition for now */ + } } else break; } @@ -269,7 +277,7 @@ static int check_pte_range(struct vm_are static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud, unsigned long addr, unsigned long end, nodemask_t *nodes, unsigned long flags, - struct list_head *pagelist) + struct list_head *pagelist, struct list_head *destlist) { pmd_t *pmd; unsigned long next; @@ -280,7 +288,7 @@ static inline int check_pmd_range(struct if (pmd_none_or_clear_bad(pmd)) continue; if (check_pte_range(vma, pmd, addr, next, nodes, - flags, pagelist)) + flags, pagelist, destlist)) return -EIO; } while (pmd++, addr = next, addr != end); return 0; @@ -289,7 +297,7 @@ static inline int check_pmd_range(struct static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd, unsigned long addr, unsigned long end, nodemask_t *nodes, unsigned long flags, - struct list_head *pagelist) + struct list_head *pagelist, struct list_head *destlist) { pud_t *pud; unsigned long next; @@ -300,19 +308,32 @@ static inline int check_pud_range(struct if (pud_none_or_clear_bad(pud)) continue; if (check_pmd_range(vma, pud, addr, next, nodes, - flags, pagelist)) + flags, pagelist, destlist)) return -EIO; } while (pud++, addr = next, addr != end); return 0; } +static inline void list_free_pages(struct list_head *l) +{ + while (!list_empty(l)) { + struct page *page; + + page =list_entry(l->next, struct page, lru); + __free_page(page); + list_del(&page->lru); + } +} + static inline int check_pgd_range(struct vm_area_struct *vma, unsigned long addr, unsigned long end, nodemask_t *nodes, unsigned long flags, - struct list_head *pagelist) + nodemask_t *dest) { pgd_t *pgd; unsigned long next; + LIST_HEAD(pagelist); + LIST_HEAD(destlist); pgd = pgd_offset(vma->vm_mm, addr); do { @@ -320,9 +341,14 @@ static inline int check_pgd_range(struct if (pgd_none_or_clear_bad(pgd)) continue; if (check_pud_range(vma, pgd, addr, next, nodes, - flags, pagelist)) + flags, &pagelist, &destlist)) return -EIO; } while (pgd++, addr = next, addr != end); + if (!list_empty(&pagelist)) { + migrate_pages(&pagelist, &destlist); + putback_lru_pages(&pagelist); + list_free_pages(&destlist); + } return 0; } @@ -343,7 +369,7 @@ static inline int vma_migratable(struct /* Step 1: check the range */ static struct vm_area_struct * check_range(struct mm_struct *mm, unsigned long start, unsigned long end, - nodemask_t *nodes, unsigned long flags, struct list_head *pagelist) + nodemask_t *nodes, unsigned long flags, nodemask_t *dest) { int err; struct vm_area_struct *first, *vma, *prev; @@ -372,7 +398,7 @@ check_range(struct mm_struct *mm, unsign if (vma->vm_start > start) start = vma->vm_start; err = check_pgd_range(vma, start, endvma, nodes, - flags, pagelist); + flags, dest); if (err) { first = ERR_PTR(err); break; @@ -446,7 +472,6 @@ long do_mbind(unsigned long start, unsig struct mempolicy *new; unsigned long end; int err; - LIST_HEAD(pagelist); if ((flags & ~(unsigned long)(MPOL_MF_STRICT | MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) || mode > MPOL_MAX) @@ -486,18 +511,10 @@ long do_mbind(unsigned long start, unsig mode,nodes_addr(nodes)[0]); down_write(&mm->mmap_sem); - vma = check_range(mm, start, end, nmask, flags, - (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) ? &pagelist : NULL); + vma = check_range(mm, start, end, nmask, flags, NULL); err = PTR_ERR(vma); - if (!IS_ERR(vma)) { + if (!IS_ERR(vma)) err = mbind_range(vma, start, end, new); - if (!list_empty(&pagelist)) - swapout_pages(&pagelist); - if (!err && !list_empty(&pagelist) && (flags & MPOL_MF_STRICT)) - err = -EIO; - } - if (!list_empty(&pagelist)) - putback_lru_pages(&pagelist); up_write(&mm->mmap_sem); mpol_free(new); @@ -639,22 +656,17 @@ int do_migrate_pages(struct mm_struct *m nodemask_t *from_nodes, nodemask_t *to_nodes) { LIST_HEAD(pagelist); - int count = 0; + int err = 0; nodemask_t nodes; nodes_andnot(nodes, *from_nodes, *to_nodes); nodes_complement(nodes, nodes); down_read(&mm->mmap_sem); - check_range(mm, mm->mmap->vm_start, TASK_SIZE -1, &nodes, - MPOL_MF_MOVE | MPOL_MF_DISCONTIG_OK, &pagelist); - if (!list_empty(&pagelist)) { - swapout_pages(&pagelist); - if (!list_empty(&pagelist)) - count = putback_lru_pages(&pagelist); - } + err = PTR_ERR(check_range(mm, mm->mmap->vm_start, TASK_SIZE -1, &nodes, + MPOL_MF_MOVE | MPOL_MF_DISCONTIG_OK, to_nodes)); up_read(&mm->mmap_sem); - return count; + return err; } /* Index: linux-2.6.14-rc4-mm1/include/linux/swap.h =================================================================== --- linux-2.6.14-rc4-mm1.orig/include/linux/swap.h 2005-10-19 14:06:14.000000000 -0700 +++ linux-2.6.14-rc4-mm1/include/linux/swap.h 2005-10-19 15:59:56.000000000 -0700 @@ -178,6 +178,7 @@ extern int vm_swappiness; extern int isolate_lru_page(struct page *p, struct list_head *l); extern int swapout_pages(struct list_head *l); +extern int migrate_pages(struct list_head *source, struct list_head *target); extern int putback_lru_pages(struct list_head *l); #ifdef CONFIG_MMU