Commit 361d744d authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

iommufd: Add iopt_area_alloc()

We never initialize the two interval tree nodes, and zero fill is not the
same as RB_CLEAR_NODE. This can hide issues where we missed adding the
area to the trees. Factor out the allocation and clear the two nodes.

Fixes: 51fe6141 ("iommufd: Data structure to provide IOVA to PFN mapping")
Link: https://lore.kernel.org/r/20231030145035.GG691768@ziepe.ca


Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent e7250ab7
Loading
Loading
Loading
Loading
+15 −3
Original line number Diff line number Diff line
@@ -222,6 +222,18 @@ static int iopt_insert_area(struct io_pagetable *iopt, struct iopt_area *area,
	return 0;
}

static struct iopt_area *iopt_area_alloc(void)
{
	struct iopt_area *area;

	area = kzalloc(sizeof(*area), GFP_KERNEL_ACCOUNT);
	if (!area)
		return NULL;
	RB_CLEAR_NODE(&area->node.rb);
	RB_CLEAR_NODE(&area->pages_node.rb);
	return area;
}

static int iopt_alloc_area_pages(struct io_pagetable *iopt,
				 struct list_head *pages_list,
				 unsigned long length, unsigned long *dst_iova,
@@ -232,7 +244,7 @@ static int iopt_alloc_area_pages(struct io_pagetable *iopt,
	int rc = 0;

	list_for_each_entry(elm, pages_list, next) {
		elm->area = kzalloc(sizeof(*elm->area), GFP_KERNEL_ACCOUNT);
		elm->area = iopt_area_alloc();
		if (!elm->area)
			return -ENOMEM;
	}
@@ -1177,11 +1189,11 @@ static int iopt_area_split(struct iopt_area *area, unsigned long iova)
	    iopt_area_start_byte(area, new_start) & (alignment - 1))
		return -EINVAL;

	lhs = kzalloc(sizeof(*area), GFP_KERNEL_ACCOUNT);
	lhs = iopt_area_alloc();
	if (!lhs)
		return -ENOMEM;

	rhs = kzalloc(sizeof(*area), GFP_KERNEL_ACCOUNT);
	rhs = iopt_area_alloc();
	if (!rhs) {
		rc = -ENOMEM;
		goto err_free_lhs;
+2 −0
Original line number Diff line number Diff line
@@ -1507,6 +1507,8 @@ void iopt_area_unfill_domains(struct iopt_area *area, struct iopt_pages *pages)
				area, domain, iopt_area_index(area),
				iopt_area_last_index(area));

	if (IS_ENABLED(CONFIG_IOMMUFD_TEST))
		WARN_ON(RB_EMPTY_NODE(&area->pages_node.rb));
	interval_tree_remove(&area->pages_node, &pages->domains_itree);
	iopt_area_unfill_domain(area, pages, area->storage_domain);
	area->storage_domain = NULL;