summaryrefslogtreecommitdiff
path: root/include/linux/mmzone.h
diff options
context:
space:
mode:
authorAndy Whitcroft <apw@shadowen.org>2005-06-23 00:08:00 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 09:45:05 -0700
commit29751f6991e845f7d002a6ae520bf996b38c8dcd (patch)
treef76c4c660ac4d204436f68851979343d2a9ba224 /include/linux/mmzone.h
parent641c767389b19859a45e6de46d8e18cd935bdb60 (diff)
downloadlwn-29751f6991e845f7d002a6ae520bf996b38c8dcd.tar.gz
lwn-29751f6991e845f7d002a6ae520bf996b38c8dcd.zip
[PATCH] sparsemem hotplug base
Make sparse's initalization be accessible at runtime. This allows sparse mappings to be created after boot in a hotplug situation. This patch is separated from the previous one just to give an indication how much of the sparse infrastructure is *just* for hotplug memory. The section_mem_map doesn't really store a pointer. It stores something that is convenient to do some math against to get a pointer. It isn't valid to just do *section_mem_map, so I don't think it should be stored as a pointer. There are a couple of things I'd like to store about a section. First of all, the fact that it is !NULL does not mean that it is present. There could be such a combination where section_mem_map *is* NULL, but the math gets you properly to a real mem_map. So, I don't think that check is safe. Since we're storing 32-bit-aligned structures, we have a few bits in the bottom of the pointer to play with. Use one bit to encode whether there's really a mem_map there, and the other one to tell whether there's a valid section there. We need to distinguish between the two because sometimes there's a gap between when a section is discovered to be present and when we can get the mem_map for it. Signed-off-by: Dave Hansen <haveblue@us.ibm.com> Signed-off-by: Andy Whitcroft <apw@shadowen.org> Signed-off-by: Jack Steiner <steiner@sgi.com> Signed-off-by: Bob Picco <bob.picco@hp.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/linux/mmzone.h')
-rw-r--r--include/linux/mmzone.h56
1 files changed, 51 insertions, 5 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 746b57e3d370..6c90461ed99f 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -476,11 +476,56 @@ extern struct pglist_data contig_page_data;
struct page;
struct mem_section {
- struct page *section_mem_map;
+ /*
+ * This is, logically, a pointer to an array of struct
+ * pages. However, it is stored with some other magic.
+ * (see sparse.c::sparse_init_one_section())
+ *
+ * Making it a UL at least makes someone do a cast
+ * before using it wrong.
+ */
+ unsigned long section_mem_map;
};
extern struct mem_section mem_section[NR_MEM_SECTIONS];
+static inline struct mem_section *__nr_to_section(unsigned long nr)
+{
+ return &mem_section[nr];
+}
+
+/*
+ * We use the lower bits of the mem_map pointer to store
+ * a little bit of information. There should be at least
+ * 3 bits here due to 32-bit alignment.
+ */
+#define SECTION_MARKED_PRESENT (1UL<<0)
+#define SECTION_HAS_MEM_MAP (1UL<<1)
+#define SECTION_MAP_LAST_BIT (1UL<<2)
+#define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1))
+
+static inline struct page *__section_mem_map_addr(struct mem_section *section)
+{
+ unsigned long map = section->section_mem_map;
+ map &= SECTION_MAP_MASK;
+ return (struct page *)map;
+}
+
+static inline int valid_section(struct mem_section *section)
+{
+ return (section->section_mem_map & SECTION_MARKED_PRESENT);
+}
+
+static inline int section_has_mem_map(struct mem_section *section)
+{
+ return (section->section_mem_map & SECTION_HAS_MEM_MAP);
+}
+
+static inline int valid_section_nr(unsigned long nr)
+{
+ return valid_section(__nr_to_section(nr));
+}
+
/*
* Given a kernel address, find the home node of the underlying memory.
*/
@@ -488,24 +533,25 @@ extern struct mem_section mem_section[NR_MEM_SECTIONS];
static inline struct mem_section *__pfn_to_section(unsigned long pfn)
{
- return &mem_section[pfn_to_section_nr(pfn)];
+ return __nr_to_section(pfn_to_section_nr(pfn));
}
#define pfn_to_page(pfn) \
({ \
unsigned long __pfn = (pfn); \
- __pfn_to_section(__pfn)->section_mem_map + __pfn; \
+ __section_mem_map_addr(__pfn_to_section(__pfn)) + __pfn; \
})
#define page_to_pfn(page) \
({ \
- page - mem_section[page_to_section(page)].section_mem_map; \
+ page - __section_mem_map_addr(__nr_to_section( \
+ page_to_section(page))); \
})
static inline int pfn_valid(unsigned long pfn)
{
if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
return 0;
- return mem_section[pfn_to_section_nr(pfn)].section_mem_map != 0;
+ return valid_section(__nr_to_section(pfn_to_section_nr(pfn)));
}
/*