aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Lameter <clameter@sgi.com>2006-09-26 02:31:17 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:48:47 -0400
commit4e4785bcf0c8503224fa6c17d8e0228de781bff6 (patch)
tree002c0a051f7f4de4548ca0a8394b664f64c63627
parentb9b15780f808efa2c897f337644ba7a2bec03ecc (diff)
[PATCH] mempolicies: fix policy_zone check
There is a check in zonelist_policy that compares pieces of the bitmap obtained from a gfp mask via GFP_ZONETYPES with a zone number in function zonelist_policy(). The bitmap is an ORed mask of __GFP_DMA, __GFP_DMA32 and __GFP_HIGHMEM. The policy_zone is a zone number with the possible values of ZONE_DMA, ZONE_DMA32, ZONE_HIGHMEM and ZONE_NORMAL. These are two different domains of values. For some reason seemed to work before the zone reduction patchset (It definitely works on SGI boxes since we just have one zone and the check cannot fail). With the zone reduction patchset this check definitely fails on systems with two zones if the system actually has memory in both zones. This is because ZONE_NORMAL is selected using no __GFP flag at all and thus gfp_zone(gfpmask) == 0. ZONE_DMA is selected when __GFP_DMA is set. __GFP_DMA is 0x01. So gfp_zone(gfpmask) == 1. policy_zone is set to ZONE_NORMAL (==1) if ZONE_NORMAL and ZONE_DMA are populated. For ZONE_NORMAL gfp_zone(<no _GFP_DMA>) yields 0 which is < policy_zone(ZONE_NORMAL) and so policy is not applied to regular memory allocations! Instead gfp_zone(__GFP_DMA) == 1 which results in policy being applied to DMA allocations! What we realy want in that place is to establish the highest allowable zone for a given gfp_mask. If the highest zone is higher or equal to the policy_zone then memory policies need to be applied. We have such a highest_zone() function in page_alloc.c. So move the highest_zone() function from mm/page_alloc.c into include/linux/gfp.h. On the way we simplify the function and use the new zone_type that was also introduced with the zone reduction patchset plus we also specify the right type for the gfp flags parameter. Signed-off-by: Christoph Lameter <clameter@sgi.com> Signed-off-by: Lee Schermerhorn <Lee.Schermerhorn@hp.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/gfp.h15
-rw-r--r--mm/mempolicy.c2
-rw-r--r--mm/page_alloc.c16
3 files changed, 16 insertions, 17 deletions
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 2a2153ebfe0b..a0992d392d79 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -85,6 +85,21 @@ static inline int gfp_zone(gfp_t gfp)
85 return zone; 85 return zone;
86} 86}
87 87
88static inline enum zone_type highest_zone(gfp_t flags)
89{
90 if (flags & __GFP_DMA)
91 return ZONE_DMA;
92#ifdef CONFIG_ZONE_DMA32
93 if (flags & __GFP_DMA32)
94 return ZONE_DMA32;
95#endif
96#ifdef CONFIG_HIGHMEM
97 if (flags & __GFP_HIGHMEM)
98 return ZONE_HIGHMEM;
99#endif
100 return ZONE_NORMAL;
101}
102
88/* 103/*
89 * There is only one page-allocator function, and two main namespaces to 104 * There is only one page-allocator function, and two main namespaces to
90 * it. The alloc_page*() variants return 'struct page *' and as such 105 * it. The alloc_page*() variants return 'struct page *' and as such
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index a9963ceddd65..9870624d72a6 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1096,7 +1096,7 @@ static struct zonelist *zonelist_policy(gfp_t gfp, struct mempolicy *policy)
1096 case MPOL_BIND: 1096 case MPOL_BIND:
1097 /* Lower zones don't get a policy applied */ 1097 /* Lower zones don't get a policy applied */
1098 /* Careful: current->mems_allowed might have moved */ 1098 /* Careful: current->mems_allowed might have moved */
1099 if (gfp_zone(gfp) >= policy_zone) 1099 if (highest_zone(gfp) >= policy_zone)
1100 if (cpuset_zonelist_valid_mems_allowed(policy->v.zonelist)) 1100 if (cpuset_zonelist_valid_mems_allowed(policy->v.zonelist))
1101 return policy->v.zonelist; 1101 return policy->v.zonelist;
1102 /*FALL THROUGH*/ 1102 /*FALL THROUGH*/
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 6c7c2dd1b3ed..25f39865e324 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1376,22 +1376,6 @@ static int __meminit build_zonelists_node(pg_data_t *pgdat,
1376 return nr_zones; 1376 return nr_zones;
1377} 1377}
1378 1378
1379static inline int highest_zone(int zone_bits)
1380{
1381 int res = ZONE_NORMAL;
1382#ifdef CONFIG_HIGHMEM
1383 if (zone_bits & (__force int)__GFP_HIGHMEM)
1384 res = ZONE_HIGHMEM;
1385#endif
1386#ifdef CONFIG_ZONE_DMA32
1387 if (zone_bits & (__force int)__GFP_DMA32)
1388 res = ZONE_DMA32;
1389#endif
1390 if (zone_bits & (__force int)__GFP_DMA)
1391 res = ZONE_DMA;
1392 return res;
1393}
1394
1395#ifdef CONFIG_NUMA 1379#ifdef CONFIG_NUMA
1396#define MAX_NODE_LOAD (num_online_nodes()) 1380#define MAX_NODE_LOAD (num_online_nodes())
1397static int __meminitdata node_load[MAX_NUMNODES]; 1381static int __meminitdata node_load[MAX_NUMNODES];