diff options
author | Andy Whitcroft <apw@shadowen.org> | 2005-06-23 03:08:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-23 12:45:05 -0400 |
commit | 29751f6991e845f7d002a6ae520bf996b38c8dcd (patch) | |
tree | f76c4c660ac4d204436f68851979343d2a9ba224 /include/linux | |
parent | 641c767389b19859a45e6de46d8e18cd935bdb60 (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')
-rw-r--r-- | include/linux/mmzone.h | 56 |
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 | ||
477 | struct page; | 477 | struct page; |
478 | struct mem_section { | 478 | struct 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 | ||
482 | extern struct mem_section mem_section[NR_MEM_SECTIONS]; | 490 | extern struct mem_section mem_section[NR_MEM_SECTIONS]; |
483 | 491 | ||
492 | static 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 | |||
507 | static 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 | |||
514 | static inline int valid_section(struct mem_section *section) | ||
515 | { | ||
516 | return (section->section_mem_map & SECTION_MARKED_PRESENT); | ||
517 | } | ||
518 | |||
519 | static inline int section_has_mem_map(struct mem_section *section) | ||
520 | { | ||
521 | return (section->section_mem_map & SECTION_HAS_MEM_MAP); | ||
522 | } | ||
523 | |||
524 | static 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 | ||
489 | static inline struct mem_section *__pfn_to_section(unsigned long pfn) | 534 | static 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 | ||
504 | static inline int pfn_valid(unsigned long pfn) | 550 | static 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 | /* |