[ARM] Tighten pfn_valid() test.
authorRussell King <rmk@dyn-67.arm.linux.org.uk>
Thu, 15 Sep 2005 14:17:59 +0000 (15:17 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 15 Sep 2005 14:17:59 +0000 (15:17 +0100)
Thomas Gleixner reported that mmaping and unmapping each physical
page in turn eventually caused the kernel to oops.  It appears
that pfn_valid() in the discontigmem case was too simplistic for
proper operation.

Tighten the logic so we also check if the PFN is within the range
of the selected memory node.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
include/asm-arm/memory.h

index e47bea7d17237de5a0cf86d998ff684ec5a5d8e7..a8a933a775db497931acd58422376a6ce6128b3e 100644 (file)
@@ -160,12 +160,25 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
 #define page_to_pfn(page)                                      \
        (( (page) - page_zone(page)->zone_mem_map)              \
          + page_zone(page)->zone_start_pfn)
+
 #define pfn_to_page(pfn)                                       \
        (PFN_TO_MAPBASE(pfn) + LOCAL_MAP_NR((pfn) << PAGE_SHIFT))
-#define pfn_valid(pfn)         (PFN_TO_NID(pfn) < MAX_NUMNODES)
+
+#define pfn_valid(pfn)                                         \
+       ({                                                      \
+               unsigned int nid = PFN_TO_NID(pfn);             \
+               int valid = nid < MAX_NUMNODES;                 \
+               if (valid) {                                    \
+                       pg_data_t *node = NODE_DATA(nid);       \
+                       valid = (pfn - node->node_start_pfn) <  \
+                               node->node_spanned_pages;       \
+               }                                               \
+               valid;                                          \
+       })
 
 #define virt_to_page(kaddr)                                    \
        (ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr))
+
 #define virt_addr_valid(kaddr) (KVADDR_TO_NID(kaddr) < MAX_NUMNODES)
 
 /*