mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-27 21:47:51 +00:00
tools: rework on vm ops
There are some problems to use VM operations in a deamon process, such as Acrnd. the list_vm() does not return VM informations, it just print VM information to stdio, so we have get_vm_list() to get VM list head vmngr_head; get_vm_list() always creates a new fresh vm list every time, and must use put_vm_list() to delete old list. So Acrnd need to create and destroy vm list frequently. In fact we just need the vmngr_head to be an extern variable. And to make it refreshable.We can insert new VMs, remove dead ones, and update their state. Reviewed-by: Yan Like <like.yan@intel.com> Signed-off-by: Tao Yuhong <yuhong.tao@intel.com>
This commit is contained in:
parent
f0fe17de96
commit
c4f9a2fd70
@ -3,6 +3,7 @@ OUT_DIR ?= .
|
|||||||
|
|
||||||
CFLAGS := -Wall
|
CFLAGS := -Wall
|
||||||
CFLAGS += -I../../devicemodel/include
|
CFLAGS += -I../../devicemodel/include
|
||||||
|
CFLAGS += -I../../devicemodel/include/public
|
||||||
ifeq ($(RELEASE),0)
|
ifeq ($(RELEASE),0)
|
||||||
CFLAGS += -g -DMNGR_DEBUG
|
CFLAGS += -g -DMNGR_DEBUG
|
||||||
endif
|
endif
|
||||||
|
@ -17,12 +17,6 @@
|
|||||||
#include "mevent.h"
|
#include "mevent.h"
|
||||||
#include "acrn_mngr.h"
|
#include "acrn_mngr.h"
|
||||||
|
|
||||||
#ifdef MNGR_DEBUG
|
|
||||||
#define pdebug() fprintf(stderr, "%s %d\n", __FUNCTION__, __LINE__)
|
|
||||||
#else
|
|
||||||
#define pdebug() while(0){}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* helpers */
|
/* helpers */
|
||||||
/* Check if @path is a directory, and create if not exist */
|
/* Check if @path is a directory, and create if not exist */
|
||||||
static int check_dir(const char *path)
|
static int check_dir(const char *path)
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
#ifndef ACRN_MANAGER_H
|
#ifndef ACRN_MANAGER_H
|
||||||
#define ACRN_MANAGER_H
|
#define ACRN_MANAGER_H
|
||||||
|
|
||||||
|
#ifdef MNGR_DEBUG
|
||||||
|
#define pdebug() fprintf(stderr, "%s %d\n", __FUNCTION__, __LINE__)
|
||||||
|
#else
|
||||||
|
#define pdebug() while(0){}
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
/* Basic message format */
|
/* Basic message format */
|
||||||
|
@ -9,28 +9,47 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include "acrnctl.h"
|
#include "acrnctl.h"
|
||||||
#include "acrn_mngr.h"
|
#include "acrn_mngr.h"
|
||||||
|
#include "mevent.h"
|
||||||
|
#include "vmm.h"
|
||||||
|
|
||||||
/* List head of all vm */
|
const char *state_str[] = {
|
||||||
static LIST_HEAD(vmmngr_list_struct, vmmngr_struct) vmmngr_head;
|
[VM_STATE_UNKNOWN] = "unknown",
|
||||||
|
[VM_CREATED] = "stopped",
|
||||||
|
[VM_STARTED] = "started",
|
||||||
|
[VM_PAUSED] = "paused",
|
||||||
|
[VM_UNTRACKED] = "untracked",
|
||||||
|
};
|
||||||
|
|
||||||
static struct vmmngr_struct *vmmngr_list_add(char *name)
|
/* Check if @path is a directory, and create if not exist */
|
||||||
|
static int check_dir(const char *path)
|
||||||
{
|
{
|
||||||
struct vmmngr_struct *s;
|
struct stat st;
|
||||||
|
|
||||||
s = calloc(1, sizeof(struct vmmngr_struct));
|
if (stat(path, &st)) {
|
||||||
if (!s) {
|
if (mkdir(path, 0666)) {
|
||||||
perror("alloc vmmngr_struct");
|
perror(path);
|
||||||
return NULL;
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(s->name, name, MAX_NAME_LEN - 1);
|
if (S_ISDIR(st.st_mode))
|
||||||
LIST_INSERT_HEAD(&vmmngr_head, s, list);
|
return 0;
|
||||||
|
|
||||||
return s;
|
fprintf(stderr, "%s exist, and not a directory!\n", path);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* List head of all vm */
|
||||||
|
static pthread_mutex_t vmmngr_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
struct vmmngr_list_struct vmmngr_head;
|
||||||
|
static unsigned long update_count = 0;
|
||||||
|
|
||||||
struct vmmngr_struct *vmmngr_find(char *name)
|
struct vmmngr_struct *vmmngr_find(char *name)
|
||||||
{
|
{
|
||||||
struct vmmngr_struct *s;
|
struct vmmngr_struct *s;
|
||||||
@ -41,67 +60,190 @@ struct vmmngr_struct *vmmngr_find(char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_vm_list(void)
|
static int send_msg(char *vmname, struct mngr_msg *req,
|
||||||
|
struct mngr_msg *ack, size_t ack_len);
|
||||||
|
|
||||||
|
static int query_state(const char *name)
|
||||||
{
|
{
|
||||||
char cmd[128] = { };
|
struct req_dm_query req;
|
||||||
char cmd_out[256] = { };
|
struct ack_dm_query ack;
|
||||||
char *vmname;
|
int ret;
|
||||||
char *pvmname = NULL;
|
|
||||||
struct vmmngr_struct *s;
|
|
||||||
size_t len = sizeof(cmd_out);
|
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd),
|
req.msg.magic = MNGR_MSG_MAGIC;
|
||||||
"find %s/add/ -name \"*.sh\" | "
|
req.msg.msgid = DM_QUERY;
|
||||||
"sed \"s/\\/opt\\/acrn\\/conf\\/add\\///g\" | "
|
req.msg.timestamp = time(NULL);
|
||||||
"sed \"s/.sh//g\"", ACRNCTL_OPT_ROOT);
|
req.msg.len = sizeof(req);
|
||||||
shell_cmd(cmd, cmd_out, sizeof(cmd_out));
|
|
||||||
|
|
||||||
/* Properly null-terminate cmd_out */
|
ret = send_msg(vmname, (struct mngr_msg *)&req,
|
||||||
cmd_out[len - 1] = '\0';
|
(struct mngr_msg *)&ack, sizeof(ack));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
vmname = strtok_r(cmd_out, "\n", &pvmname);
|
if (ack.state < 0)
|
||||||
while (vmname) {
|
pdebug();
|
||||||
s = vmmngr_list_add(vmname);
|
|
||||||
if (!s)
|
return ack.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find all the running DM process, which has */
|
||||||
|
/* /run/acrn/mngr/[vmname].monitor.[pid].socket */
|
||||||
|
static void _scan_alive_vm(void)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *entry;
|
||||||
|
struct vmmngr_struct *vm;
|
||||||
|
char name[128];
|
||||||
|
int pid;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = check_dir(ACRN_DM_SOCK_ROOT);
|
||||||
|
if (ret) {
|
||||||
|
pdebug();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir = opendir(ACRN_DM_SOCK_ROOT);
|
||||||
|
if (!dir) {
|
||||||
|
pdebug();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((entry = readdir(dir))) {
|
||||||
|
memset(name, 0, sizeof(name));
|
||||||
|
ret =
|
||||||
|
sscanf(entry->d_name, "%[^.].monitor.%d.socket", name,
|
||||||
|
&pid);
|
||||||
|
if (ret != 2)
|
||||||
continue;
|
continue;
|
||||||
s->state = VM_CREATED;
|
|
||||||
vmname = strtok_r(NULL, "\n", &pvmname);
|
if (name[sizeof(name) - 1]) {
|
||||||
|
pdebug();
|
||||||
|
/* truncate name and go a head */
|
||||||
|
name[sizeof(name) - 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pvmname = NULL;
|
vm = vmmngr_find(name);
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd),
|
if (!vm) {
|
||||||
"find %s/ -name \"*monitor.*.socket\" | "
|
vm = calloc(1, sizeof(*vm));
|
||||||
"sed \"s/\\/run\\/acrn\\/mngr\\///g\" | "
|
if (!vm) {
|
||||||
"awk -F. \'{ print $1 }\'", ACRN_DM_SOCK_ROOT);
|
pdebug();
|
||||||
shell_cmd(cmd, cmd_out, sizeof(cmd_out));
|
continue;
|
||||||
|
|
||||||
/* Properly null-terminate cmd_out */
|
|
||||||
cmd_out[len - 1] = '\0';
|
|
||||||
|
|
||||||
vmname = strtok_r(cmd_out, "\n", &pvmname);
|
|
||||||
while (vmname) {
|
|
||||||
s = vmmngr_find(vmname);
|
|
||||||
if (s)
|
|
||||||
s->state = VM_STARTED;
|
|
||||||
else {
|
|
||||||
s = vmmngr_list_add(vmname);
|
|
||||||
if (s)
|
|
||||||
s->state = VM_UNTRACKED;
|
|
||||||
}
|
}
|
||||||
vmname = strtok_r(NULL, "\n", &pvmname);
|
memcpy(vm->name, name, sizeof(vm->name) - 1);
|
||||||
|
LIST_INSERT_HEAD(&vmmngr_head, vm, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = query_state(name);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
/* unsupport query */
|
||||||
|
vm->state = VM_STARTED;
|
||||||
|
else
|
||||||
|
switch (ret) {
|
||||||
|
case VM_SUSPEND_NONE:
|
||||||
|
vm->state = VM_STARTED;
|
||||||
|
break;
|
||||||
|
case VM_SUSPEND_HALT:
|
||||||
|
vm->state = VM_PAUSED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vm->state = VM_STATE_UNKNOWN;
|
||||||
|
}
|
||||||
|
vm->update = update_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _scan_added_vm(void)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *entry;
|
||||||
|
struct vmmngr_struct *vm;
|
||||||
|
char name[128];
|
||||||
|
char suffix[128];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = check_dir(ACRNCTL_OPT_ROOT);
|
||||||
|
if (ret) {
|
||||||
|
pdebug();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = check_dir("/opt/acrn/conf/add");
|
||||||
|
if (ret) {
|
||||||
|
pdebug();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir = opendir("/opt/acrn/conf/add");
|
||||||
|
if (!dir) {
|
||||||
|
pdebug();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((entry = readdir(dir))) {
|
||||||
|
memset(name, 0, sizeof(name));
|
||||||
|
memset(suffix, 0, sizeof(suffix));
|
||||||
|
|
||||||
|
ret = strnlen(entry->d_name, sizeof(entry->d_name));
|
||||||
|
if (ret >= sizeof(name)) {
|
||||||
|
pdebug();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sscanf(entry->d_name, "%[^.].%s", name, suffix);
|
||||||
|
|
||||||
|
if (ret != 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (name[sizeof(name) - 1]) {
|
||||||
|
pdebug();
|
||||||
|
/* truncate name and go a head */
|
||||||
|
name[sizeof(name) - 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(suffix, "sh", sizeof("sh")))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vm = vmmngr_find(name);
|
||||||
|
|
||||||
|
if (!vm) {
|
||||||
|
vm = calloc(1, sizeof(*vm));
|
||||||
|
if (!vm) {
|
||||||
|
pdebug();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memcpy(vm->name, name, sizeof(vm->name) - 1);
|
||||||
|
LIST_INSERT_HEAD(&vmmngr_head, vm, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
vm->state = VM_CREATED;
|
||||||
|
vm->update = update_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_vm_list(void)
|
static void _remove_dead_vm(void)
|
||||||
{
|
{
|
||||||
struct vmmngr_struct *s;
|
struct vmmngr_struct *vm, *tvm;
|
||||||
|
|
||||||
while (!LIST_EMPTY(&vmmngr_head)) {
|
list_foreach_safe(vm, &vmmngr_head, list, tvm) {
|
||||||
s = LIST_FIRST(&vmmngr_head);
|
if (vm->update == update_count)
|
||||||
LIST_REMOVE(s, list);
|
continue;
|
||||||
free(s);
|
LIST_REMOVE(vm, list);
|
||||||
|
pdebug();
|
||||||
|
free(vm);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void vmmngr_update(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&vmmngr_mutex);
|
||||||
|
update_count++;
|
||||||
|
_scan_added_vm();
|
||||||
|
_scan_alive_vm();
|
||||||
|
_remove_dead_vm();
|
||||||
|
pthread_mutex_unlock(&vmmngr_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* helper functions */
|
/* helper functions */
|
||||||
|
@ -615,10 +615,8 @@ int main(int argc, char *argv[])
|
|||||||
if (acmds[i].valid_args(&acmds[i], argc - 1, &argv[1])) {
|
if (acmds[i].valid_args(&acmds[i], argc - 1, &argv[1])) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
get_vm_list();
|
vmmngr_update();
|
||||||
err = acmds[i].func(argc - 1, &argv[1]);
|
err = acmds[i].func(argc - 1, &argv[1]);
|
||||||
put_vm_list();
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,23 +21,7 @@ enum vm_state {
|
|||||||
VM_UNTRACKED, /* VM not created by acrnctl, or its launch script can change vm name */
|
VM_UNTRACKED, /* VM not created by acrnctl, or its launch script can change vm name */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *state_str[] = {
|
extern const char *state_str[];
|
||||||
[VM_STATE_UNKNOWN] = "unknown",
|
|
||||||
[VM_CREATED] = "stopped",
|
|
||||||
[VM_STARTED] = "started",
|
|
||||||
[VM_PAUSED] = "paused",
|
|
||||||
[VM_UNTRACKED] = "untracked",
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief search all vm and store it in vmmngr_head
|
|
||||||
*/
|
|
||||||
void get_vm_list(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief free all vmmngr_struct allocated by get_vm_list
|
|
||||||
*/
|
|
||||||
void put_vm_list(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief search vm indentified by vm from vmmngr_head
|
* @brief search vm indentified by vm from vmmngr_head
|
||||||
@ -50,11 +34,21 @@ struct vmmngr_struct *vmmngr_find(char *vmname);
|
|||||||
struct vmmngr_struct {
|
struct vmmngr_struct {
|
||||||
char name[MAX_NAME_LEN];
|
char name[MAX_NAME_LEN];
|
||||||
unsigned long state;
|
unsigned long state;
|
||||||
|
unsigned long update; /* update count, remove a vm if no update for it */
|
||||||
LIST_ENTRY(vmmngr_struct) list;
|
LIST_ENTRY(vmmngr_struct) list;
|
||||||
};
|
};
|
||||||
|
|
||||||
int shell_cmd(const char *cmd, char *outbuf, int len);
|
int shell_cmd(const char *cmd, char *outbuf, int len);
|
||||||
|
|
||||||
|
/* update names and states of VMs in SOS
|
||||||
|
* before you stop, start, pause, resume, suspend continue a VM
|
||||||
|
* use a name, it is better to run vmmngr_update() first
|
||||||
|
* and use vmngr_find() to check is this VM is still available
|
||||||
|
*/
|
||||||
|
void vmmngr_update(void);
|
||||||
|
|
||||||
|
extern LIST_HEAD(vmmngr_list_struct, vmmngr_struct) vmmngr_head;
|
||||||
|
|
||||||
/* vm life cycle ops */
|
/* vm life cycle ops */
|
||||||
int list_vm(void);
|
int list_vm(void);
|
||||||
int stop_vm(char *vmname);
|
int stop_vm(char *vmname);
|
||||||
|
Loading…
Reference in New Issue
Block a user