From nobody Sun Feb 8 18:15:15 2026 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (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 001D3365A1B for ; Fri, 9 Jan 2026 17:18:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767979101; cv=none; b=axIGiyye4UF9gF9vJZv2iJN2QjTPRsv8gErDA+wRzRZaoesP91VJhKy0w13F6rRuf9duBCEWBJf6qdFicuoP7fF72KxIr5dM06JIEN+F+tBL6U3U/wMsPkR3FzKiUjaXv1ntelaSNWu8pHtGP1vU2oenNQujs+CxjE0Gi/wB7Pw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767979101; c=relaxed/simple; bh=JyxK9DCFit9BHgUZF8EAQgzBS/s8P5HYnNwnkPHg5Qw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=QS2TAPR6tCa/fQSPh79JV7jGNJeXtmO8pkZrb3yhHdYHQ95dXCTdjyWoU+PV7lbvXQeNjYfhz0fWS8NIVr2TCdUvoqVFmjHINYO2f+E2GA5FOopkupgx4PgUc3OyGy+/uYpPUlDhWogE9Xa2zRcpLT9hyjTxYpV9Qh0JG4mYxx8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--smostafa.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=NO60K8eD; arc=none smtp.client-ip=209.85.128.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--smostafa.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="NO60K8eD" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-4775f51ce36so40061095e9.1 for ; Fri, 09 Jan 2026 09:18:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1767979095; x=1768583895; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=rXKfhlVn2c+6UG0/zcj6FymOVg8M3bXQ+ReLnrZOk7w=; b=NO60K8eDiYauSb6F/GQlh/r3oOId3xgHGH71dzI80JnI4d7SgrnuXYeL+RQG9bmILd 0mnoZzuwemwifme8xo0ZzVGxh0UiDfeIcdAhan6G4meQSMPWcIW7513HAXCS8Vuy/LAz A9hKZuW6AxSkc0UUtg4q5W70LIfNdTmXhEsyaChZ2Cxa1A/c4o1e/ROpJGG7L3lR3fGh XZ83lpfW60qqLkKic9VCqNfy6FQXploEvk0n1T8mtDnrOuRP+86S2n+W/NA2IQPjzXjQ fdoJOC/Sw9dk53Ase2a+8GZvUrSK+BJCuMf0/JpADKFaJGXQwPUHGksAB+1P3LM/n/Wt r+2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767979095; x=1768583895; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=rXKfhlVn2c+6UG0/zcj6FymOVg8M3bXQ+ReLnrZOk7w=; b=Wkc1WjM0axF2ArISayyyERvqCBWQV8qKk03bhYVwpx/zft39LRCzRaSo3UltTSQ/+M cRQ4Et9FxZ+LR01XAdxIE8wLjRKVYHipJBNqJMqeIS+bLg65nGU9iXKhFrBASCQQVndy jbg20LfTMYz7iUN1k9QN4wupvW+frRKhyz+++r1ULRQEw7ZFf9IK/RR8csZq9EdP/Uf3 vmAx3FsHgBzG2jeO9DoeLYk2zX0bAOcaUVCiDyUC7rBQEeh04ZsftBf+bshbbgYjUGSj bxBXFQsg7aPPYUGBgj+Q9PDFPhsG9t6Teeuv1vczRqGjTdpiJc9ZgpjOiO0uZV+DBsDK Mu+A== X-Forwarded-Encrypted: i=1; AJvYcCWaQirvc9ZsOFYWTXBdSBdvNoqI0IrR9+WVG+EXlyh+8fdAMeqzh+zDljQqIup4gSCF0SZPRUeD+86If1Q=@vger.kernel.org X-Gm-Message-State: AOJu0Yxrp+79FZDxAjuYdUSVUXFWq20rCyYftuYRqLsCFKbcjLEoW8C6 BWHsiSxDXm/E6t+2XO/+qVUlHgly6QM0MO9B+E3OD12yfZ3JRB/4PrOTs8vBlu7uETEslOTBMu+ WwMequHqaDaUxcA== X-Google-Smtp-Source: AGHT+IFk02O2PK0We+1RMI+gkP8sH7Gfm0sE0Pyah5F14OonFiV3bx+oHBAF9FOQ2GaQcAwCLdJfSABlkCnRwQ== X-Received: from wmbdx10.prod.google.com ([2002:a05:600c:63ca:b0:477:3fdf:4c24]) (user=smostafa job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:46c4:b0:47d:403e:4eaf with SMTP id 5b1f17b1804b1-47d84b18ef7mr134197875e9.10.1767979095241; Fri, 09 Jan 2026 09:18:15 -0800 (PST) Date: Fri, 9 Jan 2026 17:18:04 +0000 In-Reply-To: <20260109171805.901995-1-smostafa@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260109171805.901995-1-smostafa@google.com> X-Mailer: git-send-email 2.52.0.457.g6b5491de43-goog Message-ID: <20260109171805.901995-4-smostafa@google.com> Subject: [PATCH v6 3/4] iommu: debug-pagealloc: Track IOMMU pages From: Mostafa Saleh To: linux-mm@kvack.org, iommu@lists.linux.dev, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org Cc: corbet@lwn.net, joro@8bytes.org, will@kernel.org, robin.murphy@arm.com, akpm@linux-foundation.org, vbabka@suse.cz, surenb@google.com, mhocko@suse.com, jackmanb@google.com, hannes@cmpxchg.org, ziy@nvidia.com, david@redhat.com, lorenzo.stoakes@oracle.com, Liam.Howlett@oracle.com, rppt@kernel.org, xiaqinxin@huawei.com, baolu.lu@linux.intel.com, rdunlap@infradead.org, Mostafa Saleh , Samiullah Khawaja Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Using the new calls, use an atomic refcount to track how many times a page is mapped in any of the IOMMUs. For unmap we need to use iova_to_phys() to get the physical address of the pages. We use the smallest supported page size as the granularity of tracking per domain. This is important as it is possible to map pages and unmap them with larger sizes (as in map_sg()) cases. Reviewed-by: Samiullah Khawaja Reviewed-by: Lu Baolu Signed-off-by: Mostafa Saleh Reviewed-by: Pranjal Shrivastava --- drivers/iommu/iommu-debug-pagealloc.c | 84 +++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/drivers/iommu/iommu-debug-pagealloc.c b/drivers/iommu/iommu-de= bug-pagealloc.c index 1d343421da98..9eb49e1230ee 100644 --- a/drivers/iommu/iommu-debug-pagealloc.c +++ b/drivers/iommu/iommu-debug-pagealloc.c @@ -29,19 +29,103 @@ struct page_ext_operations page_iommu_debug_ops =3D { .need =3D need_iommu_debug, }; =20 +static struct page_ext *get_iommu_page_ext(phys_addr_t phys) +{ + struct page *page =3D phys_to_page(phys); + struct page_ext *page_ext =3D page_ext_get(page); + + return page_ext; +} + +static struct iommu_debug_metadata *get_iommu_data(struct page_ext *page_e= xt) +{ + return page_ext_data(page_ext, &page_iommu_debug_ops); +} + +static void iommu_debug_inc_page(phys_addr_t phys) +{ + struct page_ext *page_ext =3D get_iommu_page_ext(phys); + struct iommu_debug_metadata *d =3D get_iommu_data(page_ext); + + WARN_ON(atomic_inc_return_relaxed(&d->ref) <=3D 0); + page_ext_put(page_ext); +} + +static void iommu_debug_dec_page(phys_addr_t phys) +{ + struct page_ext *page_ext =3D get_iommu_page_ext(phys); + struct iommu_debug_metadata *d =3D get_iommu_data(page_ext); + + WARN_ON(atomic_dec_return_relaxed(&d->ref) < 0); + page_ext_put(page_ext); +} + +/* + * IOMMU page size doesn't have to match the CPU page size. So, we use + * the smallest IOMMU page size to refcount the pages in the vmemmap. + * That is important as both map and unmap has to use the same page size + * to update the refcount to avoid double counting the same page. + * And as we can't know from iommu_unmap() what was the original page size + * used for map, we just use the minimum supported one for both. + */ +static size_t iommu_debug_page_size(struct iommu_domain *domain) +{ + return 1UL << __ffs(domain->pgsize_bitmap); +} + void __iommu_debug_map(struct iommu_domain *domain, phys_addr_t phys, size= _t size) { + size_t off, end; + size_t page_size =3D iommu_debug_page_size(domain); + + if (WARN_ON(!phys || check_add_overflow(phys, size, &end))) + return; + + for (off =3D 0 ; off < size ; off +=3D page_size) { + if (!pfn_valid(__phys_to_pfn(phys + off))) + continue; + iommu_debug_inc_page(phys + off); + } +} + +static void __iommu_debug_update_iova(struct iommu_domain *domain, + unsigned long iova, size_t size, bool inc) +{ + size_t off, end; + size_t page_size =3D iommu_debug_page_size(domain); + + if (WARN_ON(check_add_overflow(iova, size, &end))) + return; + + for (off =3D 0 ; off < size ; off +=3D page_size) { + phys_addr_t phys =3D iommu_iova_to_phys(domain, iova + off); + + if (!phys || !pfn_valid(__phys_to_pfn(phys))) + continue; + + if (inc) + iommu_debug_inc_page(phys); + else + iommu_debug_dec_page(phys); + } } =20 void __iommu_debug_unmap_begin(struct iommu_domain *domain, unsigned long iova, size_t size) { + __iommu_debug_update_iova(domain, iova, size, false); } =20 void __iommu_debug_unmap_end(struct iommu_domain *domain, unsigned long iova, size_t size, size_t unmapped) { + if ((unmapped =3D=3D size) || WARN_ON_ONCE(unmapped > size)) + return; + + /* If unmap failed, re-increment the refcount. */ + __iommu_debug_update_iova(domain, iova + unmapped, + size - unmapped, true); } =20 void iommu_debug_init(void) --=20 2.52.0.457.g6b5491de43-goog