Index: linux-2.6.17-rc3/mm/migrate.c =================================================================== --- linux-2.6.17-rc3.orig/mm/migrate.c 2006-04-30 22:19:18.651956027 -0700 +++ linux-2.6.17-rc3/mm/migrate.c 2006-04-30 22:45:53.794977846 -0700 @@ -28,7 +28,7 @@ #include "internal.h" /* The maximum number of pages to take off the LRU for migration */ -#define MIGRATE_CHUNK_SIZE 1024 +#define MIGRATE_CHUNK_SIZE (PAGE_SIZE/sizeof(void *) #define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru)) @@ -503,13 +503,11 @@ * The new page will have replaced the old page if this function * is successful. */ -static int move_page(struct page *page, struct list_head *to) +static int move_page(struct page *page, struct page*newpage) { - struct page *newpage = lru_to_page(to); struct address_space *mapping; int rc; - newpage = lru_to_page(to); lock_page(newpage); /* Prepare mapping for the new page.*/ @@ -551,7 +549,7 @@ * The function attempts to obtain the lock if the page has not * already been locked. */ -static int unmap_and_move(struct page *page, struct list_head *to, int force) +static int unmap_and_move(struct page *page, struct page *newpage, int force) { int rc; @@ -572,7 +570,7 @@ */ if (try_to_unmap(page, 1) != SWAP_FAIL) { if (!page_mapped(page)) - rc = move_page(page, to); + rc = move_page(page, newpage); else rc = -EAGAIN; } else @@ -600,30 +598,31 @@ * * Return: Number of pages not migrated when "to" ran empty. */ -int migrate_pages(struct list_head *from, struct list_head *to, - struct list_head *moved, struct list_head *failed) +int migrate_pages(int nr, struct page *from[], struct page *to[], char status[]) { int retry; int nr_failed = 0; int pass = 0; struct page *page; - struct page *page2; int swapwrite = current->flags & PF_SWAPWRITE; int rc; + int i; if (!swapwrite) current->flags |= PF_SWAPWRITE; -redo: - retry = 0; - - list_for_each_entry_safe(page, page2, from, lru) { + memset(status, -EAGAIN, nr*sizeof(char)); - if (list_empty(to)) - break; + for(pass = 0; pass < 10 && retry; pass++) { + retry = 0; + for (i = 0; i < nr; i++) { + if (status[i] != -EAGAIN) + continue; cond_resched(); + page = from[i]; + if (page_count(page) == 1) /* page was freed from under us. So we are done. */ rc = 0; @@ -641,22 +640,17 @@ if (pass > 0) wait_on_page_writeback(page); - rc = unmap_and_move(page, to, pass > 5); + rc = unmap_and_move(page, to[i], pass > 5); } + status[i] = rc; if (rc) { if (rc == -EAGAIN) retry++; - else { - /* Permanent failure */ - list_move(&page->lru, failed); + else nr_failed++; - } - } else - list_move(&page->lru, moved); + } } - if (retry && pass++ < 10) - goto redo; if (!swapwrite) current->flags &= ~PF_SWAPWRITE; @@ -673,18 +667,21 @@ int migrate_pages_to(struct list_head *pagelist, struct vm_area_struct *vma, int dest) { - LIST_HEAD(newlist); - LIST_HEAD(moved); - LIST_HEAD(failed); int err = 0; unsigned long offset = 0; int nr_pages; struct page *page; struct list_head *p; + struct page**from = get_zeroed_page(); + struct page**to = get_zeroed_page(); + char *status = get_zeroed_page(); + + while (!list_empty(pagelist) && err >=0) { -redo: nr_pages = 0; list_for_each(p, pagelist) { + from[nr_pages] = p; + if (vma) { /* * The address passed to alloc_page_vma is used to @@ -707,31 +704,29 @@ err = -ENOMEM; goto out; } - list_add_tail(&page->lru, &newlist); - nr_pages++; + to[nr_pages++] = page; if (nr_pages > MIGRATE_CHUNK_SIZE) break; } - err = migrate_pages(pagelist, &newlist, &moved, &failed); + rc = migrate_pages(nr_pages, from, to, status); + if (rc <0) { + err = rc; + goto out; + } - putback_lru_pages(&moved); /* Call release pages instead ?? */ + for(i = 0; i < nr_pages; i++) + if (status[i]) { + /* Hard error */ + free_page(to[i]); + err++; + } else + move_to_lru(from[i]); - if (err >= 0 && list_empty(&newlist) && !list_empty(pagelist)) + if (err >= 0 && !list_empty(pagelist)) goto redo; out: - /* Return leftover allocated pages */ - while (!list_empty(&newlist)) { - page = list_entry(newlist.next, struct page, lru); - list_del(&page->lru); - __free_page(page); - } - list_splice(&failed, pagelist); - if (err < 0) - return err; - - /* Calculate number of leftover pages */ - nr_pages = 0; - list_for_each(p, pagelist) - nr_pages++; - return nr_pages; + free_page(from); + free_page(to); + free_page(status); + return err; } Index: linux-2.6.17-rc3/include/linux/migrate.h =================================================================== --- linux-2.6.17-rc3.orig/include/linux/migrate.h 2006-04-30 21:09:42.657645584 -0700 +++ linux-2.6.17-rc3/include/linux/migrate.h 2006-04-30 22:32:32.667000818 -0700 @@ -9,8 +9,8 @@ extern int putback_lru_pages(struct list_head *l); extern int migrate_page(struct address_space *, struct page *, struct page *); -extern int migrate_pages(struct list_head *l, struct list_head *t, - struct list_head *moved, struct list_head *failed); +extern int migrate_pages(int, struct page *[], struct page *[], + char status[]); extern int migrate_pages_to(struct list_head *pagelist, struct vm_area_struct *vma, int dest); extern int fail_migrate_page(struct address_space *, @@ -23,8 +23,8 @@ static inline int isolate_lru_page(struct page *p, struct list_head *list) { return -ENOSYS; } static inline int putback_lru_pages(struct list_head *l) { return 0; } -static inline int migrate_pages(struct list_head *l, struct list_head *t, - struct list_head *moved, struct list_head *failed) { return -ENOSYS; } +static inline int migrate_pages(int, struct page *[], struct page *[], + char status[]) { return -ENOSYS; } static inline int migrate_pages_to(struct list_head *pagelist, struct vm_area_struct *vma, int dest) { return 0; }