lkml.org 
[lkml]   [2022]   [Aug]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.19 0728/1157] mm/memremap: fix memunmap_pages() race with get_dev_pagemap()
    Date
    From: Miaohe Lin <linmiaohe@huawei.com>

    [ Upstream commit 1e57ffb6e3fd9583268c6462c4e3853575b21701 ]

    Think about the below scene:

    CPU1 CPU2
    memunmap_pages
    percpu_ref_exit
    __percpu_ref_exit
    free_percpu(percpu_count);
    /* percpu_count is freed here! */
    get_dev_pagemap
    xa_load(&pgmap_array, PHYS_PFN(phys))
    /* pgmap still in the pgmap_array */
    percpu_ref_tryget_live(&pgmap->ref)
    if __ref_is_percpu
    /* __PERCPU_REF_ATOMIC_DEAD not set yet */
    this_cpu_inc(*percpu_count)
    /* access freed percpu_count here! */
    ref->percpu_count_ptr = __PERCPU_REF_ATOMIC_DEAD;
    /* too late... */
    pageunmap_range

    To fix the issue, do percpu_ref_exit() after pgmap_array is emptied. So
    we won't do percpu_ref_tryget_live() against a being freed percpu_ref.

    Link: https://lkml.kernel.org/r/20220609121305.2508-1-linmiaohe@huawei.com
    Fixes: b7b3c01b1915 ("mm/memremap_pages: support multiple ranges per invocation")
    Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
    Cc: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    mm/memremap.c | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)

    diff --git a/mm/memremap.c b/mm/memremap.c
    index 745eea0f99c3..2bdb66854832 100644
    --- a/mm/memremap.c
    +++ b/mm/memremap.c
    @@ -141,10 +141,10 @@ void memunmap_pages(struct dev_pagemap *pgmap)
    for (i = 0; i < pgmap->nr_range; i++)
    percpu_ref_put_many(&pgmap->ref, pfn_len(pgmap, i));
    wait_for_completion(&pgmap->done);
    - percpu_ref_exit(&pgmap->ref);

    for (i = 0; i < pgmap->nr_range; i++)
    pageunmap_range(pgmap, i);
    + percpu_ref_exit(&pgmap->ref);

    WARN_ONCE(pgmap->altmap.alloc, "failed to free all reserved pages\n");
    devmap_managed_enable_put(pgmap);
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-08-16 02:23    [W:4.107 / U:0.596 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site