From apw@shadowen.org Tue May 22 15:46:11 2007 Date: Tue, 22 May 2007 23:58:58 +0100 From: Andy Whitcroft To: linux-mm@kvack.org Cc: linux-arch@vger.kernel.org, Nick Piggin , Christoph Lameter , Mel Gorman , Andy Whitcroft Subject: [PATCH 2/8] sparsemem: record when a section has a valid mem_map We have flags to indicate whether a section actually has a valid mem_map associated with it. This is never set and we rely solely on the present bit to indicate a section is valid. By definition a section is not valid if it has no mem_map and there is a window during init where the present bit is set but there is no mem_map, during which pfn_valid() will return true incorrectly. Use the existing SECTION_HAS_MEM_MAP flag to indicate the presence of a valid mem_map. Switch valid_section{,_nr} and pfn_valid() to this bit. Add a new present_section{,_nr} and pfn_present() interfaces for those users who care to know that a section is going to be valid. Signed-off-by: Andy Whitcroft Acked-by: Mel Gorman --- Index: linux-2.6.22-rc2/drivers/base/memory.c =================================================================== --- linux-2.6.22-rc2.orig/drivers/base/memory.c 2007-05-18 21:06:17.000000000 -0700 +++ linux-2.6.22-rc2/drivers/base/memory.c 2007-05-22 17:22:24.000000000 -0700 @@ -239,7 +239,7 @@ store_mem_state(struct sys_device *dev, mem = container_of(dev, struct memory_block, sysdev); phys_section_nr = mem->phys_index; - if (!valid_section_nr(phys_section_nr)) + if (!present_section_nr(phys_section_nr)) goto out; if (!strncmp(buf, "online", min((int)count, 6))) @@ -419,7 +419,7 @@ int register_new_memory(struct mem_secti int unregister_memory_section(struct mem_section *section) { - if (!valid_section(section)) + if (!present_section(section)) return -EINVAL; return remove_memory_block(0, section, 0); @@ -444,7 +444,7 @@ int __init memory_dev_init(void) * during boot and have been initialized */ for (i = 0; i < NR_MEM_SECTIONS; i++) { - if (!valid_section_nr(i)) + if (!present_section_nr(i)) continue; err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0); if (!ret) Index: linux-2.6.22-rc2/include/linux/mmzone.h =================================================================== --- linux-2.6.22-rc2.orig/include/linux/mmzone.h 2007-05-18 21:06:17.000000000 -0700 +++ linux-2.6.22-rc2/include/linux/mmzone.h 2007-05-22 17:22:24.000000000 -0700 @@ -725,12 +725,17 @@ static inline struct page *__section_mem return (struct page *)map; } -static inline int valid_section(struct mem_section *section) +static inline int present_section(struct mem_section *section) { return (section && (section->section_mem_map & SECTION_MARKED_PRESENT)); } -static inline int section_has_mem_map(struct mem_section *section) +static inline int present_section_nr(unsigned long nr) +{ + return present_section(__nr_to_section(nr)); +} + +static inline int valid_section(struct mem_section *section) { return (section && (section->section_mem_map & SECTION_HAS_MEM_MAP)); } @@ -752,6 +757,13 @@ static inline int pfn_valid(unsigned lon return valid_section(__nr_to_section(pfn_to_section_nr(pfn))); } +static inline int pfn_present(unsigned long pfn) +{ + if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) + return 0; + return present_section(__nr_to_section(pfn_to_section_nr(pfn))); +} + /* * These are _only_ used during initialisation, therefore they * can use __initdata ... They could have names to indicate Index: linux-2.6.22-rc2/mm/sparse.c =================================================================== --- linux-2.6.22-rc2.orig/mm/sparse.c 2007-05-22 17:22:05.000000000 -0700 +++ linux-2.6.22-rc2/mm/sparse.c 2007-05-22 17:23:53.000000000 -0700 @@ -170,7 +170,7 @@ unsigned long __init node_memmap_size_by if (nid != early_pfn_to_nid(pfn)) continue; - if (pfn_valid(pfn)) + if (pfn_present(pfn)) nr_pages += PAGES_PER_SECTION; } @@ -200,11 +200,12 @@ struct page *sparse_decode_mem_map(unsig static int __meminit sparse_init_one_section(struct mem_section *ms, unsigned long pnum, struct page *mem_map) { - if (!valid_section(ms)) + if (!present_section(ms)) return -EINVAL; ms->section_mem_map &= ~SECTION_MAP_MASK; - ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum); + ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum) | + SECTION_HAS_MEM_MAP; return 1; } @@ -278,7 +279,7 @@ void __init sparse_init(void) struct page *map; for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { - if (!valid_section_nr(pnum)) + if (!present_section_nr(pnum)) continue; map = sparse_early_mem_map_alloc(pnum);