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;
}