aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorMike Kravetz <mike.kravetz@oracle.com>2015-04-15 19:13:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-15 19:35:17 -0400
commit1c5ecae3a93fa1ab51a784d77e9c9ed54e67c65f (patch)
treedf351d81d1fc493470d87cda2044d592e06195a9 /mm
parentc6a918200c4f4ebf74b7e1ae4fea9115c7b297f8 (diff)
hugetlbfs: add minimum size accounting to subpools
The same routines that perform subpool maximum size accounting hugepage_subpool_get/put_pages() are modified to also perform minimum size accounting. When a delta value is passed to these routines, calculate how global reservations must be adjusted to maintain the subpool minimum size. The routines now return this global reserve count adjustment. This global reserve count adjustment is then passed to the global accounting routine hugetlb_acct_memory(). Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Aneesh Kumar <aneesh.kumar@linux.vnet.ibm.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/hugetlb.c123
1 files changed, 100 insertions, 23 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 4494976c2042..499cb72c74b1 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -96,36 +96,89 @@ void hugepage_put_subpool(struct hugepage_subpool *spool)
96 unlock_or_release_subpool(spool); 96 unlock_or_release_subpool(spool);
97} 97}
98 98
99static int hugepage_subpool_get_pages(struct hugepage_subpool *spool, 99/*
100 * Subpool accounting for allocating and reserving pages.
101 * Return -ENOMEM if there are not enough resources to satisfy the
102 * the request. Otherwise, return the number of pages by which the
103 * global pools must be adjusted (upward). The returned value may
104 * only be different than the passed value (delta) in the case where
105 * a subpool minimum size must be manitained.
106 */
107static long hugepage_subpool_get_pages(struct hugepage_subpool *spool,
100 long delta) 108 long delta)
101{ 109{
102 int ret = 0; 110 long ret = delta;
103 111
104 if (!spool) 112 if (!spool)
105 return 0; 113 return ret;
106 114
107 spin_lock(&spool->lock); 115 spin_lock(&spool->lock);
108 if ((spool->used_hpages + delta) <= spool->max_hpages) { 116
109 spool->used_hpages += delta; 117 if (spool->max_hpages != -1) { /* maximum size accounting */
110 } else { 118 if ((spool->used_hpages + delta) <= spool->max_hpages)
111 ret = -ENOMEM; 119 spool->used_hpages += delta;
120 else {
121 ret = -ENOMEM;
122 goto unlock_ret;
123 }
112 } 124 }
113 spin_unlock(&spool->lock);
114 125
126 if (spool->min_hpages != -1) { /* minimum size accounting */
127 if (delta > spool->rsv_hpages) {
128 /*
129 * Asking for more reserves than those already taken on
130 * behalf of subpool. Return difference.
131 */
132 ret = delta - spool->rsv_hpages;
133 spool->rsv_hpages = 0;
134 } else {
135 ret = 0; /* reserves already accounted for */
136 spool->rsv_hpages -= delta;
137 }
138 }
139
140unlock_ret:
141 spin_unlock(&spool->lock);
115 return ret; 142 return ret;
116} 143}
117 144
118static void hugepage_subpool_put_pages(struct hugepage_subpool *spool, 145/*
146 * Subpool accounting for freeing and unreserving pages.
147 * Return the number of global page reservations that must be dropped.
148 * The return value may only be different than the passed value (delta)
149 * in the case where a subpool minimum size must be maintained.
150 */
151static long hugepage_subpool_put_pages(struct hugepage_subpool *spool,
119 long delta) 152 long delta)
120{ 153{
154 long ret = delta;
155
121 if (!spool) 156 if (!spool)
122 return; 157 return delta;
123 158
124 spin_lock(&spool->lock); 159 spin_lock(&spool->lock);
125 spool->used_hpages -= delta; 160
126 /* If hugetlbfs_put_super couldn't free spool due to 161 if (spool->max_hpages != -1) /* maximum size accounting */
127 * an outstanding quota reference, free it now. */ 162 spool->used_hpages -= delta;
163
164 if (spool->min_hpages != -1) { /* minimum size accounting */
165 if (spool->rsv_hpages + delta <= spool->min_hpages)
166 ret = 0;
167 else
168 ret = spool->rsv_hpages + delta - spool->min_hpages;
169
170 spool->rsv_hpages += delta;
171 if (spool->rsv_hpages > spool->min_hpages)
172 spool->rsv_hpages = spool->min_hpages;
173 }
174
175 /*
176 * If hugetlbfs_put_super couldn't free spool due to an outstanding
177 * quota reference, free it now.
178 */
128 unlock_or_release_subpool(spool); 179 unlock_or_release_subpool(spool);
180
181 return ret;
129} 182}
130 183
131static inline struct hugepage_subpool *subpool_inode(struct inode *inode) 184static inline struct hugepage_subpool *subpool_inode(struct inode *inode)
@@ -873,6 +926,14 @@ void free_huge_page(struct page *page)
873 restore_reserve = PagePrivate(page); 926 restore_reserve = PagePrivate(page);
874 ClearPagePrivate(page); 927 ClearPagePrivate(page);
875 928
929 /*
930 * A return code of zero implies that the subpool will be under its
931 * minimum size if the reservation is not restored after page is free.
932 * Therefore, force restore_reserve operation.
933 */
934 if (hugepage_subpool_put_pages(spool, 1) == 0)
935 restore_reserve = true;
936
876 spin_lock(&hugetlb_lock); 937 spin_lock(&hugetlb_lock);
877 hugetlb_cgroup_uncharge_page(hstate_index(h), 938 hugetlb_cgroup_uncharge_page(hstate_index(h),
878 pages_per_huge_page(h), page); 939 pages_per_huge_page(h), page);
@@ -890,7 +951,6 @@ void free_huge_page(struct page *page)
890 enqueue_huge_page(h, page); 951 enqueue_huge_page(h, page);
891 } 952 }
892 spin_unlock(&hugetlb_lock); 953 spin_unlock(&hugetlb_lock);
893 hugepage_subpool_put_pages(spool, 1);
894} 954}
895 955
896static void prep_new_huge_page(struct hstate *h, struct page *page, int nid) 956static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
@@ -1385,7 +1445,7 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
1385 if (chg < 0) 1445 if (chg < 0)
1386 return ERR_PTR(-ENOMEM); 1446 return ERR_PTR(-ENOMEM);
1387 if (chg || avoid_reserve) 1447 if (chg || avoid_reserve)
1388 if (hugepage_subpool_get_pages(spool, 1)) 1448 if (hugepage_subpool_get_pages(spool, 1) < 0)
1389 return ERR_PTR(-ENOSPC); 1449 return ERR_PTR(-ENOSPC);
1390 1450
1391 ret = hugetlb_cgroup_charge_cgroup(idx, pages_per_huge_page(h), &h_cg); 1451 ret = hugetlb_cgroup_charge_cgroup(idx, pages_per_huge_page(h), &h_cg);
@@ -2453,6 +2513,7 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma)
2453 struct resv_map *resv = vma_resv_map(vma); 2513 struct resv_map *resv = vma_resv_map(vma);
2454 struct hugepage_subpool *spool = subpool_vma(vma); 2514 struct hugepage_subpool *spool = subpool_vma(vma);
2455 unsigned long reserve, start, end; 2515 unsigned long reserve, start, end;
2516 long gbl_reserve;
2456 2517
2457 if (!resv || !is_vma_resv_set(vma, HPAGE_RESV_OWNER)) 2518 if (!resv || !is_vma_resv_set(vma, HPAGE_RESV_OWNER))
2458 return; 2519 return;
@@ -2465,8 +2526,12 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma)
2465 kref_put(&resv->refs, resv_map_release); 2526 kref_put(&resv->refs, resv_map_release);
2466 2527
2467 if (reserve) { 2528 if (reserve) {
2468 hugetlb_acct_memory(h, -reserve); 2529 /*
2469 hugepage_subpool_put_pages(spool, reserve); 2530 * Decrement reserve counts. The global reserve count may be
2531 * adjusted if the subpool has a minimum size.
2532 */
2533 gbl_reserve = hugepage_subpool_put_pages(spool, reserve);
2534 hugetlb_acct_memory(h, -gbl_reserve);
2470 } 2535 }
2471} 2536}
2472 2537
@@ -3446,6 +3511,7 @@ int hugetlb_reserve_pages(struct inode *inode,
3446 struct hstate *h = hstate_inode(inode); 3511 struct hstate *h = hstate_inode(inode);
3447 struct hugepage_subpool *spool = subpool_inode(inode); 3512 struct hugepage_subpool *spool = subpool_inode(inode);
3448 struct resv_map *resv_map; 3513 struct resv_map *resv_map;
3514 long gbl_reserve;
3449 3515
3450 /* 3516 /*
3451 * Only apply hugepage reservation if asked. At fault time, an 3517 * Only apply hugepage reservation if asked. At fault time, an
@@ -3482,8 +3548,13 @@ int hugetlb_reserve_pages(struct inode *inode,
3482 goto out_err; 3548 goto out_err;
3483 } 3549 }
3484 3550
3485 /* There must be enough pages in the subpool for the mapping */ 3551 /*
3486 if (hugepage_subpool_get_pages(spool, chg)) { 3552 * There must be enough pages in the subpool for the mapping. If
3553 * the subpool has a minimum size, there may be some global
3554 * reservations already in place (gbl_reserve).
3555 */
3556 gbl_reserve = hugepage_subpool_get_pages(spool, chg);
3557 if (gbl_reserve < 0) {
3487 ret = -ENOSPC; 3558 ret = -ENOSPC;
3488 goto out_err; 3559 goto out_err;
3489 } 3560 }
@@ -3492,9 +3563,10 @@ int hugetlb_reserve_pages(struct inode *inode,
3492 * Check enough hugepages are available for the reservation. 3563 * Check enough hugepages are available for the reservation.
3493 * Hand the pages back to the subpool if there are not 3564 * Hand the pages back to the subpool if there are not
3494 */ 3565 */
3495 ret = hugetlb_acct_memory(h, chg); 3566 ret = hugetlb_acct_memory(h, gbl_reserve);
3496 if (ret < 0) { 3567 if (ret < 0) {
3497 hugepage_subpool_put_pages(spool, chg); 3568 /* put back original number of pages, chg */
3569 (void)hugepage_subpool_put_pages(spool, chg);
3498 goto out_err; 3570 goto out_err;
3499 } 3571 }
3500 3572
@@ -3524,6 +3596,7 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
3524 struct resv_map *resv_map = inode_resv_map(inode); 3596 struct resv_map *resv_map = inode_resv_map(inode);
3525 long chg = 0; 3597 long chg = 0;
3526 struct hugepage_subpool *spool = subpool_inode(inode); 3598 struct hugepage_subpool *spool = subpool_inode(inode);
3599 long gbl_reserve;
3527 3600
3528 if (resv_map) 3601 if (resv_map)
3529 chg = region_truncate(resv_map, offset); 3602 chg = region_truncate(resv_map, offset);
@@ -3531,8 +3604,12 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
3531 inode->i_blocks -= (blocks_per_huge_page(h) * freed); 3604 inode->i_blocks -= (blocks_per_huge_page(h) * freed);
3532 spin_unlock(&inode->i_lock); 3605 spin_unlock(&inode->i_lock);
3533 3606
3534 hugepage_subpool_put_pages(spool, (chg - freed)); 3607 /*
3535 hugetlb_acct_memory(h, -(chg - freed)); 3608 * If the subpool has a minimum size, the number of global
3609 * reservations to be released may be adjusted.
3610 */
3611 gbl_reserve = hugepage_subpool_put_pages(spool, (chg - freed));
3612 hugetlb_acct_memory(h, -gbl_reserve);
3536} 3613}
3537 3614
3538#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE 3615#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE