diff options
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r-- | mm/mempolicy.c | 44 |
1 files changed, 35 insertions, 9 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 3bd7fb7e4b75..67af4cea1e23 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -132,19 +132,29 @@ static int mpol_check_policy(int mode, nodemask_t *nodes) | |||
132 | } | 132 | } |
133 | return nodes_subset(*nodes, node_online_map) ? 0 : -EINVAL; | 133 | return nodes_subset(*nodes, node_online_map) ? 0 : -EINVAL; |
134 | } | 134 | } |
135 | |||
135 | /* Generate a custom zonelist for the BIND policy. */ | 136 | /* Generate a custom zonelist for the BIND policy. */ |
136 | static struct zonelist *bind_zonelist(nodemask_t *nodes) | 137 | static struct zonelist *bind_zonelist(nodemask_t *nodes) |
137 | { | 138 | { |
138 | struct zonelist *zl; | 139 | struct zonelist *zl; |
139 | int num, max, nd; | 140 | int num, max, nd, k; |
140 | 141 | ||
141 | max = 1 + MAX_NR_ZONES * nodes_weight(*nodes); | 142 | max = 1 + MAX_NR_ZONES * nodes_weight(*nodes); |
142 | zl = kmalloc(sizeof(void *) * max, GFP_KERNEL); | 143 | zl = kmalloc(sizeof(struct zone *) * max, GFP_KERNEL); |
143 | if (!zl) | 144 | if (!zl) |
144 | return NULL; | 145 | return NULL; |
145 | num = 0; | 146 | num = 0; |
146 | for_each_node_mask(nd, *nodes) | 147 | /* First put in the highest zones from all nodes, then all the next |
147 | zl->zones[num++] = &NODE_DATA(nd)->node_zones[policy_zone]; | 148 | lower zones etc. Avoid empty zones because the memory allocator |
149 | doesn't like them. If you implement node hot removal you | ||
150 | have to fix that. */ | ||
151 | for (k = policy_zone; k >= 0; k--) { | ||
152 | for_each_node_mask(nd, *nodes) { | ||
153 | struct zone *z = &NODE_DATA(nd)->node_zones[k]; | ||
154 | if (z->present_pages > 0) | ||
155 | zl->zones[num++] = z; | ||
156 | } | ||
157 | } | ||
148 | zl->zones[num] = NULL; | 158 | zl->zones[num] = NULL; |
149 | return zl; | 159 | return zl; |
150 | } | 160 | } |
@@ -542,7 +552,7 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist, | |||
542 | */ | 552 | */ |
543 | if ((flags & MPOL_MF_MOVE_ALL) || page_mapcount(page) == 1) { | 553 | if ((flags & MPOL_MF_MOVE_ALL) || page_mapcount(page) == 1) { |
544 | if (isolate_lru_page(page)) | 554 | if (isolate_lru_page(page)) |
545 | list_add(&page->lru, pagelist); | 555 | list_add_tail(&page->lru, pagelist); |
546 | } | 556 | } |
547 | } | 557 | } |
548 | 558 | ||
@@ -559,6 +569,7 @@ static int migrate_pages_to(struct list_head *pagelist, | |||
559 | LIST_HEAD(moved); | 569 | LIST_HEAD(moved); |
560 | LIST_HEAD(failed); | 570 | LIST_HEAD(failed); |
561 | int err = 0; | 571 | int err = 0; |
572 | unsigned long offset = 0; | ||
562 | int nr_pages; | 573 | int nr_pages; |
563 | struct page *page; | 574 | struct page *page; |
564 | struct list_head *p; | 575 | struct list_head *p; |
@@ -566,8 +577,21 @@ static int migrate_pages_to(struct list_head *pagelist, | |||
566 | redo: | 577 | redo: |
567 | nr_pages = 0; | 578 | nr_pages = 0; |
568 | list_for_each(p, pagelist) { | 579 | list_for_each(p, pagelist) { |
569 | if (vma) | 580 | if (vma) { |
570 | page = alloc_page_vma(GFP_HIGHUSER, vma, vma->vm_start); | 581 | /* |
582 | * The address passed to alloc_page_vma is used to | ||
583 | * generate the proper interleave behavior. We fake | ||
584 | * the address here by an increasing offset in order | ||
585 | * to get the proper distribution of pages. | ||
586 | * | ||
587 | * No decision has been made as to which page | ||
588 | * a certain old page is moved to so we cannot | ||
589 | * specify the correct address. | ||
590 | */ | ||
591 | page = alloc_page_vma(GFP_HIGHUSER, vma, | ||
592 | offset + vma->vm_start); | ||
593 | offset += PAGE_SIZE; | ||
594 | } | ||
571 | else | 595 | else |
572 | page = alloc_pages_node(dest, GFP_HIGHUSER, 0); | 596 | page = alloc_pages_node(dest, GFP_HIGHUSER, 0); |
573 | 597 | ||
@@ -575,9 +599,9 @@ redo: | |||
575 | err = -ENOMEM; | 599 | err = -ENOMEM; |
576 | goto out; | 600 | goto out; |
577 | } | 601 | } |
578 | list_add(&page->lru, &newlist); | 602 | list_add_tail(&page->lru, &newlist); |
579 | nr_pages++; | 603 | nr_pages++; |
580 | if (nr_pages > MIGRATE_CHUNK_SIZE); | 604 | if (nr_pages > MIGRATE_CHUNK_SIZE) |
581 | break; | 605 | break; |
582 | } | 606 | } |
583 | err = migrate_pages(pagelist, &newlist, &moved, &failed); | 607 | err = migrate_pages(pagelist, &newlist, &moved, &failed); |
@@ -798,6 +822,8 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask, | |||
798 | nodes_clear(*nodes); | 822 | nodes_clear(*nodes); |
799 | if (maxnode == 0 || !nmask) | 823 | if (maxnode == 0 || !nmask) |
800 | return 0; | 824 | return 0; |
825 | if (maxnode > PAGE_SIZE*BITS_PER_BYTE) | ||
826 | return -EINVAL; | ||
801 | 827 | ||
802 | nlongs = BITS_TO_LONGS(maxnode); | 828 | nlongs = BITS_TO_LONGS(maxnode); |
803 | if ((maxnode % BITS_PER_LONG) == 0) | 829 | if ((maxnode % BITS_PER_LONG) == 0) |