diff options
author | Mel Gorman <mel@csn.ul.ie> | 2009-06-16 18:31:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 22:47:33 -0400 |
commit | 5117f45d11a9ee62d9b086f1312f3f31781ff155 (patch) | |
tree | 3f7b26f697d14d56be7278bcc4917e4f6d0c2c3d /mm/page_alloc.c | |
parent | 49255c619fbd482d704289b5eb2795f8e3b7ff2e (diff) |
page allocator: calculate the preferred zone for allocation only once
get_page_from_freelist() can be called multiple times for an allocation.
Part of this calculates the preferred_zone which is the first usable zone
in the zonelist but the zone depends on the GFP flags specified at the
beginning of the allocation call. This patch calculates preferred_zone
once. It's safe to do this because if preferred_zone is NULL at the start
of the call, no amount of direct reclaim or other actions will change the
fact the allocation will fail.
[akpm@linux-foundation.org: remove (void) casts]
Signed-off-by: Mel Gorman <mel@csn.ul.ie>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Reviewed-by: Pekka Enberg <penberg@cs.helsinki.fi>
Cc: Christoph Lameter <cl@linux-foundation.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Dave Hansen <dave@linux.vnet.ibm.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index b09859629e93..8fc6d1f42f0b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1388,26 +1388,21 @@ static void zlc_mark_zone_full(struct zonelist *zonelist, struct zoneref *z) | |||
1388 | */ | 1388 | */ |
1389 | static struct page * | 1389 | static struct page * |
1390 | get_page_from_freelist(gfp_t gfp_mask, nodemask_t *nodemask, unsigned int order, | 1390 | get_page_from_freelist(gfp_t gfp_mask, nodemask_t *nodemask, unsigned int order, |
1391 | struct zonelist *zonelist, int high_zoneidx, int alloc_flags) | 1391 | struct zonelist *zonelist, int high_zoneidx, int alloc_flags, |
1392 | struct zone *preferred_zone) | ||
1392 | { | 1393 | { |
1393 | struct zoneref *z; | 1394 | struct zoneref *z; |
1394 | struct page *page = NULL; | 1395 | struct page *page = NULL; |
1395 | int classzone_idx; | 1396 | int classzone_idx; |
1396 | struct zone *zone, *preferred_zone; | 1397 | struct zone *zone; |
1397 | nodemask_t *allowednodes = NULL;/* zonelist_cache approximation */ | 1398 | nodemask_t *allowednodes = NULL;/* zonelist_cache approximation */ |
1398 | int zlc_active = 0; /* set if using zonelist_cache */ | 1399 | int zlc_active = 0; /* set if using zonelist_cache */ |
1399 | int did_zlc_setup = 0; /* just call zlc_setup() one time */ | 1400 | int did_zlc_setup = 0; /* just call zlc_setup() one time */ |
1400 | 1401 | ||
1401 | (void)first_zones_zonelist(zonelist, high_zoneidx, nodemask, | ||
1402 | &preferred_zone); | ||
1403 | if (!preferred_zone) | ||
1404 | return NULL; | ||
1405 | |||
1406 | classzone_idx = zone_idx(preferred_zone); | ||
1407 | |||
1408 | if (WARN_ON_ONCE(order >= MAX_ORDER)) | 1402 | if (WARN_ON_ONCE(order >= MAX_ORDER)) |
1409 | return NULL; | 1403 | return NULL; |
1410 | 1404 | ||
1405 | classzone_idx = zone_idx(preferred_zone); | ||
1411 | zonelist_scan: | 1406 | zonelist_scan: |
1412 | /* | 1407 | /* |
1413 | * Scan zonelist, looking for a zone with enough free. | 1408 | * Scan zonelist, looking for a zone with enough free. |
@@ -1500,7 +1495,7 @@ should_alloc_retry(gfp_t gfp_mask, unsigned int order, | |||
1500 | static inline struct page * | 1495 | static inline struct page * |
1501 | __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, | 1496 | __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, |
1502 | struct zonelist *zonelist, enum zone_type high_zoneidx, | 1497 | struct zonelist *zonelist, enum zone_type high_zoneidx, |
1503 | nodemask_t *nodemask) | 1498 | nodemask_t *nodemask, struct zone *preferred_zone) |
1504 | { | 1499 | { |
1505 | struct page *page; | 1500 | struct page *page; |
1506 | 1501 | ||
@@ -1517,7 +1512,8 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, | |||
1517 | */ | 1512 | */ |
1518 | page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, | 1513 | page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, |
1519 | order, zonelist, high_zoneidx, | 1514 | order, zonelist, high_zoneidx, |
1520 | ALLOC_WMARK_HIGH|ALLOC_CPUSET); | 1515 | ALLOC_WMARK_HIGH|ALLOC_CPUSET, |
1516 | preferred_zone); | ||
1521 | if (page) | 1517 | if (page) |
1522 | goto out; | 1518 | goto out; |
1523 | 1519 | ||
@@ -1537,7 +1533,8 @@ out: | |||
1537 | static inline struct page * | 1533 | static inline struct page * |
1538 | __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, | 1534 | __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, |
1539 | struct zonelist *zonelist, enum zone_type high_zoneidx, | 1535 | struct zonelist *zonelist, enum zone_type high_zoneidx, |
1540 | nodemask_t *nodemask, int alloc_flags, unsigned long *did_some_progress) | 1536 | nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone, |
1537 | unsigned long *did_some_progress) | ||
1541 | { | 1538 | { |
1542 | struct page *page = NULL; | 1539 | struct page *page = NULL; |
1543 | struct reclaim_state reclaim_state; | 1540 | struct reclaim_state reclaim_state; |
@@ -1569,7 +1566,8 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, | |||
1569 | 1566 | ||
1570 | if (likely(*did_some_progress)) | 1567 | if (likely(*did_some_progress)) |
1571 | page = get_page_from_freelist(gfp_mask, nodemask, order, | 1568 | page = get_page_from_freelist(gfp_mask, nodemask, order, |
1572 | zonelist, high_zoneidx, alloc_flags); | 1569 | zonelist, high_zoneidx, |
1570 | alloc_flags, preferred_zone); | ||
1573 | return page; | 1571 | return page; |
1574 | } | 1572 | } |
1575 | 1573 | ||
@@ -1589,13 +1587,14 @@ is_allocation_high_priority(struct task_struct *p, gfp_t gfp_mask) | |||
1589 | static inline struct page * | 1587 | static inline struct page * |
1590 | __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order, | 1588 | __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order, |
1591 | struct zonelist *zonelist, enum zone_type high_zoneidx, | 1589 | struct zonelist *zonelist, enum zone_type high_zoneidx, |
1592 | nodemask_t *nodemask) | 1590 | nodemask_t *nodemask, struct zone *preferred_zone) |
1593 | { | 1591 | { |
1594 | struct page *page; | 1592 | struct page *page; |
1595 | 1593 | ||
1596 | do { | 1594 | do { |
1597 | page = get_page_from_freelist(gfp_mask, nodemask, order, | 1595 | page = get_page_from_freelist(gfp_mask, nodemask, order, |
1598 | zonelist, high_zoneidx, ALLOC_NO_WATERMARKS); | 1596 | zonelist, high_zoneidx, ALLOC_NO_WATERMARKS, |
1597 | preferred_zone); | ||
1599 | 1598 | ||
1600 | if (!page && gfp_mask & __GFP_NOFAIL) | 1599 | if (!page && gfp_mask & __GFP_NOFAIL) |
1601 | congestion_wait(WRITE, HZ/50); | 1600 | congestion_wait(WRITE, HZ/50); |
@@ -1618,7 +1617,7 @@ void wake_all_kswapd(unsigned int order, struct zonelist *zonelist, | |||
1618 | static inline struct page * | 1617 | static inline struct page * |
1619 | __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, | 1618 | __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, |
1620 | struct zonelist *zonelist, enum zone_type high_zoneidx, | 1619 | struct zonelist *zonelist, enum zone_type high_zoneidx, |
1621 | nodemask_t *nodemask) | 1620 | nodemask_t *nodemask, struct zone *preferred_zone) |
1622 | { | 1621 | { |
1623 | const gfp_t wait = gfp_mask & __GFP_WAIT; | 1622 | const gfp_t wait = gfp_mask & __GFP_WAIT; |
1624 | struct page *page = NULL; | 1623 | struct page *page = NULL; |
@@ -1668,7 +1667,8 @@ restart: | |||
1668 | * See also cpuset_zone_allowed() comment in kernel/cpuset.c. | 1667 | * See also cpuset_zone_allowed() comment in kernel/cpuset.c. |
1669 | */ | 1668 | */ |
1670 | page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist, | 1669 | page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist, |
1671 | high_zoneidx, alloc_flags); | 1670 | high_zoneidx, alloc_flags, |
1671 | preferred_zone); | ||
1672 | if (page) | 1672 | if (page) |
1673 | goto got_pg; | 1673 | goto got_pg; |
1674 | 1674 | ||
@@ -1678,7 +1678,7 @@ rebalance: | |||
1678 | /* Do not dip into emergency reserves if specified */ | 1678 | /* Do not dip into emergency reserves if specified */ |
1679 | if (!(gfp_mask & __GFP_NOMEMALLOC)) { | 1679 | if (!(gfp_mask & __GFP_NOMEMALLOC)) { |
1680 | page = __alloc_pages_high_priority(gfp_mask, order, | 1680 | page = __alloc_pages_high_priority(gfp_mask, order, |
1681 | zonelist, high_zoneidx, nodemask); | 1681 | zonelist, high_zoneidx, nodemask, preferred_zone); |
1682 | if (page) | 1682 | if (page) |
1683 | goto got_pg; | 1683 | goto got_pg; |
1684 | } | 1684 | } |
@@ -1695,7 +1695,8 @@ rebalance: | |||
1695 | page = __alloc_pages_direct_reclaim(gfp_mask, order, | 1695 | page = __alloc_pages_direct_reclaim(gfp_mask, order, |
1696 | zonelist, high_zoneidx, | 1696 | zonelist, high_zoneidx, |
1697 | nodemask, | 1697 | nodemask, |
1698 | alloc_flags, &did_some_progress); | 1698 | alloc_flags, preferred_zone, |
1699 | &did_some_progress); | ||
1699 | if (page) | 1700 | if (page) |
1700 | goto got_pg; | 1701 | goto got_pg; |
1701 | 1702 | ||
@@ -1707,7 +1708,7 @@ rebalance: | |||
1707 | if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) { | 1708 | if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) { |
1708 | page = __alloc_pages_may_oom(gfp_mask, order, | 1709 | page = __alloc_pages_may_oom(gfp_mask, order, |
1709 | zonelist, high_zoneidx, | 1710 | zonelist, high_zoneidx, |
1710 | nodemask); | 1711 | nodemask, preferred_zone); |
1711 | if (page) | 1712 | if (page) |
1712 | goto got_pg; | 1713 | goto got_pg; |
1713 | 1714 | ||
@@ -1752,6 +1753,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, | |||
1752 | struct zonelist *zonelist, nodemask_t *nodemask) | 1753 | struct zonelist *zonelist, nodemask_t *nodemask) |
1753 | { | 1754 | { |
1754 | enum zone_type high_zoneidx = gfp_zone(gfp_mask); | 1755 | enum zone_type high_zoneidx = gfp_zone(gfp_mask); |
1756 | struct zone *preferred_zone; | ||
1755 | struct page *page; | 1757 | struct page *page; |
1756 | 1758 | ||
1757 | lockdep_trace_alloc(gfp_mask); | 1759 | lockdep_trace_alloc(gfp_mask); |
@@ -1769,11 +1771,19 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, | |||
1769 | if (unlikely(!zonelist->_zonerefs->zone)) | 1771 | if (unlikely(!zonelist->_zonerefs->zone)) |
1770 | return NULL; | 1772 | return NULL; |
1771 | 1773 | ||
1774 | /* The preferred zone is used for statistics later */ | ||
1775 | first_zones_zonelist(zonelist, high_zoneidx, nodemask, &preferred_zone); | ||
1776 | if (!preferred_zone) | ||
1777 | return NULL; | ||
1778 | |||
1779 | /* First allocation attempt */ | ||
1772 | page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order, | 1780 | page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order, |
1773 | zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET); | 1781 | zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET, |
1782 | preferred_zone); | ||
1774 | if (unlikely(!page)) | 1783 | if (unlikely(!page)) |
1775 | page = __alloc_pages_slowpath(gfp_mask, order, | 1784 | page = __alloc_pages_slowpath(gfp_mask, order, |
1776 | zonelist, high_zoneidx, nodemask); | 1785 | zonelist, high_zoneidx, nodemask, |
1786 | preferred_zone); | ||
1777 | 1787 | ||
1778 | return page; | 1788 | return page; |
1779 | } | 1789 | } |