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 /mm/migrate.c | |
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>
Diffstat (limited to 'mm/migrate.c')
-rw-r--r-- | mm/migrate.c | 48 |
1 files changed, 23 insertions, 25 deletions
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 | } |