diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
commit | 1ebbe2b20091d306453a5cf480a87e6cd28ae76f (patch) | |
tree | f5cd7a0fa69b8b1938cb5a0faed2e7b0628072a5 /mm/page_alloc.c | |
parent | ac58c9059da8886b5e8cde012a80266b18ca146e (diff) | |
parent | 674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff) |
Merge branch 'linus'
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 113 |
1 files changed, 64 insertions, 49 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 234bd4895d14..b7f14a4799a5 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -55,7 +55,6 @@ unsigned long totalhigh_pages __read_mostly; | |||
55 | long nr_swap_pages; | 55 | long nr_swap_pages; |
56 | int percpu_pagelist_fraction; | 56 | int percpu_pagelist_fraction; |
57 | 57 | ||
58 | static void fastcall free_hot_cold_page(struct page *page, int cold); | ||
59 | static void __free_pages_ok(struct page *page, unsigned int order); | 58 | static void __free_pages_ok(struct page *page, unsigned int order); |
60 | 59 | ||
61 | /* | 60 | /* |
@@ -190,7 +189,7 @@ static void prep_compound_page(struct page *page, unsigned long order) | |||
190 | for (i = 0; i < nr_pages; i++) { | 189 | for (i = 0; i < nr_pages; i++) { |
191 | struct page *p = page + i; | 190 | struct page *p = page + i; |
192 | 191 | ||
193 | SetPageCompound(p); | 192 | __SetPageCompound(p); |
194 | set_page_private(p, (unsigned long)page); | 193 | set_page_private(p, (unsigned long)page); |
195 | } | 194 | } |
196 | } | 195 | } |
@@ -209,10 +208,24 @@ static void destroy_compound_page(struct page *page, unsigned long order) | |||
209 | if (unlikely(!PageCompound(p) | | 208 | if (unlikely(!PageCompound(p) | |
210 | (page_private(p) != (unsigned long)page))) | 209 | (page_private(p) != (unsigned long)page))) |
211 | bad_page(page); | 210 | bad_page(page); |
212 | ClearPageCompound(p); | 211 | __ClearPageCompound(p); |
213 | } | 212 | } |
214 | } | 213 | } |
215 | 214 | ||
215 | static inline void prep_zero_page(struct page *page, int order, gfp_t gfp_flags) | ||
216 | { | ||
217 | int i; | ||
218 | |||
219 | BUG_ON((gfp_flags & (__GFP_WAIT | __GFP_HIGHMEM)) == __GFP_HIGHMEM); | ||
220 | /* | ||
221 | * clear_highpage() will use KM_USER0, so it's a bug to use __GFP_ZERO | ||
222 | * and __GFP_HIGHMEM from hard or soft interrupt context. | ||
223 | */ | ||
224 | BUG_ON((gfp_flags & __GFP_HIGHMEM) && in_interrupt()); | ||
225 | for (i = 0; i < (1 << order); i++) | ||
226 | clear_highpage(page + i); | ||
227 | } | ||
228 | |||
216 | /* | 229 | /* |
217 | * function for dealing with page's order in buddy system. | 230 | * function for dealing with page's order in buddy system. |
218 | * zone->lock is already acquired when we use these. | 231 | * zone->lock is already acquired when we use these. |
@@ -423,11 +436,6 @@ static void __free_pages_ok(struct page *page, unsigned int order) | |||
423 | mutex_debug_check_no_locks_freed(page_address(page), | 436 | mutex_debug_check_no_locks_freed(page_address(page), |
424 | PAGE_SIZE<<order); | 437 | PAGE_SIZE<<order); |
425 | 438 | ||
426 | #ifndef CONFIG_MMU | ||
427 | for (i = 1 ; i < (1 << order) ; ++i) | ||
428 | __put_page(page + i); | ||
429 | #endif | ||
430 | |||
431 | for (i = 0 ; i < (1 << order) ; ++i) | 439 | for (i = 0 ; i < (1 << order) ; ++i) |
432 | reserved += free_pages_check(page + i); | 440 | reserved += free_pages_check(page + i); |
433 | if (reserved) | 441 | if (reserved) |
@@ -448,28 +456,23 @@ void fastcall __init __free_pages_bootmem(struct page *page, unsigned int order) | |||
448 | if (order == 0) { | 456 | if (order == 0) { |
449 | __ClearPageReserved(page); | 457 | __ClearPageReserved(page); |
450 | set_page_count(page, 0); | 458 | set_page_count(page, 0); |
451 | 459 | set_page_refcounted(page); | |
452 | free_hot_cold_page(page, 0); | 460 | __free_page(page); |
453 | } else { | 461 | } else { |
454 | LIST_HEAD(list); | ||
455 | int loop; | 462 | int loop; |
456 | 463 | ||
464 | prefetchw(page); | ||
457 | for (loop = 0; loop < BITS_PER_LONG; loop++) { | 465 | for (loop = 0; loop < BITS_PER_LONG; loop++) { |
458 | struct page *p = &page[loop]; | 466 | struct page *p = &page[loop]; |
459 | 467 | ||
460 | if (loop + 16 < BITS_PER_LONG) | 468 | if (loop + 1 < BITS_PER_LONG) |
461 | prefetchw(p + 16); | 469 | prefetchw(p + 1); |
462 | __ClearPageReserved(p); | 470 | __ClearPageReserved(p); |
463 | set_page_count(p, 0); | 471 | set_page_count(p, 0); |
464 | } | 472 | } |
465 | 473 | ||
466 | arch_free_page(page, order); | 474 | set_page_refcounted(page); |
467 | 475 | __free_pages(page, order); | |
468 | mod_page_state(pgfree, 1 << order); | ||
469 | |||
470 | list_add(&page->lru, &list); | ||
471 | kernel_map_pages(page, 1 << order, 0); | ||
472 | free_pages_bulk(page_zone(page), 1, &list, order); | ||
473 | } | 476 | } |
474 | } | 477 | } |
475 | 478 | ||
@@ -507,7 +510,7 @@ static inline void expand(struct zone *zone, struct page *page, | |||
507 | /* | 510 | /* |
508 | * This page is about to be returned from the page allocator | 511 | * This page is about to be returned from the page allocator |
509 | */ | 512 | */ |
510 | static int prep_new_page(struct page *page, int order) | 513 | static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) |
511 | { | 514 | { |
512 | if (unlikely(page_mapcount(page) | | 515 | if (unlikely(page_mapcount(page) | |
513 | (page->mapping != NULL) | | 516 | (page->mapping != NULL) | |
@@ -536,8 +539,15 @@ static int prep_new_page(struct page *page, int order) | |||
536 | 1 << PG_referenced | 1 << PG_arch_1 | | 539 | 1 << PG_referenced | 1 << PG_arch_1 | |
537 | 1 << PG_checked | 1 << PG_mappedtodisk); | 540 | 1 << PG_checked | 1 << PG_mappedtodisk); |
538 | set_page_private(page, 0); | 541 | set_page_private(page, 0); |
539 | set_page_refs(page, order); | 542 | set_page_refcounted(page); |
540 | kernel_map_pages(page, 1 << order, 1); | 543 | kernel_map_pages(page, 1 << order, 1); |
544 | |||
545 | if (gfp_flags & __GFP_ZERO) | ||
546 | prep_zero_page(page, order, gfp_flags); | ||
547 | |||
548 | if (order && (gfp_flags & __GFP_COMP)) | ||
549 | prep_compound_page(page, order); | ||
550 | |||
541 | return 0; | 551 | return 0; |
542 | } | 552 | } |
543 | 553 | ||
@@ -593,13 +603,14 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, | |||
593 | /* | 603 | /* |
594 | * Called from the slab reaper to drain pagesets on a particular node that | 604 | * Called from the slab reaper to drain pagesets on a particular node that |
595 | * belong to the currently executing processor. | 605 | * belong to the currently executing processor. |
606 | * Note that this function must be called with the thread pinned to | ||
607 | * a single processor. | ||
596 | */ | 608 | */ |
597 | void drain_node_pages(int nodeid) | 609 | void drain_node_pages(int nodeid) |
598 | { | 610 | { |
599 | int i, z; | 611 | int i, z; |
600 | unsigned long flags; | 612 | unsigned long flags; |
601 | 613 | ||
602 | local_irq_save(flags); | ||
603 | for (z = 0; z < MAX_NR_ZONES; z++) { | 614 | for (z = 0; z < MAX_NR_ZONES; z++) { |
604 | struct zone *zone = NODE_DATA(nodeid)->node_zones + z; | 615 | struct zone *zone = NODE_DATA(nodeid)->node_zones + z; |
605 | struct per_cpu_pageset *pset; | 616 | struct per_cpu_pageset *pset; |
@@ -609,11 +620,14 @@ void drain_node_pages(int nodeid) | |||
609 | struct per_cpu_pages *pcp; | 620 | struct per_cpu_pages *pcp; |
610 | 621 | ||
611 | pcp = &pset->pcp[i]; | 622 | pcp = &pset->pcp[i]; |
612 | free_pages_bulk(zone, pcp->count, &pcp->list, 0); | 623 | if (pcp->count) { |
613 | pcp->count = 0; | 624 | local_irq_save(flags); |
625 | free_pages_bulk(zone, pcp->count, &pcp->list, 0); | ||
626 | pcp->count = 0; | ||
627 | local_irq_restore(flags); | ||
628 | } | ||
614 | } | 629 | } |
615 | } | 630 | } |
616 | local_irq_restore(flags); | ||
617 | } | 631 | } |
618 | #endif | 632 | #endif |
619 | 633 | ||
@@ -743,13 +757,22 @@ void fastcall free_cold_page(struct page *page) | |||
743 | free_hot_cold_page(page, 1); | 757 | free_hot_cold_page(page, 1); |
744 | } | 758 | } |
745 | 759 | ||
746 | static inline void prep_zero_page(struct page *page, int order, gfp_t gfp_flags) | 760 | /* |
761 | * split_page takes a non-compound higher-order page, and splits it into | ||
762 | * n (1<<order) sub-pages: page[0..n] | ||
763 | * Each sub-page must be freed individually. | ||
764 | * | ||
765 | * Note: this is probably too low level an operation for use in drivers. | ||
766 | * Please consult with lkml before using this in your driver. | ||
767 | */ | ||
768 | void split_page(struct page *page, unsigned int order) | ||
747 | { | 769 | { |
748 | int i; | 770 | int i; |
749 | 771 | ||
750 | BUG_ON((gfp_flags & (__GFP_WAIT | __GFP_HIGHMEM)) == __GFP_HIGHMEM); | 772 | BUG_ON(PageCompound(page)); |
751 | for(i = 0; i < (1 << order); i++) | 773 | BUG_ON(!page_count(page)); |
752 | clear_highpage(page + i); | 774 | for (i = 1; i < (1 << order); i++) |
775 | set_page_refcounted(page + i); | ||
753 | } | 776 | } |
754 | 777 | ||
755 | /* | 778 | /* |
@@ -795,14 +818,8 @@ again: | |||
795 | put_cpu(); | 818 | put_cpu(); |
796 | 819 | ||
797 | BUG_ON(bad_range(zone, page)); | 820 | BUG_ON(bad_range(zone, page)); |
798 | if (prep_new_page(page, order)) | 821 | if (prep_new_page(page, order, gfp_flags)) |
799 | goto again; | 822 | goto again; |
800 | |||
801 | if (gfp_flags & __GFP_ZERO) | ||
802 | prep_zero_page(page, order, gfp_flags); | ||
803 | |||
804 | if (order && (gfp_flags & __GFP_COMP)) | ||
805 | prep_compound_page(page, order); | ||
806 | return page; | 823 | return page; |
807 | 824 | ||
808 | failed: | 825 | failed: |
@@ -1214,24 +1231,22 @@ DEFINE_PER_CPU(long, nr_pagecache_local) = 0; | |||
1214 | 1231 | ||
1215 | static void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask) | 1232 | static void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask) |
1216 | { | 1233 | { |
1217 | int cpu = 0; | 1234 | unsigned cpu; |
1218 | 1235 | ||
1219 | memset(ret, 0, nr * sizeof(unsigned long)); | 1236 | memset(ret, 0, nr * sizeof(unsigned long)); |
1220 | cpus_and(*cpumask, *cpumask, cpu_online_map); | 1237 | cpus_and(*cpumask, *cpumask, cpu_online_map); |
1221 | 1238 | ||
1222 | cpu = first_cpu(*cpumask); | 1239 | for_each_cpu_mask(cpu, *cpumask) { |
1223 | while (cpu < NR_CPUS) { | 1240 | unsigned long *in; |
1224 | unsigned long *in, *out, off; | 1241 | unsigned long *out; |
1225 | 1242 | unsigned off; | |
1226 | if (!cpu_isset(cpu, *cpumask)) | 1243 | unsigned next_cpu; |
1227 | continue; | ||
1228 | 1244 | ||
1229 | in = (unsigned long *)&per_cpu(page_states, cpu); | 1245 | in = (unsigned long *)&per_cpu(page_states, cpu); |
1230 | 1246 | ||
1231 | cpu = next_cpu(cpu, *cpumask); | 1247 | next_cpu = next_cpu(cpu, *cpumask); |
1232 | 1248 | if (likely(next_cpu < NR_CPUS)) | |
1233 | if (likely(cpu < NR_CPUS)) | 1249 | prefetch(&per_cpu(page_states, next_cpu)); |
1234 | prefetch(&per_cpu(page_states, cpu)); | ||
1235 | 1250 | ||
1236 | out = (unsigned long *)ret; | 1251 | out = (unsigned long *)ret; |
1237 | for (off = 0; off < nr; off++) | 1252 | for (off = 0; off < nr; off++) |
@@ -1764,7 +1779,7 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, | |||
1764 | continue; | 1779 | continue; |
1765 | page = pfn_to_page(pfn); | 1780 | page = pfn_to_page(pfn); |
1766 | set_page_links(page, zone, nid, pfn); | 1781 | set_page_links(page, zone, nid, pfn); |
1767 | set_page_count(page, 1); | 1782 | init_page_count(page); |
1768 | reset_page_mapcount(page); | 1783 | reset_page_mapcount(page); |
1769 | SetPageReserved(page); | 1784 | SetPageReserved(page); |
1770 | INIT_LIST_HEAD(&page->lru); | 1785 | INIT_LIST_HEAD(&page->lru); |