aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Lameter <clameter@sgi.com>2006-06-23 05:03:53 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-23 10:42:53 -0400
commit95a402c3847cc16f4ba03013cd01404fa0f14c2e (patch)
tree0fd9b3379f70cc99b2325bccaa150089abf6c8b3
parentaaa994b300a172afafab47938804836b923e5ef7 (diff)
[PATCH] page migration: use allocator function for migrate_pages()
Instead of passing a list of new pages, pass a function to allocate a new page. This allows the correct placement of MPOL_INTERLEAVE pages during page migration. It also further simplifies the callers of migrate pages. migrate_pages() becomes similar to migrate_pages_to() so drop migrate_pages_to(). The batching of new page allocations becomes unnecessary. 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.h11
-rw-r--r--mm/mempolicy.c23
-rw-r--r--mm/migrate.c115
3 files changed, 59 insertions, 90 deletions
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 83af25949fa9..5b95d6568dc4 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -3,14 +3,15 @@
3 3
4#include <linux/mm.h> 4#include <linux/mm.h>
5 5
6typedef struct page *new_page_t(struct page *, unsigned long private);
7
6#ifdef CONFIG_MIGRATION 8#ifdef CONFIG_MIGRATION
7extern int isolate_lru_page(struct page *p, struct list_head *pagelist); 9extern int isolate_lru_page(struct page *p, struct list_head *pagelist);
8extern int putback_lru_pages(struct list_head *l); 10extern int putback_lru_pages(struct list_head *l);
9extern int migrate_page(struct address_space *, 11extern int migrate_page(struct address_space *,
10 struct page *, struct page *); 12 struct page *, struct page *);
11extern int migrate_pages(struct list_head *l, struct list_head *t); 13extern int migrate_pages(struct list_head *l, new_page_t x, unsigned long);
12extern int migrate_pages_to(struct list_head *pagelist, 14
13 struct vm_area_struct *vma, int dest);
14extern int fail_migrate_page(struct address_space *, 15extern int fail_migrate_page(struct address_space *,
15 struct page *, struct page *); 16 struct page *, struct page *);
16 17
@@ -21,8 +22,8 @@ extern int migrate_prep(void);
21static inline int isolate_lru_page(struct page *p, struct list_head *list) 22static inline int isolate_lru_page(struct page *p, struct list_head *list)
22 { return -ENOSYS; } 23 { return -ENOSYS; }
23static inline int putback_lru_pages(struct list_head *l) { return 0; } 24static inline int putback_lru_pages(struct list_head *l) { return 0; }
24static inline int migrate_pages(struct list_head *l, struct list_head *t) 25static inline int migrate_pages(struct list_head *l, new_page_t x,
25 { return -ENOSYS; } 26 unsigned long private) { return -ENOSYS; }
26 27
27static inline int migrate_pages_to(struct list_head *pagelist, 28static inline int migrate_pages_to(struct list_head *pagelist,
28 struct vm_area_struct *vma, int dest) { return 0; } 29 struct vm_area_struct *vma, int dest) { return 0; }
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 244f3f130e4a..f432642e9e66 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -87,6 +87,7 @@
87#include <linux/seq_file.h> 87#include <linux/seq_file.h>
88#include <linux/proc_fs.h> 88#include <linux/proc_fs.h>
89#include <linux/migrate.h> 89#include <linux/migrate.h>
90#include <linux/rmap.h>
90 91
91#include <asm/tlbflush.h> 92#include <asm/tlbflush.h>
92#include <asm/uaccess.h> 93#include <asm/uaccess.h>
@@ -587,6 +588,11 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist,
587 isolate_lru_page(page, pagelist); 588 isolate_lru_page(page, pagelist);
588} 589}
589 590
591static struct page *new_node_page(struct page *page, unsigned long node)
592{
593 return alloc_pages_node(node, GFP_HIGHUSER, 0);
594}
595
590/* 596/*
591 * Migrate pages from one node to a target node. 597 * Migrate pages from one node to a target node.
592 * Returns error or the number of pages not migrated. 598 * Returns error or the number of pages not migrated.
@@ -604,7 +610,8 @@ int migrate_to_node(struct mm_struct *mm, int source, int dest, int flags)
604 flags | MPOL_MF_DISCONTIG_OK, &pagelist); 610 flags | MPOL_MF_DISCONTIG_OK, &pagelist);
605 611
606 if (!list_empty(&pagelist)) 612 if (!list_empty(&pagelist))
607 err = migrate_pages_to(&pagelist, NULL, dest); 613 err = migrate_pages(&pagelist, new_node_page, dest);
614
608 return err; 615 return err;
609} 616}
610 617
@@ -691,6 +698,12 @@ int do_migrate_pages(struct mm_struct *mm,
691 698
692} 699}
693 700
701static struct page *new_vma_page(struct page *page, unsigned long private)
702{
703 struct vm_area_struct *vma = (struct vm_area_struct *)private;
704
705 return alloc_page_vma(GFP_HIGHUSER, vma, page_address_in_vma(page, vma));
706}
694#else 707#else
695 708
696static void migrate_page_add(struct page *page, struct list_head *pagelist, 709static void migrate_page_add(struct page *page, struct list_head *pagelist,
@@ -703,6 +716,11 @@ int do_migrate_pages(struct mm_struct *mm,
703{ 716{
704 return -ENOSYS; 717 return -ENOSYS;
705} 718}
719
720static struct page *new_vma_page(struct page *page, unsigned long private)
721{
722 return NULL;
723}
706#endif 724#endif
707 725
708long do_mbind(unsigned long start, unsigned long len, 726long do_mbind(unsigned long start, unsigned long len,
@@ -764,7 +782,8 @@ long do_mbind(unsigned long start, unsigned long len,
764 err = mbind_range(vma, start, end, new); 782 err = mbind_range(vma, start, end, new);
765 783
766 if (!list_empty(&pagelist)) 784 if (!list_empty(&pagelist))
767 nr_failed = migrate_pages_to(&pagelist, vma, -1); 785 nr_failed = migrate_pages(&pagelist, new_vma_page,
786 (unsigned long)vma);
768 787
769 if (!err && nr_failed && (flags & MPOL_MF_STRICT)) 788 if (!err && nr_failed && (flags & MPOL_MF_STRICT))
770 err = -EIO; 789 err = -EIO;
diff --git a/mm/migrate.c b/mm/migrate.c
index d3a1810a4c9f..251a8d158257 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -28,9 +28,6 @@
28 28
29#include "internal.h" 29#include "internal.h"
30 30
31/* The maximum number of pages to take off the LRU for migration */
32#define MIGRATE_CHUNK_SIZE 256
33
34#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru)) 31#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
35 32
36/* 33/*
@@ -587,18 +584,23 @@ static int move_to_new_page(struct page *newpage, struct page *page)
587 * Obtain the lock on page, remove all ptes and migrate the page 584 * Obtain the lock on page, remove all ptes and migrate the page
588 * to the newly allocated page in newpage. 585 * to the newly allocated page in newpage.
589 */ 586 */
590static int unmap_and_move(struct page *newpage, struct page *page, int force) 587static int unmap_and_move(new_page_t get_new_page, unsigned long private,
588 struct page *page, int force)
591{ 589{
592 int rc = 0; 590 int rc = 0;
591 struct page *newpage = get_new_page(page, private);
592
593 if (!newpage)
594 return -ENOMEM;
593 595
594 if (page_count(page) == 1) 596 if (page_count(page) == 1)
595 /* page was freed from under us. So we are done. */ 597 /* page was freed from under us. So we are done. */
596 goto ret; 598 goto move_newpage;
597 599
598 rc = -EAGAIN; 600 rc = -EAGAIN;
599 if (TestSetPageLocked(page)) { 601 if (TestSetPageLocked(page)) {
600 if (!force) 602 if (!force)
601 goto ret; 603 goto move_newpage;
602 lock_page(page); 604 lock_page(page);
603 } 605 }
604 606
@@ -622,7 +624,7 @@ static int unmap_and_move(struct page *newpage, struct page *page, int force)
622 remove_migration_ptes(page, page); 624 remove_migration_ptes(page, page);
623unlock: 625unlock:
624 unlock_page(page); 626 unlock_page(page);
625ret: 627
626 if (rc != -EAGAIN) { 628 if (rc != -EAGAIN) {
627 /* 629 /*
628 * A page that has been migrated has all references 630 * A page that has been migrated has all references
@@ -632,29 +634,33 @@ ret:
632 */ 634 */
633 list_del(&page->lru); 635 list_del(&page->lru);
634 move_to_lru(page); 636 move_to_lru(page);
635
636 list_del(&newpage->lru);
637 move_to_lru(newpage);
638 } 637 }
638
639move_newpage:
640 /*
641 * Move the new page to the LRU. If migration was not successful
642 * then this will free the page.
643 */
644 move_to_lru(newpage);
639 return rc; 645 return rc;
640} 646}
641 647
642/* 648/*
643 * migrate_pages 649 * migrate_pages
644 * 650 *
645 * Two lists are passed to this function. The first list 651 * The function takes one list of pages to migrate and a function
646 * contains the pages isolated from the LRU to be migrated. 652 * that determines from the page to be migrated and the private data
647 * The second list contains new pages that the isolated pages 653 * the target of the move and allocates the page.
648 * can be moved to.
649 * 654 *
650 * The function returns after 10 attempts or if no pages 655 * The function returns after 10 attempts or if no pages
651 * are movable anymore because to has become empty 656 * are movable anymore because to has become empty
652 * or no retryable pages exist anymore. All pages will be 657 * or no retryable pages exist anymore. All pages will be
653 * retruned to the LRU or freed. 658 * retruned to the LRU or freed.
654 * 659 *
655 * Return: Number of pages not migrated. 660 * Return: Number of pages not migrated or error code.
656 */ 661 */
657int migrate_pages(struct list_head *from, struct list_head *to) 662int migrate_pages(struct list_head *from,
663 new_page_t get_new_page, unsigned long private)
658{ 664{
659 int retry = 1; 665 int retry = 1;
660 int nr_failed = 0; 666 int nr_failed = 0;
@@ -671,15 +677,14 @@ int migrate_pages(struct list_head *from, struct list_head *to)
671 retry = 0; 677 retry = 0;
672 678
673 list_for_each_entry_safe(page, page2, from, lru) { 679 list_for_each_entry_safe(page, page2, from, lru) {
674
675 if (list_empty(to))
676 break;
677
678 cond_resched(); 680 cond_resched();
679 681
680 rc = unmap_and_move(lru_to_page(to), page, pass > 2); 682 rc = unmap_and_move(get_new_page, private,
683 page, pass > 2);
681 684
682 switch(rc) { 685 switch(rc) {
686 case -ENOMEM:
687 goto out;
683 case -EAGAIN: 688 case -EAGAIN:
684 retry++; 689 retry++;
685 break; 690 break;
@@ -692,72 +697,16 @@ int migrate_pages(struct list_head *from, struct list_head *to)
692 } 697 }
693 } 698 }
694 } 699 }
695 700 rc = 0;
701out:
696 if (!swapwrite) 702 if (!swapwrite)
697 current->flags &= ~PF_SWAPWRITE; 703 current->flags &= ~PF_SWAPWRITE;
698 704
699 putback_lru_pages(from); 705 putback_lru_pages(from);
700 return nr_failed + retry;
701}
702 706
703/* 707 if (rc)
704 * Migrate the list 'pagelist' of pages to a certain destination. 708 return rc;
705 *
706 * Specify destination with either non-NULL vma or dest_node >= 0
707 * Return the number of pages not migrated or error code
708 */
709int migrate_pages_to(struct list_head *pagelist,
710 struct vm_area_struct *vma, int dest)
711{
712 LIST_HEAD(newlist);
713 int err = 0;
714 unsigned long offset = 0;
715 int nr_pages;
716 int nr_failed = 0;
717 struct page *page;
718 struct list_head *p;
719
720redo:
721 nr_pages = 0;
722 list_for_each(p, pagelist) {
723 if (vma) {
724 /*
725 * The address passed to alloc_page_vma is used to
726 * generate the proper interleave behavior. We fake
727 * the address here by an increasing offset in order
728 * to get the proper distribution of pages.
729 *
730 * No decision has been made as to which page
731 * a certain old page is moved to so we cannot
732 * specify the correct address.
733 */
734 page = alloc_page_vma(GFP_HIGHUSER, vma,
735 offset + vma->vm_start);
736 offset += PAGE_SIZE;
737 }
738 else
739 page = alloc_pages_node(dest, GFP_HIGHUSER, 0);
740
741 if (!page) {
742 err = -ENOMEM;
743 goto out;
744 }
745 list_add_tail(&page->lru, &newlist);
746 nr_pages++;
747 if (nr_pages > MIGRATE_CHUNK_SIZE)
748 break;
749 }
750 err = migrate_pages(pagelist, &newlist);
751
752 if (err >= 0) {
753 nr_failed += err;
754 if (list_empty(&newlist) && !list_empty(pagelist))
755 goto redo;
756 }
757out:
758 709
759 /* Calculate number of leftover pages */ 710 return nr_failed + retry;
760 list_for_each(p, pagelist)
761 nr_failed++;
762 return nr_failed;
763} 711}
712