static int xenbus_unmap_ring_pv()

in xenbus/xenbus_client.c [742:802]


static int xenbus_unmap_ring_pv(struct xenbus_device *dev, void *vaddr)
{
	struct xenbus_map_node *node;
	struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];
	unsigned int level;
	int i;
	bool leaked = false;
	int err;

	spin_lock(&xenbus_valloc_lock);
	list_for_each_entry(node, &xenbus_valloc_pages, next) {
		if (node->pv.area->addr == vaddr) {
			list_del(&node->next);
			goto found;
		}
	}
	node = NULL;
 found:
	spin_unlock(&xenbus_valloc_lock);

	if (!node) {
		xenbus_dev_error(dev, -ENOENT,
				 "can't find mapped virtual address %p", vaddr);
		return GNTST_bad_virt_addr;
	}

	for (i = 0; i < node->nr_handles; i++) {
		unsigned long addr;

		memset(&unmap[i], 0, sizeof(unmap[i]));
		addr = (unsigned long)vaddr + (XEN_PAGE_SIZE * i);
		unmap[i].host_addr = arbitrary_virt_to_machine(
			lookup_address(addr, &level)).maddr;
		unmap[i].dev_bus_addr = 0;
		unmap[i].handle = node->handles[i];
	}

	BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, i));

	err = GNTST_okay;
	leaked = false;
	for (i = 0; i < node->nr_handles; i++) {
		if (unmap[i].status != GNTST_okay) {
			leaked = true;
			xenbus_dev_error(dev, unmap[i].status,
					 "unmapping page at handle %d error %d",
					 node->handles[i], unmap[i].status);
			err = unmap[i].status;
			break;
		}
	}

	if (!leaked)
		free_vm_area(node->pv.area);
	else
		pr_alert("leaking VM area %p size %u page(s)",
			 node->pv.area, node->nr_handles);

	kfree(node);
	return err;
}