From e4d2f9a15974e914bd41ab2c0847c65d56d5797f Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Fri, 5 Feb 2021 16:17:01 -0800 Subject: [PATCH] dm: graceful failure in pm_vuart - Exit main() if pm_by_vuart_init() fails - Use SIGHUP to gracefully power off a VM if pm_monitor_loop() encounters a failure - Identify a closed socket as a failure in pm_monitor_loop() Tracked-On: #5736 Signed-off-by: Peter Fang Acked-by: Wang, Yu1 --- devicemodel/core/main.c | 15 +++++--- devicemodel/core/pm_vuart.c | 65 +++++++++++++++++++++++----------- devicemodel/include/pm_vuart.h | 2 +- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/devicemodel/core/main.c b/devicemodel/core/main.c index a76772197..68091e2f1 100644 --- a/devicemodel/core/main.c +++ b/devicemodel/core/main.c @@ -418,9 +418,11 @@ handle_vmexit(struct vmctx *ctx, struct vhm_request *vhm_req, int vcpu) vm_notify_request_done(ctx, vcpu); } -static void +static int guest_pm_notify_init(struct vmctx *ctx) { + int ret = 0; + /* * We don't care ioc_init return value so far. * Will add return value check once ioc is full function. @@ -430,9 +432,11 @@ guest_pm_notify_init(struct vmctx *ctx) else if (PWR_EVENT_NOTIFY_PWR_BT == pm_notify_channel) power_button_init(ctx); else if (PWR_EVENT_NOTIFY_UART == pm_notify_channel) - pm_by_vuart_init(ctx); + ret = pm_by_vuart_init(ctx); else - pr_err("No correct pm notify channel given\n"); + pr_info("No pm notify channel given\n"); + + return ret; } static void @@ -459,7 +463,9 @@ vm_init_vdevs(struct vmctx *ctx) atkbdc_init(ctx); ioapic_init(ctx); - guest_pm_notify_init(ctx); + ret = guest_pm_notify_init(ctx); + if (ret < 0) + goto pm_notify_fail; ret = vrtc_init(ctx); if (ret < 0) @@ -510,6 +516,7 @@ vpit_fail: vrtc_deinit(ctx); vrtc_fail: guest_pm_notify_deinit(ctx); +pm_notify_fail: atkbdc_deinit(ctx); pci_irq_deinit(ctx); ioapic_deinit(); diff --git a/devicemodel/core/pm_vuart.c b/devicemodel/core/pm_vuart.c index 51a97527b..28e91aaed 100644 --- a/devicemodel/core/pm_vuart.c +++ b/devicemodel/core/pm_vuart.c @@ -59,10 +59,10 @@ static struct monitor_vm_ops vm_ops = { }; /* it read from vuart, and if end is '\0' or '\n' or len = buff-len it will return */ -static bool read_bytes(int fd, uint8_t *buffer, int buf_len, int *count) +static bool read_bytes(int fd, uint8_t *buffer, int buf_len, int *count, bool *eof) { bool ready = false; - int rc; + int rc = -1; if (buf_len <= (*count)) { *count = buf_len; @@ -81,15 +81,16 @@ static bool read_bytes(int fd, uint8_t *buffer, int buf_len, int *count) } while (rc > 0 && !ready); out: + *eof = (rc == 0); return ready; } -int pm_setup_socket(void) +static int pm_setup_socket(void) { struct sockaddr_in socket_addr; socket_fd = socket(AF_INET, SOCK_STREAM, 0); - if (socket_fd == -1) { + if (socket_fd == -1) { pr_err("create a socket endpoint error\n"); return -1; } @@ -102,6 +103,7 @@ int pm_setup_socket(void) if (connect(socket_fd, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) == -1) { pr_err("initiate a connection on a socket error\n"); close(socket_fd); + socket_fd = -1; return -1; } @@ -111,15 +113,11 @@ int pm_setup_socket(void) static void *pm_monitor_loop(void *arg) { int rc; + bool eof; char buf_node[CMD_LEN+1], buf_socket[CMD_LEN+1]; int max_fd, count_node = 0, count_socket = 0; fd_set read_fd; - if (pm_setup_socket() == -1) { - pr_err("create socket to connect life-cycle manager failed\n"); - return NULL; - } - buf_node[CMD_LEN] = buf_socket[CMD_LEN] = '\0'; max_fd = (socket_fd > node_fd) ? (socket_fd + 1) : (node_fd + 1); @@ -131,7 +129,8 @@ static void *pm_monitor_loop(void *arg) rc = select(max_fd, &read_fd, NULL, NULL, NULL); if (rc > 0) { if (FD_ISSET(node_fd, &read_fd)) { - if (read_bytes(node_fd, (uint8_t *)buf_node, CMD_LEN, &count_node)) { + if (read_bytes(node_fd, (uint8_t *)buf_node, CMD_LEN, + &count_node, &eof)) { pr_info("Received msg[%s] from UOS, count=%d\r\n", buf_node, count_node); rc = write(socket_fd, buf_node, count_node); @@ -139,12 +138,14 @@ static void *pm_monitor_loop(void *arg) if (rc != count_node) { pr_err("%s:%u: write error ret_val = %d\r\n", __func__, __LINE__, rc); + break; } count_node = 0; } } if (FD_ISSET(socket_fd, &read_fd)) { - if (read_bytes(socket_fd, (uint8_t *)buf_socket, CMD_LEN, &count_socket)) { + if (read_bytes(socket_fd, (uint8_t *)buf_socket, CMD_LEN, + &count_socket, &eof)) { pr_info("Received msg[%s] from life_mngr on SOS, count=%d\r\n", buf_socket, count_socket); pthread_mutex_lock(&pm_vuart_lock); @@ -154,12 +155,20 @@ static void *pm_monitor_loop(void *arg) if (rc != count_socket) { pr_err("%s:%u: write error ret_val = %d\r\n", __func__, __LINE__, rc); + break; } count_socket = 0; + } else if (eof) { + pr_err("socket connection to life-cycle manager closed\n"); + break; } } } } + + /* power off this VM if we get here */ + raise(SIGHUP); + /* cleanup will be done in pm_by_vuart_deinit() */ return NULL; } @@ -167,9 +176,15 @@ static int start_pm_monitor_thread(void) { int ret; - ret = pthread_create(&pm_monitor_thread, NULL, pm_monitor_loop, NULL); - if (ret) { - pr_err("failed %s %d\n", __func__, __LINE__); + if (pm_setup_socket()) { + pr_err("create socket to connect life-cycle manager failed\n"); + return -1; + } + + if ((ret = pthread_create(&pm_monitor_thread, NULL, pm_monitor_loop, NULL))) { + pr_err("%s: pthread_create error: %s\n", __func__, strerror(ret)); + close(socket_fd); + socket_fd = -1; return -1; } @@ -250,30 +265,38 @@ static int set_tty_attr(int fd, int speed) return 0; } -void pm_by_vuart_init(struct vmctx *ctx) +int pm_by_vuart_init(struct vmctx *ctx) { assert(node_index < MAX_NODE_CNT); pr_info("%s idx: %d, path: %s\r\n", __func__, node_index, node_path); - if (node_index == PTY_NODE) { + if (node_index == PTY_NODE) node_fd = pty_open_virtual_uart(node_path); - } else if (node_index == TTY_NODE) { + else if (node_index == TTY_NODE) node_fd = open(node_path, O_RDWR | O_NOCTTY | O_NONBLOCK); - set_tty_attr(node_fd, B115200); - } - if (node_fd > 0) { + if (node_fd >= 0) { + if (node_index == TTY_NODE) + set_tty_attr(node_fd, B115200); if (monitor_register_vm_ops(&vm_ops, ctx, "pm-vuart") < 0) { pr_err("%s: pm-vuart register to VM monitor failed\n", node_path); close(node_fd); node_fd = -1; + return -1; } } else { pr_err("%s open failed, fd=%d\n", node_path, node_fd); + return -1; } - start_pm_monitor_thread(); + if (start_pm_monitor_thread()) { + close(node_fd); + node_fd = -1; + return -1; + } + + return 0; } void pm_by_vuart_deinit(struct vmctx *ctx) diff --git a/devicemodel/include/pm_vuart.h b/devicemodel/include/pm_vuart.h index 0956f7ba7..a2da149b6 100644 --- a/devicemodel/include/pm_vuart.h +++ b/devicemodel/include/pm_vuart.h @@ -12,7 +12,7 @@ #define __PM_VUART__ int parse_pm_by_vuart(const char *opts); -void pm_by_vuart_init(struct vmctx *ctx); +int pm_by_vuart_init(struct vmctx *ctx); void pm_by_vuart_deinit(struct vmctx *ctx); #endif