On Fri, Jan 21, 2011 at 2:20 AM, Dave Hansen <dave@xxxxxxxxxxxxxxxxxx> wrote: > On Thu, 2011-01-20 at 18:45 +0900, KyongHo Cho wrote: >> Sparsemem allows that a bank of memory spans over several adjacent >> sections if the start address and the end address of the bank >> belong to different sections. >> When gathering statictics of physical memory in mem_init() and >> show_mem(), this possiblity was not considered. >> >> This patch guarantees that simple increasing the pointer to page >> descriptors does not exceed the boundary of a section > ... >> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c >> index 57c4c5c..6ccecbe 100644 >> --- a/arch/arm/mm/init.c >> +++ b/arch/arm/mm/init.c >> @@ -93,24 +93,38 @@ void show_mem(void) >> >> pfn1 = bank_pfn_start(bank); >> pfn2 = bank_pfn_end(bank); >> - >> +#ifndef CONFIG_SPARSEMEM >> page = pfn_to_page(pfn1); >> end = pfn_to_page(pfn2 - 1) + 1; >> - >> +#else >> + pfn2--; >> do { >> - total++; >> - if (PageReserved(page)) >> - reserved++; >> - else if (PageSwapCache(page)) >> - cached++; >> - else if (PageSlab(page)) >> - slab++; >> - else if (!page_count(page)) >> - free++; >> - else >> - shared += page_count(page) - 1; >> - page++; >> - } while (page < end); >> + page = pfn_to_page(pfn1); >> + if (pfn_to_section_nr(pfn1) < pfn_to_section_nr(pfn2)) { >> + pfn1 += PAGES_PER_SECTION; >> + pfn1 &= PAGE_SECTION_MASK; >> + } else { >> + pfn1 = pfn2; >> + } >> + end = pfn_to_page(pfn1) + 1; >> +#endif > > This problem actually exists without sparsemem, too. Discontigmem (at > least) does it as well. > Actually, as long as a bank in meminfo only resides in a pgdat, no problem happens because there is no restriction of size of area in a pgdat. That's why I just considered about sparsemem. > The x86 version of show_mem() actually manages to do this without any > #ifdefs, and works for a ton of configuration options. It uses > pfn_valid() to tell whether it can touch a given pfn. > > Long-term, it might be a good idea to convert arm's show_mem() over to > use pgdat's like everything else. But, for now, you should just be able > to do something roughly like this: > > - page = pfn_to_page(pfn1); > - end = pfn_to_page(pfn2 - 1) + 1; > - > - do { > + for (pfn = pfn1; pfn < pfn2; pfn++) { > + if (!pfn_valid(pfn)) > + continue; > + page = pfn_to_page(pfn); > + > total++; > if (PageReserved(page)) > reserved++; > else if (PageSwapCache(page)) > cached++; > else if (PageSlab(page)) > slab++; > else if (!page_count(page)) > free++; > else > shared += page_count(page) - 1; > page++; > - } while (page < end); > + } > > That should work for sparsemem, or any other crazy memory models that we > come up with. pfn_to_page() is pretty quick, especially when doing it > in a tight loop like that. > That's true. I worried that pfn_to_page() in sparsemem is a bit slower than that in flatmem. Moreover, the previous one didn't use pfn_to_page() but page++ for the performance. Nevertheless, I also think that pfn_to_page() make the code neat. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxxx For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom policy in Canada: sign http://dissolvethecrtc.ca/ Don't email: <a href