diff --git a/tests/xrun/include/domain.h b/tests/xrun/include/domain.h index 459e71d1..5ba7b0d7 100644 --- a/tests/xrun/include/domain.h +++ b/tests/xrun/include/domain.h @@ -117,6 +117,7 @@ struct xen_domain_console { struct xen_domain { }; -struct xen_domain *domid_to_domain(uint32_t domid); +struct xen_domain *get_domain(uint32_t domid); +void put_domain(struct xen_domain *domain); #endif /* XENLIB_XEN_DOMAIN_H */ diff --git a/xen-console-srv/src/xen_console.c b/xen-console-srv/src/xen_console.c index 70695e19..e37d9d6b 100644 --- a/xen-console-srv/src/xen_console.c +++ b/xen-console-srv/src/xen_console.c @@ -480,6 +480,7 @@ int xen_attach_domain_console(const struct shell *shell, /* Actually, this should never happen */ shell_error(shell, "Shell is already attached to console"); k_mutex_unlock(&global_console_lock); + put_domain(domain); return -EEXIST; } current_console = console; @@ -500,6 +501,7 @@ int xen_attach_domain_console(const struct shell *shell, shell_set_bypass(shell, console_shell_cb); + put_domain(domain); return 0; } diff --git a/xen-dom-mgmt/include/domain.h b/xen-dom-mgmt/include/domain.h index 53328066..f12c57d8 100644 --- a/xen-dom-mgmt/include/domain.h +++ b/xen-dom-mgmt/include/domain.h @@ -165,6 +165,7 @@ struct xen_domain { int address_size; uint64_t max_mem_kb; sys_dnode_t node; + int refcount; /* TODO: domains can have more than one console */ struct xen_domain_console console; @@ -173,7 +174,8 @@ struct xen_domain { bool f_dom0less:1; /**< Indicates that domain was created by Xen itself */ }; -struct xen_domain *domid_to_domain(uint32_t domid); +struct xen_domain *get_domain(uint32_t domid); +void put_domain(struct xen_domain *domain); #ifdef __cplusplus } diff --git a/xen-dom-mgmt/src/xen-dom-mgmt.c b/xen-dom-mgmt/src/xen-dom-mgmt.c index f47b3d8f..c9f905e7 100644 --- a/xen-dom-mgmt/src/xen-dom-mgmt.c +++ b/xen-dom-mgmt/src/xen-dom-mgmt.c @@ -597,23 +597,67 @@ static int assign_dtdevs(int domid, char *dtdevs[], int nr_dtdevs) return rc; } -/* - * TODO: Access to domain_list and domains should be protected, considering that it may be - * destroyed after receiving pointer to actual domain. So all accesses to domains structs should be - * protected globally or via refcounts. This requires code audit in all libs, that are using this - * function (currently xenstore-srv and xen_shell). - */ -struct xen_domain *domid_to_domain(uint32_t domid) +struct xen_domain *get_domain(uint32_t domid) { struct xen_domain *iter; + k_mutex_lock(&dl_mutex, K_FOREVER); SYS_DLIST_FOR_EACH_CONTAINER (&domain_list, iter, node) { if (iter->domid == domid) { - return iter; + iter->refcount++; + break; } } + k_mutex_unlock(&dl_mutex); + return iter; +} + +void put_domain(struct xen_domain *domain) +{ + int rc; + + if (!domain) { + LOG_ERR("Domain is NULL"); + return; + } + + k_mutex_lock(&dl_mutex, K_FOREVER); + domain->refcount--; + if (domain->refcount == 0) { + if (domain->f_dom0less) { + LOG_ERR("dom0less domain#%u operation not supported", domain->domid); + return; + } + + rc = xs_remove_xenstore_backends(domain); + if (rc) { + LOG_ERR("Failed to remove_xenstore_backends domain#%u (rc=%d)", domain->domid, rc); + } + + rc = stop_domain_stored(domain); + if (rc) { + LOG_ERR("Failed to stop domain#%u store (rc=%d)", domain->domid, rc); + } + + xs_deinitialize_domain_xenstore(domain->domid); + + #ifdef CONFIG_XEN_CONSOLE_SRV + rc = xen_stop_domain_console(domain); + if (rc) { + LOG_ERR("Failed to stop domain#%u console (rc=%d)", domain->domid, rc); + } + #endif + + rc = xen_domctl_destroydomain(domain->domid); + if (rc) { + LOG_ERR("Failed to destroy domain#%u (rc=%d)", domain->domid, rc); + } - return NULL; + sys_dlist_remove(&domain->node); + --dom_num; + k_free(domain); + } + k_mutex_unlock(&dl_mutex); } int domain_create(struct xen_domain_cfg *domcfg, uint32_t domid) @@ -753,6 +797,7 @@ int domain_create(struct xen_domain_cfg *domcfg, uint32_t domid) } k_mutex_lock(&dl_mutex, K_FOREVER); + domain->refcount = 1; sys_dnode_init(&domain->node); sys_dlist_append(&domain_list, &domain->node); ++dom_num; @@ -776,57 +821,20 @@ int domain_create(struct xen_domain_cfg *domcfg, uint32_t domid) int domain_destroy(uint32_t domid) { - int rc, err = 0; struct xen_domain *domain = NULL; - domain = domid_to_domain(domid); + domain = get_domain(domid); if (!domain) { LOG_ERR("Domain with domid#%u is not found", domid); /* Domain with requested domid is not present in list */ return -EINVAL; } - if (domain->f_dom0less) { - LOG_ERR("dom0less domain#%u operation not supported", domid); - return -ENOTSUP; - } - - rc = xs_remove_xenstore_backends(domain); - if (rc) { - LOG_ERR("Failed to remove_xenstore_backends domain#%u (rc=%d)", domain->domid, rc); - err = rc; - } - - rc = stop_domain_stored(domain); - if (rc) { - LOG_ERR("Failed to stop domain#%u store (rc=%d)", domain->domid, rc); - err = rc; - } - - xs_deinitialize_domain_xenstore(domid); - -#ifdef CONFIG_XEN_CONSOLE_SRV - rc = xen_stop_domain_console(domain); - if (rc) { - LOG_ERR("Failed to stop domain#%u console (rc=%d)", domain->domid, rc); - err = rc; - } -#endif - - rc = xen_domctl_destroydomain(domid); - if (rc) { - LOG_ERR("Failed to destroy domain#%u (rc=%d)", domain->domid, rc); - err = rc; - } + /* Call put domain twice to drop the original reference and trigger freeing */ + put_domain(domain); + put_domain(domain); - k_mutex_lock(&dl_mutex, K_FOREVER); - sys_dlist_remove(&domain->node); - --dom_num; - k_mutex_unlock(&dl_mutex); - - k_free(domain); - - return err; + return 0; } int domain_pause(uint32_t domid) @@ -834,7 +842,7 @@ int domain_pause(uint32_t domid) int rc; struct xen_domain *domain = NULL; - domain = domid_to_domain(domid); + domain = get_domain(domid); if (!domain) { LOG_ERR("Domain with domid#%u is not found", domid); /* Domain with requested domid is not present in list */ @@ -842,6 +850,7 @@ int domain_pause(uint32_t domid) } rc = xen_domctl_pausedomain(domid); + put_domain(domain); return rc; } @@ -850,13 +859,14 @@ int domain_unpause(uint32_t domid) { struct xen_domain *domain = NULL; - domain = domid_to_domain(domid); + domain = get_domain(domid); if (!domain) { LOG_ERR("Domain with domid#%u is not found", domid); /* Domain with requested domid is not present in list */ return -EINVAL; } + put_domain(domain); return xen_domctl_unpausedomain(domid); } @@ -867,7 +877,7 @@ int domain_post_create(const struct xen_domain_cfg *domcfg, uint32_t domid) struct backends_state *bs = NULL; const struct backend_configuration *bc = NULL; - domain = domid_to_domain(domid); + domain = get_domain(domid); bs = &domain->back_state; bc = &domcfg->back_cfg; @@ -897,9 +907,11 @@ int domain_post_create(const struct xen_domain_cfg *domcfg, uint32_t domid) } } + put_domain(domain); return 0; deinit: + put_domain(domain); LOG_ERR("Failed to initialize xenstore for domid#%u (rc=%d)", domid, rc); domain_destroy(domid); return rc; diff --git a/xen-shell-cmd/src/xen_cmds.c b/xen-shell-cmd/src/xen_cmds.c index 8b6b154b..91852a1e 100644 --- a/xen-shell-cmd/src/xen_cmds.c +++ b/xen-shell-cmd/src/xen_cmds.c @@ -89,7 +89,7 @@ int domu_console_attach(const struct shell *shell, size_t argc, char **argv) return -EINVAL; } - domain = domid_to_domain(domid); + domain = get_domain(domid); if (!domain) { shell_error(shell, "domid#%u is not found", domid); /* Domain with requested domid is not present in list */