We need to teach the numa_maps code about transparent huge pages. The first step is to teach gather_stats() that the pte it is dealing with might represent more than one page. Note that will we use this in a moment for transparent huge pages since they have use a single pmd_t which _acts_ as a "surrogate" for a bunch of smaller pte_t's. I'm a _bit_ unhappy that this interface counts in hugetlbfs page sizes for hugetlbfs pages and PAGE_SIZE for normal pages. That means that to figure out how many _bytes_ "dirty=1" means, you must first know the hugetlbfs page size. That's easier said than done especially if you don't have visibility in to the mount. But, that's probably a discussion for another day especially since it would change behavior to fix it. But, just in case anyone wonders why this patch only passes a '1' in the hugetlb case...
Unified · Split
| @@ -877,30 +877,31 @@ struct numa_maps_private { · 876 unmodified lines | ||
| 877 | 877 | struct numa_maps md; |
| 878 | 878 | }; |
| 879 | 879 | |
| 880 | −static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty) | |
| 880 | +static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty, | |
| 881 | + unsigned long nr_pages) | |
| 881 | 882 | { |
| 882 | 883 | int count = page_mapcount(page); |
| 883 | 884 | |
| 884 | − md->pages++; | |
| 885 | + md->pages += nr_pages; | |
| 885 | 886 | if (pte_dirty || PageDirty(page)) |
| 886 | − md->dirty++; | |
| 887 | + md->dirty += nr_pages; | |
| 887 | 888 | |
| 888 | 889 | if (PageSwapCache(page)) |
| 889 | − md->swapcache++; | |
| 890 | + md->swapcache += nr_pages; | |
| 890 | 891 | |
| 891 | 892 | if (PageActive(page) || PageUnevictable(page)) |
| 892 | − md->active++; | |
| 893 | + md->active += nr_pages; | |
| 893 | 894 | |
| 894 | 895 | if (PageWriteback(page)) |
| 895 | − md->writeback++; | |
| 896 | + md->writeback += nr_pages; | |
| 896 | 897 | |
| 897 | 898 | if (PageAnon(page)) |
| 898 | − md->anon++; | |
| 899 | + md->anon += nr_pages; | |
| 899 | 900 | |
| 900 | 901 | if (count > md->mapcount_max) |
| 901 | 902 | md->mapcount_max = count; |
| 902 | 903 | |
| 903 | − md->node[page_to_nid(page)]++; | |
| 904 | + md->node[page_to_nid(page)] += nr_pages; | |
| 904 | 905 | } |
| 905 | 906 | |
| 906 | 907 | static int gather_pte_stats(pmd_t *pmd, unsigned long addr, |
| @@ -931,7 +932,7 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, · 24 unmodified lines | ||
| 931 | 932 | if (!node_isset(nid, node_states[N_HIGH_MEMORY])) |
| 932 | 933 | continue; |
| 933 | 934 | |
| 934 | − gather_stats(page, md, pte_dirty(*pte)); | |
| 935 | + gather_stats(page, md, pte_dirty(*pte), 1); | |
| 935 | 936 | |
| 936 | 937 | } while (pte++, addr += PAGE_SIZE, addr != end); |
| 937 | 938 | pte_unmap_unlock(orig_pte, ptl); |
| @@ -952,7 +953,7 @@ static int gather_hugetbl_stats(pte_t *pte, unsigned long hmask, · 14 unmodified lines | ||
| 952 | 953 | return 0; |
| 953 | 954 | |
| 954 | 955 | md = walk->private; |
| 955 | − gather_stats(page, md, pte_dirty(*pte)); | |
| 956 | + gather_stats(page, md, pte_dirty(*pte), 1); | |
| 956 | 957 | return 0; |
| 957 | 958 | } |
| 958 | 959 | |