Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 105341
b: refs/heads/master
c: 48c9068
h: refs/heads/master
i:
  105339: be8c6d2
v: v3
  • Loading branch information
Yasunori Goto authored and Linus Torvalds committed Jul 24, 2008
1 parent 0dc176a commit 53a5884
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f84f9504bddeec33a72d64ebe95143d3aaeb3f9b
refs/heads/master: 48c906823f3927b981db9f0b03c2e2499977ee93
78 changes: 77 additions & 1 deletion trunk/mm/sparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,16 +269,92 @@ static unsigned long *__kmalloc_section_usemap(void)
}
#endif /* CONFIG_MEMORY_HOTPLUG */

#ifdef CONFIG_MEMORY_HOTREMOVE
static unsigned long * __init
sparse_early_usemap_alloc_pgdat_section(struct pglist_data *pgdat)
{
unsigned long section_nr;

/*
* A page may contain usemaps for other sections preventing the
* page being freed and making a section unremovable while
* other sections referencing the usemap retmain active. Similarly,
* a pgdat can prevent a section being removed. If section A
* contains a pgdat and section B contains the usemap, both
* sections become inter-dependent. This allocates usemaps
* from the same section as the pgdat where possible to avoid
* this problem.
*/
section_nr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT);
return alloc_bootmem_section(usemap_size(), section_nr);
}

static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
{
unsigned long usemap_snr, pgdat_snr;
static unsigned long old_usemap_snr = NR_MEM_SECTIONS;
static unsigned long old_pgdat_snr = NR_MEM_SECTIONS;
struct pglist_data *pgdat = NODE_DATA(nid);
int usemap_nid;

usemap_snr = pfn_to_section_nr(__pa(usemap) >> PAGE_SHIFT);
pgdat_snr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT);
if (usemap_snr == pgdat_snr)
return;

if (old_usemap_snr == usemap_snr && old_pgdat_snr == pgdat_snr)
/* skip redundant message */
return;

old_usemap_snr = usemap_snr;
old_pgdat_snr = pgdat_snr;

usemap_nid = sparse_early_nid(__nr_to_section(usemap_snr));
if (usemap_nid != nid) {
printk(KERN_INFO
"node %d must be removed before remove section %ld\n",
nid, usemap_snr);
return;
}
/*
* There is a circular dependency.
* Some platforms allow un-removable section because they will just
* gather other removable sections for dynamic partitioning.
* Just notify un-removable section's number here.
*/
printk(KERN_INFO "Section %ld and %ld (node %d)", usemap_snr,
pgdat_snr, nid);
printk(KERN_CONT
" have a circular dependency on usemap and pgdat allocations\n");
}
#else
static unsigned long * __init
sparse_early_usemap_alloc_pgdat_section(struct pglist_data *pgdat)
{
return NULL;
}

static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
{
}
#endif /* CONFIG_MEMORY_HOTREMOVE */

static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum)
{
unsigned long *usemap;
struct mem_section *ms = __nr_to_section(pnum);
int nid = sparse_early_nid(ms);

usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size());
usemap = sparse_early_usemap_alloc_pgdat_section(NODE_DATA(nid));
if (usemap)
return usemap;

usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size());
if (usemap) {
check_usemap_section_nr(nid, usemap);
return usemap;
}

/* Stupid: suppress gcc warning for SPARSEMEM && !NUMA */
nid = 0;

Expand Down

0 comments on commit 53a5884

Please sign in to comment.