From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794590733; b=K/bS5xdQ2eNavG6I/0QeMlhfwten5YBsdhAj8HMakEsff1d03x1b7B6S/UQa5biUbkKY Cjvi/8E20zj1YaU9DBzVjjHbxls1DkzinSWboTE4FDFXRoOme+QgQOUWThG6jgQaFyVFA mOQi8pkkzhykBFTT/qsN35ljoptIwMKVERMk39eB5eGLdYUZrqdJQQyMHZmQeqbIvDCdc +Xxo7xEnPENZWIvOv73zLhwrJ00S3zn8bWZgA0gdKn1ATZ/dgjQzztJuKOFACxJYCrxox 6qen9SZSoJkh0l7Q4WIdhC7RlyjIuG5N0iFU1SEla93GtWGwCu4z1zFmQHjznXwYS9Q== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794590733; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=ucomWbRW708BHlfWkhOhuDa/GLZ9bIU0KxC+XUcveSU=; b=o5ZLiGLPSxfZdmlLNEsK4z+cISJdZF5Or7gV2is3x1zpb1jtbeco8VE9UszOW4DKwpsI oP5sYq4rVTW24yoQSMbNCRWJxmP8VpvlKub6noIsnch1bGRARDEnwlGyu0J8sK8rE3Oym K7m8QCVLgz3wcWHbujuqQojDIftgbmky9P4TJiw2gBAwgywiKQ1V6eds6ET6wv5rz7/TO SGEXRF/2u4CX9tNf/E2LsZBlC8u4DJNENzN2WkbF8TTnEcWvW5a/OGU8PqTYBZdtmrw2V ACR8EhtYDT9+Io3q91q1iQhW0MpM6CBWyIpvz55IC8tr5/ez9lDhkLKdtloOHmOzTDA== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=UcpOSWOK; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6788B6079D7B; Fri, 13 Nov 2026 17:25:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=UcpOSWOK Received: by smtp.kernel.org (Postfix) with ESMTPSA id C602E1F000C4; Fri, 13 Nov 2026 17:25:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794590733; bh=ucomWbRW708BHlfWkhOhuDa/GLZ9bIU0KxC+XUcveSU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=UcpOSWOK5KgFeWeRJB71t6+yxPdUdLQp4nCTYhf3tcMcUnAGqx8IJzLhuu60SqRCp T6ebOOnFB6vTR8fzJcoRHTt/VnIxZBrTIkbG73un7q9mqAw0wnH08UAvhp7dp4nm+o sbk+PjNmnbMfDWcTCrCTN56AA468vsqOI+RPOws0= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Hongfu Li , Andrew Morton , "David Hildenbrand (Arm)" , Baolin Wang , Hugh Dickins , Muchun Song , Oscar Salvador , Vivek Kasireddy , Sasha Levin Subject: [PATCH 6.18 636/686] mm/memfd: fix hugetlb reservation accounting in error paths Date: Fri, 13 Nov 2026 10:52:49 -0500 Message-ID: <20261113153843.366233531@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261113153820.902362109@linuxfoundation.org> References: <20261113153820.902362109@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: stable@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Hongfu Li [ Upstream commit 50ee565c1e900e247e439e4139839b060c968343 ] If hugetlb_add_to_page_cache() in memfd_alloc_folio() fails with -EEXIST, a concurrent fault has already instantiated the folio in the page cache, and the reservation now belongs to that folio. Calling hugetlb_unreserve_pages() in that case incorrectly removes the region backing the cached folio and releases one reservation more than it should, leaving that folio in the page cache with no region recording it. That leaves resv_huge_pages one page short until that folio is removed from the page cache, so available_huge_pages() reports a page that is not actually free and the pool can grant one reservation more than it can back. Applications using hugetlb memfds can then fail to allocate or fault in a page they already reserved. They see -ENOMEM or -ENOSPC from the allocation or fault path even though the reservation and HugePages_Free still look healthy. So hold the hugetlb fault mutex from hugetlb_reserve_pages() until the error-path unreserve completes to make the reserve, allocate and instantiate steps atomic against concurrent faults. With the mutex held from the start, a concurrent fault can no longer consume the reservation between reserve and allocate/instantiate. If a fault completed before the mutex was taken, it has already added the region for that index, so hugetlb_reserve_pages() returns 0 and the error path leaves the region in place. Link: https://lore.kernel.org/20260927094757.31665-1-hongfu.li@linux.dev Link: https://lore.kernel.org/20260903030134.7407-1-hongfu.li@linux.dev Fixes: 717cf9357325 ("mm/memfd: reserve hugetlb folios before allocation") Signed-off-by: Hongfu Li Signed-off-by: Andrew Morton Acked-by: David Hildenbrand (Arm) Cc: Baolin Wang Cc: Hugh Dickins Cc: Muchun Song Cc: Oscar Salvador Cc: Vivek Kasireddy Cc: [ sashal: Used 0 instead of EMPTY_VMA_FLAGS in hugetlb_reserve_pages() to match the vm_flags_t API. ] Signed-off-by: Sasha Levin --- mm/memfd.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/mm/memfd.c b/mm/memfd.c index aa3c948e55738..d09157cd486a2 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -82,22 +82,31 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx) struct hstate *h = hstate_file(memfd); int err = -ENOMEM; long nr_resv; + u32 hash; gfp_mask = htlb_alloc_mask(h); gfp_mask &= ~(__GFP_HIGHMEM | __GFP_MOVABLE); idx >>= huge_page_order(h); + /* + * Serialize hugepage allocation and instantiation to prevent + * races with concurrent allocations, as required by all other + * callers of hugetlb_add_to_page_cache(). + */ + hash = hugetlb_fault_mutex_hash(memfd->f_mapping, idx); + mutex_lock(&hugetlb_fault_mutex_table[hash]); + nr_resv = hugetlb_reserve_pages(inode, idx, idx + 1, NULL, 0); - if (nr_resv < 0) - return ERR_PTR(nr_resv); + if (nr_resv < 0) { + err = nr_resv; + goto out_unlock; + } folio = alloc_hugetlb_folio_reserve(h, numa_node_id(), NULL, gfp_mask); if (folio) { - u32 hash; - /* * Zero the folio to prevent information leaks to userspace. * Use folio_zero_user() which is optimized for huge/gigantic @@ -112,20 +121,9 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx) */ __folio_mark_uptodate(folio); - /* - * Serialize hugepage allocation and instantiation to prevent - * races with concurrent allocations, as required by all other - * callers of hugetlb_add_to_page_cache(). - */ - hash = hugetlb_fault_mutex_hash(memfd->f_mapping, idx); - mutex_lock(&hugetlb_fault_mutex_table[hash]); - err = hugetlb_add_to_page_cache(folio, memfd->f_mapping, idx); - - mutex_unlock(&hugetlb_fault_mutex_table[hash]); - if (err) { folio_put(folio); goto err_unresv; @@ -133,11 +131,14 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx) hugetlb_set_folio_subpool(folio, subpool_inode(inode)); folio_unlock(folio); + mutex_unlock(&hugetlb_fault_mutex_table[hash]); return folio; } err_unresv: if (nr_resv > 0) hugetlb_unreserve_pages(inode, idx, idx + 1, 0); +out_unlock: + mutex_unlock(&hugetlb_fault_mutex_table[hash]); return ERR_PTR(err); } #endif -- 2.53.0