From 4cb9884ed7d3ca98ccd9bf2abbd508255b4e1fb7 Mon Sep 17 00:00:00 2001 From: DreamConnected <1487442471@qq.com> Date: Sun, 26 Oct 2025 13:28:13 +0800 Subject: [PATCH] lxc/{terminal, file_utils}: ensure complete data writes in ptx/peer io handlers MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Previously, lxc_write_nointr could return without writing all data when write() returned EAGAIN/EWOULDBLOCK due to buffer full conditions.  This change: - Implements a loop to continue writing until all data is sent - Handles EINTR, EAGAIN, and EWOULDBLOCK errors appropriately - Uses poll() to wait for fd to become ready when blocked - Maintains backward compatibility while fixing partial write issues Signed-off-by: DreamConnected <1487442471@qq.com> [ alex ] - introduce a separate helper lxc_write_all and use it only in ptx/peer io handlers - cleanup the code a bit Signed-off-by: Alexander Mikhalitsyn --- src/lxc/file_utils.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ src/lxc/file_utils.h | 2 ++ src/lxc/terminal.c | 4 +-- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/lxc/file_utils.c b/src/lxc/file_utils.c index e8bf9321b..ea54939f3 100644 --- a/src/lxc/file_utils.c +++ b/src/lxc/file_utils.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "file_utils.h" #include "macro.h" @@ -147,6 +148,91 @@ ssize_t lxc_read_try_buf_at(int dfd, const char *path, void *buf, size_t count) return ret; } +static int __lxc_wait_for_io_ready(int fd, int event, int timeout_ms) +{ + int ret; + struct pollfd pfd = { + .fd = fd, + .events = event, + .revents = 0 + }; + + do { + ret = poll(&pfd, 1, timeout_ms); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -errno; + + if (ret == 0) + return -ETIMEDOUT; + + if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { + if (pfd.revents & POLLERR) + return -EPIPE; + if (pfd.revents & POLLHUP) + return -EPIPE; + if (pfd.revents & POLLNVAL) + return -EBADF; + } + + if (!(pfd.revents & event)) + return -EAGAIN; + + return ret; +} + +ssize_t lxc_write_all(int fd, const void *buf, size_t count) +{ + ssize_t left_to_write = count; + const char *ptr = buf; + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return ret_set_errno(-1, errno); + + /* only non-blocking fds are allowed */ + if (!(flags & O_NONBLOCK)) + return ret_set_errno(-1, EINVAL); + + while (left_to_write > 0) { + int ret = write(fd, ptr, left_to_write); + + if (ret > 0) { + left_to_write -= ret; + ptr += ret; + continue; + } + + if (ret == 0) + break; + + /* ret < 0 */ + if (errno == EINTR) + continue; + + if (errno == EAGAIN) { + int pret = __lxc_wait_for_io_ready(fd, POLLOUT, 5000); + + /* we've got an event on fd */ + if (pret > 0) + continue; + + if (pret == -ETIMEDOUT) + break; + + if (pret < 0) + return ret_set_errno(-1, -pret); + } + + /* some other error */ + return ret_set_errno(-1, errno); + } + + return count - left_to_write; +} + ssize_t lxc_write_nointr(int fd, const void *buf, size_t count) { ssize_t ret; diff --git a/src/lxc/file_utils.h b/src/lxc/file_utils.h index 4fcaa4785..7d277dad3 100644 --- a/src/lxc/file_utils.h +++ b/src/lxc/file_utils.h @@ -35,6 +35,8 @@ __hidden extern int lxc_read_from_file(const char *filename, void *buf, size_t c __access_w(2, 3); /* send and receive buffers completely */ +__hidden extern ssize_t lxc_write_all(int fd, const void *buf, size_t count) __access_r(2, 3); + __hidden extern ssize_t lxc_write_nointr(int fd, const void *buf, size_t count) __access_r(2, 3); __hidden extern ssize_t lxc_pwrite_nointr(int fd, const void *buf, size_t count, off_t offset) diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c index 86fe785b6..d066c2b9e 100644 --- a/src/lxc/terminal.c +++ b/src/lxc/terminal.c @@ -338,7 +338,7 @@ static int lxc_terminal_ptx_io(struct lxc_terminal *terminal) w_rbuf = w_log = 0; /* write to peer first */ if (terminal->peer >= 0) - w = lxc_write_nointr(terminal->peer, buf, r); + w = lxc_write_all(terminal->peer, buf, r); /* write to terminal ringbuffer */ if (terminal->buffer_size > 0) @@ -375,7 +375,7 @@ static int lxc_terminal_peer_io(struct lxc_terminal *terminal) return -1; } - w = lxc_write_nointr(terminal->ptx, buf, r); + w = lxc_write_all(terminal->ptx, buf, r); if (w != r) WARN("Short write on terminal r:%d != w:%d", r, w); -- 2.47.3