Skip to content

Commit

Permalink
xen-dom-mgmt: Add refcount to domain structure
Browse files Browse the repository at this point in the history
Add reference counting to the domain structure to make accessing it
safe without global locks. domain_create initializes the refcount to 1
to prevent the domain from being freed right away, this original
reference is dropped in domain_destroy to trigger freeing the domain.

Also update test headers to keep them in sync with the changes.

Signed-off-by: Mykyta Poturai <[email protected]>
  • Loading branch information
Deedone committed May 13, 2024
1 parent 70cf034 commit bbba06a
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 57 deletions.
3 changes: 2 additions & 1 deletion tests/xrun/include/domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
2 changes: 2 additions & 0 deletions xen-console-srv/src/xen_console.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down
4 changes: 3 additions & 1 deletion xen-dom-mgmt/include/domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
}
Expand Down
120 changes: 66 additions & 54 deletions xen-dom-mgmt/src/xen-dom-mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -776,72 +821,36 @@ 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)
{
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 */
return -EINVAL;
}

rc = xen_domctl_pausedomain(domid);
put_domain(domain);

return rc;
}
Expand All @@ -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);
}

Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion xen-shell-cmd/src/xen_cmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit bbba06a

Please sign in to comment.