lkml.org 
[lkml]   [2015]   [May]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 2/2] mm/hugetlb: handle races in alloc_huge_page and hugetlb_reserve_pages
    Date
    alloc_huge_page and hugetlb_reserve_pages use region_chg to
    calculate the number of pages which will be added to the reserve
    map. Subpool and global reserve counts are adjusted based on
    the output of region_chg. Before the pages are actually added
    to the reserve map, these routines could race and add fewer
    pages than expected. If this happens, the subpool and global
    reserve counts are not correct.

    Compare the number of pages actually added (region_add) to those
    expected to added (region_chg). If fewer pages are actually added,
    this indicates a race and adjust counters accordingly.

    Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
    ---
    mm/hugetlb.c | 34 ++++++++++++++++++++++++++++++----
    1 file changed, 30 insertions(+), 4 deletions(-)

    diff --git a/mm/hugetlb.c b/mm/hugetlb.c
    index 3855889..9234163 100644
    --- a/mm/hugetlb.c
    +++ b/mm/hugetlb.c
    @@ -1540,7 +1540,7 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
    struct hugepage_subpool *spool = subpool_vma(vma);
    struct hstate *h = hstate_vma(vma);
    struct page *page;
    - long chg;
    + long chg, commit;
    int ret, idx;
    struct hugetlb_cgroup *h_cg;

    @@ -1581,7 +1581,20 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,

    set_page_private(page, (unsigned long)spool);

    - vma_commit_reservation(h, vma, addr);
    + commit = vma_commit_reservation(h, vma, addr);
    + if (unlikely(chg > commit)) {
    + /*
    + * The page was added to the reservation map between
    + * vma_needs_reservation and vma_commit_reservation.
    + * This indicates a race with hugetlb_reserve_pages.
    + * Adjust for the subpool count incremented above AND
    + * in hugetlb_reserve_pages for the same page. Also,
    + * the reservation count added in hugetlb_reserve_pages
    + * no longer applies.
    + */
    + hugepage_subpool_put_pages(spool, 1);
    + hugetlb_acct_memory(h, -1);
    + }
    return page;

    out_uncharge_cgroup:
    @@ -3695,8 +3708,21 @@ int hugetlb_reserve_pages(struct inode *inode,
    * consumed reservations are stored in the map. Hence, nothing
    * else has to be done for private mappings here
    */
    - if (!vma || vma->vm_flags & VM_MAYSHARE)
    - region_add(resv_map, from, to);
    + if (!vma || vma->vm_flags & VM_MAYSHARE) {
    + long add = region_add(resv_map, from, to);
    +
    + if (unlikely(chg > add)) {
    + /*
    + * pages in this range were added to the reserve
    + * map between region_chg and region_add. This
    + * indicates a race with alloc_huge_page. Adjust
    + * the subpool and reserve counts modified above
    + * based on the difference.
    + */
    + hugepage_subpool_put_pages(spool, chg - add);
    + hugetlb_acct_memory(h, -(chg - ret));
    + }
    + }
    return 0;
    out_err:
    if (vma && is_vma_resv_set(vma, HPAGE_RESV_OWNER))
    --
    2.1.0


    \
     
     \ /
      Last update: 2015-05-23 06:41    [W:2.698 / U:0.256 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site