From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BC8D421348 for ; Tue, 4 Nov 2025 00:15:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762215322; cv=none; b=WYKr5AuxEyVaH8yxLjN4Dr+bJZGPONMDBtA8AJD19YPJJZU9uQr+WUpfrWIanzUP/aE4BkUqBscXgPEQx9YJFdvc2JWGL+rO7Wf3V++QURBgt9aMmbuxkaitL1jc5Bwi5d1c4U6+EGkTJt/mAR4LBPUhHLKTv0DIv6uni0+mkzA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762215322; c=relaxed/simple; bh=H6brIF8jxyf5Fedu+T4DroNbUrftDL2liW+acA9iy6I=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=NDWVVddLbdXX740jL6r45Y6imcwMuVgKF8B+kAYazpanwP64lbPLebC7zVbHgD0PQVLQIAwwIeuyAiG4ydVTzwL3jtx2DB4KXwXMPs5GekzJz4uOosDzE14m0YCNR9S942thDoe0WOe17woJGB6SIyQxTAKLqI2yx2PHjc4ZMBU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0FBC81D14; Mon, 3 Nov 2025 16:15:11 -0800 (PST) Received: from [10.163.73.5] (unknown [10.163.73.5]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 310173F694; Mon, 3 Nov 2025 16:15:15 -0800 (PST) Message-ID: Date: Tue, 4 Nov 2025 05:45:13 +0530 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [RESEND] [PATCH v2] arm64/mm: Elide TLB flush in certain pte protection transitions To: Dev Jain , catalin.marinas@arm.com, will@kernel.org Cc: wangkefeng.wang@huawei.com, ryan.roberts@arm.com, baohua@kernel.org, pjaroszynski@nvidia.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org References: <20251017160251.96717-1-dev.jain@arm.com> Content-Language: en-US From: Anshuman Khandual In-Reply-To: <20251017160251.96717-1-dev.jain@arm.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit On 17/10/25 9:32 PM, Dev Jain wrote: > Currently arm64 does an unconditional TLB flush in mprotect(). This is not > required for some cases, for example, when changing from PROT_NONE to > PROT_READ | PROT_WRITE (a real usecase - glibc malloc does this to emulate > growing into the non-main heaps), and unsetting uffd-wp in a range. > > Therefore, implement pte_needs_flush() for arm64, which is already > implemented by some other arches as well. > > Running a userspace program changing permissions back and forth between > PROT_NONE and PROT_READ | PROT_WRITE, and measuring the average time taken > for the none->rw transition, I get a reduction from 3.2 microseconds to > 2.85 microseconds, giving a 12.3% improvement. > > Reviewed-by: Kefeng Wang > Signed-off-by: Dev Jain > --- > mm-selftests pass. Based on 6.18-rc1. > > v1->v2: > - Drop PTE_PRESENT_INVALID and PTE_AF checks, use ptdesc_t instead of > pteval_t, return !!diff (Ryan) > > arch/arm64/include/asm/tlbflush.h | 27 +++++++++++++++++++++++++++ > 1 file changed, 27 insertions(+) > > diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h > index 18a5dc0c9a54..40df783ba09a 100644 > --- a/arch/arm64/include/asm/tlbflush.h > +++ b/arch/arm64/include/asm/tlbflush.h > @@ -524,6 +524,33 @@ static inline void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *b > { > __flush_tlb_range_nosync(mm, start, end, PAGE_SIZE, true, 3); > } > + > +static inline bool __pte_flags_need_flush(ptdesc_t oldval, ptdesc_t newval) > +{ > + ptdesc_t diff = oldval ^ newval; > + > + /* invalid to valid transition requires no flush */ > + if (!(oldval & PTE_VALID)) Using pte_valid() helper would be better. if (!pte_valid(oldval)) return false; > + return false; > + > + /* Transition in the SW bits requires no flush */ > + diff &= ~PTE_SWBITS_MASK; > + > + return !!diff; > +} > + > +static inline bool pte_needs_flush(pte_t oldpte, pte_t newpte) > +{ > + return __pte_flags_need_flush(pte_val(oldpte), pte_val(newpte)); > +} > +#define pte_needs_flush pte_needs_flush > + > +static inline bool huge_pmd_needs_flush(pmd_t oldpmd, pmd_t newpmd) > +{ > + return __pte_flags_need_flush(pmd_val(oldpmd), pmd_val(newpmd)); > +} > +#define huge_pmd_needs_flush huge_pmd_needs_flush > + > #endif > > #endif