[systemd-devel] [PATCH] journald: collect process data from socket data

Piotr Wilczek p.wilczek at samsung.com
Fri May 30 03:45:21 PDT 2014


This patch adds posibility for journal to get process data from
socket data (if available) instead of from procfs.

Additionally a new procinfo structure is added to store all process
data in single place. This data include creditentials and status.

To enable this functionality, SO_PASSPROC socket option must be set.
This option is introduced in:
http://lwn.net/Articles/600564/

With this patch journald cpu usage is decresed by about 20%

Signed-off-by: Piotr Wilczek <p.wilczek at samsung.com>
---
 src/journal/journald-kmsg.c   |   2 +-
 src/journal/journald-native.c |  24 ++++----
 src/journal/journald-native.h |   4 +-
 src/journal/journald-server.c | 131 +++++++++++++++++++++++++++++++++---------
 src/journal/journald-server.h |  17 +++++-
 src/journal/journald-stream.c |   7 ++-
 src/journal/journald-syslog.c |  15 +++--
 src/journal/journald-syslog.h |   2 +-
 8 files changed, 155 insertions(+), 47 deletions(-)

diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index 12992e7..0bac0df 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -304,7 +304,7 @@ static void dev_kmsg_record(Server *s, char *p, size_t l) {
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
 
-        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority, 0);
+        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, priority, 0);
 
 finish:
         for (j = 0; j < z; j++)
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index c54f647..b2c44d6 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -75,9 +75,7 @@ static bool allow_object_pid(struct ucred *ucred) {
 void server_process_native_message(
                 Server *s,
                 const void *buffer, size_t buffer_size,
-                struct ucred *ucred,
-                struct timeval *tv,
-                const char *label, size_t label_len) {
+                struct procinfo *procinfo) {
 
         struct iovec *iovec = NULL;
         unsigned n = 0, j, tn = (unsigned) -1;
@@ -87,12 +85,20 @@ void server_process_native_message(
         char *identifier = NULL, *message = NULL;
         pid_t object_pid = 0;
 
+        struct ucred *ucred = NULL;
+        struct timeval *tv = NULL;
+
         assert(s);
         assert(buffer || buffer_size == 0);
 
         p = buffer;
         remaining = buffer_size;
 
+        if (procinfo) {
+                ucred = procinfo->ucred;
+                tv = procinfo->tv;
+        }
+
         while (remaining > 0) {
                 const char *e, *q;
 
@@ -106,7 +112,7 @@ void server_process_native_message(
 
                 if (e == p) {
                         /* Entry separator */
-                        server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
+                        server_dispatch_message(s, iovec, n, m, procinfo, NULL, priority, object_pid);
                         n = 0;
                         priority = LOG_INFO;
 
@@ -266,7 +272,7 @@ void server_process_native_message(
                         server_forward_wall(s, priority, identifier, message, ucred);
         }
 
-        server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
+        server_dispatch_message(s, iovec, n, m, procinfo, NULL, priority, object_pid);
 
 finish:
         for (j = 0; j < n; j++)  {
@@ -286,9 +292,7 @@ finish:
 void server_process_native_file(
                 Server *s,
                 int fd,
-                struct ucred *ucred,
-                struct timeval *tv,
-                const char *label, size_t label_len) {
+                struct procinfo *procinfo) {
 
         struct stat st;
         _cleanup_free_ void *p = NULL;
@@ -298,7 +302,7 @@ void server_process_native_file(
         assert(s);
         assert(fd >= 0);
 
-        if (!ucred || ucred->uid != 0) {
+        if (!procinfo || !procinfo->ucred || procinfo->ucred->uid != 0) {
                 _cleanup_free_ char *sl = NULL, *k = NULL;
                 const char *e;
 
@@ -362,7 +366,7 @@ void server_process_native_file(
         if (n < 0)
                 log_error("Failed to read file, ignoring: %s", strerror(-n));
         else if (n > 0)
-                server_process_native_message(s, p, n, ucred, tv, label, label_len);
+                server_process_native_message(s, p, n, procinfo);
 }
 
 int server_open_native_socket(Server*s) {
diff --git a/src/journal/journald-native.h b/src/journal/journald-native.h
index bf02fee..858a3d8 100644
--- a/src/journal/journald-native.h
+++ b/src/journal/journald-native.h
@@ -30,8 +30,8 @@
 
 bool valid_user_field(const char *p, size_t l, bool allow_protected);
 
-void server_process_native_message(Server *s, const void *buffer, size_t buffer_size, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len);
+void server_process_native_message(Server *s, const void *buffer, size_t buffer_size, struct procinfo *procinfo);
 
-void server_process_native_file(Server *s, int fd, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len);
+void server_process_native_file(Server *s, int fd, struct procinfo *procinfo);
 
 int server_open_native_socket(Server*s);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 381d80a..6c029b3 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -533,12 +533,34 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
                 server_schedule_sync(s, priority);
 }
 
+static int get_cap(const char *status, const char *cap_name, char **cap_val)
+{
+        char *k, *l, *p;
+
+        if (!status || !cap_name)
+                return -1;
+
+        k = strstr(status, cap_name);
+        if (!k)
+                return -1;
+        k += strlen(cap_name);
+
+        p = strchr(k, '\n');
+        if (!p)
+                return -1;
+        l = strndup(k, p - k);
+        if (!l)
+                return -1;
+
+        *cap_val = l;
+
+        return 0;
+}
+
 static void dispatch_message_real(
                 Server *s,
                 struct iovec *iovec, unsigned n, unsigned m,
-                struct ucred *ucred,
-                struct timeval *tv,
-                const char *label, size_t label_len,
+                struct procinfo *procinfo,
                 const char *unit_id,
                 int priority,
                 pid_t object_pid) {
@@ -567,13 +589,19 @@ static void dispatch_message_real(
         uint32_t audit;
         uid_t loginuid;
 #endif
+        struct ucred *ucred = NULL;
+        struct timeval *tv = NULL;
+#ifdef HAVE_SELINUX
+        const char *label = NULL;
+        size_t label_len = 0;
+#endif
 
         assert(s);
         assert(iovec);
         assert(n > 0);
         assert(n + N_IOVEC_META_FIELDS + (object_pid ? N_IOVEC_OBJECT_FIELDS : 0) <= m);
 
-        if (ucred) {
+        if (procinfo && procinfo->ucred) {
                 realuid = ucred->uid;
 
                 sprintf(pid, "_PID="PID_FMT, ucred->pid);
@@ -585,28 +613,47 @@ static void dispatch_message_real(
                 sprintf(gid, "_GID="GID_FMT, ucred->gid);
                 IOVEC_SET_STRING(iovec[n++], gid);
 
-                r = get_process_comm(ucred->pid, &t);
-                if (r >= 0) {
-                        x = strappenda("_COMM=", t);
-                        free(t);
+                if (procinfo->comm) {
+                        x = strappenda("_COMM=", procinfo->comm);
                         IOVEC_SET_STRING(iovec[n++], x);
+                } else {
+                        r = get_process_comm(ucred->pid, &t);
+                        if (r >= 0) {
+                                x = strappenda("_COMM=", t);
+                                free(t);
+                                IOVEC_SET_STRING(iovec[n++], x);
+                        }
                 }
 
-                r = get_process_exe(ucred->pid, &t);
-                if (r >= 0) {
-                        x = strappenda("_EXE=", t);
-                        free(t);
+                if (procinfo->exe) {
+                        x = strappenda("_EXE=", procinfo->exe);
                         IOVEC_SET_STRING(iovec[n++], x);
+                } else {
+                        r = get_process_exe(ucred->pid, &t);
+                        if (r >= 0) {
+                                x = strappenda("_EXE=", t);
+                                free(t);
+                                IOVEC_SET_STRING(iovec[n++], x);
+                        }
                 }
 
-                r = get_process_cmdline(ucred->pid, 0, false, &t);
-                if (r >= 0) {
-                        x = strappenda("_CMDLINE=", t);
-                        free(t);
+                if (procinfo->cmdline) {
+                        x = strappenda("_CMDLINE=", procinfo->cmdline);
                         IOVEC_SET_STRING(iovec[n++], x);
+                } else {
+                        r = get_process_cmdline(ucred->pid, 0, false, &t);
+                        if (r >= 0) {
+                                x = strappenda("_CMDLINE=", t);
+                                free(t);
+                                IOVEC_SET_STRING(iovec[n++], x);
+                        }
                 }
 
-                r = get_process_capeff(ucred->pid, &t);
+                r = -1;
+                if (procinfo->status)
+                        r = get_cap(procinfo->status, "CapEff:\t", &t);
+                if (r < 0)
+                        r = get_process_capeff(ucred->pid, &t);
                 if (r >= 0) {
                         x = strappenda("_CAP_EFFECTIVE=", t);
                         free(t);
@@ -825,6 +872,7 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
         int n = 0;
         va_list ap;
         struct ucred ucred = {};
+        struct procinfo procinfo = {};
 
         assert(s);
         assert(format);
@@ -849,15 +897,15 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
         ucred.uid = getuid();
         ucred.gid = getgid();
 
-        dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, LOG_INFO, 0);
+        procinfo.ucred = &ucred;
+
+        dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &procinfo, NULL, LOG_INFO, 0);
 }
 
 void server_dispatch_message(
                 Server *s,
                 struct iovec *iovec, unsigned n, unsigned m,
-                struct ucred *ucred,
-                struct timeval *tv,
-                const char *label, size_t label_len,
+                struct procinfo *procinfo,
                 const char *unit_id,
                 int priority,
                 pid_t object_pid) {
@@ -865,10 +913,14 @@ void server_dispatch_message(
         int rl, r;
         _cleanup_free_ char *path = NULL;
         char *c;
+        struct ucred *ucred = NULL;
 
         assert(s);
         assert(iovec || n == 0);
 
+        if (procinfo)
+                ucred = procinfo->ucred;
+
         if (n == 0)
                 return;
 
@@ -915,7 +967,7 @@ void server_dispatch_message(
                                       "Suppressed %u messages from %s", rl - 1, path);
 
 finish:
-        dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid);
+        dispatch_message_real(s, iovec, n, m, procinfo, unit_id, priority, object_pid);
 }
 
 
@@ -1122,6 +1174,9 @@ int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userda
                 char *label = NULL;
                 size_t label_len = 0;
                 struct iovec iovec;
+                struct procinfo procinfo;
+
+                memset(&procinfo, 0x00, sizeof(struct procinfo));
 
                 union {
                         struct cmsghdr cmsghdr;
@@ -1136,7 +1191,7 @@ int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userda
                         uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
                                     CMSG_SPACE(sizeof(struct timeval)) +
                                     CMSG_SPACE(sizeof(int)) + /* fd */
-                                    CMSG_SPACE(NAME_MAX)]; /* selinux label */
+                                    CMSG_SPACE(PATH_MAX)]; /* selinux label */
                 } control = {};
                 struct msghdr msghdr = {
                         .msg_iov = &iovec,
@@ -1189,20 +1244,44 @@ int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userda
                                 fds = (int*) CMSG_DATA(cmsg);
                                 n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
                         }
+                        else if (cmsg->cmsg_level == SOL_SOCKET &&
+                                 cmsg->cmsg_type == SCM_PROCINFO) {
+
+                                unsigned int i;
+                                char *ptr = CMSG_DATA(cmsg);
+
+                                procinfo.ucred = ucred;
+                                procinfo.label = label;
+                                procinfo.label_len = label_len;
+                                procinfo.tv = tv;
+
+                                for (i = 0; i < cmsg->cmsg_len; i+=strlen(ptr+i)+1) {
+                                        if (strlen(ptr+i) == 0)
+                                                continue;
+                                        if (strncmp(ptr+i, "COMM=", strlen("COMM=")) == 0)
+                                                procinfo.comm = ptr+i+strlen("COMM=");
+                                        if (strncmp(ptr+i, "EXE=", strlen("EXE=")) == 0)
+                                                procinfo.exe = ptr+i+strlen("EXE=");
+                                        if (strncmp(ptr+i, "CMDLINE=", strlen("CMDLINE=")) == 0)
+                                                procinfo.cmdline = ptr+i+strlen("CMDLINE=");
+                                        if (strncmp(ptr+i, "STATUS=", strlen("STATUS=")) == 0)
+                                                procinfo.status = ptr+i+strlen("STATUS=");
+                                }
+                        }
                 }
 
                 if (fd == s->syslog_fd) {
                         if (n > 0 && n_fds == 0) {
                                 s->buffer[n] = 0;
-                                server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
+                                server_process_syslog_message(s, strstrip(s->buffer), &procinfo);
                         } else if (n_fds > 0)
                                 log_warning("Got file descriptors via syslog socket. Ignoring.");
 
                 } else {
                         if (n > 0 && n_fds == 0)
-                                server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
+                                server_process_native_message(s, s->buffer, n, &procinfo);
                         else if (n == 0 && n_fds == 1)
-                                server_process_native_file(s, fds[0], ucred, tv, label, label_len);
+                                server_process_native_file(s, fds[0], &procinfo);
                         else if (n_fds > 0)
                                 log_warning("Got too many file descriptors via native socket. Ignoring.");
                 }
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index e468b82..3f9b43f 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -143,12 +143,27 @@ typedef struct Server {
         char *cgroup_root;
 } Server;
 
+#ifndef SCM_PROCINFO
+#define SCM_PROCINFO    0x05
+#endif
+
+struct procinfo {
+        struct ucred *ucred;
+        struct timeval *tv;
+        char *label;
+        size_t label_len;
+        char *comm;
+        char *exe;
+        char *cmdline;
+        char *status;
+};
+
 #define N_IOVEC_META_FIELDS 20
 #define N_IOVEC_KERNEL_FIELDS 64
 #define N_IOVEC_UDEV_FIELDS 32
 #define N_IOVEC_OBJECT_FIELDS 11
 
-void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid);
+void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct procinfo *procinfo, const char *unit_id, int priority, pid_t object_pid);
 void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,4);
 
 /* gperf lookup function */
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 89da150..1a62462 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -86,6 +86,7 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
         unsigned n = 0;
         char *label = NULL;
         size_t label_len = 0;
+        struct procinfo procinfo = { 0 };
 
         assert(s);
         assert(p);
@@ -137,7 +138,11 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
         }
 #endif
 
-        server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
+        procinfo.ucred = &s->ucred;
+        procinfo.label = label;
+        procinfo.label_len = label_len;
+
+        server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &procinfo, s->unit_id, priority, 0);
         return 0;
 }
 
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 434eac4..4bbc389 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -351,10 +351,7 @@ static void syslog_skip_date(char **buf) {
 void server_process_syslog_message(
         Server *s,
         const char *buf,
-        struct ucred *ucred,
-        struct timeval *tv,
-        const char *label,
-        size_t label_len) {
+        struct procinfo *procinfo) {
 
         char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
         struct iovec iovec[N_IOVEC_META_FIELDS + 6];
@@ -363,9 +360,17 @@ void server_process_syslog_message(
         char *identifier = NULL, *pid = NULL;
         const char *orig;
 
+        struct ucred *ucred = NULL;
+        struct timeval *tv = NULL;
+
         assert(s);
         assert(buf);
 
+        if (procinfo) {
+                ucred = procinfo->ucred;
+                tv = procinfo->tv;
+        }
+
         orig = buf;
         syslog_parse_priority(&buf, &priority, true);
 
@@ -409,7 +414,7 @@ void server_process_syslog_message(
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
 
-        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority, 0);
+        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), procinfo, NULL, priority, 0);
 
         free(message);
         free(identifier);
diff --git a/src/journal/journald-syslog.h b/src/journal/journald-syslog.h
index 057ea79..79f6949 100644
--- a/src/journal/journald-syslog.h
+++ b/src/journal/journald-syslog.h
@@ -30,7 +30,7 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid);
 
 void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv);
 
-void server_process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len);
+void server_process_syslog_message(Server *s, const char *buf, struct procinfo *procinfo);
 int server_open_syslog_socket(Server *s);
 
 void server_maybe_warn_forward_syslog_missed(Server *s);
-- 
1.9.1



More information about the systemd-devel mailing list