diff --git a/drivers/virt/gunyah/gunyah_irqfd.c b/drivers/virt/gunyah/gunyah_irqfd.c index 7629e5777137..0371fd3da578 100644 --- a/drivers/virt/gunyah/gunyah_irqfd.c +++ b/drivers/virt/gunyah/gunyah_irqfd.c @@ -54,7 +54,7 @@ static void irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh, p add_wait_queue(wqh, &irq_ctx->wait); } -static int gh_irqfd_populate(struct gh_vm_resource_ticket *ticket, struct gh_resource *ghrsc) +static bool gh_irqfd_populate(struct gh_vm_resource_ticket *ticket, struct gh_resource *ghrsc) { struct gh_irqfd *irqfd = container_of(ticket, struct gh_irqfd, ticket); u64 enable_mask = GH_BELL_NONBLOCK; @@ -64,7 +64,7 @@ static int gh_irqfd_populate(struct gh_vm_resource_ticket *ticket, struct gh_res if (irqfd->ghrsc) { pr_warn("irqfd%d already got a Gunyah resource. Check if multiple resources with same label were configured.\n", irqfd->ticket.label); - return -1; + return false; } irqfd->ghrsc = ghrsc; @@ -75,7 +75,7 @@ static int gh_irqfd_populate(struct gh_vm_resource_ticket *ticket, struct gh_res irqfd->ticket.label); } - return 0; + return true; } static void gh_irqfd_unpopulate(struct gh_vm_resource_ticket *ticket, struct gh_resource *ghrsc) diff --git a/drivers/virt/gunyah/gunyah_vcpu.c b/drivers/virt/gunyah/gunyah_vcpu.c index b6692afca3de..c329184e5fb6 100644 --- a/drivers/virt/gunyah/gunyah_vcpu.c +++ b/drivers/virt/gunyah/gunyah_vcpu.c @@ -323,14 +323,16 @@ static const struct file_operations gh_vcpu_fops = { .mmap = gh_vcpu_mmap, }; -static int gh_vcpu_populate(struct gh_vm_resource_ticket *ticket, struct gh_resource *ghrsc) +static bool gh_vcpu_populate(struct gh_vm_resource_ticket *ticket, struct gh_resource *ghrsc) { struct gh_vcpu *vcpu = container_of(ticket, struct gh_vcpu, ticket); int ret; mutex_lock(&vcpu->run_lock); if (vcpu->rsc) { - ret = -1; + pr_warn("vcpu%d already got a Gunyah resource. Check if multiple resources with same label were configured.\n", + vcpu->ticket.label); + ret = -EEXIST; goto out; } @@ -344,7 +346,7 @@ static int gh_vcpu_populate(struct gh_vm_resource_ticket *ticket, struct gh_reso out: mutex_unlock(&vcpu->run_lock); - return ret; + return !ret; } static void gh_vcpu_unpopulate(struct gh_vm_resource_ticket *ticket, diff --git a/drivers/virt/gunyah/vm_mgr.c b/drivers/virt/gunyah/vm_mgr.c index fe546220b7c1..a0b067c25b56 100644 --- a/drivers/virt/gunyah/vm_mgr.c +++ b/drivers/virt/gunyah/vm_mgr.c @@ -190,11 +190,11 @@ EXPORT_SYMBOL_GPL(gh_vm_function_unregister); int gh_vm_add_resource_ticket(struct gh_vm *ghvm, struct gh_vm_resource_ticket *ticket) { struct gh_vm_resource_ticket *iter; - struct gh_resource *ghrsc; + struct gh_resource *ghrsc, *rsc_iter; int ret = 0; mutex_lock(&ghvm->resources_lock); - list_for_each_entry(iter, &ghvm->resource_tickets, list) { + list_for_each_entry(iter, &ghvm->resource_tickets, vm_list) { if (iter->resource_type == ticket->resource_type && iter->label == ticket->label) { ret = -EEXIST; goto out; @@ -206,10 +206,10 @@ int gh_vm_add_resource_ticket(struct gh_vm *ghvm, struct gh_vm_resource_ticket * goto out; } - list_add(&ticket->list, &ghvm->resource_tickets); + list_add(&ticket->vm_list, &ghvm->resource_tickets); INIT_LIST_HEAD(&ticket->resources); - list_for_each_entry(ghrsc, &ghvm->resources, list) { + list_for_each_entry_safe(ghrsc, rsc_iter, &ghvm->resources, list) { if (ghrsc->type == ticket->resource_type && ghrsc->rm_label == ticket->label) { if (ticket->populate(ticket, ghrsc)) list_move(&ghrsc->list, &ticket->resources); @@ -232,7 +232,7 @@ void gh_vm_remove_resource_ticket(struct gh_vm *ghvm, struct gh_vm_resource_tick } module_put(ticket->owner); - list_del(&ticket->list); + list_del(&ticket->vm_list); mutex_unlock(&ghvm->resources_lock); } EXPORT_SYMBOL_GPL(gh_vm_remove_resource_ticket); @@ -242,12 +242,17 @@ static void gh_vm_add_resource(struct gh_vm *ghvm, struct gh_resource *ghrsc) struct gh_vm_resource_ticket *ticket; mutex_lock(&ghvm->resources_lock); - list_for_each_entry(ticket, &ghvm->resource_tickets, list) { + list_for_each_entry(ticket, &ghvm->resource_tickets, vm_list) { if (ghrsc->type == ticket->resource_type && ghrsc->rm_label == ticket->label) { - if (!ticket->populate(ticket, ghrsc)) { + if (ticket->populate(ticket, ghrsc)) list_add(&ghrsc->list, &ticket->resources); - goto found; - } + else + list_add(&ghrsc->list, &ghvm->resources); + /* unconditonal -- we prevent multiple identical + * resource tickets so there will not be some other + * ticket elsewhere in the list if populate() failed. + */ + goto found; } } list_add(&ghrsc->list, &ghvm->resources); @@ -255,6 +260,26 @@ found: mutex_unlock(&ghvm->resources_lock); } +static void gh_vm_clean_resources(struct gh_vm *ghvm) +{ + struct gh_vm_resource_ticket *ticket, *titer; + struct gh_resource *ghrsc, *riter; + + mutex_lock(&ghvm->resources_lock); + if (!list_empty(&ghvm->resource_tickets)) { + dev_warn(ghvm->parent, "Dangling resource tickets:\n"); + list_for_each_entry_safe(ticket, titer, &ghvm->resource_tickets, vm_list) { + dev_warn(ghvm->parent, " %pS\n", ticket->populate); + gh_vm_remove_resource_ticket(ghvm, ticket); + } + } + + list_for_each_entry_safe(ghrsc, riter, &ghvm->resources, list) { + gh_rm_free_resource(ghrsc); + } + mutex_unlock(&ghvm->resources_lock); +} + static int _gh_vm_io_handler_compare(const struct rb_node *node, const struct rb_node *parent) { struct gh_vm_io_handler *n = container_of(node, struct gh_vm_io_handler, node); @@ -417,8 +442,6 @@ static void gh_vm_stop(struct gh_vm *ghvm) static void gh_vm_free(struct work_struct *work) { struct gh_vm *ghvm = container_of(work, struct gh_vm, free_work); - struct gh_vm_resource_ticket *ticket, *titer; - struct gh_resource *ghrsc, *riter; struct gh_vm_mem *mapping, *tmp; int ret; @@ -429,20 +452,7 @@ static void gh_vm_free(struct work_struct *work) case GH_RM_VM_STATUS_INIT_FAILED: case GH_RM_VM_STATUS_EXITED: gh_vm_remove_functions(ghvm); - - mutex_lock(&ghvm->resources_lock); - if (!list_empty(&ghvm->resource_tickets)) { - dev_warn(ghvm->parent, "Dangling resource tickets:\n"); - list_for_each_entry_safe(ticket, titer, &ghvm->resource_tickets, list) { - dev_warn(ghvm->parent, " %pS\n", ticket->populate); - gh_vm_remove_resource_ticket(ghvm, ticket); - } - } - - list_for_each_entry_safe(ghrsc, riter, &ghvm->resources, list) { - gh_rm_free_resource(ghrsc); - } - mutex_unlock(&ghvm->resources_lock); + gh_vm_clean_resources(ghvm); /* vm_status == LOAD if user creates VM, but then destroys it * without ever trying to start it. In that case, we have only diff --git a/include/linux/gunyah_vm_mgr.h b/include/linux/gunyah_vm_mgr.h index 1527861a5c63..0fa3cf6bcaca 100644 --- a/include/linux/gunyah_vm_mgr.h +++ b/include/linux/gunyah_vm_mgr.h @@ -85,13 +85,13 @@ void gh_vm_function_unregister(struct gh_vm_function *f); MODULE_ALIAS_GH_VM_FUNCTION(_type, _idx) struct gh_vm_resource_ticket { - struct list_head list; /* for gh_vm's resources list */ - struct list_head resources; /* for gh_resources's list */ + struct list_head vm_list; /* for gh_vm's resource tickets list */ + struct list_head resources; /* resources associated with this ticket */ enum gh_resource_type resource_type; u32 label; struct module *owner; - int (*populate)(struct gh_vm_resource_ticket *ticket, struct gh_resource *ghrsc); + bool (*populate)(struct gh_vm_resource_ticket *ticket, struct gh_resource *ghrsc); void (*unpopulate)(struct gh_vm_resource_ticket *ticket, struct gh_resource *ghrsc); };