[systemd-devel] systemd-journald doesn't follow max datagram length when forwarding messages to syslog

Umut Tezduyar Lindskog umut at tezduyar.com
Wed Aug 6 12:08:04 PDT 2014


Hi,

journald fails to forward messages to syslog when it is using
Server->syslog_fd even before the limit of
/proc/sys/net/unix/max_dgram_qlen is reached.

For this experiment,

1) I have made sure /proc/sys/net/unix/max_dgram_qlen is set to 9999
before syslog.socket is created.
2) Replaced rsyslog.service's ExecStart with /bin/sleep
3) Booted system and observed following messages:

systemd-journal[434]: Forwarding to syslog missed 2 messages. (succeed
274 messages) [*]
systemd-journal[434]: Forwarding to syslog missed 183 messages.
(succeed 274 messages)
systemd-journal[434]: Forwarding to syslog missed 41 messages.
(succeed 274 messages)

This got me interested since we are loosing messages and after further
debugging I have come up with attached patch [**]. After booting up
the system and filling up the journal with "systemd-cat echo hello",
following correct behavior is observed.

systemd-journal[449]: Forwarding to syslog missed 1 messages. (succeed
10000 messages)

It is same hardware and clearly I have enough memory to store 1000
messages. I can't explain why it would make a difference to use
Server->syslog_fd vs a new socket fd but something is not right and
hopefully someone can explain. Further, we can fix journal so we won't
miss messages.

Thank you
Umut


[*] The number 274 fluctuates a bit between boots and I patched
journald to display how many messages have been sent to syslog.
[**] Patch is only to show proof of concept and not optimized.
-------------- next part --------------
diff --git a/systemd/src/journal/journald-server.h b/systemd/src/journal/journald-server.h
index 42a2235..b4117f7 100644
--- a/systemd/src/journal/journald-server.h
+++ b/systemd/src/journal/journald-server.h
@@ -100,6 +100,7 @@ typedef struct Server {
         bool forward_to_wall;
 
         unsigned n_forward_syslog_missed;
+        unsigned n_forward_syslog_success;
         usec_t last_warn_forward_syslog_missed;
 
         uint64_t cached_available_space;
diff --git a/systemd/src/journal/journald-syslog.c b/systemd/src/journal/journald-syslog.c
index b826e23..537386f 100644
--- a/systemd/src/journal/journald-syslog.c
+++ b/systemd/src/journal/journald-syslog.c
@@ -37,6 +37,7 @@
 
 static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
 
+        int fd = -1;
         union sockaddr_union sa = {
                 .un.sun_family = AF_UNIX,
                 .un.sun_path = "/run/systemd/journal/syslog",
@@ -71,12 +72,22 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
                 msghdr.msg_controllen = cmsg->cmsg_len;
         }
 
+        fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (fd < 0) {
+                log_debug("Failed to create a socket");
+                return;
+        }
+
+
         /* Forward the syslog message we received via /dev/log to
          * /run/systemd/syslog. Unfortunately we currently can't set
          * the SO_TIMESTAMP auxiliary data, and hence we don't. */
 
-        if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
+        if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
+                s->n_forward_syslog_success++;
+                close(fd);
                 return;
+	}
 
         /* The socket is full? I guess the syslog implementation is
          * too slow, and we shouldn't wait for that... */
@@ -96,17 +107,22 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
                 u.pid = getpid();
                 memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred));
 
-                if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
+                if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
+                        s->n_forward_syslog_success++;
+                        close(fd);
                         return;
+		}
 
                 if (errno == EAGAIN) {
                         s->n_forward_syslog_missed++;
+                        close(fd);
                         return;
                 }
         }
 
         if (errno != ENOENT)
                 log_debug("Failed to forward syslog message: %m");
+        close(fd);
 }
 
 static void forward_syslog_raw(Server *s, int priority, const char *buffer, struct ucred *ucred, struct timeval *tv) {
@@ -492,7 +508,8 @@ void server_maybe_warn_forward_syslog_missed(Server *s) {
         if (s->last_warn_forward_syslog_missed + WARN_FORWARD_SYSLOG_MISSED_USEC > n)
                 return;
 
-        server_driver_message(s, SD_MESSAGE_FORWARD_SYSLOG_MISSED, "Forwarding to syslog missed %u messages.", s->n_forward_syslog_missed);
+        server_driver_message(s, SD_MESSAGE_FORWARD_SYSLOG_MISSED, "Forwarding to syslog missed %u messages. (succeed %u messages)", s->n_forward_syslog_missed,
+                                                                                                                                     s->n_forward_syslog_success);
 
         s->n_forward_syslog_missed = 0;
         s->last_warn_forward_syslog_missed = n;


More information about the systemd-devel mailing list