mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 20:22:46 +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;
|
arg.ctx_arg = ctx;
|
||||||
register_command_handler(user_vm_destroy_handler, &arg, DESTROY);
|
register_command_handler(user_vm_destroy_handler, &arg, DESTROY);
|
||||||
register_command_handler(user_vm_blkrescan_handler, &arg, BLKRESCAN);
|
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)
|
int init_cmd_monitor(struct vmctx *ctx)
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#define CMD_OBJS \
|
#define CMD_OBJS \
|
||||||
GEN_CMD_OBJ(DESTROY), \
|
GEN_CMD_OBJ(DESTROY), \
|
||||||
GEN_CMD_OBJ(BLKRESCAN), \
|
GEN_CMD_OBJ(BLKRESCAN), \
|
||||||
|
GEN_CMD_OBJ(REGISTER_VM_EVENT_CLIENT), \
|
||||||
|
|
||||||
struct command dm_command_list[CMDS_NUM] = {CMD_OBJS};
|
struct command dm_command_list[CMDS_NUM] = {CMD_OBJS};
|
||||||
|
|
||||||
|
@ -10,8 +10,9 @@
|
|||||||
|
|
||||||
#define DESTROY "destroy"
|
#define DESTROY "destroy"
|
||||||
#define BLKRESCAN "blkrescan"
|
#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_NAME_MAX 32U
|
||||||
#define CMD_ARG_MAX 320U
|
#define CMD_ARG_MAX 320U
|
||||||
|
|
||||||
|
@ -67,6 +67,78 @@ static int send_socket_ack(struct socket_dev *sock, int fd, bool normal)
|
|||||||
return ret;
|
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 user_vm_destroy_handler(void *arg, void *command_para)
|
||||||
{
|
{
|
||||||
int ret;
|
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_destroy_handler(void *arg, void *command_para);
|
||||||
int user_vm_blkrescan_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
|
#endif
|
||||||
|
@ -47,13 +47,23 @@ err:
|
|||||||
}
|
}
|
||||||
static void free_socket_client(struct socket_dev *sock, struct socket_client *client)
|
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);
|
pthread_mutex_lock(&sock->client_mtx);
|
||||||
LIST_REMOVE(client, list);
|
LIST_REMOVE(client, list);
|
||||||
pthread_mutex_unlock(&sock->client_mtx);
|
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);
|
close(client->fd);
|
||||||
client->fd = -1;
|
client->fd = -1;
|
||||||
free(client);
|
free(client);
|
||||||
|
if (per_client_mutex) {
|
||||||
|
pthread_mutex_unlock(per_client_mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_socket_char(struct socket_client *client)
|
int write_socket_char(struct socket_client *client)
|
||||||
@ -142,7 +152,8 @@ static struct socket_client *new_socket_client(struct socket_dev *sock)
|
|||||||
__func__);
|
__func__);
|
||||||
goto alloc_client;
|
goto alloc_client;
|
||||||
}
|
}
|
||||||
|
/* If per client mutex is needed, init in callback */
|
||||||
|
client->per_client_mutex = NULL;
|
||||||
client->addr_len = sizeof(client->addr);
|
client->addr_len = sizeof(client->addr);
|
||||||
client->fd =
|
client->fd =
|
||||||
accept(sock->sock_fd, (struct sockaddr *)&client->addr,
|
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));
|
__func__, sock->sock_fd, strerror(errno));
|
||||||
goto accept_con;
|
goto accept_con;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&sock->client_mtx);
|
pthread_mutex_lock(&sock->client_mtx);
|
||||||
LIST_INSERT_HEAD(&sock->client_head, client, list);
|
LIST_INSERT_HEAD(&sock->client_head, client, list);
|
||||||
pthread_mutex_unlock(&sock->client_mtx);
|
pthread_mutex_unlock(&sock->client_mtx);
|
||||||
|
@ -21,7 +21,11 @@ struct socket_client {
|
|||||||
socklen_t addr_len;
|
socklen_t addr_len;
|
||||||
char buf[CLIENT_BUF_LEN];
|
char buf[CLIENT_BUF_LEN];
|
||||||
int len; /* 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;
|
LIST_ENTRY(socket_client) list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,4 +36,7 @@ unsigned get_wakeup_reason(void);
|
|||||||
int set_wakeup_timer(time_t t);
|
int set_wakeup_timer(time_t t);
|
||||||
int acrn_parse_intr_monitor(const char *opt);
|
int acrn_parse_intr_monitor(const char *opt);
|
||||||
int vm_monitor_blkrescan(void *arg, char *devargs);
|
int vm_monitor_blkrescan(void *arg, char *devargs);
|
||||||
|
|
||||||
|
int vm_monitor_send_vm_event(const char *msg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user