diff options
-rw-r--r-- | mm/hugetlb.c | 123 |
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 | ||
99 | static 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 | */ | ||
107 | static 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 | |||
140 | unlock_ret: | ||
141 | spin_unlock(&spool->lock); | ||
115 | return ret; | 142 | return ret; |
116 | } | 143 | } |
117 | 144 | ||
118 | static 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 | */ | ||
151 | static 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 | ||
131 | static inline struct hugepage_subpool *subpool_inode(struct inode *inode) | 184 | static 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 | ||
896 | static void prep_new_huge_page(struct hstate *h, struct page *page, int nid) | 956 | static 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 |