From nobody Sat Sep 26 07:14:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 5B5024E80D6; Thu, 3 Sep 2026 15:50:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450615; cv=none; b=qglkP4VsF2iVroTjQbbxxFcBQ2ok6WX4Uib0QcJeyBxU89ghJHwJzdPFSjO9pmbrX9ZfwtHCPgPSaPuSWRjnMgqs9T1OHLG0+r7xElpHxdKKivYOYLi9XwwGn0dKgZxw0YMw99XkOciBLispITozYj/GJT52C1wgsJ8orwQTkCc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450615; c=relaxed/simple; bh=wirvMfzcnmt9OrC6uut7rdUyKpHqT+LtpfZGnNovN+Q=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uLNScfSls8bZG2niouWH/lWxfaBppd2nmKT2HjFxPVOwklhImstN6eWsEC/FvyFVmKj4ZGNZHINqsykWQ9Ap+ywmLSgJYRestgi2VL5pwf/gBpE5Cn0kBO6j0+SXDHuHFnaxfqAiTuNIm2vl80ScqnNqTdzGYZI4K5usTTg+HOY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ixu35zh7; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ixu35zh7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E674F1F00A3F; Thu, 3 Sep 2026 15:50:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788450612; bh=mPNWvkEDUAJw+M0V5DscJNLnjX28HgRup/o43yOuiB8=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=ixu35zh7QD27Tqvzurmn7hUrdPhUWY2Jj5GPigjtjTOoZHCey3Nrj30X5NcP33ffM 6LQBnpbqCxGxH/K3do4zpDhcOz0HNl9Ve6VTX6mH/wHuhgc0LVlx2nFke7S5OX0mGi bUFWVixLPLPPLt/euGwch+HPkxuwsaXIPfGXPjhAmdEtUqeY+fyfpU4NHdIVrbKbBw K62EcK20bSg4RwctzOXE034YpwjdG0eoW3ze4+eopgXxKdO3OH1sbDHGeXzA0JLsRg TCOCZV4zawrC7y+UVeGSUjFwC//xyLvOFJxiKYOSaHeLSXF8ZKSvUGJ37yAnjjBJX1 /zNR9364P95Ww== From: "Mike Rapoport (Microsoft)" Date: Thu, 03 Sep 2026 18:49:58 +0300 Subject: [PATCH 1/5] mm/execmem: free ROX cache chunks only when they span an entire vm area Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-execmem-rox-cache-pmd-v1-v1-1-11beb2a3d249@kernel.org> References: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> In-Reply-To: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> To: Andrew Morton , Benjamin Tissoires , Jiri Kosina , Uladzislau Rezki Cc: Luis Chamberlain , Mike Rapoport , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, stable@vger.kernel.org X-Mailer: b4 0.17-dev When execmem refills the ROX cache, it vmalloc()s multiples of PMD_SIZE aligned to PMD_SIZE. For every such allocation vmalloc creates a vm area. The first part of the vmalloc()ed chunk is returned to the allocation that triggered the cache refill and the remaining part is added to the cache and handed out for subsequent allocations with execmem_alloc(). When only the first part is freed, the entire vm area remains in the ROX cache and can be handed out again. In the case when the first allocation is larger than PMD_SIZE and the second allocation from the freed first part of the chunk is exactly PMD_SIZE, execmem_cache_clean() will free the entire chunk while part of it is still in use. For example: /* * vmalloc(4M), return p0 to the caller * add [p0 + 3M, p0 + 4M) to the cache */ p0 =3D execmem_alloc(3M); /* return p0 + 3M from the cache to the caller */ p1 =3D execmem_alloc(1M); /* put [p0, p0 + 3M) back into the cache */ execmem_free(p0); /* return p0 from the cache to the caller */ p2 =3D execmem_alloc(2M); /* return p0 + 2M from the cache to the caller */ p3 =3D execmem_alloc(1M); /* bah! execmem_cache_clean() frees the entire 4M chunk */ execmem_free(p2); Make sure that the ranges that execmem_cache_clean() frees cover the entire vm area. Fixes: 2e45474ab14f ("execmem: add support for cache of large ROX pages") Assisted-by: copilot:claude-opus-5 Signed-off-by: Mike Rapoport (Microsoft) Cc: stable@vger.kernel.org --- mm/execmem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm/execmem.c b/mm/execmem.c index ad07cae9ed585..ba277790e3132 100644 --- a/mm/execmem.c +++ b/mm/execmem.c @@ -143,9 +143,11 @@ static void execmem_cache_clean(struct work_struct *wo= rk) =20 mutex_lock(mutex); mas_for_each(&mas, area, ULONG_MAX) { + struct vm_struct *vm =3D find_vm_area(area); size_t size =3D mas_range_len(&mas); =20 - if (IS_ALIGNED(size, PMD_SIZE) && + if (vm && get_vm_area_size(vm) =3D=3D size && + IS_ALIGNED(size, PMD_SIZE) && IS_ALIGNED(mas.index, PMD_SIZE)) { mas_store_gfp(&mas, NULL, GFP_KERNEL); vfree(area); --=20 2.53.0 From nobody Sat Sep 26 07:14:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 EA4AD4AA006; Thu, 3 Sep 2026 15:50:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450616; cv=none; b=hWeo+z+MifugTVtuS1R6hQ1dTES6x3S5Js1h0K97TJ9KOXDKNvEGvZf6q4F86XsozyeJNb6TQZbSl9h9+TPOViUG3ZCCyBzw7qj9uYIaNPuS+Qdf5I7b9vj6eCs6mOOWRinCfIGsdnp2pVVwc2QguVA7K6LqbDw5ODExHO73DFY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450616; c=relaxed/simple; bh=buyWxt0I1SrEkXs2Ifwprv+7bPz9xmj8G04s9XU86sc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pNgufGH9JofHFCf3SHijq+AuibfLBjw+hxO0QqWysS6aXNpywVw7e0JAf5HDCzHonD/MlMl+uacKfvfm065Tt/UMq8fPLBblPgl8ybsp6nnj0DhNXW/VgMjrx7iO0LcrH9j5X8I8GPXSk2gB7C8Nt0wIr3UKjD5mY0AqohC7xhs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HyoLOKJl; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="HyoLOKJl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AD8AB1F00A3D; Thu, 3 Sep 2026 15:50:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788450614; bh=xpQ+G6UtTo2w3vyGJPJeznHQWpBOtRAhjixM5nGiCoI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=HyoLOKJlU9flwF2tT95Ezp08U5AhXSIDW6og1SM/XSDUw+ZQVccfNY8oQaha0E0Kv /rU0Pr4QbVxBgR8Xy+3VEwTVZhF36XqveFhT3x79iLceMUMQg1hb2ZY4ZyMYy/qz03 62r8CxxYR9CU1ryqkbjIG4TFhmGcFIWz5fcP/Nhd7i2GGIVre1vHE4RFycDA3QxQwG kvywX37z7XHhtxCdfK6XJD7DslU/in2CwWvyvs5Mxmq9EjR79fNlCfHnEfTAhPXd3K 9Ntn063U9QxDcrODPy77wGWla25VW1v9uZsR2acs2+VMWoO5qb7GoGxjhFFzouPdn4 E1HS8YABSiUXA== From: "Mike Rapoport (Microsoft)" Date: Thu, 03 Sep 2026 18:49:59 +0300 Subject: [PATCH 2/5] mm/execmem: handle potential allocation errors in the maple tree Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-execmem-rox-cache-pmd-v1-v1-2-11beb2a3d249@kernel.org> References: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> In-Reply-To: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> To: Andrew Morton , Benjamin Tissoires , Jiri Kosina , Uladzislau Rezki Cc: Luis Chamberlain , Mike Rapoport , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org X-Mailer: b4 0.17-dev execmem_cache_clean() and execmem_cache_alloc_locked() ignore potential allocation failures in mas_store_gfp(). While in practice they are unlikely to happen, it's better to handle those errors and ensure the integrity of the ROX cache. Preallocate the maple tree nodes for the stores that must not fail and order the maple tree updates so that there won't be any failures once a tree has been modified. Assisted-by: copilot:claude-opus-5 Signed-off-by: Mike Rapoport (Microsoft) --- mm/execmem.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/mm/execmem.c b/mm/execmem.c index ba277790e3132..00dd6324cae01 100644 --- a/mm/execmem.c +++ b/mm/execmem.c @@ -149,7 +149,15 @@ static void execmem_cache_clean(struct work_struct *wo= rk) if (vm && get_vm_area_size(vm) =3D=3D size && IS_ALIGNED(size, PMD_SIZE) && IS_ALIGNED(mas.index, PMD_SIZE)) { - mas_store_gfp(&mas, NULL, GFP_KERNEL); + /* + * Preallocate to ensure mas_store does not fail + * If there is no memory for the tree update, bail out, + * next execmem_free() might be more lucky + */ + if (mas_preallocate(&mas, NULL, GFP_KERNEL)) + break; + + mas_store_prealloc(&mas, NULL); vfree(area); } } @@ -219,30 +227,34 @@ static void *execmem_cache_alloc_locked(struct execme= m_range *range, size_t size addr =3D mas_free.index; last =3D mas_free.last; =20 + mas_set_range(&mas_free, addr, addr + size - 1); + if (mas_preallocate(&mas_free, NULL, GFP_KERNEL)) + return NULL; + /* insert allocated size to busy_areas at range [addr, addr + size) */ mas_set_range(&mas_busy, addr, addr + size - 1); err =3D mas_store_gfp(&mas_busy, (void *)addr, GFP_KERNEL); if (err) - return NULL; + goto err_destroy_mas_free; =20 - mas_store_gfp(&mas_free, NULL, GFP_KERNEL); + mas_store_prealloc(&mas_free, NULL); if (area_size > size) { - void *ptr =3D (void *)(addr + size); - /* * re-insert remaining free size to free_areas at range * [addr + size, last] + * the range matches an existing entry, so this cannot allocate */ + ptr =3D (void *)(addr + size); mas_set_range(&mas_free, addr + size, last); - err =3D mas_store_gfp(&mas_free, ptr, GFP_KERNEL); - if (err) { - mas_store_gfp(&mas_busy, NULL, GFP_KERNEL); - return NULL; - } + mas_store_gfp(&mas_free, ptr, GFP_KERNEL); } ptr =3D (void *)addr; =20 return ptr; + +err_destroy_mas_free: + mas_destroy(&mas_free); + return NULL; } =20 static void *__execmem_cache_alloc(struct execmem_range *range, size_t siz= e) --=20 2.53.0 From nobody Sat Sep 26 07:14:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 81B204E80C8; Thu, 3 Sep 2026 15:50:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450618; cv=none; b=ITthGmaVGbFwliegvf4I3DuYay1v/lLgK2RdhjVykDSIckfVW60te7/LRacoN4LdC+HLZ3Gc096HLyTc0aH91uM2Xj6enCVW4JIr/z9ZQgWfFY+SCvysSmlEqaTdGQFK5hOubZrpdWGgV4ZTZrgh5scvMVmAsbKWMoftZMQjExo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450618; c=relaxed/simple; bh=lh2dT7ZewrgHg9g4KMVMPX90guRzzwDyD8C2CSWrPmk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=t35Dho0aRahsPUolMPyE0EP2kpfUuIrGmQ1/MbnS/NppDOEaouw25ZmmDQ+/I2GlwmWxuqpf5DJMf2g3Xdu2v4nD0eMwMERF2CHWTQyYI1IzCUTU4rmdd/wPh8vmF0m/Y0VMPOrrPsKOzE+GidbnXQsWM7mkGWEt4pwTZM8m9ZM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OYJ+Zl3t; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OYJ+Zl3t" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4180E1F00A3F; Thu, 3 Sep 2026 15:50:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788450617; bh=Z0X9ZLAQ4mUEchhwpqleI41xzP5aRuvK6f6Sh6Yxzi4=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=OYJ+Zl3tMLn1MD1z6fiXKp4+i9tHpSYBMlJNN0tpYuVSfwQKTR5zVkw45bX7Q4PTw o6NmhmyOQC1T8A7OxYMHgBjsFPek/w5rxSk5f3hxPJ7wUkgyINX5RUuG5hZErfLTDK d8FnpW/qGCiLySjLSSd7a5lqoeN4/j150u5+rP8OLeGhNApjIC16fJT869KuufeTIf Xz+fwfT6vjd7WFXrTSmMhfp1+3YJtwirO/TcznnlXg4cFTacvgDB1ywtBQ022spaHK A5TX3vACapU+ds4GgORfT0T1iv6dfsmsWcn7E41bTU0lD7+wbcf2SY42YlJ4vMlOeH geH2yghWdDQmg== From: "Mike Rapoport (Microsoft)" Date: Thu, 03 Sep 2026 18:50:00 +0300 Subject: [PATCH 3/5] mm/execmem: make sure ROX cache always contains multiples of PMD_SIZE Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-execmem-rox-cache-pmd-v1-v1-3-11beb2a3d249@kernel.org> References: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> In-Reply-To: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> To: Andrew Morton , Benjamin Tissoires , Jiri Kosina , Uladzislau Rezki Cc: Luis Chamberlain , Mike Rapoport , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org X-Mailer: b4 0.17-dev The ROX cache relies on its chunks being PMD mapped. For a PMD mapped chunk, set_memory_rox() updates the direct map alias one PMD at a time and the large mappings there survive. When execmem refills the cache, it rounds up the requested allocation size to PMD_SIZE and tries to allocate that with vmalloc(VM_ALLOW_HUGE_VMAP). If that allocation fails, execmem falls back to vmalloc() of the original size. There are two issues with this approach: * If huge pages are not available, __vmalloc_node_range() silently falls back to base pages. The area execmem gets is virtually contiguous, but it is backed by 512 scattered base pages. Permission updates on such areas split large mappings in the direct map that contain those base pages, up to 512 PMD splits in the worst case. * execmem's own fallback adds a small base page mapped area to the cache. This adds the overhead of cache management to these allocations with no benefit of reducing fragmentation either in the vmalloc/modules address space or in the direct map. Worse, these areas are never freed from the cache, because execmem_cache_clean() releases only chunks that are a multiple of PMD_SIZE and aligned to PMD_SIZE, exactly to minimize the number of base page mappings. Add VM_REQUIRE_HUGE_VMAP option to vmalloc that fails if the allocation of huge pages fails or if such an allocation is not possible because huge page allocations in vmalloc were disabled or the architecture does not support them. Use this option when populating the ROX cache. If vmalloc(VM_REQUIRE_HUGE_VMAP) fails or vmalloc of huge pages is unavailable, handle the memory allocation outside the ROX cache with plain vmalloc(). Since the fallback allocation has to return ROX memory, add an execmem_alloc_rox() helper and use it for both populating the ROX cache and dealing with a fallback allocation in a ROX execmem_range. With that, the cache only ever contains PMD aligned chunks sized as a multiple of PMD_SIZE, and the PMD checks in execmem_cache_clean() become a VM_WARN_ON_ONCE() to ensure that the PMD mapping invariant does not change. Assisted-by: copilot:claude-opus-5 Signed-off-by: Mike Rapoport (Microsoft) --- include/linux/vmalloc.h | 1 + mm/execmem.c | 76 ++++++++++++++++++++++++++++++---------------= ---- mm/vmalloc.c | 15 +++++++++- 3 files changed, 62 insertions(+), 30 deletions(-) diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index aed121d729b01..6e555e31e6225 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -38,6 +38,7 @@ struct iov_iter; /* in uio.h */ #define VM_DEFER_KMEMLEAK 0 #endif #define VM_SPARSE 0x00001000 /* sparse vm_area. not all pages are present= . */ +#define VM_REQUIRE_HUGE_VMAP 0x00002000 /* huge page mapping or nothing */ =20 /* bits [20..32] reserved for arch specific ioremap internals */ =20 diff --git a/mm/execmem.c b/mm/execmem.c index 00dd6324cae01..77653b7f163dc 100644 --- a/mm/execmem.c +++ b/mm/execmem.c @@ -51,7 +51,8 @@ static void *execmem_vmalloc(struct execmem_range *range,= size_t size, } =20 if (!p) { - pr_warn_ratelimited("unable to allocate memory\n"); + if (!(vm_flags & VM_REQUIRE_HUGE_VMAP)) + pr_warn_ratelimited("unable to allocate memory\n"); return NULL; } =20 @@ -146,9 +147,10 @@ static void execmem_cache_clean(struct work_struct *wo= rk) struct vm_struct *vm =3D find_vm_area(area); size_t size =3D mas_range_len(&mas); =20 - if (vm && get_vm_area_size(vm) =3D=3D size && - IS_ALIGNED(size, PMD_SIZE) && - IS_ALIGNED(mas.index, PMD_SIZE)) { + if (vm && get_vm_area_size(vm) =3D=3D size) { + VM_WARN_ON_ONCE(!IS_ALIGNED(mas.index, PMD_SIZE) || + !IS_ALIGNED(size, PMD_SIZE)); + /* * Preallocate to ensure mas_store does not fail * If there is no memory for the tree update, bail out, @@ -264,38 +266,41 @@ static void *__execmem_cache_alloc(struct execmem_ran= ge *range, size_t size) return execmem_cache_alloc_locked(range, size); } =20 -static void *execmem_cache_populate_alloc(struct execmem_range *range, siz= e_t size) +static void *execmem_vmalloc_rox(struct execmem_range *range, size_t size, + unsigned long vm_flags) { - unsigned long vm_flags =3D VM_ALLOW_HUGE_VMAP; - struct mutex *mutex =3D &execmem_cache.mutex; - struct vm_struct *vm; - size_t alloc_size; - int err =3D -ENOMEM; - void *p; - - alloc_size =3D round_up(size, PMD_SIZE); - p =3D execmem_vmalloc(range, alloc_size, PAGE_KERNEL, vm_flags); - if (!p) { - alloc_size =3D size; - p =3D execmem_vmalloc(range, alloc_size, PAGE_KERNEL, vm_flags); - } + void *p =3D execmem_vmalloc(range, size, PAGE_KERNEL, vm_flags); + int err; =20 if (!p) return NULL; =20 - vm =3D find_vm_area(p); - if (!vm) - goto err_free_mem; - /* fill memory with instructions that will trap */ - execmem_fill_trapping_insns(p, alloc_size); - + execmem_fill_trapping_insns(p, size); set_vm_flush_reset_perms(p); - - err =3D set_memory_rox((unsigned long)p, vm->nr_pages); + err =3D set_memory_rox((unsigned long)p, size >> PAGE_SHIFT); if (err) goto err_free_mem; =20 + return p; + +err_free_mem: + vfree(p); + return NULL; +} + +static void *execmem_cache_populate_alloc(struct execmem_range *range, siz= e_t size) +{ + unsigned long vm_flags =3D VM_REQUIRE_HUGE_VMAP; + size_t alloc_size =3D round_up(size, PMD_SIZE); + struct mutex *mutex =3D &execmem_cache.mutex; + int err; + void *p; + + p =3D execmem_vmalloc_rox(range, alloc_size, vm_flags); + if (!p) + return NULL; + /* * New memory blocks must be allocated and added to the cache * as an atomic operation, otherwise they may be consumed @@ -317,6 +322,11 @@ static void *execmem_cache_populate_alloc(struct execm= em_range *range, size_t si return NULL; } =20 +static void *execmem_alloc_rox(struct execmem_range *range, size_t size) +{ + return execmem_vmalloc_rox(range, size, 0); +} + static void *execmem_cache_alloc(struct execmem_range *range, size_t size) { void *p; @@ -444,6 +454,11 @@ static void *execmem_cache_alloc(struct execmem_range = *range, size_t size) return NULL; } =20 +static void *execmem_alloc_rox(struct execmem_range *range, size_t size) +{ + return NULL; +} + static bool execmem_cache_free(void *ptr) { return false; @@ -453,17 +468,20 @@ static bool execmem_cache_free(void *ptr) void *execmem_alloc(enum execmem_type type, size_t size) { struct execmem_range *range =3D &execmem_info->ranges[type]; - bool use_cache =3D range->flags & EXECMEM_ROX_CACHE; + bool use_rox_cache =3D range->flags & EXECMEM_ROX_CACHE; unsigned long vm_flags =3D VM_FLUSH_RESET_PERMS; pgprot_t pgprot =3D range->pgprot; void *p =3D NULL; =20 size =3D PAGE_ALIGN(size); =20 - if (use_cache) + if (use_rox_cache) { p =3D execmem_cache_alloc(range, size); - else + if (!p) + p =3D execmem_alloc_rox(range, size); + } else { p =3D execmem_vmalloc(range, size, pgprot, vm_flags); + } =20 return kasan_reset_tag(p); } diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 6ed6c160abed7..4df5c25786c6d 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -4027,6 +4027,12 @@ static gfp_t vmalloc_fix_flags(gfp_t flags) * %__GFP_SKIP_KASAN can be used to skip unpoisoning of mapped pages * (when prot=3D%PAGE_KERNEL). * + * %VM_ALLOW_HUGE_VMAP allocates huge pages when possible and falls back to + * base pages if huge page allocation fails. + * + * %VM_REQUIRE_HUGE_VMAP implies %VM_ALLOW_HUGE_VMAP and fails instead of + * silently falling back to base pages. + * * Can not be called from interrupt nor NMI contexts. * Return: the address of the area or %NULL on failure */ @@ -4052,6 +4058,10 @@ void *__vmalloc_node_range_noprof(unsigned long size= , unsigned long align, return NULL; } =20 + /* VM_REQUIRE_HUGE_VMAP implies VM_ALLOW_HUGE_VMAP */ + if (vm_flags & VM_REQUIRE_HUGE_VMAP) + vm_flags |=3D VM_ALLOW_HUGE_VMAP; + if (vmap_allow_huge && (vm_flags & VM_ALLOW_HUGE_VMAP)) { /* * Try huge pages. Only try for PAGE_KERNEL allocations, @@ -4068,6 +4078,9 @@ void *__vmalloc_node_range_noprof(unsigned long size,= unsigned long align, align =3D max(original_align, 1UL << shift); } =20 + if ((vm_flags & VM_REQUIRE_HUGE_VMAP) && shift =3D=3D PAGE_SHIFT) + return NULL; + again: area =3D __get_vm_area_node(size, align, shift, VM_ALLOC | VM_UNINITIALIZED | vm_flags, start, end, node, @@ -4142,7 +4155,7 @@ void *__vmalloc_node_range_noprof(unsigned long size,= unsigned long align, return area->addr; =20 fail: - if (shift > PAGE_SHIFT) { + if (shift > PAGE_SHIFT && !(vm_flags & VM_REQUIRE_HUGE_VMAP)) { shift =3D PAGE_SHIFT; align =3D original_align; goto again; --=20 2.53.0 From nobody Sat Sep 26 07:14:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 EDE254E80AD; Thu, 3 Sep 2026 15:50:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450621; cv=none; b=pI6DuN1F0gUY7OflOKmuIUoYkYCm3saFR4uashUZ9lNjQMflF3eM4PUOhYDluNdQ8KjscXnncawvc/wKAWG3+HhGf27e4y4rcriSdob56mat1N3CMBzXw30MoObxom9/lLelfdfZE1EH7s5V/0//FODQFvRKWdkDQoOnIofQY0k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450621; c=relaxed/simple; bh=ZRM/vI4pMdCAo6YUtblt4PuGHpZv2gO8Gpotzfpm4o0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QYwPaEkYtyb2K8G5xOrsIV51KEansGH0lUkc6SFRShBoq6HVUYmyxeElDCqcly/nMBVk0c32YB0udhMvcXhk/lFpHD8M+JTqieDvSyyWejXJNG44q5YaI0YiF7/TEILDGMu8ttQ6uDpzC3zpnG8IrXG9uJPNGtYuOi15WEjVt0A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gKSbt6d9; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gKSbt6d9" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C9EBC1F00A3D; Thu, 3 Sep 2026 15:50:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788450619; bh=7gSlHxYgypuWgcZDQkom/SXcL5+3gzhc1fw1FAM1Py0=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=gKSbt6d9D0uAdEaOVghOguJ6c5AtIVGFZ05HuItgg8aSgDE7+88HwvowvZDc8M4u4 g5ZZqw3Lc7+MZm/ErnQ6lTH7QY1fKwso02uiRPA4Lqq2HQpjUBxVRHu9XcggliatYB Ir8GpFHtraTriTsZPrQ7SPsYncQAtbqXCCnIz2jfVM5TtQHgUZLP18dr8d7VBx/0pv SShtK+ubAdzhIquF0nf2gnu5G64PAJSJz9JbbW0oQBIxX2mhFJ6wgyRuuKgGI68uqF qdRQd/XHSPvXQhsyPAEyo8sNgKYYrb9VcqX/Ub/P7IMdntF7IP5C2xnlesXk1istpT LDFrk2HJ8zXHQ== From: "Mike Rapoport (Microsoft)" Date: Thu, 03 Sep 2026 18:50:01 +0300 Subject: [PATCH 4/5] mm/vmalloc: add DEFINE_FREE() for vfree() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-execmem-rox-cache-pmd-v1-v1-4-11beb2a3d249@kernel.org> References: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> In-Reply-To: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> To: Andrew Morton , Benjamin Tissoires , Jiri Kosina , Uladzislau Rezki Cc: Luis Chamberlain , Mike Rapoport , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org X-Mailer: b4 0.17-dev ... and use it in hid-core, the only place with a cleanup for a vmalloc() allocation. Signed-off-by: Mike Rapoport (Microsoft) --- drivers/hid/hid-core.c | 4 ++-- include/linux/vmalloc.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a3ff0514f9cdf..ec7c2860c93ef 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -944,7 +944,7 @@ static int hid_scan_report(struct hid_device *hid) hid_parser_reserved }; =20 - struct hid_parser *parser __free(kvfree) =3D vzalloc(sizeof(*parser)); + struct hid_parser *parser __free(vfree) =3D vzalloc(sizeof(*parser)); if (!parser) return -ENOMEM; =20 @@ -1265,7 +1265,7 @@ static int hid_parse_collections(struct hid_device *d= evice) hid_parser_reserved }; =20 - struct hid_parser *parser __free(kvfree) =3D vzalloc(sizeof(*parser)); + struct hid_parser *parser __free(vfree) =3D vzalloc(sizeof(*parser)); if (!parser) return -ENOMEM; =20 diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 6e555e31e6225..034a693777ca0 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -3,6 +3,7 @@ #define _LINUX_VMALLOC_H =20 #include +#include #include #include #include @@ -215,6 +216,8 @@ void *__must_check vrealloc_node_align_noprof(const voi= d *p, size_t size, extern void vfree(const void *addr); extern void vfree_atomic(const void *addr); =20 +DEFINE_FREE(vfree, void *, if (!IS_ERR_OR_NULL(_T)) vfree(_T)) + extern void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot); void *vmap_pfn(unsigned long *pfns, unsigned int count, pgprot_t prot); --=20 2.53.0 From nobody Sat Sep 26 07:14:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 B7A854EBAC4; Thu, 3 Sep 2026 15:50:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450623; cv=none; b=nmfPeaSukkvnGFVAcDdbKqr3k/3xLhxnNuqSbfMN4CZHM1F3i7WIoFGhjDn/C9wBhQn8EeTURG/k1cUNtsxA90hwGbaksSr2TOGDH3qHmjfXfnTroSKKDbiIOcqFUpvU8v3OsOq1opbsAAwgiYrsarMBkdmxibc1bZa11bAmIhs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788450623; c=relaxed/simple; bh=FtoH+kwk2wKBBnqh3eHduPPmGppQi2AbEvfg6AlBsj0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Tj41QMwr52dxJwYuto7fKlsPMlSKgGm+WckfcgDy8Lf6E7GZEojCQW/nIwIT0PXsClzH4FL6UntdlDIxnHR5UYoVn4sjEBEEeiURysTdaPSsvmGO5wmb7uoC/BNA1Gk1d1JR1KgyjRfm+Qb8+PJH7QsVnyZKG7SfW63SH5L0Ois= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Rq53Txo2; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Rq53Txo2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5DA251F000E9; Thu, 3 Sep 2026 15:50:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788450622; bh=c57DBNEt0+woR56ZuvNbkfIrlDXYh8oKXIQm/KMduWA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Rq53Txo23LaqkMe5fufGOjTXt1HCpC3UBmUOtCC7iNt9tPfm6kTXXnPSDCAk9nxFE lwemGFrATyN+XAg13ALbLeKBqqCnEFjZCIw3m+OgJcoF6R2o55nl9zlR2nD0eTX5GV 5WP02yiztn4pzZBwyYJctDQamuvIJP/ix0ISO8UHAZl1Jm02IkgCxK2aY27CDvv6Hc 7QDyJftBmqBtwrh6mtysocnwg4FnJVx3Sfz+AXJds6nDGeBfsYx3+pfkjMCTK3jRpK /JYp0S0gnBA1SSNnCmI0CtvQhXnnUR5Tw1Fd/hwLuWwcoJS3sNrNTSUndJiU/wpXbY mJG5w/QHSQw6w== From: "Mike Rapoport (Microsoft)" Date: Thu, 03 Sep 2026 18:50:02 +0300 Subject: [PATCH 5/5] mm/execmem: use cleanup infrastructure in ROX cache functions Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-execmem-rox-cache-pmd-v1-v1-5-11beb2a3d249@kernel.org> References: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> In-Reply-To: <20260903-execmem-rox-cache-pmd-v1-v1-0-11beb2a3d249@kernel.org> To: Andrew Morton , Benjamin Tissoires , Jiri Kosina , Uladzislau Rezki Cc: Luis Chamberlain , Mike Rapoport , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org X-Mailer: b4 0.17-dev After splitting out execmem_alloc_rox() from execmem_cache_populate_alloc(), the error paths of both functions became less complex and can be easily switched to use the cleanup infrastructure. Use __free(vfree) to free allocated memory on the error paths and guard(mutex) for synchronization in ROX cache functions. Signed-off-by: Mike Rapoport (Microsoft) --- mm/execmem.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/mm/execmem.c b/mm/execmem.c index 77653b7f163dc..349cadd874863 100644 --- a/mm/execmem.c +++ b/mm/execmem.c @@ -138,11 +138,10 @@ int execmem_restore_rox(void *ptr, size_t size) static void execmem_cache_clean(struct work_struct *work) { struct maple_tree *free_areas =3D &execmem_cache.free_areas; - struct mutex *mutex =3D &execmem_cache.mutex; MA_STATE(mas, free_areas, 0, ULONG_MAX); void *area; =20 - mutex_lock(mutex); + guard(mutex)(&execmem_cache.mutex); mas_for_each(&mas, area, ULONG_MAX) { struct vm_struct *vm =3D find_vm_area(area); size_t size =3D mas_range_len(&mas); @@ -163,7 +162,6 @@ static void execmem_cache_clean(struct work_struct *wor= k) vfree(area); } } - mutex_unlock(mutex); } =20 static DECLARE_WORK(execmem_cache_clean_work, execmem_cache_clean); @@ -269,7 +267,7 @@ static void *__execmem_cache_alloc(struct execmem_range= *range, size_t size) static void *execmem_vmalloc_rox(struct execmem_range *range, size_t size, unsigned long vm_flags) { - void *p =3D execmem_vmalloc(range, size, PAGE_KERNEL, vm_flags); + void *p __free(vfree) =3D execmem_vmalloc(range, size, PAGE_KERNEL, vm_fl= ags); int err; =20 if (!p) @@ -280,22 +278,17 @@ static void *execmem_vmalloc_rox(struct execmem_range= *range, size_t size, set_vm_flush_reset_perms(p); err =3D set_memory_rox((unsigned long)p, size >> PAGE_SHIFT); if (err) - goto err_free_mem; - - return p; + return NULL; =20 -err_free_mem: - vfree(p); - return NULL; + return no_free_ptr(p); } =20 static void *execmem_cache_populate_alloc(struct execmem_range *range, siz= e_t size) { unsigned long vm_flags =3D VM_REQUIRE_HUGE_VMAP; size_t alloc_size =3D round_up(size, PMD_SIZE); - struct mutex *mutex =3D &execmem_cache.mutex; + void *p __free(vfree) =3D NULL; int err; - void *p; =20 p =3D execmem_vmalloc_rox(range, alloc_size, vm_flags); if (!p) @@ -306,20 +299,15 @@ static void *execmem_cache_populate_alloc(struct exec= mem_range *range, size_t si * as an atomic operation, otherwise they may be consumed * by a parallel call to the execmem_cache_alloc function. */ - mutex_lock(mutex); + guard(mutex)(&execmem_cache.mutex); err =3D execmem_cache_add_locked(p, alloc_size, GFP_KERNEL); - if (!err) - p =3D execmem_cache_alloc_locked(range, size); - mutex_unlock(mutex); - if (err) - goto err_free_mem; + return NULL; =20 - return p; + /* the chunk belongs to the cache now */ + retain_and_null_ptr(p); =20 -err_free_mem: - vfree(p); - return NULL; + return execmem_cache_alloc_locked(range, size); } =20 static void *execmem_alloc_rox(struct execmem_range *range, size_t size) --=20 2.53.0