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=1794585779; b=kUg94o3i7mrtl832bRJTlbMBAHwOadFxw3FWbDzsOllQnRdpU6HilLrVbcHjIWcQrhhB 7lEgERR4kEM9fWpBXBnrQi5UEpgPkSy1SnMizoVtxJg+B1Kjqo/QixA7iXeLZ/7F/XDGI kP/o31MIgJlDgZaHjq3DKAxKGbEXJBnWXS0BNWrsM4NYSuF4zQDf4BleP69dWTPQIcN3N /Yv5FBQWOCtR8Mc/tTmby0IONnLKbTnslN4raepn9nTt22UBYmhEtLKoUUzIaYBZtR4pb 77oVeOfIW7cGm6LsFFQhb401D3B9MzrAXD/zq751dUbZ6MqtY3pE8i+hhE8iIcGcKqA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794585779; 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=VRwAZumVn617QfkGlMZZu4ilSd0Ybyfymw4Rip48/lI=; b=SojpXDWFSqB9VQArShav//9b4tW8G/Hn2hqcpnZ/f7CQxr/sdgt5xfhbkw4eaz0pM4wI ukl6CaJOxMpUezQSY4i3KEym3iJP5pUMb6OxFvgTGdrLcVTor4mMcxVBo8iFhR+0tuCH3 ozg0zk9YlZlCY4d7l10AqEp923AGTtaXuFuo0Zjv419XM1bN0k4ucQ3WjWbe/IGP2aIuH fDA1PQGlGO0ng0VNgZh2gTsGpgF8leXQX2dKHCJWElK9QGg/dRWUx57auJJCtlZfYhEpV SGgE10xGdRfbQ9RcGrswz/7YQarJlXtbLcVVBjM5XuMN1hq+LxopG03iGPeO+GKTy/A== 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=e4ljYxWJ; 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 1F9F8606D466; Fri, 13 Nov 2026 16:02:59 +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=e4ljYxWJ Received: by smtp.kernel.org (Postfix) with ESMTPSA id C4D841F000C4; Fri, 13 Nov 2026 16:02:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794585779; bh=VRwAZumVn617QfkGlMZZu4ilSd0Ybyfymw4Rip48/lI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=e4ljYxWJwte1yntmUkQ63Rvy2pL95FqVWpmeWdfRC7XkvhePYsE3eWrU4o8CRV2mc IToT2tSyp5TioumDTpgrE2UvVMhE0Ooz33/cwBrb7z4+go+LbIMWnovcHvQFk27zwD 7dDDpqTtVcUj0ik6n6UBBU8vCcjJy4iivLet6QFA= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Chris Mason , "Lorenzo Stoakes (ARM)" , "Gregory Price (Meta)" , Muhammad Usama Anjum , Lance Yang , "David Hildenbrand (Arm)" , Sasha Levin Subject: [PATCH 7.3 327/507] mm/vma: call ->may_split() before a partial merge Date: Fri, 13 Nov 2026 10:50:31 -0500 Message-ID: <20261113153806.465959935@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261113153753.358973689@linuxfoundation.org> References: <20261113153753.358973689@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 7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Chris Mason [ Upstream commit 0193e83368022a308d19ee0293f55a4f5d548e40 ] A driver can use the ->may_split() hook to forbid a VMA boundary at certain addresses. A device-dax device is a character device that gives raw access to a range of memory through mmap(). device-dax refuses any address that is not a multiple of the device's alignment through vm_ops->may_split. vma_merge_existing_range() can move boundaries, but does not call vm_ops->may_split. If a range at the edge of a VMA gets the attributes of the adjacent VMA, the function moves only that range over to the neighbour: one VMA shrinks and the other grows. This is a partial merge, and vma_modify() tries it before any split. Take a device-dax VMA that lies next to another VMA of the same file. The user calls mprotect() on the one page of the first VMA that touches the second VMA, and asks for the protection that the second VMA already has. The result is a partial merge. It puts the boundary inside a 1 GiB mapping, which is a single leaf entry at the PUD level. As part of the merge, the kernel looks for a huge PMD to split at the new boundary. That code does not expect a PUD leaf: vma_merge_existing_range() commit_merge() vma_adjust_trans_huge() split_huge_pmd_address() mm_find_pmd() treats the PUD leaf as a pointer to a PMD table, so the "table" is the device memory that the leaf maps __split_huge_pmd() reads a PMD that the user wrote to the device memory folio_put() on the folio that this PMD names Bad. While the code must at some point be taught to split PUD entries as well, the issue here is that we move VMA boundaries such that they are incompatible with the driver. Fix this by calling ->may_split() on the address that a partial merge would move the boundary to, and by abandoning the merge if the driver refuses. vma_modify() then tries the split, which fails with -EINVAL. Factor out existing split handling into check_split() and reuse it. Fix generated by an LLM and sent by Chris Mason in private. Fixes: 38607c62b34b ("fs/dax: properly refcount fs dax pages") Cc: stable@vger.kernel.org Signed-off-by: Chris Mason Reviewed-by: Lorenzo Stoakes (ARM) [ david: improve description; cleanup the code ] Reviewed-by: Gregory Price (Meta) Tested-by: Gregory Price (Meta) Signed-off-by: Gregory Price (Meta) Tested-by: Muhammad Usama Anjum Link: https://patch.msgid.link/20261031-fixes_core-v3-42-d6437171ecc3@kernel.org Reviewed-by: Lance Yang Signed-off-by: David Hildenbrand (Arm) Signed-off-by: Sasha Levin --- mm/vma.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/mm/vma.c b/mm/vma.c index 2962670f27b5e..b257365f6e3c4 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -535,6 +535,15 @@ void unmap_region(struct unmap_desc *unmap) tlb_finish_mmu(&tlb); } +static int check_split(struct vm_area_struct *vma, unsigned long addr) +{ + if (!vma->vm_ops) + return 0; + if (!vma->vm_ops->may_split) + return 0; + return vma->vm_ops->may_split(vma, addr); +} + /* * __split_vma() bypasses sysctl_max_map_count checking. We use this where it * has already been checked or doesn't make sense to fail. @@ -551,11 +560,9 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, WARN_ON(vma->vm_start >= addr); WARN_ON(vma->vm_end <= addr); - if (vma->vm_ops && vma->vm_ops->may_split) { - err = vma->vm_ops->may_split(vma, addr); - if (err) - return err; - } + err = check_split(vma, addr); + if (err) + return err; vma_start_write(vma); new = vm_area_dup(vma); @@ -964,6 +971,10 @@ static __must_check struct vm_area_struct *vma_merge_existing_range( if (vmg->__remove_middle && !can_merge_remove_vma(middle)) return NULL; + /* If middle isn't removed then it's resized, i.e. splits. */ + if (!vmg->__remove_middle && check_split(middle, left_side ? end : start)) + return NULL; + /* * If we merge both VMAs, then next is also deleted. This implies * merge_will_delete_vma also. -- 2.53.0