diff options
author | Christoph Lameter <clameter@sgi.com> | 2006-06-23 05:03:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-23 10:42:53 -0400 |
commit | aaa994b300a172afafab47938804836b923e5ef7 (patch) | |
tree | ccc1acf72e9d1dfbd25fa5f8e067a195f93b0319 | |
parent | e24f0b8f76cc3dd96f36f5b6a9f020f6c3fce198 (diff) |
[PATCH] page migration: handle freeing of pages in migrate_pages()
Do not leave pages on the lists passed to migrate_pages(). Seems that we will
not need any postprocessing of pages. This will simplify the handling of
pages by the callers of migrate_pages().
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Jes Sorensen <jes@trained-monkey.org>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Lee Schermerhorn <lee.schermerhorn@hp.com>
Cc: Andi Kleen <ak@muc.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | include/linux/migrate.h | 7 | ||||
-rw-r--r-- | mm/mempolicy.c | 8 | ||||
-rw-r--r-- | mm/migrate.c | 48 |
3 files changed, 27 insertions, 36 deletions
diff --git a/include/linux/migrate.h b/include/linux/migrate.h index 287c47b5e5df..83af25949fa9 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h | |||
@@ -8,8 +8,7 @@ extern int isolate_lru_page(struct page *p, struct list_head *pagelist); | |||
8 | extern int putback_lru_pages(struct list_head *l); | 8 | extern int putback_lru_pages(struct list_head *l); |
9 | extern int migrate_page(struct address_space *, | 9 | extern int migrate_page(struct address_space *, |
10 | struct page *, struct page *); | 10 | struct page *, struct page *); |
11 | extern int migrate_pages(struct list_head *l, struct list_head *t, | 11 | extern int migrate_pages(struct list_head *l, struct list_head *t); |
12 | struct list_head *moved, struct list_head *failed); | ||
13 | extern int migrate_pages_to(struct list_head *pagelist, | 12 | extern int migrate_pages_to(struct list_head *pagelist, |
14 | struct vm_area_struct *vma, int dest); | 13 | struct vm_area_struct *vma, int dest); |
15 | extern int fail_migrate_page(struct address_space *, | 14 | extern int fail_migrate_page(struct address_space *, |
@@ -22,8 +21,8 @@ extern int migrate_prep(void); | |||
22 | static inline int isolate_lru_page(struct page *p, struct list_head *list) | 21 | static inline int isolate_lru_page(struct page *p, struct list_head *list) |
23 | { return -ENOSYS; } | 22 | { return -ENOSYS; } |
24 | static inline int putback_lru_pages(struct list_head *l) { return 0; } | 23 | static inline int putback_lru_pages(struct list_head *l) { return 0; } |
25 | static inline int migrate_pages(struct list_head *l, struct list_head *t, | 24 | static inline int migrate_pages(struct list_head *l, struct list_head *t) |
26 | struct list_head *moved, struct list_head *failed) { return -ENOSYS; } | 25 | { return -ENOSYS; } |
27 | 26 | ||
28 | static inline int migrate_pages_to(struct list_head *pagelist, | 27 | static inline int migrate_pages_to(struct list_head *pagelist, |
29 | struct vm_area_struct *vma, int dest) { return 0; } | 28 | struct vm_area_struct *vma, int dest) { return 0; } |
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 8778f58880c4..244f3f130e4a 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -603,11 +603,8 @@ int migrate_to_node(struct mm_struct *mm, int source, int dest, int flags) | |||
603 | check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nmask, | 603 | check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nmask, |
604 | flags | MPOL_MF_DISCONTIG_OK, &pagelist); | 604 | flags | MPOL_MF_DISCONTIG_OK, &pagelist); |
605 | 605 | ||
606 | if (!list_empty(&pagelist)) { | 606 | if (!list_empty(&pagelist)) |
607 | err = migrate_pages_to(&pagelist, NULL, dest); | 607 | err = migrate_pages_to(&pagelist, NULL, dest); |
608 | if (!list_empty(&pagelist)) | ||
609 | putback_lru_pages(&pagelist); | ||
610 | } | ||
611 | return err; | 608 | return err; |
612 | } | 609 | } |
613 | 610 | ||
@@ -773,9 +770,6 @@ long do_mbind(unsigned long start, unsigned long len, | |||
773 | err = -EIO; | 770 | err = -EIO; |
774 | } | 771 | } |
775 | 772 | ||
776 | if (!list_empty(&pagelist)) | ||
777 | putback_lru_pages(&pagelist); | ||
778 | |||
779 | up_write(&mm->mmap_sem); | 773 | up_write(&mm->mmap_sem); |
780 | mpol_free(new); | 774 | mpol_free(new); |
781 | return err; | 775 | return err; |
diff --git a/mm/migrate.c b/mm/migrate.c index 09038163bfec..d3a1810a4c9f 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -624,6 +624,15 @@ unlock: | |||
624 | unlock_page(page); | 624 | unlock_page(page); |
625 | ret: | 625 | ret: |
626 | if (rc != -EAGAIN) { | 626 | if (rc != -EAGAIN) { |
627 | /* | ||
628 | * A page that has been migrated has all references | ||
629 | * removed and will be freed. A page that has not been | ||
630 | * migrated will have kepts its references and be | ||
631 | * restored. | ||
632 | */ | ||
633 | list_del(&page->lru); | ||
634 | move_to_lru(page); | ||
635 | |||
627 | list_del(&newpage->lru); | 636 | list_del(&newpage->lru); |
628 | move_to_lru(newpage); | 637 | move_to_lru(newpage); |
629 | } | 638 | } |
@@ -640,12 +649,12 @@ ret: | |||
640 | * | 649 | * |
641 | * The function returns after 10 attempts or if no pages | 650 | * The function returns after 10 attempts or if no pages |
642 | * are movable anymore because to has become empty | 651 | * are movable anymore because to has become empty |
643 | * or no retryable pages exist anymore. | 652 | * or no retryable pages exist anymore. All pages will be |
653 | * retruned to the LRU or freed. | ||
644 | * | 654 | * |
645 | * Return: Number of pages not migrated when "to" ran empty. | 655 | * Return: Number of pages not migrated. |
646 | */ | 656 | */ |
647 | int migrate_pages(struct list_head *from, struct list_head *to, | 657 | int migrate_pages(struct list_head *from, struct list_head *to) |
648 | struct list_head *moved, struct list_head *failed) | ||
649 | { | 658 | { |
650 | int retry = 1; | 659 | int retry = 1; |
651 | int nr_failed = 0; | 660 | int nr_failed = 0; |
@@ -675,11 +684,9 @@ int migrate_pages(struct list_head *from, struct list_head *to, | |||
675 | retry++; | 684 | retry++; |
676 | break; | 685 | break; |
677 | case 0: | 686 | case 0: |
678 | list_move(&page->lru, moved); | ||
679 | break; | 687 | break; |
680 | default: | 688 | default: |
681 | /* Permanent failure */ | 689 | /* Permanent failure */ |
682 | list_move(&page->lru, failed); | ||
683 | nr_failed++; | 690 | nr_failed++; |
684 | break; | 691 | break; |
685 | } | 692 | } |
@@ -689,6 +696,7 @@ int migrate_pages(struct list_head *from, struct list_head *to, | |||
689 | if (!swapwrite) | 696 | if (!swapwrite) |
690 | current->flags &= ~PF_SWAPWRITE; | 697 | current->flags &= ~PF_SWAPWRITE; |
691 | 698 | ||
699 | putback_lru_pages(from); | ||
692 | return nr_failed + retry; | 700 | return nr_failed + retry; |
693 | } | 701 | } |
694 | 702 | ||
@@ -702,11 +710,10 @@ int migrate_pages_to(struct list_head *pagelist, | |||
702 | struct vm_area_struct *vma, int dest) | 710 | struct vm_area_struct *vma, int dest) |
703 | { | 711 | { |
704 | LIST_HEAD(newlist); | 712 | LIST_HEAD(newlist); |
705 | LIST_HEAD(moved); | ||
706 | LIST_HEAD(failed); | ||
707 | int err = 0; | 713 | int err = 0; |
708 | unsigned long offset = 0; | 714 | unsigned long offset = 0; |
709 | int nr_pages; | 715 | int nr_pages; |
716 | int nr_failed = 0; | ||
710 | struct page *page; | 717 | struct page *page; |
711 | struct list_head *p; | 718 | struct list_head *p; |
712 | 719 | ||
@@ -740,26 +747,17 @@ redo: | |||
740 | if (nr_pages > MIGRATE_CHUNK_SIZE) | 747 | if (nr_pages > MIGRATE_CHUNK_SIZE) |
741 | break; | 748 | break; |
742 | } | 749 | } |
743 | err = migrate_pages(pagelist, &newlist, &moved, &failed); | 750 | err = migrate_pages(pagelist, &newlist); |
744 | 751 | ||
745 | putback_lru_pages(&moved); /* Call release pages instead ?? */ | 752 | if (err >= 0) { |
746 | 753 | nr_failed += err; | |
747 | if (err >= 0 && list_empty(&newlist) && !list_empty(pagelist)) | 754 | if (list_empty(&newlist) && !list_empty(pagelist)) |
748 | goto redo; | 755 | goto redo; |
749 | out: | ||
750 | /* Return leftover allocated pages */ | ||
751 | while (!list_empty(&newlist)) { | ||
752 | page = list_entry(newlist.next, struct page, lru); | ||
753 | list_del(&page->lru); | ||
754 | __free_page(page); | ||
755 | } | 756 | } |
756 | list_splice(&failed, pagelist); | 757 | out: |
757 | if (err < 0) | ||
758 | return err; | ||
759 | 758 | ||
760 | /* Calculate number of leftover pages */ | 759 | /* Calculate number of leftover pages */ |
761 | nr_pages = 0; | ||
762 | list_for_each(p, pagelist) | 760 | list_for_each(p, pagelist) |
763 | nr_pages++; | 761 | nr_failed++; |
764 | return nr_pages; | 762 | return nr_failed; |
765 | } | 763 | } |