From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-186.mta0.migadu.com (out-186.mta0.migadu.com [91.218.175.186]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 83873188596 for ; Fri, 27 Mar 2026 02:14:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.186 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774577660; cv=none; b=XQRdYR7ftTj/eD+hxfJB6RWLiO99eSoq+cjyhipoDvjWGRCJi5iVDm7oNbibSLNo+VPOoQcqWE7TTz07Z1dtvHOzn0RUr4ljk2Xi5k0M3IEFoyhUtFruk+nnevsCxyn6HaLAvNfJpDx8Jtfube3xnbZxMLnsGHcdIqgCoUdmxLE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774577660; c=relaxed/simple; bh=a0weMuyoTIRziCg5iagpSP3kXAOGRR06q6WMxemQMLI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jP/hZArmR5T94CcN5tHVIhbnAoRsv/HAl1kwnahXlYEZx3gZk/jTCvamGvky3PIRk8LmGnYK7JSG96EltK2tQ9rZwjMSVeeqbA9WEXyMItQYr5rpi/Oa1egVAytAdoGt33hPU05Am+XnE6isi1+PcBm9U1a43QC8EWkTYFzwgD0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=AyyvqfAT; arc=none smtp.client-ip=91.218.175.186 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="AyyvqfAT" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1774577656; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=35ZUueVWTNj5ENc9hO0kXufOV22N6/4M8lIMyGx5nWI=; b=AyyvqfATC2BCM88QS4aIPXad5Ss5lC9cHT+xptmrLSNcMLknDQOu4gCyD1sp2YYHpHTvk4 VNJ9tKHO1z4pcHLd7iTIFFjH3tGKbBu91MSXsXrZW8sVi+XZU0uHE+BRUOx22o/9NBQ71z P3xX9UxGsvxqcy4J1vMbAqdE12t9QJ4= From: Usama Arif To: Andrew Morton , david@kernel.org, Lorenzo Stoakes , willy@infradead.org, linux-mm@kvack.org Cc: fvdl@google.com, hannes@cmpxchg.org, riel@surriel.com, shakeel.butt@linux.dev, kas@kernel.org, baohua@kernel.org, dev.jain@arm.com, baolin.wang@linux.alibaba.com, npache@redhat.com, Liam.Howlett@oracle.com, ryan.roberts@arm.com, Vlastimil Babka , lance.yang@linux.dev, linux-kernel@vger.kernel.org, kernel-team@meta.com, maddy@linux.ibm.com, mpe@ellerman.id.au, linuxppc-dev@lists.ozlabs.org, hca@linux.ibm.com, gor@linux.ibm.com, agordeev@linux.ibm.com, borntraeger@linux.ibm.com, svens@linux.ibm.com, linux-s390@vger.kernel.org, Usama Arif Subject: [v3 01/24] mm: thp: make split_huge_pmd functions return int for error propagation Date: Thu, 26 Mar 2026 19:08:43 -0700 Message-ID: <20260327021403.214713-2-usama.arif@linux.dev> In-Reply-To: <20260327021403.214713-1-usama.arif@linux.dev> References: <20260327021403.214713-1-usama.arif@linux.dev> Precedence: bulk X-Mailing-List: linux-s390@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT Currently split cannot fail, but future patches will add lazy PTE page table allocation. With lazy PTE page table allocation at THP split time __split_huge_pmd() calls pte_alloc_one() which can fail if order-0 allocation cannot be satisfied. Split functions currently return void, so callers have no way to detect this failure. The PMD would remain huge, but callers assumed the split succeeded and proceeded to operate on that basis — interpreting a huge PMD entry as a page table pointer could result in a kernel bug. Change __split_huge_pmd(), split_huge_pmd(), split_huge_pmd_if_needed() and split_huge_pmd_address() to return 0 on success (-ENOMEM on allocation failure in later patch). Convert the split_huge_pmd macro to a static inline function that propagates the return value. The return values will be handled by the callers in future commits. The CONFIG_TRANSPARENT_HUGEPAGE=n stubs are changed to return 0. No behaviour change is expected with this patch. Signed-off-by: Usama Arif --- include/linux/huge_mm.h | 34 ++++++++++++++++++---------------- mm/huge_memory.c | 16 ++++++++++------ 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index 1258fa37e85b5..b081ce044c735 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -418,7 +418,7 @@ static inline int split_huge_page(struct page *page) extern struct list_lru deferred_split_lru; void deferred_split_folio(struct folio *folio, bool partially_mapped); -void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, +int __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, unsigned long address, bool freeze); /** @@ -447,15 +447,15 @@ static inline bool pmd_is_huge(pmd_t pmd) return false; } -#define split_huge_pmd(__vma, __pmd, __address) \ - do { \ - pmd_t *____pmd = (__pmd); \ - if (pmd_is_huge(*____pmd)) \ - __split_huge_pmd(__vma, __pmd, __address, \ - false); \ - } while (0) +static inline int split_huge_pmd(struct vm_area_struct *vma, + pmd_t *pmd, unsigned long address) +{ + if (pmd_is_huge(*pmd)) + return __split_huge_pmd(vma, pmd, address, false); + return 0; +} -void split_huge_pmd_address(struct vm_area_struct *vma, unsigned long address, +int split_huge_pmd_address(struct vm_area_struct *vma, unsigned long address, bool freeze); void __split_huge_pud(struct vm_area_struct *vma, pud_t *pud, @@ -649,13 +649,15 @@ static inline int try_folio_split_to_order(struct folio *folio, } static inline void deferred_split_folio(struct folio *folio, bool partially_mapped) {} -#define split_huge_pmd(__vma, __pmd, __address) \ - do { } while (0) - -static inline void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, - unsigned long address, bool freeze) {} -static inline void split_huge_pmd_address(struct vm_area_struct *vma, - unsigned long address, bool freeze) {} +static inline int split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, + unsigned long address) +{ + return 0; +} +static inline int __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, + unsigned long address, bool freeze) { return 0; } +static inline int split_huge_pmd_address(struct vm_area_struct *vma, + unsigned long address, bool freeze) { return 0; } static inline void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address, pmd_t *pmd, bool freeze) {} diff --git a/mm/huge_memory.c b/mm/huge_memory.c index b2a6060b3c202..976a1c74c0870 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -3283,7 +3283,7 @@ void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address, __split_huge_pmd_locked(vma, pmd, address, freeze); } -void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, +int __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, unsigned long address, bool freeze) { spinlock_t *ptl; @@ -3297,20 +3297,22 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, split_huge_pmd_locked(vma, range.start, pmd, freeze); spin_unlock(ptl); mmu_notifier_invalidate_range_end(&range); + + return 0; } -void split_huge_pmd_address(struct vm_area_struct *vma, unsigned long address, +int split_huge_pmd_address(struct vm_area_struct *vma, unsigned long address, bool freeze) { pmd_t *pmd = mm_find_pmd(vma->vm_mm, address); if (!pmd) - return; + return 0; - __split_huge_pmd(vma, pmd, address, freeze); + return __split_huge_pmd(vma, pmd, address, freeze); } -static inline void split_huge_pmd_if_needed(struct vm_area_struct *vma, unsigned long address) +static inline int split_huge_pmd_if_needed(struct vm_area_struct *vma, unsigned long address) { /* * If the new address isn't hpage aligned and it could previously @@ -3319,7 +3321,9 @@ static inline void split_huge_pmd_if_needed(struct vm_area_struct *vma, unsigned if (!IS_ALIGNED(address, HPAGE_PMD_SIZE) && range_in_vma(vma, ALIGN_DOWN(address, HPAGE_PMD_SIZE), ALIGN(address, HPAGE_PMD_SIZE))) - split_huge_pmd_address(vma, address, false); + return split_huge_pmd_address(vma, address, false); + + return 0; } void vma_adjust_trans_huge(struct vm_area_struct *vma, -- 2.52.0