From 9502363455188344dcfd7d1202cd48b7b554a5de Mon Sep 17 00:00:00 2001
From: Li Feng <lifeng2221dd1@zoho.com.cn>
Date: Wed, 20 Jan 2021 14:22:33 +0800
Subject: [PATCH 18/18] IO: fix io data miss when exec with pipes

Signed-off-by: Li Feng <lifeng2221dd1@zoho.com.cn>
---
 src/lxc/attach.c   |  4 ++--
 src/lxc/mainloop.c | 14 ++++++++++++++
 src/lxc/mainloop.h |  2 ++
 src/lxc/start.c    |  4 ++--
 src/lxc/terminal.c | 12 ++++++++----
 5 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 87e23c229..c5fc56150 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -1754,7 +1754,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
 		}
 	#endif
 		if (options->attach_flags & LXC_ATTACH_TERMINAL) {
-			ret = lxc_mainloop(&descr, -1);
+			ret = isulad_safe_mainloop(&descr, -1);
 			if (ret < 0) {
 				ret_parent = -1;
 				to_cleanup_pid = attached_pid;
@@ -1763,7 +1763,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
 
 #ifdef HAVE_ISULAD
 		// do lxc_mainloop to make sure we do not lose any output
-		(void)lxc_mainloop(&isulad_descr, 100);
+		(void)isulad_safe_mainloop(&isulad_descr, 100);
 		if (g_attach_timeout_state == ATTACH_TIMEOUT && err_msg != NULL && *err_msg == NULL) {
 			*err_msg = safe_strdup("Attach exceeded timeout");
 		}
diff --git a/src/lxc/mainloop.c b/src/lxc/mainloop.c
index 6d4c5935a..35186f4b5 100644
--- a/src/lxc/mainloop.c
+++ b/src/lxc/mainloop.c
@@ -141,3 +141,17 @@ void lxc_mainloop_close(struct lxc_epoll_descr *descr)
 
 	close_prot_errno_disarm(descr->epfd);
 }
+
+int isulad_safe_mainloop(struct lxc_epoll_descr *descr, int timeout_ms)
+{
+    int ret;
+
+    ret = lxc_mainloop(descr, timeout_ms);
+
+    // There are stdout and stderr channels, and two epolls should be performed to prevent
+    // one of the channels from exiting first, causing the other channel to not receive data,
+    // resulting in data loss
+    (void)lxc_mainloop(descr, 100);
+
+    return ret;
+}
\ No newline at end of file
diff --git a/src/lxc/mainloop.h b/src/lxc/mainloop.h
index 8afac60d3..dad79188c 100644
--- a/src/lxc/mainloop.h
+++ b/src/lxc/mainloop.h
@@ -34,4 +34,6 @@ extern void lxc_mainloop_close(struct lxc_epoll_descr *descr);
 
 define_cleanup_function(struct lxc_epoll_descr *, lxc_mainloop_close);
 
+extern int isulad_safe_mainloop(struct lxc_epoll_descr *descr, int timeout_ms);
+
 #endif
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 50a1a8203..e6e217042 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -590,13 +590,13 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
 	}
 #endif
 
-	ret = lxc_mainloop(&descr, -1);
+	ret = isulad_safe_mainloop(&descr, -1);
 	close_prot_errno_disarm(descr.epfd);
 	if (ret < 0 || !handler->init_died)
 		goto out_mainloop_console;
 
 	if (has_console)
-		ret = lxc_mainloop(&descr_console, 100);
+		ret = isulad_safe_mainloop(&descr_console, 100);
 
 out_mainloop_console:
 	if (has_console) {
diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c
index a4c6ad0c8..1e467f5a6 100644
--- a/src/lxc/terminal.c
+++ b/src/lxc/terminal.c
@@ -679,19 +679,22 @@ static void lxc_forward_data_to_fifo(struct lxc_list *list, bool is_err, const c
 	struct lxc_list *it  = NULL;
 	struct lxc_list *next = NULL;
 	struct lxc_fifos_fd *elem = NULL;
+	ssize_t w = 0;
 
 	lxc_list_for_each_safe(it, list, next) {
 		elem = it->elem;
 		if (is_err) {
 			if (elem->err_fd >= 0) {
-				if (lxc_write_nointr_for_fifo(elem->err_fd, buf, r) < 0) {
-					ERROR("Failed to write to fifo fd %d with error: %s", elem->err_fd, strerror(errno));
+				w = lxc_write_nointr_for_fifo(elem->err_fd, buf, r);
+				if (w != r) {
+					WARN("Failed to write to fifo fd %d with error: %s", elem->err_fd, strerror(errno));
 				}
 			}
 		} else {
 			if (elem->out_fd >= 0) {
-				if (lxc_write_nointr_for_fifo(elem->out_fd, buf, r) < 0) {
-					ERROR("Failed to write to fifo fd %d with error: %s", elem->out_fd, strerror(errno));
+				w = lxc_write_nointr_for_fifo(elem->out_fd, buf, r);
+				if (w != r) {
+					WARN("Failed to write to fifo fd %d with error: %s", elem->out_fd, strerror(errno));
 				}
 			}
 		}
@@ -1673,6 +1676,7 @@ int lxc_terminal_create(struct lxc_terminal *terminal)
 			ERROR("Failed to create stdin pipe");
 			goto err;
 		}
+
 		/* for stdout */
 		if (pipe2(terminal->pipes[1], O_CLOEXEC)) {
 			ERROR("Failed to create stdout pipe");
-- 
2.25.1

