From: Patrick Donnelly Date: Thu, 27 Oct 2022 15:09:21 +0000 (-0400) Subject: log: add tests for stderr writes to fifos X-Git-Tag: v17.2.7~446^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=0f71a10f7659dc8597be508244e4b7c63794d9db;p=ceph.git log: add tests for stderr writes to fifos Signed-off-by: Patrick Donnelly (cherry picked from commit 48323ac07728a6246136993c1ce9219aec9a0f67) --- diff --git a/src/log/test.cc b/src/log/test.cc index f1ea107518ed..08ba5bff6afb 100644 --- a/src/log/test.cc +++ b/src/log/test.cc @@ -10,6 +10,10 @@ #include "global/global_context.h" #include "common/dout.h" +#include + +#include + using namespace std; using namespace ceph::logging; @@ -166,6 +170,125 @@ TEST(Log, ManyGather) log.stop(); } +static void readpipe(int fd, int verify) +{ + while (1) { + /* Use larger buffer on receiver as Linux will allow pipes buffers to + * exceed PIPE_BUF. We can't avoid tearing due to small read buffers from + * the Ceph side. + */ + + char buf[65536] = ""; + int rc = read(fd, buf, (sizeof buf) - 1); + if (rc == 0) { + _exit(0); + } else if (rc == -1) { + _exit(1); + } else if (rc > 0) { + if (verify) { + char* p = strrchr(buf, '\n'); + /* verify no torn writes */ + if (p == NULL) { + _exit(2); + } else if (p[1] != '\0') { + write(2, buf, strlen(buf)); + _exit(3); + } + } + } else _exit(100); + usleep(500); + } +} + +TEST(Log, StderrPipeAtomic) +{ + int pfd[2] = {-1, -1}; + int rc = pipe(pfd); + ASSERT_EQ(rc, 0); + pid_t pid = fork(); + if (pid == 0) { + close(pfd[1]); + readpipe(pfd[0], 1); + } else if (pid == (pid_t)-1) { + ASSERT_EQ(0, 1); + } + close(pfd[0]); + + SubsystemMap subs; + subs.set_log_level(1, 20); + subs.set_gather_level(1, 10); + Log log(&subs); + log.start(); + log.set_log_file(""); + log.reopen_log_file(); + log.set_stderr_fd(pfd[1]); + log.set_stderr_level(1, 20); + /* -128 for prefix space */ + for (int i = 0; i < PIPE_BUF-128; i++) { + MutableEntry e(1, 1); + auto& s = e.get_ostream(); + for (int j = 0; j < i; j++) { + char c = 'a'; + c += (j % 26); + s << c; + } + log.submit_entry(std::move(e)); + } + log.flush(); + log.stop(); + close(pfd[1]); + int status; + pid_t waited = waitpid(pid, &status, 0); + ASSERT_EQ(pid, waited); + ASSERT_NE(WIFEXITED(status), 0); + ASSERT_EQ(WEXITSTATUS(status), 0); +} + +TEST(Log, StderrPipeBig) +{ + int pfd[2] = {-1, -1}; + int rc = pipe(pfd); + ASSERT_EQ(rc, 0); + pid_t pid = fork(); + if (pid == 0) { + /* no verification as some reads will be torn due to size > PIPE_BUF */ + close(pfd[1]); + readpipe(pfd[0], 0); + } else if (pid == (pid_t)-1) { + ASSERT_EQ(0, 1); + } + close(pfd[0]); + + SubsystemMap subs; + subs.set_log_level(1, 20); + subs.set_gather_level(1, 10); + Log log(&subs); + log.start(); + log.set_log_file(""); + log.reopen_log_file(); + log.set_stderr_fd(pfd[1]); + log.set_stderr_level(1, 20); + /* -128 for prefix space */ + for (int i = 0; i < PIPE_BUF*2; i++) { + MutableEntry e(1, 1); + auto& s = e.get_ostream(); + for (int j = 0; j < i; j++) { + char c = 'a'; + c += (j % 26); + s << c; + } + log.submit_entry(std::move(e)); + } + log.flush(); + log.stop(); + close(pfd[1]); + int status; + pid_t waited = waitpid(pid, &status, 0); + ASSERT_EQ(pid, waited); + ASSERT_NE(WIFEXITED(status), 0); + ASSERT_EQ(WEXITSTATUS(status), 0); +} + void do_segv() { SubsystemMap subs;