summaryrefslogtreecommitdiff
path: root/src/journal/journald-native.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-10-30 17:36:02 +0100
committerLennart Poettering <lennart@poettering.net>2014-10-30 17:36:02 +0100
commitc79e98eadd3056a36a662699fa650db5b1bca0c3 (patch)
tree456bcce009973aafa5269f62a4e04f34c339f5e6 /src/journal/journald-native.c
parentdd4540da0e1f983540d862cc657df7161a3bdd06 (diff)
journal: when sending huge log messages prefer memfds over temporary files in /dev/shm
Previously when a log message grew beyond the maximum AF_UNIX/SOCK_DGRAM datagram limit we'd send an fd to a deleted file in /dev/shm instead. Because the sender could still modify the file after delivery we had to immediately copy the data on the receiving side. With memfds we can optimize this logic, and also remove the dependency on /dev/shm: simply send a sealed memfd around, and if we detect the seal memory map the fd and use it directly.
Diffstat (limited to 'src/journal/journald-native.c')
-rw-r--r--src/journal/journald-native.c68
1 files changed, 50 insertions, 18 deletions
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index a6352022d..6a9ae8a6c 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <stddef.h>
#include <sys/epoll.h>
+#include <sys/mman.h>
#include "socket-util.h"
#include "path-util.h"
@@ -306,17 +307,29 @@ void server_process_native_file(
const char *label, size_t label_len) {
struct stat st;
- _cleanup_free_ void *p = NULL;
- ssize_t n;
+ bool sealed;
int r;
+ /* Data is in the passed fd, since it didn't fit in a
+ * datagram. */
+
assert(s);
assert(fd >= 0);
- if (!ucred || ucred->uid != 0) {
+ /* If it's a memfd, check if it is sealed. If so, we can just
+ * use map it and use it, and do not need to copy the data
+ * out. */
+ r = fcntl(fd, F_GET_SEALS);
+ sealed = r >= 0 &&
+ (r & (F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL)) == (F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL);
+
+ if (!sealed && (!ucred || ucred->uid != 0)) {
_cleanup_free_ char *sl = NULL, *k = NULL;
const char *e;
+ /* If this is not a sealed memfd, and the peer is unknown or
+ * unprivileged, then verify the path. */
+
if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
log_oom();
return;
@@ -344,11 +357,6 @@ void server_process_native_file(
}
}
- /* Data is in the passed file, since it didn't fit in a
- * datagram. We can't map the file here, since clients might
- * then truncate it and trigger a SIGBUS for us. So let's
- * stupidly read it */
-
if (fstat(fd, &st) < 0) {
log_error("Failed to stat passed file, ignoring: %m");
return;
@@ -367,17 +375,41 @@ void server_process_native_file(
return;
}
- p = malloc(st.st_size);
- if (!p) {
- log_oom();
- return;
- }
+ if (sealed) {
+ void *p;
+ size_t ps;
+
+ /* The file is sealed, we can just map it and use it. */
- n = pread(fd, p, st.st_size, 0);
- 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);
+ ps = PAGE_ALIGN(st.st_size);
+ p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (p == MAP_FAILED) {
+ log_error("Failed to map memfd, ignoring: %m");
+ return;
+ }
+
+ server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len);
+ assert_se(munmap(p, ps) >= 0);
+ } else {
+ _cleanup_free_ void *p = NULL;
+ ssize_t n;
+
+ /* The file is not sealed, we can't map the file here, since
+ * clients might then truncate it and trigger a SIGBUS for
+ * us. So let's stupidly read it */
+
+ p = malloc(st.st_size);
+ if (!p) {
+ log_oom();
+ return;
+ }
+
+ n = pread(fd, p, st.st_size, 0);
+ 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);
+ }
}
int server_open_native_socket(Server*s) {