From patchwork Fri Mar 21 13:06:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Ghiti X-Patchwork-Id: 14025421 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id A2375C36002 for ; Fri, 21 Mar 2025 13:13:53 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 482EA280009; Fri, 21 Mar 2025 09:13:51 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 43184280001; Fri, 21 Mar 2025 09:13:51 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 2D300280009; Fri, 21 Mar 2025 09:13:51 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 0D72B280001 for ; Fri, 21 Mar 2025 09:13:51 -0400 (EDT) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id 6C1FFAB0C6 for ; Fri, 21 Mar 2025 13:13:52 +0000 (UTC) X-FDA: 83245600704.21.151D62A Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) by imf02.hostedemail.com (Postfix) with ESMTP id 6E8378000D for ; Fri, 21 Mar 2025 13:13:50 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=rivosinc-com.20230601.gappssmtp.com header.s=20230601 header.b=UsSk2a2U; dmarc=none; spf=pass (imf02.hostedemail.com: domain of alexghiti@rivosinc.com designates 209.85.221.52 as permitted sender) smtp.mailfrom=alexghiti@rivosinc.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1742562830; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=ws5N2/PtP1Eu6ihB8rghsKDx2GXJblSk7INWyBMy7EM=; b=eqskbMSFfCcCWPBKvm9rvuF6gpL9m6KHNJv4R0o2o7Ft7lAQb6fFJhF+UgogQ+dQlQYx+o ASX5kHQH6R/npD3BMtmpO93WzXgZWi3JO0UrJhCyYA4Q4ZdkHtwCKPv1MhzFsQOwYGKnPn LvijfaJiByavF6UHVONEDRNgISikgSo= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1742562830; a=rsa-sha256; cv=none; b=r0SRN9g87+uu01xLpPl08Buuf18J9N7HNVLf3nlH5RX+Tz1KPtgZNTDNFzNJbJ+O5Gyvbz tuwUeW1fostBSiaX7FwiBkh9kcXFa7VaqsfYzUmFcyCjxlPZN1HRdv9JVX8ZHttFg/kNc+ EjSWuUwx01FQ6x2K8rjuZE5p/nPy+Fg= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=rivosinc-com.20230601.gappssmtp.com header.s=20230601 header.b=UsSk2a2U; dmarc=none; spf=pass (imf02.hostedemail.com: domain of alexghiti@rivosinc.com designates 209.85.221.52 as permitted sender) smtp.mailfrom=alexghiti@rivosinc.com Received: by mail-wr1-f52.google.com with SMTP id ffacd0b85a97d-38f2f391864so1095666f8f.3 for ; Fri, 21 Mar 2025 06:13:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1742562829; x=1743167629; darn=kvack.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ws5N2/PtP1Eu6ihB8rghsKDx2GXJblSk7INWyBMy7EM=; b=UsSk2a2UdEz4J7dqZrvgEpei2tOxDZ/xvYeN41Bz2e0hdelezPOq2eNgSXv6XdbDgj XBJ2XaSBXhNhaWVVE38khDuzXajbnf4dk17APPYT21EbgnINzMr+x/Sc8G8s19Sy5/OW WpvkmZSE+ShGGsT/23vHYx8eDBSXWs0XuPIcHdJ/37o6Hu23iIdsrot3fKNeEFMPuqCD 49sq2+nYyyHAbxOzoNlwsjyPX/0ncFHa48IC9EPa5ekA+XBdQna6GuzsVPonqlaRSOCL SjoAwopWU6Gs4zQKt6SWaMSeIZUcngiycmCMOmDQggM9q1r073WkffUK6nF7APs20Qzd o8iQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742562829; x=1743167629; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ws5N2/PtP1Eu6ihB8rghsKDx2GXJblSk7INWyBMy7EM=; b=SVJuJt601UbBkdZTvTCcd/MWQ6PtYwXwii4VOTyFcjwmYcPl28b01w5aZBau0xnppY EGzPal1+ojQX4KZt1PGIg6dOmP0Bv8BPc0sWObve/E4KkAXG+K6LiLXC6jXTPiapyhQ/ pS32mlSoJ54cHcDFJRkzBZ47FCxgl7p/0ZFuqwJKW/zeX/Fiy4rSYwyCYckhA2dlYLLn uaSmc37nrEVISzcFADmBJvnvWFZTMMv00cLaT3G1YeonS7apmOuts80UlE6huNk8xHvm D5U5FE3/wGdDotgWVPb564xeeuDSOmANQKJEikbuHKrfVku9oNKnt4IKtKWxVblJuaVI VClA== X-Forwarded-Encrypted: i=1; AJvYcCXH6cAwZAGF3ehIovn5NAkgK2hLOAmRZFohB6vuhw55/AvCxP3UreU6d1Jzzkh5lV+D0nR36eaMnw==@kvack.org X-Gm-Message-State: AOJu0YxB+VUtLL1FoL9ekaTVExSOg/RIp4S4/D8w+E7Jau/Gzl+rJyIe +WlnXA6k7Oj3uK3MFQAVZCscv4rY+XxKCpZDReVDQfH4Q+dwIrTl7gg227Urj18= X-Gm-Gg: ASbGncvTjJbW+dQEoAt5I4EL54uWdrcmHmiLmaATuTn9MTr1iDlllnPynsG7EH054Nq RjMQNNvgOTjipFiMCba8RPkp6bIz9SFwFxR2mZlNGqqPkji7zo17uwns2ncAfuSg/sIW9lys8Tm xiYY1LMvXciu+HfLkJZPKMVJ9ljQZu933cQTqMDeA/t5gbxiieiUjMnSicCK+G4PjnqNwycwjjL uRWhenW3gKX0SNerKIL1YHoGWa2Xc8cDwF/+1OINgPhZ9CQkzuhZFBtDjQWprcprklIJipOWTzW NsX8RvHoA/XyCfNLdtnYBwjcaA2JMOPmcXXzEDnzHq5vSo0yXYNRPerY225Z3f19RwTHDmjdm/N 1Kb8/ X-Google-Smtp-Source: AGHT+IGUJnxhjyGu7ufB6wyGpdYdbKS7+6k2eyHYgFKxVHRlB/Xm7E8vrXAFhp0hvlUzI9R7KED60g== X-Received: by 2002:a5d:64af:0:b0:391:2db0:2961 with SMTP id ffacd0b85a97d-3997f932efcmr3397837f8f.38.1742562828869; Fri, 21 Mar 2025 06:13:48 -0700 (PDT) Received: from alex-rivos.ba.rivosinc.com ([2001:861:3382:ef90:3d12:52fe:c1cc:c94]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3997f9e674fsm2292970f8f.80.2025.03.21.06.13.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Mar 2025 06:13:48 -0700 (PDT) From: Alexandre Ghiti To: Catalin Marinas , Will Deacon , Ryan Roberts , Mark Rutland , Matthew Wilcox , Paul Walmsley , Palmer Dabbelt , Alexandre Ghiti , Andrew Morton , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-riscv@lists.infradead.org, linux-mm@kvack.org Cc: Alexandre Ghiti Subject: [PATCH v5 7/9] mm: Use common huge_ptep_set_access_flags() function for riscv/arm64 Date: Fri, 21 Mar 2025 14:06:33 +0100 Message-Id: <20250321130635.227011-8-alexghiti@rivosinc.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20250321130635.227011-1-alexghiti@rivosinc.com> References: <20250321130635.227011-1-alexghiti@rivosinc.com> MIME-Version: 1.0 X-Rspamd-Server: rspam07 X-Rspamd-Queue-Id: 6E8378000D X-Stat-Signature: kut8i81wtw6qzrbpd8i37ud3jah9ktsg X-Rspam-User: X-HE-Tag: 1742562830-410119 X-HE-Meta: U2FsdGVkX1/IxH7y10jw1GPZUwxkOnsii3wzJw1hyds0wN+BozDwRpTXWAUNWs7RdSmRI1oRnGSAh/BYUrnBbPigoV5db0n0zcYN+J1808tGVDvFPW59E1ivoSOv4QS7UPda+WrobIcEXlQQqfQAajQ8OtscmfiKFmU5FqTIdc1NTH/xSfF1qDb3CFDIWKBdyHqZnKqSBLn3IK5R94VQB2CecWF6XD7n1XaKYnSxOXlFdN3/jqesbC6FYUSIOICESN+hSKpIY9yT5RxQymJ/sqn/UfTfi49mtWytEmVbEFsYbvOWSJFL0x9AiEKgmnSUC+PWUllZBDT6ELdMH5ssf0Ph2Ctp0ERlmddxzVHIRuoc8ZJchYp2ComCdqVxN7PvALXIG63wxh/b87cIeXVdQYQbXzwJCYdCuHyoJp4LL5BAyDvP74wOnDiQyVDYNgTd+DG+P6w+7KRh/IxayY+TL0isuPB05VtDgF3SPHjMnyo1vBzGIfjC4gJKhLl1lRrENzewOY/BRn+adnn8sndTzmgIHde+rAgLQq22rzVH3Gde6RnN3ElnrRdtz8Jbq8wGlMQNdb3mv6trzx/YZ1XoXKfh2K0RGHmxIK16X0PVX6KhCzozFuMlreQumzCwc8abg2hdieRj95EdBUyZ5E8BW4NOkN0g8BYfV8xemoss3U73MxRRREmPOopZQepaJaPteZXWToqmgIAap5ajGslWKgoW5wHTQdYqwCOd0cq3rJK3kJsR5f1++oUA9utEn0Q9fE31X/4RmLanCBTYO4ybg4nuxI/x+BRcjjarG6LZ7MI75veyuZ+Vc0z9j5NmhlHRvS/tEFrBHSiDyd7aSeYPKzEUskNTlKVY0atipxKkYTCJvLp5SG+rXAIUF7rzq5kLzQv/nSvawAGkURJYdEU5R+PXFX+g6GfmjUELszaY6XyJK1zlq3vcSKmnl62TV/jRQN96P6WbUWJWfsQ2Dp6 GwQH1gmr RDI/hyj6S8zAb6FZsNSirHYwhRGZ+S/tPHVr7kolNBjcBI5zH3WWrDpIWhd84qUfOOKxTxtbqqozrg4zmhLNdncVH3VSHhXcDtF01QHQxtGGpIxlokm8Fq8mOEZD3yjPiZWW8Se87rQnnmSatBSmVDPhVGiYO58XGO5ZVhoN+WBCLWGUciGPe50mU9v6Gh5CWZGoSGphtuGCXdfEfjL5rYujBv8M2IYGhoatOUN7aBz8tjb/nPKgX2RlNT0L6BOj9puHpksWhxe/JhPpd/X1GaIOh6vEMBTtNfz0XdZFZ6qv8pgxkfyn9TWKlhOeWYxmSwdRHUAa4jf/vAYj0x3RbUktkjnEwA1quQf3QSEUvePedhYC5et2gt3TnZp3wlwyrBUHIC8YIiX4TW2H8DBcSDRmT20FuWRCyBOxN1qNTU7m4bBebuH3bCI4uJDDK2LlfaIf2DZa6SO+6KkNA8RlSxI4VXA== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Both architectures have almost the same implementation: __cont_access_flags_changed() is also correct on riscv and brings the same benefits (ie don't do anything if the flags are unchanged). As in the previous commit, get_clear_contig_flush() is duplicated in both the arch and the generic codes, it will be removed from the arch code when the last reference there gets moved to the generic code. Signed-off-by: Alexandre Ghiti --- arch/arm64/include/asm/hugetlb.h | 4 -- arch/arm64/include/asm/pgtable.h | 15 +++++- arch/arm64/mm/hugetlbpage.c | 69 +-------------------------- arch/riscv/include/asm/hugetlb.h | 5 -- arch/riscv/include/asm/pgtable.h | 11 +++-- arch/riscv/mm/hugetlbpage.c | 32 ++----------- arch/riscv/mm/pgtable.c | 6 +-- include/linux/hugetlb_contpte.h | 5 ++ mm/hugetlb_contpte.c | 81 ++++++++++++++++++++++++++++++-- 9 files changed, 110 insertions(+), 118 deletions(-) diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h index 9b1c25775bea..29a9dac52cef 100644 --- a/arch/arm64/include/asm/hugetlb.h +++ b/arch/arm64/include/asm/hugetlb.h @@ -35,10 +35,6 @@ static inline void arch_clear_hugetlb_flags(struct folio *folio) pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags); #define arch_make_huge_pte arch_make_huge_pte -#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS -extern int huge_ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep, - pte_t pte, int dirty); #define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT extern void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep); diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index af8156929c1d..9b5c57e56691 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -1847,12 +1847,23 @@ static inline bool __hugetlb_valid_size(unsigned long size) return false; } -static inline int arch_contpte_get_num_contig(pte_t *ptep, - unsigned long size, +extern int find_num_contig(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, size_t *pgsize); + +static inline int arch_contpte_get_num_contig(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, unsigned long size, size_t *pgsize) { int contig_ptes = 1; + /* + * If the size is not passed, we need to go through the page table to + * find out the number of contiguous ptes. + */ + if (size == 0) + return find_num_contig(mm, addr, ptep, pgsize); + if (pgsize) *pgsize = size; diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c index 62a66ce2b2fe..03cb757f7935 100644 --- a/arch/arm64/mm/hugetlbpage.c +++ b/arch/arm64/mm/hugetlbpage.c @@ -63,8 +63,8 @@ bool arch_hugetlb_migration_supported(struct hstate *h) } #endif -static int find_num_contig(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, size_t *pgsize) +int find_num_contig(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, size_t *pgsize) { pgd_t *pgdp = pgd_offset(mm, addr); p4d_t *p4dp; @@ -260,71 +260,6 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags) return entry; } -/* - * huge_ptep_set_access_flags will update access flags (dirty, accesssed) - * and write permission. - * - * For a contiguous huge pte range we need to check whether or not write - * permission has to change only on the first pte in the set. Then for - * all the contiguous ptes we need to check whether or not there is a - * discrepancy between dirty or young. - */ -static int __cont_access_flags_changed(pte_t *ptep, pte_t pte, int ncontig) -{ - int i; - - if (pte_write(pte) != pte_write(__ptep_get(ptep))) - return 1; - - for (i = 0; i < ncontig; i++) { - pte_t orig_pte = __ptep_get(ptep + i); - - if (pte_dirty(pte) != pte_dirty(orig_pte)) - return 1; - - if (pte_young(pte) != pte_young(orig_pte)) - return 1; - } - - return 0; -} - -int huge_ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep, - pte_t pte, int dirty) -{ - int ncontig, i; - size_t pgsize = 0; - unsigned long pfn = pte_pfn(pte), dpfn; - struct mm_struct *mm = vma->vm_mm; - pgprot_t hugeprot; - pte_t orig_pte; - - if (!pte_cont(pte)) - return __ptep_set_access_flags(vma, addr, ptep, pte, dirty); - - ncontig = find_num_contig(mm, addr, ptep, &pgsize); - dpfn = pgsize >> PAGE_SHIFT; - - if (!__cont_access_flags_changed(ptep, pte, ncontig)) - return 0; - - orig_pte = get_clear_contig_flush(mm, addr, ptep, pgsize, ncontig); - - /* Make sure we don't lose the dirty or young state */ - if (pte_dirty(orig_pte)) - pte = pte_mkdirty(pte); - - if (pte_young(orig_pte)) - pte = pte_mkyoung(pte); - - hugeprot = pte_pgprot(pte); - for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) - __set_ptes(mm, addr, ptep, pfn_pte(pfn, hugeprot), 1); - - return 1; -} - void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { diff --git a/arch/riscv/include/asm/hugetlb.h b/arch/riscv/include/asm/hugetlb.h index 0fbb6b19df79..bf533c2cef84 100644 --- a/arch/riscv/include/asm/hugetlb.h +++ b/arch/riscv/include/asm/hugetlb.h @@ -28,11 +28,6 @@ pte_t huge_ptep_clear_flush(struct vm_area_struct *vma, void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep); -#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS -int huge_ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep, - pte_t pte, int dirty); - pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags); #define arch_make_huge_pte arch_make_huge_pte diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 72d3592454d3..081385e0d10a 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -613,7 +613,9 @@ static inline void ___set_ptes(struct mm_struct *mm, unsigned long addr, * Some hugetlb functions can be called on !present ptes, so we must use the * size parameter when it is passed. */ -static inline int arch_contpte_get_num_contig(pte_t *ptep, unsigned long size, +static inline int arch_contpte_get_num_contig(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, unsigned long size, size_t *pgsize) { unsigned long hugepage_shift; @@ -657,9 +659,8 @@ static inline void __pte_clear(struct mm_struct *mm, __set_pte_at(mm, ptep, __pte(0)); } -#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS /* defined in mm/pgtable.c */ -extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address, - pte_t *ptep, pte_t entry, int dirty); +extern int __ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address, + pte_t *ptep, pte_t entry, int dirty); #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG /* defined in mm/pgtable.c */ extern int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, pte_t *ptep); @@ -788,6 +789,8 @@ static inline pte_t __ptep_get_and_clear(struct mm_struct *mm, #define __HAVE_ARCH_PTEP_GET_AND_CLEAR #define ptep_get_and_clear __ptep_get_and_clear #define pte_clear __pte_clear +#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS +#define ptep_set_access_flags __ptep_set_access_flags #define pgprot_nx pgprot_nx static inline pgprot_t pgprot_nx(pgprot_t _prot) diff --git a/arch/riscv/mm/hugetlbpage.c b/arch/riscv/mm/hugetlbpage.c index 87168123d4a2..b2046f4bd445 100644 --- a/arch/riscv/mm/hugetlbpage.c +++ b/arch/riscv/mm/hugetlbpage.c @@ -176,33 +176,6 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags) return entry; } -int huge_ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long addr, - pte_t *ptep, - pte_t pte, - int dirty) -{ - struct mm_struct *mm = vma->vm_mm; - pte_t orig_pte; - int pte_num; - - if (!pte_napot(pte)) - return ptep_set_access_flags(vma, addr, ptep, pte, dirty); - - pte_num = arch_contpte_get_num_contig(ptep, 0, NULL); - orig_pte = get_clear_contig_flush(mm, addr, ptep, pte_num); - - if (pte_dirty(orig_pte)) - pte = pte_mkdirty(pte); - - if (pte_young(orig_pte)) - pte = pte_mkyoung(pte); - - set_ptes(mm, addr, ptep, pte, pte_num); - - return true; -} - void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) @@ -216,7 +189,8 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm, return; } - pte_num = arch_contpte_get_num_contig(ptep, 0, NULL); + pte_num = arch_contpte_get_num_contig(mm, addr, ptep, 0, NULL); + orig_pte = get_clear_contig_flush(mm, addr, ptep, pte_num); orig_pte = pte_wrprotect(orig_pte); @@ -234,7 +208,7 @@ pte_t huge_ptep_clear_flush(struct vm_area_struct *vma, if (!pte_napot(pte)) return ptep_clear_flush(vma, addr, ptep); - pte_num = arch_contpte_get_num_contig(ptep, 0, NULL); + pte_num = arch_contpte_get_num_contig(vma->vm_mm, addr, ptep, 0, NULL); return get_clear_contig_flush(vma->vm_mm, addr, ptep, pte_num); } diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c index 4ae67324f992..af8b3769a349 100644 --- a/arch/riscv/mm/pgtable.c +++ b/arch/riscv/mm/pgtable.c @@ -5,9 +5,9 @@ #include #include -int ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long address, pte_t *ptep, - pte_t entry, int dirty) +int __ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep, + pte_t entry, int dirty) { asm goto(ALTERNATIVE("nop", "j %l[svvptc]", 0, RISCV_ISA_EXT_SVVPTC, 1) : : : : svvptc); diff --git a/include/linux/hugetlb_contpte.h b/include/linux/hugetlb_contpte.h index 1c8f46ff95ea..e129578f6500 100644 --- a/include/linux/hugetlb_contpte.h +++ b/include/linux/hugetlb_contpte.h @@ -23,4 +23,9 @@ extern pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep, unsigned long sz); +#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS +extern int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep, + pte_t pte, int dirty); + #endif /* _LINUX_HUGETLB_CONTPTE_H */ diff --git a/mm/hugetlb_contpte.c b/mm/hugetlb_contpte.c index 82f49eb79ffb..b4c409d11195 100644 --- a/mm/hugetlb_contpte.c +++ b/mm/hugetlb_contpte.c @@ -15,7 +15,7 @@ pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep) if (!pte_present(orig_pte) || !pte_cont(orig_pte)) return orig_pte; - ncontig = arch_contpte_get_num_contig(ptep, + ncontig = arch_contpte_get_num_contig(mm, addr, ptep, page_size(pte_page(orig_pte)), NULL); @@ -69,7 +69,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, int i; int ncontig; - ncontig = arch_contpte_get_num_contig(ptep, sz, &pgsize); + ncontig = arch_contpte_get_num_contig(mm, addr, ptep, sz, &pgsize); if (!pte_present(pte)) { for (i = 0; i < ncontig; i++, ptep++, addr += pgsize) @@ -93,7 +93,7 @@ void huge_pte_clear(struct mm_struct *mm, unsigned long addr, int i, ncontig; size_t pgsize; - ncontig = arch_contpte_get_num_contig(ptep, sz, &pgsize); + ncontig = arch_contpte_get_num_contig(mm, addr, ptep, sz, &pgsize); for (i = 0; i < ncontig; i++, addr += pgsize, ptep++) __pte_clear(mm, addr, ptep); @@ -145,7 +145,80 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, int ncontig; size_t pgsize; - ncontig = arch_contpte_get_num_contig(ptep, sz, &pgsize); + ncontig = arch_contpte_get_num_contig(mm, addr, ptep, sz, &pgsize); return get_clear_contig(mm, addr, ptep, pgsize, ncontig); } + +/* + * huge_ptep_set_access_flags will update access flags (dirty, accesssed) + * and write permission. + * + * For a contiguous huge pte range we need to check whether or not write + * permission has to change only on the first pte in the set. Then for + * all the contiguous ptes we need to check whether or not there is a + * discrepancy between dirty or young. + */ +static int __cont_access_flags_changed(pte_t *ptep, pte_t pte, int ncontig) +{ + int i; + + if (pte_write(pte) != pte_write(__ptep_get(ptep))) + return 1; + + for (i = 0; i < ncontig; i++) { + pte_t orig_pte = __ptep_get(ptep + i); + + if (pte_dirty(pte) != pte_dirty(orig_pte)) + return 1; + + if (pte_young(pte) != pte_young(orig_pte)) + return 1; + } + + return 0; +} + +static pte_t get_clear_contig_flush(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, + unsigned long pgsize, + unsigned long ncontig) +{ + pte_t orig_pte = get_clear_contig(mm, addr, ptep, pgsize, ncontig); + struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0); + + flush_tlb_range(&vma, addr, addr + (pgsize * ncontig)); + return orig_pte; +} + +int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep, + pte_t pte, int dirty) +{ + int ncontig; + size_t pgsize = 0; + struct mm_struct *mm = vma->vm_mm; + pte_t orig_pte; + + if (!pte_cont(pte)) + return __ptep_set_access_flags(vma, addr, ptep, pte, dirty); + + ncontig = arch_contpte_get_num_contig(vma->vm_mm, addr, ptep, 0, &pgsize); + + if (!__cont_access_flags_changed(ptep, pte, ncontig)) + return 0; + + orig_pte = get_clear_contig_flush(mm, addr, ptep, pgsize, ncontig); + + /* Make sure we don't lose the dirty or young state */ + if (pte_dirty(orig_pte)) + pte = pte_mkdirty(pte); + + if (pte_young(orig_pte)) + pte = pte_mkyoung(pte); + + set_contptes(mm, addr, ptep, pte, ncontig, pgsize); + + return 1; +}