From afc966e288b5013de55c56b18ddc9a5723b865d5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2015 16:26:31 +0200 Subject: util: remove ring.[ch] + pty.[ch] and tests This was used by consoled, which was removed, let's remove this too now. --- src/basic/ring.c | 209 ----------------- src/basic/ring.h | 55 ----- src/shared/pty.c | 633 --------------------------------------------------- src/shared/pty.h | 72 ------ src/test/test-pty.c | 142 ------------ src/test/test-ring.c | 130 ----------- 6 files changed, 1241 deletions(-) delete mode 100644 src/basic/ring.c delete mode 100644 src/basic/ring.h delete mode 100644 src/shared/pty.c delete mode 100644 src/shared/pty.h delete mode 100644 src/test/test-pty.c delete mode 100644 src/test/test-ring.c (limited to 'src') diff --git a/src/basic/ring.c b/src/basic/ring.c deleted file mode 100644 index 6814918464..0000000000 --- a/src/basic/ring.c +++ /dev/null @@ -1,209 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include "macro.h" -#include "ring.h" - -#define RING_MASK(_r, _v) ((_v) & ((_r)->size - 1)) - -void ring_flush(Ring *r) { - assert(r); - - r->start = 0; - r->used = 0; -} - -void ring_clear(Ring *r) { - assert(r); - - free(r->buf); - zero(*r); -} - -/* - * Get data pointers for current ring-buffer data. @vec must be an array of 2 - * iovec objects. They are filled according to the data available in the - * ring-buffer. 0, 1 or 2 is returned according to the number of iovec objects - * that were filled (0 meaning buffer is empty). - * - * Hint: "struct iovec" is defined in and looks like this: - * struct iovec { - * void *iov_base; - * size_t iov_len; - * }; - */ -size_t ring_peek(Ring *r, struct iovec *vec) { - assert(r); - - if (r->used == 0) { - return 0; - } else if (r->start + r->used <= r->size) { - if (vec) { - vec[0].iov_base = &r->buf[r->start]; - vec[0].iov_len = r->used; - } - return 1; - } else { - if (vec) { - vec[0].iov_base = &r->buf[r->start]; - vec[0].iov_len = r->size - r->start; - vec[1].iov_base = r->buf; - vec[1].iov_len = r->used - (r->size - r->start); - } - return 2; - } -} - -/* - * Copy data from the ring buffer into the linear external buffer @buf. Copy - * at most @size bytes. If the ring buffer size is smaller, copy less bytes and - * return the number of bytes copied. - */ -size_t ring_copy(Ring *r, void *buf, size_t size) { - size_t l; - - assert(r); - assert(buf); - - if (size > r->used) - size = r->used; - - if (size > 0) { - l = r->size - r->start; - if (size <= l) { - memcpy(buf, &r->buf[r->start], size); - } else { - memcpy(buf, &r->buf[r->start], l); - memcpy((uint8_t*)buf + l, r->buf, size - l); - } - } - - return size; -} - -/* - * Resize ring-buffer to size @nsize. @nsize must be a power-of-2, otherwise - * ring operations will behave incorrectly. - */ -static int ring_resize(Ring *r, size_t nsize) { - uint8_t *buf; - size_t l; - - assert(r); - assert(nsize > 0); - - buf = malloc(nsize); - if (!buf) - return -ENOMEM; - - if (r->used > 0) { - l = r->size - r->start; - if (r->used <= l) { - memcpy(buf, &r->buf[r->start], r->used); - } else { - memcpy(buf, &r->buf[r->start], l); - memcpy(&buf[l], r->buf, r->used - l); - } - } - - free(r->buf); - r->buf = buf; - r->size = nsize; - r->start = 0; - - return 0; -} - -/* - * Resize ring-buffer to provide enough room for @add bytes of new data. This - * resizes the buffer if it is too small. It returns -ENOMEM on OOM and 0 on - * success. - */ -static int ring_grow(Ring *r, size_t add) { - size_t need; - - assert(r); - - if (r->size - r->used >= add) - return 0; - - need = r->used + add; - if (need <= r->used) - return -ENOMEM; - else if (need < 4096) - need = 4096; - - need = ALIGN_POWER2(need); - if (need == 0) - return -ENOMEM; - - return ring_resize(r, need); -} - -/* - * Push @len bytes from @u8 into the ring buffer. The buffer is resized if it - * is too small. -ENOMEM is returned on OOM, 0 on success. - */ -int ring_push(Ring *r, const void *u8, size_t size) { - int err; - size_t pos, l; - - assert(r); - assert(u8); - - if (size == 0) - return 0; - - err = ring_grow(r, size); - if (err < 0) - return err; - - pos = RING_MASK(r, r->start + r->used); - l = r->size - pos; - if (l >= size) { - memcpy(&r->buf[pos], u8, size); - } else { - memcpy(&r->buf[pos], u8, l); - memcpy(r->buf, (const uint8_t*)u8 + l, size - l); - } - - r->used += size; - - return 0; -} - -/* - * Remove @len bytes from the start of the ring-buffer. Note that we protect - * against overflows so removing more bytes than available is safe. - */ -void ring_pull(Ring *r, size_t size) { - assert(r); - - if (size > r->used) - size = r->used; - - r->start = RING_MASK(r, r->start + size); - r->used -= size; -} diff --git a/src/basic/ring.h b/src/basic/ring.h deleted file mode 100644 index dbd6296384..0000000000 --- a/src/basic/ring.h +++ /dev/null @@ -1,55 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - - -typedef struct Ring Ring; - -struct Ring { - uint8_t *buf; /* buffer or NULL */ - size_t size; /* actual size of @buf */ - size_t start; /* start position of ring */ - size_t used; /* number of actually used bytes */ -}; - -/* flush buffer so it is empty again */ -void ring_flush(Ring *r); - -/* flush buffer, free allocated data and reset to initial state */ -void ring_clear(Ring *r); - -/* get pointers to buffer data and their length */ -size_t ring_peek(Ring *r, struct iovec *vec); - -/* copy data into external linear buffer */ -size_t ring_copy(Ring *r, void *buf, size_t size); - -/* push data to the end of the buffer */ -int ring_push(Ring *r, const void *u8, size_t size); - -/* pull data from the front of the buffer */ -void ring_pull(Ring *r, size_t size); - -/* return size of occupied buffer in bytes */ -static inline size_t ring_get_size(Ring *r) { - return r->used; -} diff --git a/src/shared/pty.c b/src/shared/pty.c deleted file mode 100644 index 35d9ff5f4d..0000000000 --- a/src/shared/pty.c +++ /dev/null @@ -1,633 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -/* - * PTY - * A PTY object represents a single PTY connection between a master and a - * child. The child process is fork()ed so the caller controls what program - * will be run. - * - * Programs like /bin/login tend to perform a vhangup() on their TTY - * before running the login procedure. This also causes the pty master - * to get a EPOLLHUP event as long as no client has the TTY opened. - * This means, we cannot use the TTY connection as reliable way to track - * the client. Instead, we _must_ rely on the PID of the client to track - * them. - * However, this has the side effect that if the client forks and the - * parent exits, we loose them and restart the client. But this seems to - * be the expected behavior so we implement it here. - * - * Unfortunately, epoll always polls for EPOLLHUP so as long as the - * vhangup() is ongoing, we will _always_ get EPOLLHUP and cannot sleep. - * This gets worse if the client closes the TTY but doesn't exit. - * Therefore, the fd must be edge-triggered in the epoll-set so we - * only get the events once they change. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "barrier.h" -#include "macro.h" -#include "ring.h" -#include "util.h" -#include "signal-util.h" -#include "pty.h" - -#define PTY_BUFSIZE 4096 - -enum { - PTY_ROLE_UNKNOWN, - PTY_ROLE_PARENT, - PTY_ROLE_CHILD, -}; - -struct Pty { - unsigned long ref; - Barrier barrier; - int fd; - pid_t child; - sd_event_source *fd_source; - sd_event_source *child_source; - - char in_buf[PTY_BUFSIZE]; - Ring out_buf; - - pty_event_t event_fn; - void *event_fn_userdata; - - bool needs_requeue : 1; - unsigned int role : 2; -}; - -int pty_new(Pty **out) { - _pty_unref_ Pty *pty = NULL; - int r; - - assert_return(out, -EINVAL); - - pty = new0(Pty, 1); - if (!pty) - return -ENOMEM; - - pty->ref = 1; - pty->fd = -1; - pty->barrier = (Barrier) BARRIER_NULL; - - pty->fd = posix_openpt(O_RDWR | O_NOCTTY | O_CLOEXEC | O_NONBLOCK); - if (pty->fd < 0) - return -errno; - - /* - * The slave-node is initialized to uid/gid of the caller of - * posix_openpt(). Only if devpts is mounted with fixed uid/gid this is - * skipped. In that case, grantpt() can overwrite these, but then you - * have to be root to use chown() (or a pt_chown helper has to be - * present). In those cases grantpt() really does something, - * otherwise it's a no-op. We call grantpt() here to try supporting - * those cases, even though no-one uses that, I guess. If you need other - * access-rights, set them yourself after this call returns (no, this is - * not racy, it looks racy, but races regarding your own UID are never - * important as an attacker could ptrace you; and the slave-pty is also - * still locked). - */ - r = grantpt(pty->fd); - if (r < 0) - return -errno; - - r = barrier_create(&pty->barrier); - if (r < 0) - return r; - - *out = pty; - pty = NULL; - return 0; -} - -Pty *pty_ref(Pty *pty) { - if (!pty || pty->ref < 1) - return NULL; - - ++pty->ref; - return pty; -} - -Pty *pty_unref(Pty *pty) { - if (!pty || pty->ref < 1 || --pty->ref > 0) - return NULL; - - pty_close(pty); - pty->child_source = sd_event_source_unref(pty->child_source); - barrier_destroy(&pty->barrier); - ring_clear(&pty->out_buf); - free(pty); - - return NULL; -} - -Barrier *pty_get_barrier(Pty *pty) { - assert(pty); - return &pty->barrier; -} - -bool pty_is_unknown(Pty *pty) { - return pty && pty->role == PTY_ROLE_UNKNOWN; -} - -bool pty_is_parent(Pty *pty) { - return pty && pty->role == PTY_ROLE_PARENT; -} - -bool pty_is_child(Pty *pty) { - return pty && pty->role == PTY_ROLE_CHILD; -} - -bool pty_has_child(Pty *pty) { - return pty_is_parent(pty) && pty->child > 0; -} - -pid_t pty_get_child(Pty *pty) { - return pty_has_child(pty) ? pty->child : -ECHILD; -} - -bool pty_is_open(Pty *pty) { - return pty && pty->fd >= 0; -} - -int pty_get_fd(Pty *pty) { - assert_return(pty, -EINVAL); - - return pty_is_open(pty) ? pty->fd : -EPIPE; -} - -int pty_make_child(Pty *pty) { - _cleanup_free_ char *slave_name = NULL; - int r, fd; - - assert_return(pty, -EINVAL); - assert_return(pty_is_unknown(pty), -EALREADY); - - r = ptsname_malloc(pty->fd, &slave_name); - if (r < 0) - return -errno; - - fd = open(slave_name, O_RDWR | O_CLOEXEC | O_NOCTTY); - if (fd < 0) - return -errno; - - safe_close(pty->fd); - pty->fd = fd; - pty->child = getpid(); - pty->role = PTY_ROLE_CHILD; - barrier_set_role(&pty->barrier, BARRIER_CHILD); - - return 0; -} - -int pty_make_parent(Pty *pty, pid_t child) { - assert_return(pty, -EINVAL); - assert_return(pty_is_unknown(pty), -EALREADY); - - pty->child = child; - pty->role = PTY_ROLE_PARENT; - - return 0; -} - -int pty_unlock(Pty *pty) { - assert_return(pty, -EINVAL); - assert_return(pty_is_unknown(pty) || pty_is_parent(pty), -EINVAL); - assert_return(pty_is_open(pty), -ENODEV); - - return unlockpt(pty->fd) < 0 ? -errno : 0; -} - -int pty_setup_child(Pty *pty) { - struct termios attr; - pid_t pid; - int r; - - assert_return(pty, -EINVAL); - assert_return(pty_is_child(pty), -EINVAL); - assert_return(pty_is_open(pty), -EALREADY); - - r = reset_signal_mask(); - if (r < 0) - return r; - - r = reset_all_signal_handlers(); - if (r < 0) - return r; - - pid = setsid(); - if (pid < 0 && errno != EPERM) - return -errno; - - r = ioctl(pty->fd, TIOCSCTTY, 0); - if (r < 0) - return -errno; - - r = tcgetattr(pty->fd, &attr); - if (r < 0) - return -errno; - - /* erase character should be normal backspace, PLEASEEE! */ - attr.c_cc[VERASE] = 010; - /* always set UTF8 flag */ - attr.c_iflag |= IUTF8; - - r = tcsetattr(pty->fd, TCSANOW, &attr); - if (r < 0) - return -errno; - - if (dup2(pty->fd, STDIN_FILENO) != STDIN_FILENO || - dup2(pty->fd, STDOUT_FILENO) != STDOUT_FILENO || - dup2(pty->fd, STDERR_FILENO) != STDERR_FILENO) - return -errno; - - /* only close FD if it's not a std-fd */ - pty->fd = (pty->fd > 2) ? safe_close(pty->fd) : -1; - - return 0; -} - -void pty_close(Pty *pty) { - if (!pty_is_open(pty)) - return; - - pty->fd_source = sd_event_source_unref(pty->fd_source); - pty->fd = safe_close(pty->fd); -} - -/* - * Drain input-queue and dispatch data via the event-handler. Returns <0 on - * error, 0 if queue is empty and 1 if we couldn't empty the input queue fast - * enough and there's still data left. - */ -static int pty_dispatch_read(Pty *pty) { - unsigned int i; - ssize_t len; - int r; - - /* - * We're edge-triggered, means we need to read the whole queue. This, - * however, might cause us to stall if the writer is faster than we - * are. Therefore, try reading as much as 8 times (32KiB) and only - * bail out then. - */ - - for (i = 0; i < 8; ++i) { - len = read(pty->fd, pty->in_buf, sizeof(pty->in_buf) - 1); - if (len < 0) { - if (errno == EINTR) - continue; - - return (errno == EAGAIN) ? 0 : -errno; - } else if (len == 0) - continue; - - /* set terminating zero for debugging safety */ - pty->in_buf[len] = 0; - r = pty->event_fn(pty, pty->event_fn_userdata, PTY_DATA, pty->in_buf, len); - if (r < 0) - return r; - } - - /* still data left, make sure we're queued again */ - pty->needs_requeue = true; - - return 1; -} - -/* - * Drain output-queue by writing data to the pty. Returns <0 on error, 0 if the - * output queue is empty now and 1 if we couldn't empty the output queue fast - * enough and there's still data left. - */ -static int pty_dispatch_write(Pty *pty) { - struct iovec vec[2]; - unsigned int i; - ssize_t len; - size_t num; - - /* - * Same as pty_dispatch_read(), we're edge-triggered so we need to call - * write() until either all data is written or it returns EAGAIN. We - * call it twice and if it still writes successfully, we reschedule. - */ - - for (i = 0; i < 2; ++i) { - num = ring_peek(&pty->out_buf, vec); - if (num < 1) - return 0; - - len = writev(pty->fd, vec, (int)num); - if (len < 0) { - if (errno == EINTR) - continue; - - return (errno == EAGAIN) ? 1 : -errno; - } else if (len == 0) - continue; - - ring_pull(&pty->out_buf, (size_t)len); - } - - /* still data left, make sure we're queued again */ - if (ring_get_size(&pty->out_buf) > 0) { - pty->needs_requeue = true; - return 1; - } - - return 0; -} - -static int pty_fd_fn(sd_event_source *source, int fd, uint32_t revents, void *userdata) { - Pty *pty = userdata; - int r_hup = 0, r_write = 0, r_read = 0, r; - - /* - * Whenever we encounter I/O errors, we have to make sure to drain the - * input queue first, before we handle any HUP. A child might send us - * a message and immediately close the queue. We must not handle the - * HUP first or we loose data. - * Therefore, if we read a message successfully, we always return - * success and wait for the next event-loop iteration. Furthermore, - * whenever there is a write-error, we must try reading from the input - * queue even if EPOLLIN is not set. The input might have arrived in - * between epoll_wait() and write(). Therefore, write-errors are only - * ever handled if the input-queue is empty. In all other cases they - * are ignored until either reading fails or the input queue is empty. - */ - - if (revents & (EPOLLHUP | EPOLLERR)) - r_hup = -EPIPE; - - if (revents & EPOLLOUT) - r_write = pty_dispatch_write(pty); - - /* Awesome! Kernel signals HUP without IN but queues are not empty.. */ - if ((revents & EPOLLIN) || r_hup < 0 || r_write < 0) { - r_read = pty_dispatch_read(pty); - if (r_read > 0) - return 0; /* still data left to fetch next round */ - } - - if (r_hup < 0 || r_write < 0 || r_read < 0) { - /* PTY closed and input-queue drained */ - pty_close(pty); - r = pty->event_fn(pty, pty->event_fn_userdata, PTY_HUP, NULL, 0); - if (r < 0) - return r; - } - - return 0; -} - -static int pty_fd_prepare_fn(sd_event_source *source, void *userdata) { - Pty *pty = userdata; - int r; - - if (pty->needs_requeue) { - /* - * We're edge-triggered. In case we couldn't handle all events - * or in case new write-data is queued, we set needs_requeue. - * Before going asleep, we set the io-events *again*. sd-event - * notices that we're edge-triggered and forwards the call to - * the kernel even if the events didn't change. The kernel will - * check the events and re-queue us on the ready queue in case - * an event is pending. - */ - r = sd_event_source_set_io_events(source, EPOLLHUP | EPOLLERR | EPOLLIN | EPOLLOUT | EPOLLET); - if (r >= 0) - pty->needs_requeue = false; - } - - return 0; -} - -static int pty_child_fn(sd_event_source *source, const siginfo_t *si, void *userdata) { - Pty *pty = userdata; - int r; - - pty->child = 0; - - r = pty->event_fn(pty, pty->event_fn_userdata, PTY_CHILD, si, sizeof(*si)); - if (r < 0) - return r; - - return 0; -} - -int pty_attach_event(Pty *pty, sd_event *event, pty_event_t event_fn, void *event_fn_userdata) { - int r; - - assert_return(pty, -EINVAL); - assert_return(event, -EINVAL); - assert_return(event_fn, -EINVAL); - assert_return(pty_is_parent(pty), -EINVAL); - - pty_detach_event(pty); - - if (pty_is_open(pty)) { - r = sd_event_add_io(event, - &pty->fd_source, - pty->fd, - EPOLLHUP | EPOLLERR | EPOLLIN | EPOLLOUT | EPOLLET, - pty_fd_fn, - pty); - if (r < 0) - goto error; - - r = sd_event_source_set_prepare(pty->fd_source, pty_fd_prepare_fn); - if (r < 0) - goto error; - } - - if (pty_has_child(pty)) { - r = sd_event_add_child(event, - &pty->child_source, - pty->child, - WEXITED, - pty_child_fn, - pty); - if (r < 0) - goto error; - } - - pty->event_fn = event_fn; - pty->event_fn_userdata = event_fn_userdata; - - return 0; - -error: - pty_detach_event(pty); - return r; -} - -void pty_detach_event(Pty *pty) { - if (!pty) - return; - - pty->child_source = sd_event_source_unref(pty->child_source); - pty->fd_source = sd_event_source_unref(pty->fd_source); - pty->event_fn = NULL; - pty->event_fn_userdata = NULL; -} - -int pty_write(Pty *pty, const void *buf, size_t size) { - bool was_empty; - int r; - - assert_return(pty, -EINVAL); - assert_return(pty_is_open(pty), -ENODEV); - assert_return(pty_is_parent(pty), -ENODEV); - - if (size < 1) - return 0; - - /* - * Push @buf[0..@size] into the output ring-buffer. In case the - * ring-buffer wasn't empty beforehand, we're already waiting for - * EPOLLOUT and we're done. If it was empty, we have to re-queue the - * FD for EPOLLOUT as we're edge-triggered and wouldn't get any new - * EPOLLOUT event. - */ - - was_empty = ring_get_size(&pty->out_buf) < 1; - - r = ring_push(&pty->out_buf, buf, size); - if (r < 0) - return r; - - if (was_empty) - pty->needs_requeue = true; - - return 0; -} - -int pty_signal(Pty *pty, int sig) { - assert_return(pty, -EINVAL); - assert_return(pty_is_open(pty), -ENODEV); - assert_return(pty_is_parent(pty), -ENODEV); - - return ioctl(pty->fd, TIOCSIG, sig) < 0 ? -errno : 0; -} - -int pty_resize(Pty *pty, unsigned short term_width, unsigned short term_height) { - struct winsize ws = { - .ws_col = term_width, - .ws_row = term_height, - }; - - assert_return(pty, -EINVAL); - assert_return(pty_is_open(pty), -ENODEV); - assert_return(pty_is_parent(pty), -ENODEV); - - /* - * This will send SIGWINCH to the pty slave foreground process group. - * We will also get one, but we don't need it. - */ - return ioctl(pty->fd, TIOCSWINSZ, &ws) < 0 ? -errno : 0; -} - -pid_t pty_fork(Pty **out, sd_event *event, pty_event_t event_fn, void *event_fn_userdata, unsigned short initial_term_width, unsigned short initial_term_height) { - _pty_unref_ Pty *pty = NULL; - int r; - pid_t pid; - - assert_return(out, -EINVAL); - assert_return((event && event_fn) || (!event && !event_fn), -EINVAL); - - r = pty_new(&pty); - if (r < 0) - return r; - - r = pty_unlock(pty); - if (r < 0) - return r; - - pid = fork(); - if (pid < 0) - return -errno; - - if (pid == 0) { - /* child */ - - r = pty_make_child(pty); - if (r < 0) - _exit(-r); - - r = pty_setup_child(pty); - if (r < 0) - _exit(-r); - - /* sync with parent */ - if (!barrier_place_and_sync(&pty->barrier)) - _exit(1); - - /* fallthrough and return the child's PTY object */ - } else { - /* parent */ - - r = pty_make_parent(pty, pid); - if (r < 0) - goto parent_error; - - r = pty_resize(pty, initial_term_width, initial_term_height); - if (r < 0) - goto parent_error; - - if (event) { - r = pty_attach_event(pty, event, event_fn, event_fn_userdata); - if (r < 0) - goto parent_error; - } - - /* sync with child */ - if (!barrier_place_and_sync(&pty->barrier)) { - r = -ECHILD; - goto parent_error; - } - - /* fallthrough and return the parent's PTY object */ - } - - *out = pty; - pty = NULL; - return pid; - -parent_error: - barrier_abort(&pty->barrier); - waitpid(pty->child, NULL, 0); - pty->child = 0; - return r; -} diff --git a/src/shared/pty.h b/src/shared/pty.h deleted file mode 100644 index 63c7db2833..0000000000 --- a/src/shared/pty.h +++ /dev/null @@ -1,72 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "barrier.h" -#include "macro.h" -#include "sd-event.h" - -typedef struct Pty Pty; - -enum { - PTY_CHILD, - PTY_HUP, - PTY_DATA, -}; - -typedef int (*pty_event_t) (Pty *pty, void *userdata, unsigned int event, const void *ptr, size_t size); - -int pty_new(Pty **out); -Pty *pty_ref(Pty *pty); -Pty *pty_unref(Pty *pty); - -#define _pty_unref_ _cleanup_(pty_unrefp) -DEFINE_TRIVIAL_CLEANUP_FUNC(Pty*, pty_unref); - -Barrier *pty_get_barrier(Pty *pty); - -bool pty_is_unknown(Pty *pty); -bool pty_is_parent(Pty *pty); -bool pty_is_child(Pty *pty); -bool pty_has_child(Pty *pty); -pid_t pty_get_child(Pty *pty); - -bool pty_is_open(Pty *pty); -int pty_get_fd(Pty *pty); - -int pty_make_child(Pty *pty); -int pty_make_parent(Pty *pty, pid_t child); -int pty_unlock(Pty *pty); -int pty_setup_child(Pty *pty); -void pty_close(Pty *pty); - -int pty_attach_event(Pty *pty, sd_event *event, pty_event_t event_fn, void *event_fn_userdata); -void pty_detach_event(Pty *pty); - -int pty_write(Pty *pty, const void *buf, size_t size); -int pty_signal(Pty *pty, int sig); -int pty_resize(Pty *pty, unsigned short term_width, unsigned short term_height); - -pid_t pty_fork(Pty **out, sd_event *event, pty_event_t event_fn, void *event_fn_userdata, unsigned short initial_term_width, unsigned short initial_term_height); diff --git a/src/test/test-pty.c b/src/test/test-pty.c deleted file mode 100644 index fbab3d4ebe..0000000000 --- a/src/test/test-pty.c +++ /dev/null @@ -1,142 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "pty.h" -#include "util.h" -#include "signal-util.h" - -static const char sndmsg[] = "message\n"; -static const char rcvmsg[] = "message\r\n"; -static char rcvbuf[128]; -static size_t rcvsiz = 0; -static sd_event *event; - -static void run_child(Pty *pty) { - ssize_t r, l; - char buf[512]; - - r = read(0, buf, sizeof(buf)); - assert_se((size_t)r == strlen(sndmsg)); - assert_se(!strncmp(buf, sndmsg, r)); - - l = write(1, buf, r); - assert_se(l == r); -} - -static int pty_fn(Pty *pty, void *userdata, unsigned int ev, const void *ptr, size_t size) { - switch (ev) { - case PTY_DATA: - assert_se(rcvsiz < strlen(rcvmsg) * 2); - assert_se(rcvsiz + size < sizeof(rcvbuf)); - - memcpy(&rcvbuf[rcvsiz], ptr, size); - rcvsiz += size; - - if (rcvsiz >= strlen(rcvmsg) * 2) { - assert_se(rcvsiz == strlen(rcvmsg) * 2); - assert_se(!memcmp(rcvbuf, rcvmsg, strlen(rcvmsg))); - assert_se(!memcmp(&rcvbuf[strlen(rcvmsg)], rcvmsg, strlen(rcvmsg))); - } - - break; - case PTY_HUP: - /* This is guaranteed to appear _after_ the input queues are - * drained! */ - assert_se(rcvsiz == strlen(rcvmsg) * 2); - break; - case PTY_CHILD: - /* this may appear at any time */ - break; - default: - assert_se(0); - break; - } - - /* if we got HUP _and_ CHILD, exit */ - if (pty_get_fd(pty) < 0 && pty_get_child(pty) < 0) - sd_event_exit(event, 0); - - return 0; -} - -static void run_parent(Pty *pty) { - int r; - - /* write message to pty, ECHO mode guarantees that we get it back - * twice: once via ECHO, once from the run_child() fn */ - assert_se(pty_write(pty, sndmsg, strlen(sndmsg)) >= 0); - - r = sd_event_loop(event); - assert_se(r >= 0); -} - -static void test_pty(void) { - pid_t pid; - Pty *pty = NULL; - - rcvsiz = 0; - zero(rcvbuf); - - assert_se(sd_event_default(&event) >= 0); - - pid = pty_fork(&pty, event, pty_fn, NULL, 80, 25); - assert_se(pid >= 0); - - if (pid == 0) { - /* child */ - run_child(pty); - exit(0); - } - - /* parent */ - run_parent(pty); - - /* Make sure the PTY recycled the child; yeah, this is racy if the - * PID was already reused; but that seems fine for a test. */ - assert_se(waitpid(pid, NULL, WNOHANG) < 0 && errno == ECHILD); - - pty_unref(pty); - sd_event_unref(event); -} - -int main(int argc, char *argv[]) { - unsigned int i; - - log_parse_environment(); - log_open(); - - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0); - - /* Oh, there're ugly races in the TTY layer regarding HUP vs IN. Turns - * out they appear only 10% of the time. I fixed all of them and - * don't see them, anymore. But let's be safe and run this 1000 times - * so we catch any new ones, in case they appear again. */ - for (i = 0; i < 1000; ++i) - test_pty(); - - return 0; -} diff --git a/src/test/test-ring.c b/src/test/test-ring.c deleted file mode 100644 index cb8a5d4e9e..0000000000 --- a/src/test/test-ring.c +++ /dev/null @@ -1,130 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include - -#include "def.h" -#include "ring.h" - -static void test_ring(void) { - static const char buf[8192]; - Ring r; - size_t l; - struct iovec vec[2]; - int s; - - zero(r); - - l = ring_peek(&r, vec); - assert_se(l == 0); - - s = ring_push(&r, buf, 2048); - assert_se(!s); - assert_se(ring_get_size(&r) == 2048); - - l = ring_peek(&r, vec); - assert_se(l == 1); - assert_se(vec[0].iov_len == 2048); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(ring_get_size(&r) == 2048); - - ring_pull(&r, 2048); - assert_se(ring_get_size(&r) == 0); - - l = ring_peek(&r, vec); - assert_se(l == 0); - assert_se(ring_get_size(&r) == 0); - - s = ring_push(&r, buf, 2048); - assert_se(!s); - assert_se(ring_get_size(&r) == 2048); - - l = ring_peek(&r, vec); - assert_se(l == 1); - assert_se(vec[0].iov_len == 2048); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(ring_get_size(&r) == 2048); - - s = ring_push(&r, buf, 1); - assert_se(!s); - assert_se(ring_get_size(&r) == 2049); - - l = ring_peek(&r, vec); - assert_se(l == 2); - assert_se(vec[0].iov_len == 2048); - assert_se(vec[1].iov_len == 1); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(!memcmp(vec[1].iov_base, buf, vec[1].iov_len)); - assert_se(ring_get_size(&r) == 2049); - - ring_pull(&r, 2048); - assert_se(ring_get_size(&r) == 1); - - l = ring_peek(&r, vec); - assert_se(l == 1); - assert_se(vec[0].iov_len == 1); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(ring_get_size(&r) == 1); - - ring_pull(&r, 1); - assert_se(ring_get_size(&r) == 0); - - s = ring_push(&r, buf, 2048); - assert_se(!s); - assert_se(ring_get_size(&r) == 2048); - - s = ring_push(&r, buf, 2049); - assert_se(!s); - assert_se(ring_get_size(&r) == 4097); - - l = ring_peek(&r, vec); - assert_se(l == 1); - assert_se(vec[0].iov_len == 4097); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(ring_get_size(&r) == 4097); - - ring_pull(&r, 1); - assert_se(ring_get_size(&r) == 4096); - - s = ring_push(&r, buf, 4096); - assert_se(!s); - assert_se(ring_get_size(&r) == 8192); - - l = ring_peek(&r, vec); - assert_se(l == 2); - assert_se(vec[0].iov_len == 8191); - assert_se(vec[1].iov_len == 1); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(!memcmp(vec[1].iov_base, buf, vec[1].iov_len)); - assert_se(ring_get_size(&r) == 8192); - - ring_clear(&r); - assert_se(ring_get_size(&r) == 0); -} - -int main(int argc, char *argv[]) { - log_parse_environment(); - log_open(); - - test_ring(); - - return 0; -} -- cgit v1.2.3-54-g00ecf From d53d94743c5e5e3a4a668b0c707826a90a08949a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2015 16:48:24 +0200 Subject: core: refactor cpu shares/blockio weight cgroup logic Let's stop using the "unsigned long" type for weights/shares, and let's just use uint64_t for this, as that's what we expose on the bus. Unify parsers, and always validate the range for these fields. Correct the default blockio weight to 500, since that's what the kernel actually uses. When parsing the weight/shares settings from unit files accept the empty string as a way to reset the weight/shares value. When getting it via the bus, uniformly map (uint64_t) -1 to unset. Open up StartupCPUShares= and StartupBlockIOWeight= to transient units. --- man/systemd.resource-control.xml | 9 +-- src/basic/cgroup-util.c | 40 +++++++++++++ src/basic/cgroup-util.h | 27 +++++++++ src/core/cgroup.c | 54 +++++++++-------- src/core/cgroup.h | 14 ++--- src/core/dbus-cgroup.c | 125 +++++++++++++++------------------------ src/core/load-fragment.c | 54 +++++++---------- src/core/unit.c | 4 +- src/shared/bus-util.c | 35 +++++++---- 9 files changed, 203 insertions(+), 159 deletions(-) (limited to 'src') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 6b9329bbee..98f4d75ddb 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -118,10 +118,11 @@ Assign the specified CPU time share weight to the - processes executed. Those options take an integer value and + processes executed. These options take an integer value and control the cpu.shares control group - attribute, which defaults to 1024. For details about this - control group attribute, see sched-design-CFS.txt. The available CPU time is split up among all units within one slice relative to their CPU time share weight. @@ -258,7 +259,7 @@ the executed processes. Takes a single weight value (between 10 and 1000) to set the default block IO weight. This controls the blkio.weight control group attribute, - which defaults to 1000. For details about this control group + which defaults to 500. For details about this control group attribute, see blkio-controller.txt. The available IO bandwidth is split up among all units within diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 6099dc8721..4bf08cfe03 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2207,6 +2207,46 @@ bool cg_is_legacy_wanted(void) { return !cg_is_unified_wanted(); } +int cg_cpu_shares_parse(const char *s, uint64_t *ret) { + uint64_t u; + int r; + + if (isempty(s)) { + *ret = CGROUP_CPU_SHARES_INVALID; + return 0; + } + + r = safe_atou64(s, &u); + if (r < 0) + return r; + + if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX) + return -ERANGE; + + *ret = u; + return 0; +} + +int cg_blkio_weight_parse(const char *s, uint64_t *ret) { + uint64_t u; + int r; + + if (isempty(s)) { + *ret = CGROUP_BLKIO_WEIGHT_INVALID; + return 0; + } + + r = safe_atou64(s, &u); + if (r < 0) + return r; + + if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX) + return -ERANGE; + + *ret = u; + return 0; +} + static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = { [CGROUP_CONTROLLER_CPU] = "cpu", [CGROUP_CONTROLLER_CPUACCT] = "cpuacct", diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 7e1b4f9c72..33ca28cab7 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -53,6 +53,30 @@ typedef enum CGroupMask { _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1 } CGroupMask; +/* Special values for the cpu.shares attribute */ +#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1) +#define CGROUP_CPU_SHARES_MIN UINT64_C(2) +#define CGROUP_CPU_SHARES_MAX UINT64_C(262144) +#define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024) + +static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) { + return + x == CGROUP_CPU_SHARES_INVALID || + (x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX); +} + +/* Special values for the blkio.weight attribute */ +#define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1) +#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10) +#define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000) +#define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500) + +static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) { + return + x == CGROUP_BLKIO_WEIGHT_INVALID || + (x >= CGROUP_BLKIO_WEIGHT_MIN && x <= CGROUP_BLKIO_WEIGHT_MAX); +} + /* * General rules: * @@ -161,3 +185,6 @@ bool cg_is_legacy_wanted(void); const char* cgroup_controller_to_string(CGroupController c) _const_; CGroupController cgroup_controller_from_string(const char *s) _pure_; + +int cg_cpu_shares_parse(const char *s, uint64_t *ret); +int cg_blkio_weight_parse(const char *s, uint64_t *ret); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 48000d4e6e..4999a1e116 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -37,14 +37,16 @@ void cgroup_context_init(CGroupContext *c) { /* Initialize everything to the kernel defaults, assuming the * structure is preinitialized to 0 */ - c->cpu_shares = (unsigned long) -1; - c->startup_cpu_shares = (unsigned long) -1; + c->cpu_shares = CGROUP_CPU_SHARES_INVALID; + c->startup_cpu_shares = CGROUP_CPU_SHARES_INVALID; + c->cpu_quota_per_sec_usec = USEC_INFINITY; + c->memory_limit = (uint64_t) -1; - c->blockio_weight = (unsigned long) -1; - c->startup_blockio_weight = (unsigned long) -1; - c->tasks_max = (uint64_t) -1; - c->cpu_quota_per_sec_usec = USEC_INFINITY; + c->blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID; + c->startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID; + + c->tasks_max = (uint64_t) -1; } void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) { @@ -102,11 +104,12 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { "%sCPUAccounting=%s\n" "%sBlockIOAccounting=%s\n" "%sMemoryAccounting=%s\n" - "%sCPUShares=%lu\n" - "%sStartupCPUShares=%lu\n" + "%sTasksAccounting=%s\n" + "%sCPUShares=%" PRIu64 "\n" + "%sStartupCPUShares=%" PRIu64 "\n" "%sCPUQuotaPerSecSec=%s\n" - "%sBlockIOWeight=%lu\n" - "%sStartupBlockIOWeight=%lu\n" + "%sBlockIOWeight=%" PRIu64 "\n" + "%sStartupBlockIOWeight=%" PRIu64 "\n" "%sMemoryLimit=%" PRIu64 "\n" "%sTasksMax=%" PRIu64 "\n" "%sDevicePolicy=%s\n" @@ -114,6 +117,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { prefix, yes_no(c->cpu_accounting), prefix, yes_no(c->blockio_accounting), prefix, yes_no(c->memory_accounting), + prefix, yes_no(c->tasks_accounting), prefix, c->cpu_shares, prefix, c->startup_cpu_shares, prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1), @@ -133,7 +137,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { LIST_FOREACH(device_weights, w, c->blockio_device_weights) fprintf(f, - "%sBlockIODeviceWeight=%s %lu", + "%sBlockIODeviceWeight=%s %" PRIu64, prefix, w->path, w->weight); @@ -309,11 +313,11 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M * and missing cgroups, i.e. EROFS and ENOENT. */ if ((mask & CGROUP_MASK_CPU) && !is_root) { - char buf[MAX(DECIMAL_STR_MAX(unsigned long), DECIMAL_STR_MAX(usec_t)) + 1]; + char buf[MAX(DECIMAL_STR_MAX(uint64_t), DECIMAL_STR_MAX(usec_t)) + 1]; - sprintf(buf, "%lu\n", - IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != (unsigned long) -1 ? c->startup_cpu_shares : - c->cpu_shares != (unsigned long) -1 ? c->cpu_shares : 1024); + sprintf(buf, "%" PRIu64 "\n", + IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->startup_cpu_shares : + c->cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->cpu_shares : CGROUP_CPU_SHARES_DEFAULT); r = cg_set_attribute("cpu", path, "cpu.shares", buf); if (r < 0) log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, @@ -336,15 +340,15 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M } if (mask & CGROUP_MASK_BLKIO) { - char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1, - DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1, - DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; + char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1, + DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; CGroupBlockIODeviceWeight *w; CGroupBlockIODeviceBandwidth *b; if (!is_root) { - sprintf(buf, "%lu\n", IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != (unsigned long) -1 ? c->startup_blockio_weight : - c->blockio_weight != (unsigned long) -1 ? c->blockio_weight : 1000); + sprintf(buf, "%" PRIu64 "\n", + IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->startup_blockio_weight : + c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT); r = cg_set_attribute("blkio", path, "blkio.weight", buf); if (r < 0) log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, @@ -358,7 +362,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M if (r < 0) continue; - sprintf(buf, "%u:%u %lu", major(dev), minor(dev), w->weight); + sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight); r = cg_set_attribute("blkio", path, "blkio.weight_device", buf); if (r < 0) log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, @@ -493,14 +497,14 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) { /* Figure out which controllers we need */ if (c->cpu_accounting || - c->cpu_shares != (unsigned long) -1 || - c->startup_cpu_shares != (unsigned long) -1 || + c->cpu_shares != CGROUP_CPU_SHARES_INVALID || + c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID || c->cpu_quota_per_sec_usec != USEC_INFINITY) mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU; if (c->blockio_accounting || - c->blockio_weight != (unsigned long) -1 || - c->startup_blockio_weight != (unsigned long) -1 || + c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || + c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || c->blockio_device_weights || c->blockio_device_bandwidths) mask |= CGROUP_MASK_BLKIO; diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 3ba09d56a4..3d455d93ed 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -58,7 +58,7 @@ struct CGroupDeviceAllow { struct CGroupBlockIODeviceWeight { LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights); char *path; - unsigned long weight; + uint64_t weight; }; struct CGroupBlockIODeviceBandwidth { @@ -74,12 +74,12 @@ struct CGroupContext { bool memory_accounting; bool tasks_accounting; - unsigned long cpu_shares; - unsigned long startup_cpu_shares; + uint64_t cpu_shares; + uint64_t startup_cpu_shares; usec_t cpu_quota_per_sec_usec; - unsigned long blockio_weight; - unsigned long startup_blockio_weight; + uint64_t blockio_weight; + uint64_t startup_blockio_weight; LIST_HEAD(CGroupBlockIODeviceWeight, blockio_device_weights); LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths); @@ -88,9 +88,9 @@ struct CGroupContext { CGroupDevicePolicy device_policy; LIST_HEAD(CGroupDeviceAllow, device_allow); - bool delegate; - uint64_t tasks_max; + + bool delegate; }; #include "unit.h" diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 94de92c3dd..78841ba656 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -133,34 +133,16 @@ static int property_get_device_allow( return sd_bus_message_close_container(reply); } -static int property_get_ulong_as_u64( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - unsigned long *ul = userdata; - - assert(bus); - assert(reply); - assert(ul); - - return sd_bus_message_append(reply, "t", *ul == (unsigned long) -1 ? (uint64_t) -1 : (uint64_t) *ul); -} - const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0), SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0), - SD_BUS_PROPERTY("CPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, cpu_shares), 0), - SD_BUS_PROPERTY("StartupCPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_cpu_shares), 0), + SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0), + SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0), SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0), SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0), - SD_BUS_PROPERTY("BlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, blockio_weight), 0), - SD_BUS_PROPERTY("StartupBlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_blockio_weight), 0), + SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0), + SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0), SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0), SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), @@ -237,49 +219,45 @@ int bus_cgroup_set_property( return 1; } else if (streq(name, "CPUShares")) { - uint64_t u64; - unsigned long ul; + uint64_t shares; - r = sd_bus_message_read(message, "t", &u64); + r = sd_bus_message_read(message, "t", &shares); if (r < 0) return r; - if (u64 == (uint64_t) -1) - ul = (unsigned long) -1; - else { - ul = (unsigned long) u64; - if (ul <= 0 || (uint64_t) ul != u64) - return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range"); - } + if (!CGROUP_CPU_SHARES_IS_OK(shares)) + return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range"); if (mode != UNIT_CHECK) { - c->cpu_shares = ul; + c->cpu_shares = shares; u->cgroup_realized_mask &= ~CGROUP_MASK_CPU; - unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul); + + if (shares == CGROUP_CPU_SHARES_INVALID) + unit_write_drop_in_private(u, mode, name, "CPUShares="); + else + unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares); } return 1; } else if (streq(name, "StartupCPUShares")) { - uint64_t u64; - unsigned long ul; + uint64_t shares; - r = sd_bus_message_read(message, "t", &u64); + r = sd_bus_message_read(message, "t", &shares); if (r < 0) return r; - if (u64 == (uint64_t) -1) - ul = (unsigned long) -1; - else { - ul = (unsigned long) u64; - if (ul <= 0 || (uint64_t) ul != u64) - return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range"); - } + if (!CGROUP_CPU_SHARES_IS_OK(shares)) + return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range"); if (mode != UNIT_CHECK) { - c->startup_cpu_shares = ul; + c->startup_cpu_shares = shares; u->cgroup_realized_mask &= ~CGROUP_MASK_CPU; - unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul); + + if (shares == CGROUP_CPU_SHARES_INVALID) + unit_write_drop_in_private(u, mode, name, "StartupCPUShares="); + else + unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares); } return 1; @@ -318,49 +296,45 @@ int bus_cgroup_set_property( return 1; } else if (streq(name, "BlockIOWeight")) { - uint64_t u64; - unsigned long ul; + uint64_t weight; - r = sd_bus_message_read(message, "t", &u64); + r = sd_bus_message_read(message, "t", &weight); if (r < 0) return r; - if (u64 == (uint64_t) -1) - ul = (unsigned long) -1; - else { - ul = (unsigned long) u64; - if (ul < 10 || ul > 1000) - return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range"); - } + if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight)) + return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range"); if (mode != UNIT_CHECK) { - c->blockio_weight = ul; + c->blockio_weight = weight; u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; - unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul); + + if (weight == CGROUP_BLKIO_WEIGHT_INVALID) + unit_write_drop_in_private(u, mode, name, "BlockIOWeight="); + else + unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight); } return 1; } else if (streq(name, "StartupBlockIOWeight")) { - uint64_t u64; - unsigned long ul; + uint64_t weight; - r = sd_bus_message_read(message, "t", &u64); + r = sd_bus_message_read(message, "t", &weight); if (r < 0) return r; - if (u64 == (uint64_t) -1) - ul = (unsigned long) -1; - else { - ul = (unsigned long) u64; - if (ul < 10 || ul > 1000) - return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range"); - } + if (CGROUP_BLKIO_WEIGHT_IS_OK(weight)) + return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range"); if (mode != UNIT_CHECK) { - c->startup_blockio_weight = ul; + c->startup_blockio_weight = weight; u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; - unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul); + + if (weight == CGROUP_BLKIO_WEIGHT_INVALID) + unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight="); + else + unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight); } return 1; @@ -455,17 +429,16 @@ int bus_cgroup_set_property( } else if (streq(name, "BlockIODeviceWeight")) { const char *path; - uint64_t u64; + uint64_t weight; unsigned n = 0; r = sd_bus_message_enter_container(message, 'a', "(st)"); if (r < 0) return r; - while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { - unsigned long ul = u64; + while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) { - if (ul < 10 || ul > 1000) + if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID) return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range"); if (mode != UNIT_CHECK) { @@ -491,7 +464,7 @@ int bus_cgroup_set_property( LIST_PREPEND(device_weights,c->blockio_device_weights, a); } - a->weight = ul; + a->weight = weight; } n++; @@ -520,7 +493,7 @@ int bus_cgroup_set_property( fputs("BlockIODeviceWeight=\n", f); LIST_FOREACH(device_weights, a, c->blockio_device_weights) - fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight); + fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight); fflush(f); unit_write_drop_in_private(u, mode, name, buf); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index f7a8539910..b476d472b3 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2605,26 +2605,19 @@ int config_parse_cpu_shares( void *data, void *userdata) { - unsigned long *shares = data, lu; + uint64_t *shares = data; int r; assert(filename); assert(lvalue); assert(rvalue); - if (isempty(rvalue)) { - *shares = (unsigned long) -1; - return 0; - } - - r = safe_atolu(rvalue, &lu); - if (r < 0 || lu <= 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "CPU shares '%s' invalid. Ignoring.", rvalue); + r = cg_cpu_shares_parse(rvalue, shares); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue); return 0; } - *shares = lu; return 0; } @@ -2805,26 +2798,19 @@ int config_parse_blockio_weight( void *data, void *userdata) { - unsigned long *weight = data, lu; + uint64_t *weight = data; int r; assert(filename); assert(lvalue); assert(rvalue); - if (isempty(rvalue)) { - *weight = (unsigned long) -1; - return 0; - } - - r = safe_atolu(rvalue, &lu); - if (r < 0 || lu < 10 || lu > 1000) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Block IO weight '%s' invalid. Ignoring.", rvalue); + r = cg_blkio_weight_parse(rvalue, weight); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue); return 0; } - *weight = lu; return 0; } @@ -2843,8 +2829,8 @@ int config_parse_blockio_device_weight( _cleanup_free_ char *path = NULL; CGroupBlockIODeviceWeight *w; CGroupContext *c = data; - unsigned long lu; const char *weight; + uint64_t u; size_t n; int r; @@ -2861,9 +2847,10 @@ int config_parse_blockio_device_weight( n = strcspn(rvalue, WHITESPACE); weight = rvalue + n; - if (!*weight) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Expected block device and device weight. Ignoring."); + weight += strspn(weight, WHITESPACE); + + if (isempty(weight)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring."); return 0; } @@ -2872,19 +2859,18 @@ int config_parse_blockio_device_weight( return log_oom(); if (!path_startswith(path, "/dev")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid device node path '%s'. Ignoring.", path); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path); return 0; } - weight += strspn(weight, WHITESPACE); - r = safe_atolu(weight, &lu); - if (r < 0 || lu < 10 || lu > 1000) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Block IO weight '%s' invalid. Ignoring.", rvalue); + r = cg_blkio_weight_parse(weight, &u); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight); return 0; } + assert(u != CGROUP_BLKIO_WEIGHT_INVALID); + w = new0(CGroupBlockIODeviceWeight, 1); if (!w) return log_oom(); @@ -2892,7 +2878,7 @@ int config_parse_blockio_device_weight( w->path = path; path = NULL; - w->weight = lu; + w->weight = u; LIST_PREPEND(device_weights, c->blockio_device_weights, w); return 0; diff --git a/src/core/unit.c b/src/core/unit.c index 2ebfb09a7a..f12d1c95cb 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1177,8 +1177,8 @@ static int unit_add_startup_units(Unit *u) { if (!c) return 0; - if (c->startup_cpu_shares == (unsigned long) -1 && - c->startup_blockio_weight == (unsigned long) -1) + if (c->startup_cpu_shares == CGROUP_CPU_SHARES_INVALID && + c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID) return 0; return set_put(u->manager->startup_units, u); diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 4dc4ca581d..a2c5d8acca 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -23,22 +23,24 @@ #include "sd-daemon.h" #include "sd-event.h" -#include "util.h" -#include "strv.h" -#include "macro.h" +#include "sd-bus.h" + +#include "bus-error.h" +#include "bus-internal.h" +#include "bus-label.h" +#include "bus-message.h" +#include "cgroup-util.h" #include "def.h" -#include "path-util.h" +#include "macro.h" #include "missing.h" +#include "path-util.h" #include "set.h" #include "signal-util.h" +#include "strv.h" #include "unit-name.h" +#include "util.h" -#include "sd-bus.h" -#include "bus-error.h" -#include "bus-label.h" -#include "bus-message.h" #include "bus-util.h" -#include "bus-internal.h" static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { sd_event *e = userdata; @@ -1463,10 +1465,21 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "t", n); - } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) { + } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) { + uint64_t u; + + r = cg_cpu_shares_parse(eq, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", u); + + } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) { uint64_t u; - r = safe_atou64(eq, &u); + r = cg_cpu_shares_parse(eq, &u); if (r < 0) { log_error("Failed to parse %s value %s.", field, eq); return -EINVAL; -- cgit v1.2.3-54-g00ecf From aa36007ca18ece54495d108332ed21b4bf918f3b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2015 16:49:12 +0200 Subject: timesyncd: fix how we print a PID --- src/timesync/timesyncd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 7b4178c993..3cb7d435cd 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -131,7 +131,7 @@ int main(int argc, char *argv[]) { if (r < 0) log_warning_errno(r, "Failed to parse configuration file: %m"); - log_debug("systemd-timesyncd running as pid %lu", (unsigned long) getpid()); + log_debug("systemd-timesyncd running as pid " PID_FMT, getpid()); sd_notify(false, "READY=1\n" "STATUS=Daemon is running"); -- cgit v1.2.3-54-g00ecf From 5269eb6b32f662d21638e54bb13171a5b97fe58f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2015 17:25:35 +0200 Subject: core: allocate sets of startup and failed units on-demand There's a good chance we never needs these sets, hence allocate them only when needed. --- src/core/manager.c | 21 ++++++++++----------- src/core/manager.h | 2 +- src/core/unit.c | 9 +++++++-- 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index d918007bb8..8fa2e5079e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -602,14 +602,6 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) { if (r < 0) goto fail; - r = set_ensure_allocated(&m->startup_units, NULL); - if (r < 0) - goto fail; - - r = set_ensure_allocated(&m->failed_units, NULL); - if (r < 0) - goto fail; - r = sd_event_default(&m->event); if (r < 0) goto fail; @@ -3069,8 +3061,9 @@ const char *manager_get_runtime_prefix(Manager *m) { getenv("XDG_RUNTIME_DIR"); } -void manager_update_failed_units(Manager *m, Unit *u, bool failed) { +int manager_update_failed_units(Manager *m, Unit *u, bool failed) { unsigned size; + int r; assert(m); assert(u->manager == m); @@ -3078,13 +3071,19 @@ void manager_update_failed_units(Manager *m, Unit *u, bool failed) { size = set_size(m->failed_units); if (failed) { + r = set_ensure_allocated(&m->failed_units, NULL); + if (r < 0) + return log_oom(); + if (set_put(m->failed_units, u) < 0) - log_oom(); + return log_oom(); } else - set_remove(m->failed_units, u); + (void) set_remove(m->failed_units, u); if (set_size(m->failed_units) != size) bus_manager_send_change_signal(m); + + return 0; } ManagerState manager_state(Manager *m) { diff --git a/src/core/manager.h b/src/core/manager.h index 78a0e50a33..5cf0dbd508 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -369,7 +369,7 @@ const char *manager_get_runtime_prefix(Manager *m); ManagerState manager_state(Manager *m); -void manager_update_failed_units(Manager *m, Unit *u, bool failed); +int manager_update_failed_units(Manager *m, Unit *u, bool failed); const char *manager_state_to_string(ManagerState m) _const_; ManagerState manager_state_from_string(const char *s) _pure_; diff --git a/src/core/unit.c b/src/core/unit.c index f12d1c95cb..3bfc2460bc 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -528,7 +528,7 @@ void unit_free(Unit *u) { unit_release_cgroup(u); - manager_update_failed_units(u->manager, u, false); + (void) manager_update_failed_units(u->manager, u, false); set_remove(u->manager->startup_units, u); free(u->description); @@ -1172,6 +1172,7 @@ static int unit_add_mount_dependencies(Unit *u) { static int unit_add_startup_units(Unit *u) { CGroupContext *c; + int r; c = unit_get_cgroup_context(u); if (!c) @@ -1181,6 +1182,10 @@ static int unit_add_startup_units(Unit *u) { c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID) return 0; + r = set_ensure_allocated(&u->manager->startup_units, NULL); + if (r < 0) + return r; + return set_put(u->manager->startup_units, u); } @@ -1807,7 +1812,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su } /* Keep track of failed units */ - manager_update_failed_units(u->manager, u, ns == UNIT_FAILED); + (void) manager_update_failed_units(u->manager, u, ns == UNIT_FAILED); /* Make sure the cgroup is always removed when we become inactive */ if (UNIT_IS_INACTIVE_OR_FAILED(ns)) -- cgit v1.2.3-54-g00ecf From 54eb2300ae07d28922a18a9d14dc597850535e9c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2015 18:14:11 +0200 Subject: execute: invalidate idle pipe after use Not strictly necessary, but makes clear the fds are invalidated. Make sure we do the same here as in most other cases. --- src/core/execute.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index d1acda6682..8773d9cdfb 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1160,8 +1160,8 @@ static void do_idle_pipe_dance(int idle_pipe[4]) { assert(idle_pipe); - safe_close(idle_pipe[1]); - safe_close(idle_pipe[2]); + idle_pipe[1] = safe_close(idle_pipe[1]); + idle_pipe[2] = safe_close(idle_pipe[2]); if (idle_pipe[0] >= 0) { int r; @@ -1176,11 +1176,11 @@ static void do_idle_pipe_dance(int idle_pipe[4]) { fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC); } - safe_close(idle_pipe[0]); + idle_pipe[0] = safe_close(idle_pipe[0]); } - safe_close(idle_pipe[3]); + idle_pipe[3] = safe_close(idle_pipe[3]); } static int build_environment( -- cgit v1.2.3-54-g00ecf From c7cc737fce8e5ba8438c1613756b48a0c2ecbb0f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2015 18:15:08 +0200 Subject: execute: fix return type from write() --- src/core/execute.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 8773d9cdfb..3c308e3e3e 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1169,9 +1169,11 @@ static void do_idle_pipe_dance(int idle_pipe[4]) { r = fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC); if (idle_pipe[3] >= 0 && r == 0 /* timeout */) { + ssize_t n; + /* Signal systemd that we are bored and want to continue. */ - r = write(idle_pipe[3], "x", 1); - if (r > 0) + n = write(idle_pipe[3], "x", 1); + if (n > 0) /* Wait for systemd to react to the signal above. */ fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC); } -- cgit v1.2.3-54-g00ecf From cd72bd8a4650c9e78a04cb7df1cbce697e14e512 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2015 18:15:58 +0200 Subject: core: invalidate idle pipe event source in manager_close_idle_pipe() In all occasions when this function is called we do so anyway, so let's move this inside, to make things easier. --- src/core/manager.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 8fa2e5079e..3b64d524da 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -317,6 +317,8 @@ static int manager_watch_idle_pipe(Manager *m) { static void manager_close_idle_pipe(Manager *m) { assert(m); + m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source); + safe_close_pair(m->idle_pipe); safe_close_pair(m->idle_pipe + 2); } @@ -936,7 +938,6 @@ Manager* manager_free(Manager *m) { sd_event_source_unref(m->notify_event_source); sd_event_source_unref(m->time_change_event_source); sd_event_source_unref(m->jobs_in_progress_event_source); - sd_event_source_unref(m->idle_pipe_event_source); sd_event_source_unref(m->run_queue_event_source); safe_close(m->signal_fd); @@ -1954,7 +1955,6 @@ static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32 m->no_console_output = m->n_on_console > 0; - m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source); manager_close_idle_pipe(m); return 0; @@ -2694,7 +2694,6 @@ void manager_check_finished(Manager *m) { manager_flip_auto_status(m, false); /* Notify Type=idle units that we are done now */ - m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source); manager_close_idle_pipe(m); /* Turn off confirm spawn now */ -- cgit v1.2.3-54-g00ecf From 1afaa7e8d29c0fd70a621d96a59487ab54b157fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2015 18:18:01 +0200 Subject: transaction: clarify via void-casting that we ignore the pipe2() return value for a reason --- src/core/transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/transaction.c b/src/core/transaction.c index b8f69ec6f3..2d120af4b5 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -736,8 +736,8 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 && m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) { - pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC); - pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC); + (void) pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC); + (void) pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC); } } -- cgit v1.2.3-54-g00ecf From e7ab4d1ac9f8d99eecd5e2d22eb482a1fb0fbf23 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2015 18:21:53 +0200 Subject: cgroup: unify how we invalidate cgroup controller settings Let's make sure that we follow the same codepaths when adjusting a cgroup property via the dbus SetProperty() call, and when we execute the StartupCPUShares= effect. --- src/core/cgroup.c | 26 ++++++++++++++++++++++++++ src/core/cgroup.h | 4 ++++ src/core/dbus-cgroup.c | 30 +++++++++++++++--------------- src/core/manager.c | 11 ++--------- 4 files changed, 47 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 4999a1e116..7d2a2ba67a 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1581,6 +1581,32 @@ bool unit_cgroup_delegate(Unit *u) { return c->delegate; } +void unit_invalidate_cgroup(Unit *u, CGroupMask m) { + assert(u); + + if (!UNIT_HAS_CGROUP_CONTEXT(u)) + return; + + if (m == 0) + return; + + if ((u->cgroup_realized_mask & m) == 0) + return; + + u->cgroup_realized_mask &= ~m; + unit_add_to_cgroup_queue(u); +} + +void manager_invalidate_startup_units(Manager *m) { + Iterator i; + Unit *u; + + assert(m); + + SET_FOREACH(u, m->startup_units, i) + unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_BLKIO); +} + static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = { [CGROUP_AUTO] = "auto", [CGROUP_CLOSED] = "closed", diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 3d455d93ed..e897b31451 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -149,5 +149,9 @@ bool unit_cgroup_delegate(Unit *u); int unit_notify_cgroup_empty(Unit *u); int manager_notify_cgroup_empty(Manager *m, const char *group); +void unit_invalidate_cgroup(Unit *u, CGroupMask m); + +void manager_invalidate_startup_units(Manager *m); + const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_; CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_; diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 78841ba656..f334dc928d 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -212,7 +212,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->cpu_accounting = b; - u->cgroup_realized_mask &= ~CGROUP_MASK_CPUACCT; + unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU); unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no"); } @@ -230,7 +230,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->cpu_shares = shares; - u->cgroup_realized_mask &= ~CGROUP_MASK_CPU; + unit_invalidate_cgroup(u, CGROUP_MASK_CPU); if (shares == CGROUP_CPU_SHARES_INVALID) unit_write_drop_in_private(u, mode, name, "CPUShares="); @@ -252,7 +252,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->startup_cpu_shares = shares; - u->cgroup_realized_mask &= ~CGROUP_MASK_CPU; + unit_invalidate_cgroup(u, CGROUP_MASK_CPU); if (shares == CGROUP_CPU_SHARES_INVALID) unit_write_drop_in_private(u, mode, name, "StartupCPUShares="); @@ -274,7 +274,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->cpu_quota_per_sec_usec = u64; - u->cgroup_realized_mask &= ~CGROUP_MASK_CPU; + unit_invalidate_cgroup(u, CGROUP_MASK_CPU); unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000)); } @@ -289,7 +289,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->blockio_accounting = b; - u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; + unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no"); } @@ -307,7 +307,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->blockio_weight = weight; - u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; + unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); if (weight == CGROUP_BLKIO_WEIGHT_INVALID) unit_write_drop_in_private(u, mode, name, "BlockIOWeight="); @@ -329,7 +329,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->startup_blockio_weight = weight; - u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; + unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); if (weight == CGROUP_BLKIO_WEIGHT_INVALID) unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight="); @@ -403,7 +403,7 @@ int bus_cgroup_set_property( cgroup_context_free_blockio_device_bandwidth(c, a); } - u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; + unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); f = open_memstream(&buf, &size); if (!f) @@ -485,7 +485,7 @@ int bus_cgroup_set_property( cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights); } - u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO; + unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); f = open_memstream(&buf, &size); if (!f) @@ -510,7 +510,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->memory_accounting = b; - u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY; + unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no"); } @@ -525,7 +525,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->memory_limit = limit; - u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY; + unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); if (limit == (uint64_t) -1) unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity"); @@ -551,7 +551,7 @@ int bus_cgroup_set_property( char *buf; c->device_policy = p; - u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICES; + unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES); buf = strjoina("DevicePolicy=", policy); unit_write_drop_in_private(u, mode, name, buf); @@ -630,7 +630,7 @@ int bus_cgroup_set_property( cgroup_context_free_device_allow(c, c->device_allow); } - u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICES; + unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES); f = open_memstream(&buf, &size); if (!f) @@ -655,7 +655,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->tasks_accounting = b; - u->cgroup_realized_mask &= ~CGROUP_MASK_PIDS; + unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no"); } @@ -670,7 +670,7 @@ int bus_cgroup_set_property( if (mode != UNIT_CHECK) { c->tasks_max = limit; - u->cgroup_realized_mask &= ~CGROUP_MASK_PIDS; + unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); if (limit == (uint64_t) -1) unit_write_drop_in_private(u, mode, name, "TasksMax=infinity"); diff --git a/src/core/manager.c b/src/core/manager.c index 3b64d524da..8e518fbaaf 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2667,9 +2667,6 @@ static void manager_notify_finished(Manager *m) { } void manager_check_finished(Manager *m) { - Unit *u = NULL; - Iterator i; - assert(m); if (m->n_reloading > 0) @@ -2682,11 +2679,9 @@ void manager_check_finished(Manager *m) { return; if (hashmap_size(m->jobs) > 0) { - if (m->jobs_in_progress_event_source) /* Ignore any failure, this is only for feedback */ - (void) sd_event_source_set_time(m->jobs_in_progress_event_source, - now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC); + (void) sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC); return; } @@ -2712,9 +2707,7 @@ void manager_check_finished(Manager *m) { manager_notify_finished(m); - SET_FOREACH(u, m->startup_units, i) - if (u->cgroup_path) - cgroup_context_apply(unit_get_cgroup_context(u), unit_get_own_mask(u), u->cgroup_path, manager_state(m)); + manager_invalidate_startup_units(m); } static int create_generator_dir(Manager *m, char **generator, const char *name) { -- cgit v1.2.3-54-g00ecf