lkml.org 
[lkml]   [2021]   [Jul]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 294/593] swap: fix do_swap_page() race with swapoff
    Date
    From: Miaohe Lin <linmiaohe@huawei.com>

    [ Upstream commit 2799e77529c2a25492a4395db93996e3dacd762d ]

    When I was investigating the swap code, I found the below possible race
    window:

    CPU 1 CPU 2
    ----- -----
    do_swap_page
    if (data_race(si->flags & SWP_SYNCHRONOUS_IO)
    swap_readpage
    if (data_race(sis->flags & SWP_FS_OPS)) {
    swapoff
    ..
    p->swap_file = NULL;
    ..
    struct file *swap_file = sis->swap_file;
    struct address_space *mapping = swap_file->f_mapping;[oops!]

    Note that for the pages that are swapped in through swap cache, this isn't
    an issue. Because the page is locked, and the swap entry will be marked
    with SWAP_HAS_CACHE, so swapoff() can not proceed until the page has been
    unlocked.

    Fix this race by using get/put_swap_device() to guard against concurrent
    swapoff.

    Link: https://lkml.kernel.org/r/20210426123316.806267-3-linmiaohe@huawei.com
    Fixes: 0bcac06f27d7 ("mm,swap: skip swapcache for swapin of synchronous device")
    Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
    Reviewed-by: "Huang, Ying" <ying.huang@intel.com>
    Cc: Alex Shi <alexs@kernel.org>
    Cc: David Hildenbrand <david@redhat.com>
    Cc: Dennis Zhou <dennis@kernel.org>
    Cc: Hugh Dickins <hughd@google.com>
    Cc: Johannes Weiner <hannes@cmpxchg.org>
    Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
    Cc: Matthew Wilcox <willy@infradead.org>
    Cc: Michal Hocko <mhocko@suse.com>
    Cc: Minchan Kim <minchan@kernel.org>
    Cc: Tim Chen <tim.c.chen@linux.intel.com>
    Cc: Wei Yang <richard.weiyang@gmail.com>
    Cc: Yang Shi <shy828301@gmail.com>
    Cc: Yu Zhao <yuzhao@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    include/linux/swap.h | 9 +++++++++
    mm/memory.c | 11 +++++++++--
    2 files changed, 18 insertions(+), 2 deletions(-)

    diff --git a/include/linux/swap.h b/include/linux/swap.h
    index fbc6805358da..dfabf4660a67 100644
    --- a/include/linux/swap.h
    +++ b/include/linux/swap.h
    @@ -503,6 +503,15 @@ static inline struct swap_info_struct *swp_swap_info(swp_entry_t entry)
    return NULL;
    }

    +static inline struct swap_info_struct *get_swap_device(swp_entry_t entry)
    +{
    + return NULL;
    +}
    +
    +static inline void put_swap_device(struct swap_info_struct *si)
    +{
    +}
    +
    #define swap_address_space(entry) (NULL)
    #define get_nr_swap_pages() 0L
    #define total_swap_pages 0L
    diff --git a/mm/memory.c b/mm/memory.c
    index eb31b3e4ef93..0a905e0a7e67 100644
    --- a/mm/memory.c
    +++ b/mm/memory.c
    @@ -3302,6 +3302,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
    {
    struct vm_area_struct *vma = vmf->vma;
    struct page *page = NULL, *swapcache;
    + struct swap_info_struct *si = NULL;
    swp_entry_t entry;
    pte_t pte;
    int locked;
    @@ -3329,14 +3330,16 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
    goto out;
    }

    + /* Prevent swapoff from happening to us. */
    + si = get_swap_device(entry);
    + if (unlikely(!si))
    + goto out;

    delayacct_set_flag(DELAYACCT_PF_SWAPIN);
    page = lookup_swap_cache(entry, vma, vmf->address);
    swapcache = page;

    if (!page) {
    - struct swap_info_struct *si = swp_swap_info(entry);
    -
    if (data_race(si->flags & SWP_SYNCHRONOUS_IO) &&
    __swap_count(entry) == 1) {
    /* skip swapcache */
    @@ -3507,6 +3510,8 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
    unlock:
    pte_unmap_unlock(vmf->pte, vmf->ptl);
    out:
    + if (si)
    + put_swap_device(si);
    return ret;
    out_nomap:
    pte_unmap_unlock(vmf->pte, vmf->ptl);
    @@ -3518,6 +3523,8 @@ out_release:
    unlock_page(swapcache);
    put_page(swapcache);
    }
    + if (si)
    + put_swap_device(si);
    return ret;
    }

    --
    2.30.2


    \
     
     \ /
      Last update: 2021-07-12 09:10    [W:3.296 / U:0.328 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site