mirror of https://github.com/containers/conmon.git
Fix k8s-file log corruption during log rotation
The k8s-file log driver was corrupting log entries when the log file reached max_size and needed rotation. This manifested as garbled output with repeated timestamps and broken log entries. The root cause was in writev_buffer_flush() which incorrectly handled partial writes. When writev() returned a partial write, the function would modify the original iovec base pointers, corrupting the buffer state. During log rotation, this corrupted state would carry over to the new file descriptor, causing subsequent log entries to be malformed. Changes: - Simplify writev_buffer_flush() to use individual write() calls instead of complex writev() partial write handling - Always reset buffer state after log rotation to ensure clean state with new file descriptor - Remove conditional buffer reset that could leave corrupted state This fixes the issue where long-running containers (like GitLab CE) would produce corrupted logs after reaching the configured max_size. Fixes: Log corruption with --log-driver k8s-file --log-opt max_size=20mb Signed-off-by: Jindrich Novy <jnovy@redhat.com>
This commit is contained in:
parent
c5c98fd510
commit
29d17becab
|
|
@ -444,12 +444,13 @@ static int write_k8s_log(stdpipe_t pipe, const char *buf, ssize_t buflen)
|
||||||
if ((log_size_max > 0) && (k8s_bytes_written + bytes_to_be_written) > log_size_max) {
|
if ((log_size_max > 0) && (k8s_bytes_written + bytes_to_be_written) > log_size_max) {
|
||||||
if (writev_buffer_flush(k8s_log_fd, &bufv) < 0) {
|
if (writev_buffer_flush(k8s_log_fd, &bufv) < 0) {
|
||||||
nwarn("failed to flush buffer to log");
|
nwarn("failed to flush buffer to log");
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* We are going to reopen the file anyway, in case of
|
* Always reset the buffer after rotation to ensure clean state
|
||||||
* errors discard all we have in the buffer.
|
* with the new file descriptor. Any unflushed data is lost, but
|
||||||
|
* this prevents corruption of subsequent log entries.
|
||||||
*/
|
*/
|
||||||
bufv.iovcnt = 0;
|
bufv.iovcnt = 0;
|
||||||
}
|
|
||||||
reopen_k8s_file();
|
reopen_k8s_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -520,35 +521,28 @@ static bool get_line_len(ptrdiff_t *line_len, const char *buf, ssize_t buflen)
|
||||||
static ssize_t writev_buffer_flush(int fd, writev_buffer_t *buf)
|
static ssize_t writev_buffer_flush(int fd, writev_buffer_t *buf)
|
||||||
{
|
{
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
int iovcnt = buf->iovcnt;
|
|
||||||
struct iovec *iov = buf->iov;
|
|
||||||
|
|
||||||
while (iovcnt > 0) {
|
for (int i = 0; i < buf->iovcnt; i++) {
|
||||||
ssize_t res;
|
const char *ptr = buf->iov[i].iov_base;
|
||||||
do {
|
size_t remaining = buf->iov[i].iov_len;
|
||||||
res = writev(fd, iov, iovcnt);
|
|
||||||
} while (res == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if (res <= 0)
|
while (remaining > 0) {
|
||||||
|
ssize_t written = write(fd, ptr, remaining);
|
||||||
|
if (written < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (written == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
count += res;
|
ptr += written;
|
||||||
|
remaining -= written;
|
||||||
while (res > 0) {
|
count += written;
|
||||||
size_t from_this = MIN((size_t)res, iov->iov_len);
|
|
||||||
iov->iov_len -= from_this;
|
|
||||||
iov->iov_base += from_this;
|
|
||||||
res -= from_this;
|
|
||||||
|
|
||||||
if (iov->iov_len == 0) {
|
|
||||||
iov++;
|
|
||||||
iovcnt--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->iovcnt = 0;
|
buf->iovcnt = 0;
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue