mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-18 19:57:31 +00:00
dm: vm_event: add vm_event support in cmd monitor
This patch added vm_event support in command monitor, so that vm_event can be sent to a client (e.g., Libvirt) through the monitor. As the command monitor works in socket server mode, the vm_event sending process is designed in this way: 1. If a client wishes to receive vm_event, it issues a REGISTER_VM_EVENT_CLIENT command to the monitor. 2. Command monitor then handles the REGISTER_VM_EVENT_CLIENT command. If it is legitimate, the client is registered as as vm_event receiver. The command monitor then send a ACK to the client, and keeps the socket connection. 3. When a vm_event is generated, the command monitor send it out through the socket connection. 4. Only one event client is allowed. 5. The registration is cancelled on socket disconnection. Tracked-On: #8547 Signed-off-by: Wu Zhou <wu.zhou@intel.com> Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com>
This commit is contained in:
parent
d9ccf1ccb2
commit
c77fb77e78
@ -99,6 +99,7 @@ static void register_socket_message_handlers(struct vmctx *ctx)
|
||||
arg.ctx_arg = ctx;
|
||||
register_command_handler(user_vm_destroy_handler, &arg, DESTROY);
|
||||
register_command_handler(user_vm_blkrescan_handler, &arg, BLKRESCAN);
|
||||
register_command_handler(user_vm_register_vm_event_client_handler, &arg, REGISTER_VM_EVENT_CLIENT);
|
||||
}
|
||||
|
||||
int init_cmd_monitor(struct vmctx *ctx)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define CMD_OBJS \
|
||||
GEN_CMD_OBJ(DESTROY), \
|
||||
GEN_CMD_OBJ(BLKRESCAN), \
|
||||
GEN_CMD_OBJ(REGISTER_VM_EVENT_CLIENT), \
|
||||
|
||||
struct command dm_command_list[CMDS_NUM] = {CMD_OBJS};
|
||||
|
||||
|
@ -10,8 +10,9 @@
|
||||
|
||||
#define DESTROY "destroy"
|
||||
#define BLKRESCAN "blkrescan"
|
||||
#define REGISTER_VM_EVENT_CLIENT "register_vm_event_client"
|
||||
|
||||
#define CMDS_NUM 2U
|
||||
#define CMDS_NUM 3U
|
||||
#define CMD_NAME_MAX 32U
|
||||
#define CMD_ARG_MAX 320U
|
||||
|
||||
|
@ -67,6 +67,78 @@ static int send_socket_ack(struct socket_dev *sock, int fd, bool normal)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct socket_client *vm_event_client = NULL;
|
||||
static pthread_mutex_t vm_event_client_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void vm_event_free_cb(struct socket_client *self)
|
||||
{
|
||||
vm_event_client = NULL;
|
||||
}
|
||||
|
||||
static int set_vm_event_client(struct socket_client *client)
|
||||
{
|
||||
if (vm_event_client != NULL) {
|
||||
pr_err("vm event client already registerred.\n");
|
||||
return -1;
|
||||
} else {
|
||||
vm_event_client = client;
|
||||
client->per_client_mutex = &vm_event_client_mutex;
|
||||
client->free_client_cb = vm_event_free_cb;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int vm_monitor_send_vm_event(const char *msg)
|
||||
{
|
||||
int ret = -1;
|
||||
struct socket_client *client;
|
||||
pthread_mutex_t *per_client_mutex = &vm_event_client_mutex;
|
||||
|
||||
pthread_mutex_lock(per_client_mutex);
|
||||
client = vm_event_client;
|
||||
if (msg == NULL || client == NULL) {
|
||||
pthread_mutex_unlock(per_client_mutex);
|
||||
return -1;
|
||||
}
|
||||
memset(client->buf, 0, CLIENT_BUF_LEN);
|
||||
memcpy(client->buf, msg, strlen(msg));
|
||||
client->len = strlen(msg);
|
||||
ret = write_socket_char(client);
|
||||
pthread_mutex_unlock(per_client_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* When a client issues the REGISTER_VM_EVENT_CLIENT command,
|
||||
* this handler will register that client as this VM's only vm_event receiver,
|
||||
* and keeps the socket connection. Then vm events will be sent to
|
||||
* the client through this connection.
|
||||
*/
|
||||
int user_vm_register_vm_event_client_handler(void *arg, void *command_para)
|
||||
{
|
||||
int ret;
|
||||
struct command_parameters *cmd_para = (struct command_parameters *)command_para;
|
||||
struct handler_args *hdl_arg = (struct handler_args *)arg;
|
||||
struct socket_dev *sock = (struct socket_dev *)hdl_arg->channel_arg;
|
||||
struct socket_client *client = NULL;
|
||||
bool cmd_completed = false;
|
||||
|
||||
client = find_socket_client(sock, cmd_para->fd);
|
||||
if (client == NULL)
|
||||
return -1;
|
||||
|
||||
if (set_vm_event_client(client) == 0) {
|
||||
cmd_completed = true;
|
||||
}
|
||||
|
||||
pr_dbg("%s: client with fd %d registerred\n", __func__, client->fd);
|
||||
|
||||
ret = send_socket_ack(sock, cmd_para->fd, cmd_completed);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: Failed to send ACK message by socket.\n", __func__);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int user_vm_destroy_handler(void *arg, void *command_para)
|
||||
{
|
||||
int ret;
|
||||
|
@ -9,4 +9,6 @@ extern struct socket_dev *sock_server;
|
||||
|
||||
int user_vm_destroy_handler(void *arg, void *command_para);
|
||||
int user_vm_blkrescan_handler(void *arg, void *command_para);
|
||||
int user_vm_register_vm_event_client_handler(void *arg, void *command_para);
|
||||
|
||||
#endif
|
||||
|
@ -47,13 +47,23 @@ err:
|
||||
}
|
||||
static void free_socket_client(struct socket_dev *sock, struct socket_client *client)
|
||||
{
|
||||
pthread_mutex_t *per_client_mutex = client->per_client_mutex;
|
||||
pthread_mutex_lock(&sock->client_mtx);
|
||||
LIST_REMOVE(client, list);
|
||||
pthread_mutex_unlock(&sock->client_mtx);
|
||||
|
||||
if (per_client_mutex) {
|
||||
pthread_mutex_lock(per_client_mutex);
|
||||
}
|
||||
if (client->free_client_cb) {
|
||||
client->free_client_cb(client);
|
||||
}
|
||||
close(client->fd);
|
||||
client->fd = -1;
|
||||
free(client);
|
||||
if (per_client_mutex) {
|
||||
pthread_mutex_unlock(per_client_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
int write_socket_char(struct socket_client *client)
|
||||
@ -142,7 +152,8 @@ static struct socket_client *new_socket_client(struct socket_dev *sock)
|
||||
__func__);
|
||||
goto alloc_client;
|
||||
}
|
||||
|
||||
/* If per client mutex is needed, init in callback */
|
||||
client->per_client_mutex = NULL;
|
||||
client->addr_len = sizeof(client->addr);
|
||||
client->fd =
|
||||
accept(sock->sock_fd, (struct sockaddr *)&client->addr,
|
||||
@ -153,7 +164,6 @@ static struct socket_client *new_socket_client(struct socket_dev *sock)
|
||||
__func__, sock->sock_fd, strerror(errno));
|
||||
goto accept_con;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&sock->client_mtx);
|
||||
LIST_INSERT_HEAD(&sock->client_head, client, list);
|
||||
pthread_mutex_unlock(&sock->client_mtx);
|
||||
|
@ -21,7 +21,11 @@ struct socket_client {
|
||||
socklen_t addr_len;
|
||||
char buf[CLIENT_BUF_LEN];
|
||||
int len; /* buf len */
|
||||
|
||||
/* When a client is registered as vm_event receiver, we need this per_client_mutex
|
||||
* to make sure it is safe to free the client when client disconnects.
|
||||
*/
|
||||
pthread_mutex_t *per_client_mutex;
|
||||
void (*free_client_cb)(struct socket_client *self);
|
||||
LIST_ENTRY(socket_client) list;
|
||||
};
|
||||
|
||||
|
@ -36,4 +36,7 @@ unsigned get_wakeup_reason(void);
|
||||
int set_wakeup_timer(time_t t);
|
||||
int acrn_parse_intr_monitor(const char *opt);
|
||||
int vm_monitor_blkrescan(void *arg, char *devargs);
|
||||
|
||||
int vm_monitor_send_vm_event(const char *msg);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user