drivers/iommu/iommu-debug-pagealloc.c

Source file repositories/reference/linux-study-clean/drivers/iommu/iommu-debug-pagealloc.c

File Facts

System
Linux kernel
Corpus path
drivers/iommu/iommu-debug-pagealloc.c
Extension
.c
Size
4062 bytes
Lines
165
Domain
Driver Families
Bucket
drivers/iommu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct iommu_debug_metadata {
	atomic_t ref;
};

static __init bool need_iommu_debug(void)
{
	return needed;
}

struct page_ext_operations page_iommu_debug_ops = {
	.size = sizeof(struct iommu_debug_metadata),
	.need = need_iommu_debug,
};

static struct iommu_debug_metadata *get_iommu_data(struct page_ext *page_ext)
{
	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 = page_ext_from_phys(phys);
	struct iommu_debug_metadata *d;

	if (!page_ext)
		return;

	d = get_iommu_data(page_ext);
	WARN_ON(atomic_inc_return_relaxed(&d->ref) <= 0);
	page_ext_put(page_ext);
}

static void iommu_debug_dec_page(phys_addr_t phys)
{
	struct page_ext *page_ext = page_ext_from_phys(phys);
	struct iommu_debug_metadata *d;

	if (!page_ext)
		return;

	d = 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);
}

static bool iommu_debug_page_count(const struct page *page)
{
	unsigned int ref;
	struct page_ext *page_ext = page_ext_get(page);
	struct iommu_debug_metadata *d = get_iommu_data(page_ext);

	ref = atomic_read(&d->ref);
	page_ext_put(page_ext);
	return ref != 0;
}

void __iommu_debug_check_unmapped(const struct page *page, int numpages)
{
	while (numpages--) {
		if (WARN_ON(iommu_debug_page_count(page))) {
			pr_warn("iommu: Detected page leak!\n");
			dump_page_owner(page);
		}
		page++;
	}
}

void __iommu_debug_map(struct iommu_domain *domain, phys_addr_t phys, size_t size)
{
	size_t off, end;
	size_t page_size = iommu_debug_page_size(domain);

	if (WARN_ON(!phys || check_add_overflow(phys, size, &end)))
		return;

	for (off = 0 ; off < size ; off += page_size)
		iommu_debug_inc_page(phys + off);

Annotation

Implementation Notes