@@ -96,36 +96,89 @@ void hugepage_put_subpool(struct hugepage_subpool *spool)
9696 unlock_or_release_subpool (spool );
9797}
9898
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 ,
100108 long delta )
101109{
102- int ret = 0 ;
110+ long ret = delta ;
103111
104112 if (!spool )
105- return 0 ;
113+ return ret ;
106114
107115 spin_lock (& spool -> lock );
108- if ((spool -> used_hpages + delta ) <= spool -> max_hpages ) {
109- spool -> used_hpages += delta ;
110- } else {
111- ret = - ENOMEM ;
116+
117+ if (spool -> max_hpages != -1 ) { /* maximum size accounting */
118+ if ((spool -> used_hpages + delta ) <= spool -> max_hpages )
119+ spool -> used_hpages += delta ;
120+ else {
121+ ret = - ENOMEM ;
122+ goto unlock_ret ;
123+ }
112124 }
113- spin_unlock (& spool -> lock );
114125
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 );
115142 return ret ;
116143}
117144
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 ,
119152 long delta )
120153{
154+ long ret = delta ;
155+
121156 if (!spool )
122- return ;
157+ return delta ;
123158
124159 spin_lock (& spool -> lock );
125- spool -> used_hpages -= delta ;
126- /* If hugetlbfs_put_super couldn't free spool due to
127- * an outstanding quota reference, free it now. */
160+
161+ if (spool -> max_hpages != -1 ) /* maximum size accounting */
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+ */
128179 unlock_or_release_subpool (spool );
180+
181+ return ret ;
129182}
130183
131184static inline struct hugepage_subpool * subpool_inode (struct inode * inode )
@@ -873,6 +926,14 @@ void free_huge_page(struct page *page)
873926 restore_reserve = PagePrivate (page );
874927 ClearPagePrivate (page );
875928
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+
876937 spin_lock (& hugetlb_lock );
877938 hugetlb_cgroup_uncharge_page (hstate_index (h ),
878939 pages_per_huge_page (h ), page );
@@ -890,7 +951,6 @@ void free_huge_page(struct page *page)
890951 enqueue_huge_page (h , page );
891952 }
892953 spin_unlock (& hugetlb_lock );
893- hugepage_subpool_put_pages (spool , 1 );
894954}
895955
896956static 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,
13851445 if (chg < 0 )
13861446 return ERR_PTR (- ENOMEM );
13871447 if (chg || avoid_reserve )
1388- if (hugepage_subpool_get_pages (spool , 1 ))
1448+ if (hugepage_subpool_get_pages (spool , 1 ) < 0 )
13891449 return ERR_PTR (- ENOSPC );
13901450
13911451 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)
24532513 struct resv_map * resv = vma_resv_map (vma );
24542514 struct hugepage_subpool * spool = subpool_vma (vma );
24552515 unsigned long reserve , start , end ;
2516+ long gbl_reserve ;
24562517
24572518 if (!resv || !is_vma_resv_set (vma , HPAGE_RESV_OWNER ))
24582519 return ;
@@ -2465,8 +2526,12 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma)
24652526 kref_put (& resv -> refs , resv_map_release );
24662527
24672528 if (reserve ) {
2468- hugetlb_acct_memory (h , - reserve );
2469- hugepage_subpool_put_pages (spool , reserve );
2529+ /*
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 );
24702535 }
24712536}
24722537
@@ -3446,6 +3511,7 @@ int hugetlb_reserve_pages(struct inode *inode,
34463511 struct hstate * h = hstate_inode (inode );
34473512 struct hugepage_subpool * spool = subpool_inode (inode );
34483513 struct resv_map * resv_map ;
3514+ long gbl_reserve ;
34493515
34503516 /*
34513517 * Only apply hugepage reservation if asked. At fault time, an
@@ -3482,8 +3548,13 @@ int hugetlb_reserve_pages(struct inode *inode,
34823548 goto out_err ;
34833549 }
34843550
3485- /* There must be enough pages in the subpool for the mapping */
3486- if (hugepage_subpool_get_pages (spool , chg )) {
3551+ /*
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 ) {
34873558 ret = - ENOSPC ;
34883559 goto out_err ;
34893560 }
@@ -3492,9 +3563,10 @@ int hugetlb_reserve_pages(struct inode *inode,
34923563 * Check enough hugepages are available for the reservation.
34933564 * Hand the pages back to the subpool if there are not
34943565 */
3495- ret = hugetlb_acct_memory (h , chg );
3566+ ret = hugetlb_acct_memory (h , gbl_reserve );
34963567 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 );
34983570 goto out_err ;
34993571 }
35003572
@@ -3524,15 +3596,20 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
35243596 struct resv_map * resv_map = inode_resv_map (inode );
35253597 long chg = 0 ;
35263598 struct hugepage_subpool * spool = subpool_inode (inode );
3599+ long gbl_reserve ;
35273600
35283601 if (resv_map )
35293602 chg = region_truncate (resv_map , offset );
35303603 spin_lock (& inode -> i_lock );
35313604 inode -> i_blocks -= (blocks_per_huge_page (h ) * freed );
35323605 spin_unlock (& inode -> i_lock );
35333606
3534- hugepage_subpool_put_pages (spool , (chg - freed ));
3535- hugetlb_acct_memory (h , - (chg - freed ));
3607+ /*
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 );
35363613}
35373614
35383615#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
0 commit comments