mm: have zonelist contains structs with both a zone pointer and zone_idx
[sfrench/cifs-2.6.git] / include / linux / mmzone.h
index 8d8d1977736e01c05e48c7c0d3172c30a29bf427..d34b4c290017821570662cbcf82964a231a49c1b 100644 (file)
@@ -393,10 +393,10 @@ static inline int zone_is_oom_locked(const struct zone *zone)
  * The NUMA zonelists are doubled becausse we need zonelists that restrict the
  * allocations to a single node for GFP_THISNODE.
  *
- * [0 .. MAX_NR_ZONES -1]              : Zonelists with fallback
- * [MAZ_NR_ZONES ... MAZ_ZONELISTS -1]  : No fallback (GFP_THISNODE)
+ * [0] : Zonelist with fallback
+ * [1] : No fallback (GFP_THISNODE)
  */
-#define MAX_ZONELISTS (2 * MAX_NR_ZONES)
+#define MAX_ZONELISTS 2
 
 
 /*
@@ -464,10 +464,19 @@ struct zonelist_cache {
        unsigned long last_full_zap;            /* when last zap'd (jiffies) */
 };
 #else
-#define MAX_ZONELISTS MAX_NR_ZONES
+#define MAX_ZONELISTS 1
 struct zonelist_cache;
 #endif
 
+/*
+ * This struct contains information about a zone in a zonelist. It is stored
+ * here to avoid dereferences into large structures and lookups of tables
+ */
+struct zoneref {
+       struct zone *zone;      /* Pointer to actual zone */
+       int zone_idx;           /* zone_idx(zoneref->zone) */
+};
+
 /*
  * One allocation request operates on a zonelist. A zonelist
  * is a list of zones, the first one is the 'goal' of the
@@ -476,34 +485,23 @@ struct zonelist_cache;
  *
  * If zlcache_ptr is not NULL, then it is just the address of zlcache,
  * as explained above.  If zlcache_ptr is NULL, there is no zlcache.
+ * *
+ * To speed the reading of the zonelist, the zonerefs contain the zone index
+ * of the entry being read. Helper functions to access information given
+ * a struct zoneref are
+ *
+ * zonelist_zone()     - Return the struct zone * for an entry in _zonerefs
+ * zonelist_zone_idx() - Return the index of the zone for an entry
+ * zonelist_node_idx() - Return the index of the node for an entry
  */
-
 struct zonelist {
        struct zonelist_cache *zlcache_ptr;                  // NULL or &zlcache
-       struct zone *zones[MAX_ZONES_PER_ZONELIST + 1];      // NULL delimited
+       struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];
 #ifdef CONFIG_NUMA
        struct zonelist_cache zlcache;                       // optional ...
 #endif
 };
 
-#ifdef CONFIG_NUMA
-/*
- * Only custom zonelists like MPOL_BIND need to be filtered as part of
- * policies. As described in the comment for struct zonelist_cache, these
- * zonelists will not have a zlcache so zlcache_ptr will not be set. Use
- * that to determine if the zonelists needs to be filtered or not.
- */
-static inline int alloc_should_filter_zonelist(struct zonelist *zonelist)
-{
-       return !zonelist->zlcache_ptr;
-}
-#else
-static inline int alloc_should_filter_zonelist(struct zonelist *zonelist)
-{
-       return 0;
-}
-#endif /* CONFIG_NUMA */
-
 #ifdef CONFIG_ARCH_POPULATES_NODE_MAP
 struct node_active_region {
        unsigned long start_pfn;
@@ -637,9 +635,10 @@ static inline int is_normal_idx(enum zone_type idx)
 static inline int is_highmem(struct zone *zone)
 {
 #ifdef CONFIG_HIGHMEM
-       int zone_idx = zone - zone->zone_pgdat->node_zones;
-       return zone_idx == ZONE_HIGHMEM ||
-               (zone_idx == ZONE_MOVABLE && zone_movable_is_highmem());
+       int zone_off = (char *)zone - (char *)zone->zone_pgdat->node_zones;
+       return zone_off == ZONE_HIGHMEM * sizeof(*zone) ||
+              (zone_off == ZONE_MOVABLE * sizeof(*zone) &&
+               zone_movable_is_highmem());
 #else
        return 0;
 #endif
@@ -699,7 +698,6 @@ extern char numa_zonelist_order[];
 extern struct pglist_data contig_page_data;
 #define NODE_DATA(nid)         (&contig_page_data)
 #define NODE_MEM_MAP(nid)      mem_map
-#define MAX_NODES_SHIFT                1
 
 #else /* CONFIG_NEED_MULTIPLE_NODES */
 
@@ -731,6 +729,73 @@ extern struct zone *next_zone(struct zone *zone);
             zone;                                      \
             zone = next_zone(zone))
 
+static inline struct zone *zonelist_zone(struct zoneref *zoneref)
+{
+       return zoneref->zone;
+}
+
+static inline int zonelist_zone_idx(struct zoneref *zoneref)
+{
+       return zoneref->zone_idx;
+}
+
+static inline int zonelist_node_idx(struct zoneref *zoneref)
+{
+#ifdef CONFIG_NUMA
+       /* zone_to_nid not available in this context */
+       return zoneref->zone->node;
+#else
+       return 0;
+#endif /* CONFIG_NUMA */
+}
+
+static inline void zoneref_set_zone(struct zone *zone, struct zoneref *zoneref)
+{
+       zoneref->zone = zone;
+       zoneref->zone_idx = zone_idx(zone);
+}
+
+/* Returns the first zone at or below highest_zoneidx in a zonelist */
+static inline struct zoneref *first_zones_zonelist(struct zonelist *zonelist,
+                                       enum zone_type highest_zoneidx)
+{
+       struct zoneref *z;
+
+       /* Find the first suitable zone to use for the allocation */
+       z = zonelist->_zonerefs;
+       while (zonelist_zone_idx(z) > highest_zoneidx)
+               z++;
+
+       return z;
+}
+
+/* Returns the next zone at or below highest_zoneidx in a zonelist */
+static inline struct zoneref *next_zones_zonelist(struct zoneref *z,
+                                       enum zone_type highest_zoneidx)
+{
+       /* Find the next suitable zone to use for the allocation */
+       while (zonelist_zone_idx(z) > highest_zoneidx)
+               z++;
+
+       return z;
+}
+
+/**
+ * for_each_zone_zonelist - helper macro to iterate over valid zones in a zonelist at or below a given zone index
+ * @zone - The current zone in the iterator
+ * @z - The current pointer within zonelist->zones being iterated
+ * @zlist - The zonelist being iterated
+ * @highidx - The zone index of the highest zone to return
+ *
+ * This iterator iterates though all zones at or below a given zone index.
+ */
+#define for_each_zone_zonelist(zone, z, zlist, highidx) \
+       for (z = first_zones_zonelist(zlist, highidx),                  \
+                                       zone = zonelist_zone(z++);      \
+               zone;                                                   \
+               z = next_zones_zonelist(z, highidx),                    \
+                                       zone = zonelist_zone(z++))
+
 #ifdef CONFIG_SPARSEMEM
 #include <asm/sparsemem.h>
 #endif