Received: by 2002:a05:6a10:1d13:0:0:0:0 with SMTP id pp19csp4623574pxb; Tue, 31 Aug 2021 09:21:51 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw2ArrduFR+lJM2M1CIvl4+rHbf8fm4ofmkADVg+JJXHlnX4kGTsNLMjpW4jtWtnpzPscLc X-Received: by 2002:a05:6402:1d04:: with SMTP id dg4mr29241782edb.157.1630426911057; Tue, 31 Aug 2021 09:21:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1630426911; cv=none; d=google.com; s=arc-20160816; b=PAb4b9dw6aewlKDYQLS8qzE6jwjp8gFMeRQ9ohHo9v8vHIbxgOHFZW0I++Eb3A3sDe ILvJaIsyRcJBpaKItV/hBEfAsc61bwB1FSdWJ12Wp5OewcsTEazJtaZEIPAJEkUgMybZ KjZziuuI4XAW5P7ohNSqcDDnHRFTn7WVvMqGAo4ES5ivY3tKwRUABJGHL0IWP6wHDGMd /N1mS3SmDk1XOPJ9axgr/4rT5I7jaD1y/McavUP0A0zRfKS5NgiOKkZSGWUsHzohLla/ HSHOEQLUI8MtuInHvCBR3H1gbuJIuna9IsEzhTnEa0q47/tDzii/VocleNIkmkjddiZO vPFw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:message-id:date:subject:cc:to:from :dkim-signature; bh=jUjZnzjHu9GsMs6wMwVvYSFPL5+G8RVZ2+4T5OE5Dqo=; b=TUy+hX/Ljp2/RxXI9nygONf6wmcD4NV0IEAcvDvzW8RfXHHvgVNcVguVro/XilAbdB mlD4mKtbxMSXSvHgKHFH97ZLVMBPc1g2zU9VO3N5DoaKl8eRIduz8fCOsUEYboeFz7Ox kNavDg7T/GZv9qmu2fAJEruk10GaN545MkEcVUsJKbJuwbAG07oVoObSoDCR0qit9GMM PrahuiYAve1sxu/N+WdQncvVZ0ucx4SYJ+rnSNylEGQcRjzUXJyPJCwfokH7DtuO3SpN UomAOADJS+8nVDIzY8gif0RHaKNYwSIZUlJ5OTnkYoUhItvOJAzYpaRJt+Rv85q9UDlM 4Qfg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=Q3uA4sgZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id hs15si4713031ejc.20.2021.08.31.09.21.24; Tue, 31 Aug 2021 09:21:51 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=Q3uA4sgZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239852AbhHaQTl (ORCPT + 99 others); Tue, 31 Aug 2021 12:19:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34908 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239733AbhHaQTk (ORCPT ); Tue, 31 Aug 2021 12:19:40 -0400 Received: from mail-qt1-x82c.google.com (mail-qt1-x82c.google.com [IPv6:2607:f8b0:4864:20::82c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 123E2C061575 for ; Tue, 31 Aug 2021 09:18:45 -0700 (PDT) Received: by mail-qt1-x82c.google.com with SMTP id l24so15112597qtj.4 for ; Tue, 31 Aug 2021 09:18:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=jUjZnzjHu9GsMs6wMwVvYSFPL5+G8RVZ2+4T5OE5Dqo=; b=Q3uA4sgZs3IF8PBhXxHoeuB5YC9886TGhXSqYAEjUq9hzx1s2LApIrOF/AgLA7VFU2 uNMZ6njXDDp4HyA5q/3Ugf2CaOGuxMNi3bRr4KS+9J1LN2CsfYImYT6AEyIaMIa8371K i2DdLR5Nx8yt3pU/lomxT6adLiQUCdukjPXnj1sASIGATazsTEaXPXctsVkKT7h+OYzb jRbQzCBdk7OrDta4hASDWjwSb0+rNXsg51uWDruM9Y0Whn9glayFudDZoameoqjKZ5LN Haei/tGSFkqQbBJuYPsbnjE+UBOZo7gnAv3W4FhAI2VRnhfDpEtNAGgnh8M6NhWsiuLk cQYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=jUjZnzjHu9GsMs6wMwVvYSFPL5+G8RVZ2+4T5OE5Dqo=; b=nT21t+wihkV7J6UKFZm941zho9R1OMsj4Y7tdlRU+39nrFGO2CGVV9jA78hOqjuxfL BXk+TU8xV5wOkRB2WFOCqJVz8++5u1RpcZ2KY4JkEkr6IB4/uRU90GReQyzl8MXvM4gz Hy7rEyTFT/iBZFUGmY2hmaUBdm2cDh5e4B6mx5HUPXCgftlAUYbRZFMzgHcbC855kgPZ UZtaateexoBnZoaIaVaUcJz6YFCBBOKm+PSM7xS/L7ErufowKrFMmbqXSUIGyaFfbyb5 drikGHQgohRwxUFJElB7A/CkfhMiXpsxEa7aPNl6/hfwZVkImpx0kbXZUtP7bcxWxnyp lXQw== X-Gm-Message-State: AOAM5317Vy1PXO2+PiieXRpoGW9a6LpJblX9j3f3gXAI+BgUCDDGvfzZ wOg+B9tt8/gW8LeJA2x/4sY= X-Received: by 2002:ac8:7d0d:: with SMTP id g13mr3463954qtb.367.1630426724005; Tue, 31 Aug 2021 09:18:44 -0700 (PDT) Received: from localhost.localdomain (ec2-35-169-212-159.compute-1.amazonaws.com. [35.169.212.159]) by smtp.gmail.com with ESMTPSA id n14sm10757112qti.47.2021.08.31.09.18.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Aug 2021 09:18:43 -0700 (PDT) From: SeongJae Park To: akpm@linux-foundation.org Cc: david@redhat.com, markubo@amazon.com, linux-mm@kvack.org, linux-kernel@vger.kernel.org, SeongJae Park Subject: [PATCH v2] mm/damon/vaddr: Safely walk page table Date: Tue, 31 Aug 2021 16:18:00 +0000 Message-Id: <20210831161800.29419-1-sj38.park@gmail.com> X-Mailer: git-send-email 2.17.1 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: SeongJae Park Commit d7f647622761 ("mm/damon: implement primitives for the virtual memory address spaces") of linux-mm[1] tries to find PTE or PMD for arbitrary virtual address using 'follow_invalidate_pte()' without proper locking[2]. This commit fixes the issue by using another page table walk function for more general use case ('walk_page_range()') under proper locking (holding mmap read lock). [1] https://github.com/hnaz/linux-mm/commit/d7f647622761 [2] https://lore.kernel.org/linux-mm/3b094493-9c1e-6024-bfd5-7eca66399b7e@redhat.com Fixes: d7f647622761 ("mm/damon: implement primitives for the virtual memory address spaces") Reported-by: David Hildenbrand Signed-off-by: SeongJae Park --- Changes from v1 (https://lore.kernel.org/linux-mm/20210827150400.6305-1-sj38.park@gmail.com/) - Hold only mmap read lock (David Hildenbrand) - Access the PTE/PMD from the walk_page_range() callbacks (David Hildenbrand) mm/damon/vaddr.c | 136 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 39 deletions(-) diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c index 230db7413278..58c1fb2aafa9 100644 --- a/mm/damon/vaddr.c +++ b/mm/damon/vaddr.c @@ -8,10 +8,12 @@ #define pr_fmt(fmt) "damon-va: " fmt #include +#include #include #include #include #include +#include #include #include #include @@ -446,22 +448,42 @@ static void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm, #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ } -static void damon_va_mkold(struct mm_struct *mm, unsigned long addr) +static int damon_mkold_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) { - pte_t *pte = NULL; - pmd_t *pmd = NULL; + pte_t *pte; spinlock_t *ptl; - if (follow_invalidate_pte(mm, addr, NULL, &pte, &pmd, &ptl)) - return; - - if (pte) { - damon_ptep_mkold(pte, mm, addr); - pte_unmap_unlock(pte, ptl); - } else { - damon_pmdp_mkold(pmd, mm, addr); + if (pmd_huge(*pmd)) { + ptl = pmd_lock(walk->mm, pmd); + if (pmd_huge(*pmd)) { + damon_pmdp_mkold(pmd, walk->mm, addr); + spin_unlock(ptl); + return 0; + } spin_unlock(ptl); } + + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + return 0; + pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); + if (!pte_present(*pte)) + goto out; + damon_ptep_mkold(pte, walk->mm, addr); +out: + pte_unmap_unlock(pte, ptl); + return 0; +} + +static struct mm_walk_ops damon_mkold_ops = { + .pmd_entry = damon_mkold_pmd_entry, +}; + +static void damon_va_mkold(struct mm_struct *mm, unsigned long addr) +{ + mmap_read_lock(mm); + walk_page_range(mm, addr, addr + 1, &damon_mkold_ops, NULL); + mmap_read_unlock(mm); } /* @@ -492,43 +514,79 @@ void damon_va_prepare_access_checks(struct damon_ctx *ctx) } } -static bool damon_va_young(struct mm_struct *mm, unsigned long addr, - unsigned long *page_sz) +struct damon_young_walk_private { + unsigned long *page_sz; + bool young; +}; + +static int damon_young_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) { - pte_t *pte = NULL; - pmd_t *pmd = NULL; + pte_t *pte; spinlock_t *ptl; struct page *page; - bool young = false; - - if (follow_invalidate_pte(mm, addr, NULL, &pte, &pmd, &ptl)) - return false; - - *page_sz = PAGE_SIZE; - if (pte) { - page = damon_get_page(pte_pfn(*pte)); - if (page && (pte_young(*pte) || !page_is_idle(page) || - mmu_notifier_test_young(mm, addr))) - young = true; - if (page) - put_page(page); - pte_unmap_unlock(pte, ptl); - return young; - } + struct damon_young_walk_private *priv = walk->private; #ifdef CONFIG_TRANSPARENT_HUGEPAGE - page = damon_get_page(pmd_pfn(*pmd)); - if (page && (pmd_young(*pmd) || !page_is_idle(page) || - mmu_notifier_test_young(mm, addr))) - young = true; - if (page) + if (pmd_huge(*pmd)) { + ptl = pmd_lock(walk->mm, pmd); + if (!pmd_huge(*pmd)) { + spin_unlock(ptl); + goto regular_page; + } + page = damon_get_page(pmd_pfn(*pmd)); + if (!page) + goto huge_out; + if (pmd_young(*pmd) || !page_is_idle(page) || + mmu_notifier_test_young(walk->mm, + addr)) { + *priv->page_sz = ((1UL) << HPAGE_PMD_SHIFT); + priv->young = true; + } put_page(page); +huge_out: + spin_unlock(ptl); + return 0; + } - spin_unlock(ptl); - *page_sz = ((1UL) << HPAGE_PMD_SHIFT); +regular_page: #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ - return young; + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + return -EINVAL; + pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); + if (!pte_present(*pte)) + goto out; + page = damon_get_page(pte_pfn(*pte)); + if (!page) + goto out; + if (pte_young(*pte) || !page_is_idle(page) || + mmu_notifier_test_young(walk->mm, addr)) { + *priv->page_sz = PAGE_SIZE; + priv->young = true; + } + put_page(page); +out: + pte_unmap_unlock(pte, ptl); + return 0; +} + +static struct mm_walk_ops damon_young_ops = { + .pmd_entry = damon_young_pmd_entry, +}; + +static bool damon_va_young(struct mm_struct *mm, unsigned long addr, + unsigned long *page_sz) +{ + struct damon_young_walk_private arg = { + .page_sz = page_sz, + .young = false, + }; + + mmap_read_lock(mm); + walk_page_range(mm, addr, addr + 1, &damon_young_ops, &arg); + mmap_read_unlock(mm); + return arg.young; } /* -- 2.17.1