aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/mmzone.h
diff options
context:
space:
mode:
authorAndy Whitcroft <apw@shadowen.org>2005-06-23 03:08:00 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:05 -0400
commit29751f6991e845f7d002a6ae520bf996b38c8dcd (patch)
treef76c4c660ac4d204436f68851979343d2a9ba224 /include/linux/mmzone.h
parent641c767389b19859a45e6de46d8e18cd935bdb60 (diff)
[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;
476 476
477struct page; 477struct page;
478struct mem_section { 478struct mem_section {
479 struct page *section_mem_map; 479 /*
480 * This is, logically, a pointer to an array of struct
481 * pages. However, it is stored with some other magic.
482 * (see sparse.c::sparse_init_one_section())
483 *
484 * Making it a UL at least makes someone do a cast
485 * before using it wrong.
486 */
487 unsigned long section_mem_map;
480}; 488};
481 489
482extern struct mem_section mem_section[NR_MEM_SECTIONS]; 490extern struct mem_section mem_section[NR_MEM_SECTIONS];
483 491
492static inline struct mem_section *__nr_to_section(unsigned long nr)
493{
494 return &mem_section[nr];
495}
496
497/*
498 * We use the lower bits of the mem_map pointer to store
499 * a little bit of information. There should be at least
500 * 3 bits here due to 32-bit alignment.
501 */
502#define SECTION_MARKED_PRESENT (1UL<<0)
503#define SECTION_HAS_MEM_MAP (1UL<<1)
504#define SECTION_MAP_LAST_BIT (1UL<<2)
505#define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1))
506
507static inline struct page *__section_mem_map_addr(struct mem_section *section)
508{
509 unsigned long map = section->section_mem_map;
510 map &= SECTION_MAP_MASK;
511 return (struct page *)map;
512}
513
514static inline int valid_section(struct mem_section *section)
515{
516 return (section->section_mem_map & SECTION_MARKED_PRESENT);
517}
518
519static inline int section_has_mem_map(struct mem_section *section)
520{
521 return (section->section_mem_map & SECTION_HAS_MEM_MAP);
522}
523
524static inline int valid_section_nr(unsigned long nr)
525{
526 return valid_section(__nr_to_section(nr));
527}
528
484/* 529/*
485 * Given a kernel address, find the home node of the underlying memory. 530 * Given a kernel address, find the home node of the underlying memory.
486 */ 531 */
@@ -488,24 +533,25 @@ extern struct mem_section mem_section[NR_MEM_SECTIONS];
488 533
489static inline struct mem_section *__pfn_to_section(unsigned long pfn) 534static inline struct mem_section *__pfn_to_section(unsigned long pfn)
490{ 535{
491 return &mem_section[pfn_to_section_nr(pfn)]; 536 return __nr_to_section(pfn_to_section_nr(pfn));
492} 537}
493 538
494#define pfn_to_page(pfn) \ 539#define pfn_to_page(pfn) \
495({ \ 540({ \
496 unsigned long __pfn = (pfn); \ 541 unsigned long __pfn = (pfn); \
497 __pfn_to_section(__pfn)->section_mem_map + __pfn; \ 542 __section_mem_map_addr(__pfn_to_section(__pfn)) + __pfn; \
498}) 543})
499#define page_to_pfn(page) \ 544#define page_to_pfn(page) \
500({ \ 545({ \
501 page - mem_section[page_to_section(page)].section_mem_map; \ 546 page - __section_mem_map_addr(__nr_to_section( \
547 page_to_section(page))); \
502}) 548})
503 549
504static inline int pfn_valid(unsigned long pfn) 550static inline int pfn_valid(unsigned long pfn)
505{ 551{
506 if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) 552 if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
507 return 0; 553 return 0;
508 return mem_section[pfn_to_section_nr(pfn)].section_mem_map != 0; 554 return valid_section(__nr_to_section(pfn_to_section_nr(pfn)));
509} 555}
510 556
511/* 557/*