| From: Wanpeng Li <liwanp@linux.vnet.ibm.com> |
| Date: Fri, 22 Mar 2013 15:04:40 -0700 |
| Subject: mm/hugetlb: fix total hugetlbfs pages count when using memory |
| overcommit accouting |
| |
| commit d00285884c0892bb1310df96bce6056e9ce9b9d9 upstream. |
| |
| hugetlb_total_pages is used for overcommit calculations but the current |
| implementation considers only the default hugetlb page size (which is |
| either the first defined hugepage size or the one specified by |
| default_hugepagesz kernel boot parameter). |
| |
| If the system is configured for more than one hugepage size, which is |
| possible since commit a137e1cc6d6e ("hugetlbfs: per mount huge page |
| sizes") then the overcommit estimation done by __vm_enough_memory() |
| (resp. shown by meminfo_proc_show) is not precise - there is an |
| impression of more available/allowed memory. This can lead to an |
| unexpected ENOMEM/EFAULT resp. SIGSEGV when memory is accounted. |
| |
| Testcase: |
| boot: hugepagesz=1G hugepages=1 |
| the default overcommit ratio is 50 |
| before patch: |
| |
| egrep 'CommitLimit' /proc/meminfo |
| CommitLimit: 55434168 kB |
| |
| after patch: |
| |
| egrep 'CommitLimit' /proc/meminfo |
| CommitLimit: 54909880 kB |
| |
| [akpm@linux-foundation.org: coding-style tweak] |
| Signed-off-by: Wanpeng Li <liwanp@linux.vnet.ibm.com> |
| Acked-by: Michal Hocko <mhocko@suse.cz> |
| Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> |
| Cc: Hillf Danton <dhillf@gmail.com> |
| Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| mm/hugetlb.c | 8 ++++++-- |
| 1 file changed, 6 insertions(+), 2 deletions(-) |
| |
| --- a/mm/hugetlb.c |
| +++ b/mm/hugetlb.c |
| @@ -2092,8 +2092,12 @@ int hugetlb_report_node_meminfo(int nid, |
| /* Return the number pages of memory we physically have, in PAGE_SIZE units. */ |
| unsigned long hugetlb_total_pages(void) |
| { |
| - struct hstate *h = &default_hstate; |
| - return h->nr_huge_pages * pages_per_huge_page(h); |
| + struct hstate *h; |
| + unsigned long nr_total_pages = 0; |
| + |
| + for_each_hstate(h) |
| + nr_total_pages += h->nr_huge_pages * pages_per_huge_page(h); |
| + return nr_total_pages; |
| } |
| |
| static int hugetlb_acct_memory(struct hstate *h, long delta) |