From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 49096313E07 for ; Tue, 6 Jan 2026 14:39:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.176 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767710348; cv=none; b=s2spy5s8UflOp03yszaQODBchpnCIbix+1kb2p1/IlPtDSZpVrF8WECDm8WupjfhCiD1FTQh3KODyrGLGI6K4MdzknVdqVB6bxj9EmtkJ+8GCEdJys+2dTE0kBU8vzSF5ZIH/u/9EPoPrbGUwbNJDhC4GymnehN4Y9vjewy59Ys= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767710348; c=relaxed/simple; bh=oZqlyrNd/Koj+FeveBwXgHL8mCmPA7SJ8WwhyPp+dNI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SEVjfBf7ltb2KfDt2EYXBrvoM4Vg43FcpLe7J7zcJtoiTaI/vPZ6gDbH2vhyF12dARUnZ+2Qv3lHBfdi4pryYv1QkJVWMdzfQziLnImlCuO7yewZvZzspc4lzJOCWrcEem96olvUhJ4bDYfSVNmBkAbeXo1RxGoZiH69bqN71L8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=i7UDv7T5; arc=none smtp.client-ip=209.85.214.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="i7UDv7T5" Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-2a2ea96930cso11341935ad.2 for ; Tue, 06 Jan 2026 06:39:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1767710346; x=1768315146; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=7VIp5+b/FUp58Pj56Ud8/gwkkUuum/+Qm0yZ3zmzI/E=; b=i7UDv7T56aMYfkm1LuC9XBx3RwcB8bQVMtPRl40kbtSaCEusGSsOZ9suDpD9hMvq8A 7mKQ0Qk24rsObepYDrmAXVAjgSjqDmtENEsnwtvp/JXiuRjRtVEKdCJTSFK2cdRGX4z7 CbDX0AbJmm2LwJ+sYspvxzNDyCT8u0dxVfz7C+bfnjFMfgsGMUKHmDKZP4TDsHCnv8i8 K0jDndS2XfQfXOGM1U6PbFUDKRMxTbG1A5fnFo1Sr22o8pr/VCwarX9vYmco1Vg842h9 z9ZRSkOtOGn/PD4D5zbzmJ5siI7d+wFl3XAvbbnH0zvMXIMKtZG22vo3rlqYwXOomwVQ vc2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767710346; x=1768315146; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=7VIp5+b/FUp58Pj56Ud8/gwkkUuum/+Qm0yZ3zmzI/E=; b=WjNoC2/Ywvr8ivVL1t12p/segB7MXQnaGCH2pxiefgAnKJ3OSOl3kHEcdCp7u4bpWn 776uvN08G3uwDxhf4Hkr17ljdkJn8GaXi9Y9G2+otoKtkfhn+pvhXGli17DnV9cXjG6U MPm1jSN0V35W5D7cU7muD0eAfqZKgDnfqvEwy/yo4aISRAALq+T88bX69K8fUm0Xq6ak RMNghYF71EpsbayOxY+tguBeAlkCHrdFBadqvt7I3sA7Tjz3s15mnnIcJV6m56QNabYz 4jbHbPnSRK9rESSV6Qey4NavKfpRI3ks1GOj/BXNp2pz2yPby90BRPqpcCcKaxzKkC7t kSrw== X-Gm-Message-State: AOJu0Yyx4QPh/6oCrGeDVC/2iYALDJq+wcBCt1pRfcZ9goMp+mtoUrEb iqZZoS/QCBS+uwrfJ76Os/+wAscb5msTJCo1uxOZMIb2TR/iUpHp06Cd X-Gm-Gg: AY/fxX7fQJSZ3CztKFTjQQvqAE1JeyPPI/Yog1sCy/lOasV+sKuPbTOgx7qMf2o2dqU fF/JewlcSs0eQ4KJbQGs9KL0UUm+JJW62Ym0LhxULIh4XBboWO8PVdGUxz6c7BhzDJAeg9467QV dOjeVDY/W5032lPlNrR7utrcAshKVvkPq9rBQvFMWt/Ig+D572Layo/T6cFLVqvQbxStS36n3NZ qlcMF1C54O3I+wOFUf7X2N5Lzi6NbNdn/tzxbj3mdoIPFlhbu0jE4SP7GLY4WIGaGl6PlEUZO2s rRKnykXfShMEDbb/oTQmQP2X70yaMDpn9FqinSWFDJeuZ0UjRFUxwr70p9Zgs2/6B76TK48W+ky R7hWN93QiCAaLUR7+6/4EWBpG9r9I/q1sprulJq0oeq+GbYOlVrfcrA0Q/Xu2vo6h6WquthQAeh smttEGuUjFUuQDZyYltjbC86IPTj2faZCy2u5NAQ== X-Google-Smtp-Source: AGHT+IEqFUUyiYHpKxzQSJtqoMaAJZgBbYwR10X/oeNQQLKSHydwIeGcPR/JhLZ7iH7ssace0cvXYQ== X-Received: by 2002:a17:902:e78f:b0:2a0:d46d:f990 with SMTP id d9443c01a7336-2a3e2defd6emr35809415ad.31.1767710346390; Tue, 06 Jan 2026 06:39:06 -0800 (PST) Received: from name2965-Precision-7820-Tower.. ([121.185.186.233]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a3e3cd2acdsm24661985ad.89.2026.01.06.06.39.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Jan 2026 06:39:05 -0800 (PST) From: Jeongjun Park To: syzbot+b165fc2e11771c66d8ba@syzkaller.appspotmail.com Cc: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com Subject: Re: [syzbot] [mm?] WARNING in folio_remove_rmap_ptes Date: Tue, 6 Jan 2026 23:39:02 +0900 Message-Id: <20260106143902.1152190-1-aha310510@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <694a2745.050a0220.19928e.0017.GAE@google.com> References: <694a2745.050a0220.19928e.0017.GAE@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit #syz test upstream master --- mm/vma.c | 111 ++++++++++++++++++++++++++++++++++++------------------- mm/vma.h | 3 ++ 2 files changed, 77 insertions(+), 37 deletions(-) diff --git a/mm/vma.c b/mm/vma.c index fc90befd162f..dc92f3dd8514 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -67,18 +67,13 @@ struct mmap_state { .state = VMA_MERGE_START, \ } -/* - * If, at any point, the VMA had unCoW'd mappings from parents, it will maintain - * more than one anon_vma_chain connecting it to more than one anon_vma. A merge - * would mean a wider range of folios sharing the root anon_vma lock, and thus - * potential lock contention, we do not wish to encourage merging such that this - * scales to a problem. - */ -static bool vma_had_uncowed_parents(struct vm_area_struct *vma) +/* Was this VMA ever forked from a parent, i.e. maybe contains CoW mappings? */ +static bool vma_is_fork_child(struct vm_area_struct *vma) { /* * The list_is_singular() test is to avoid merging VMA cloned from - * parents. This can improve scalability caused by anon_vma lock. + * parents. This can improve scalability caused by the anon_vma root + * lock. */ return vma && vma->anon_vma && !list_is_singular(&vma->anon_vma_chain); } @@ -115,11 +110,19 @@ static bool is_mergeable_anon_vma(struct vma_merge_struct *vmg, bool merge_next) VM_WARN_ON(src && src_anon != src->anon_vma); /* Case 1 - we will dup_anon_vma() from src into tgt. */ - if (!tgt_anon && src_anon) - return !vma_had_uncowed_parents(src); + if (!tgt_anon && src_anon) { + struct vm_area_struct *copied_from = vmg->copied_from; + + if (vma_is_fork_child(src)) + return false; + if (vma_is_fork_child(copied_from)) + return false; + + return true; + } /* Case 2 - we will simply use tgt's anon_vma. */ if (tgt_anon && !src_anon) - return !vma_had_uncowed_parents(tgt); + return !vma_is_fork_child(tgt); /* Case 3 - the anon_vma's are already shared. */ return src_anon == tgt_anon; } @@ -829,6 +832,8 @@ static __must_check struct vm_area_struct *vma_merge_existing_range( VM_WARN_ON_VMG(middle && !(vma_iter_addr(vmg->vmi) >= middle->vm_start && vma_iter_addr(vmg->vmi) < middle->vm_end), vmg); + /* An existing merge can never be used by the mremap() logic. */ + VM_WARN_ON_VMG(vmg->copied_from, vmg); vmg->state = VMA_MERGE_NOMERGE; @@ -1098,6 +1103,33 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg) return NULL; } +/* + * vma_merge_copied_range - Attempt to merge a VMA that is being copied by + * mremap() + * + * @vmg: Describes the VMA we are adding, in the copied-to range @vmg->start to + * @vmg->end (exclusive), which we try to merge with any adjacent VMAs if + * possible. + * + * vmg->prev, next, start, end, pgoff should all be relative to the COPIED TO + * range, i.e. the target range for the VMA. + * + * Returns: In instances where no merge was possible, NULL. Otherwise, a pointer + * to the VMA we expanded. + * + * ASSUMPTIONS: Same as vma_merge_new_range(), except vmg->middle must contain + * the copied-from VMA. + */ +static struct vm_area_struct *vma_merge_copied_range(struct vma_merge_struct *vmg) +{ + /* We must have a copied-from VMA. */ + VM_WARN_ON_VMG(!vmg->middle, vmg); + + vmg->copied_from = vmg->middle; + vmg->middle = NULL; + return vma_merge_new_range(vmg); +} + /* * vma_expand - Expand an existing VMA * @@ -1117,46 +1149,52 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg) int vma_expand(struct vma_merge_struct *vmg) { struct vm_area_struct *anon_dup = NULL; - bool remove_next = false; struct vm_area_struct *target = vmg->target; struct vm_area_struct *next = vmg->next; + bool remove_next = false; vm_flags_t sticky_flags; - - sticky_flags = vmg->vm_flags & VM_STICKY; - sticky_flags |= target->vm_flags & VM_STICKY; - - VM_WARN_ON_VMG(!target, vmg); + int ret = 0; mmap_assert_write_locked(vmg->mm); - vma_start_write(target); - if (next && (target != next) && (vmg->end == next->vm_end)) { - int ret; - sticky_flags |= next->vm_flags & VM_STICKY; + if (next && target != next && vmg->end == next->vm_end) remove_next = true; - /* This should already have been checked by this point. */ - VM_WARN_ON_VMG(!can_merge_remove_vma(next), vmg); - vma_start_write(next); - /* - * In this case we don't report OOM, so vmg->give_up_on_mm is - * safe. - */ - ret = dup_anon_vma(target, next, &anon_dup); - if (ret) - return ret; - } + /* We must have a target. */ + VM_WARN_ON_VMG(!target, vmg); + /* This should have already been checked by this point. */ + VM_WARN_ON_VMG(remove_next && !can_merge_remove_vma(next), vmg); /* Not merging but overwriting any part of next is not handled. */ VM_WARN_ON_VMG(next && !remove_next && next != target && vmg->end > next->vm_start, vmg); - /* Only handles expanding */ + /* Only handles expanding. */ VM_WARN_ON_VMG(target->vm_start < vmg->start || target->vm_end > vmg->end, vmg); + sticky_flags = vmg->vm_flags & VM_STICKY; + sticky_flags |= target->vm_flags & VM_STICKY; if (remove_next) - vmg->__remove_next = true; + sticky_flags |= next->vm_flags & VM_STICKY; + + /* + * If we are removing the next VMA or copying from a VMA + * (e.g. mremap()'ing), we must propagate anon_vma state. + * + * Note that, by convention, callers ignore OOM for this case, so + * we don't need to account for vmg->give_up_on_mm here. + */ + if (remove_next) + ret = dup_anon_vma(target, next, &anon_dup); + if (!ret && vmg->copied_from) + ret = dup_anon_vma(target, vmg->copied_from, &anon_dup); + if (ret) + return ret; + if (remove_next) { + vma_start_write(next); + vmg->__remove_next = true; + } if (commit_merge(vmg)) goto nomem; @@ -1828,10 +1866,9 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, if (new_vma && new_vma->vm_start < addr + len) return NULL; /* should never get here */ - vmg.middle = NULL; /* New VMA range. */ vmg.pgoff = pgoff; vmg.next = vma_iter_next_rewind(&vmi, NULL); - new_vma = vma_merge_new_range(&vmg); + new_vma = vma_merge_copied_range(&vmg); if (new_vma) { /* diff --git a/mm/vma.h b/mm/vma.h index abada6a64c4e..9d5ee6ac913a 100644 --- a/mm/vma.h +++ b/mm/vma.h @@ -106,6 +106,9 @@ struct vma_merge_struct { struct anon_vma_name *anon_name; enum vma_merge_state state; + /* If copied from (i.e. mremap()'d) the VMA from which we are copying. */ + struct vm_area_struct *copied_from; + /* Flags which callers can use to modify merge behaviour: */ /* --