[systemd-commits] 5 commits - Makefile.am TODO src/core src/import src/machine src/shared src/systemctl

Lennart Poettering lennart at kemper.freedesktop.org
Mon Mar 2 03:15:34 PST 2015


 Makefile.am               |    2 
 TODO                      |    2 
 src/core/cgroup.c         |   98 ++++++++++++++-
 src/core/cgroup.h         |    4 
 src/core/dbus-unit.c      |   42 ++++--
 src/core/mount.c          |    7 -
 src/core/mount.h          |    2 
 src/core/scope.c          |    3 
 src/core/service.c        |    7 -
 src/core/service.h        |    2 
 src/core/slice.c          |    3 
 src/core/socket.c         |    8 +
 src/core/socket.h         |    2 
 src/core/swap.c           |    8 +
 src/core/swap.h           |    2 
 src/core/unit.c           |   10 +
 src/core/unit.h           |    3 
 src/import/importd.c      |  263 -----------------------------------------
 src/machine/machinectl.c  |    2 
 src/shared/machine-pool.c |  295 ++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/machine-pool.h |   26 ++++
 src/systemctl/systemctl.c |    9 +
 22 files changed, 509 insertions(+), 291 deletions(-)

New commits:
commit 4d1d2f0858bb2fa6c45f0a7b3d427e657c0d4f67
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Mar 2 12:15:11 2015 +0100

    update TODO

diff --git a/TODO b/TODO
index e8e4800..74a0602 100644
--- a/TODO
+++ b/TODO
@@ -34,6 +34,8 @@ External:
 
 Features:
 
+* gpg2 compat
+
 * When logging about multiple units (stopping BoundTo units, conflicts, etc.),
   log both units as UNIT=, so that journalctl -u triggers on both.
 

commit 172a6ce5aea8575c61a466d5debf4f5b488085eb
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Mar 2 12:15:01 2015 +0100

    machinectl: update --help text to clarify that set-limit can also change pool size

diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index d25b526..49e28ee 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -2063,7 +2063,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  rename NAME NAME            Rename an image\n"
                "  read-only NAME [BOOL]       Mark or unmark image read-only\n"
                "  remove NAME...              Remove an image\n"
-               "  set-limit [NAME] BYTES      Set image size limit (quota)\n\n"
+               "  set-limit [NAME] BYTES      Set image or pool size limit (quota)\n\n"
                "Image Transfer Commands:\n"
                "  pull-tar URL [NAME]         Download a TAR container image\n"
                "  pull-raw URL [NAME]         Download a RAW container or VM image\n"

commit 403e5b32301cab098151814acbd08821475c00c3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Mar 1 16:46:50 2015 +0100

    importd: take a lock while we set up /var/lib/machines/
    
    This way, we can safely set up the directories from two processes at the
    same time, including machined and importd simultaneously.

diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c
index add19bb..7b17395 100644
--- a/src/shared/machine-pool.c
+++ b/src/shared/machine-pool.c
@@ -161,6 +161,7 @@ fail:
 }
 
 int setup_machine_directory(sd_bus_error *error) {
+        _cleanup_release_lock_file_ LockFile lock_file = LOCK_FILE_INIT;
         struct loop_info64 info = {
                 .lo_flags = LO_FLAGS_AUTOCLEAR,
         };
@@ -170,6 +171,11 @@ int setup_machine_directory(sd_bus_error *error) {
         bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
         int r, nr = -1;
 
+        /* Make sure we only set the directory up once at a time */
+        r = make_lock_file("/run/systemd/machines.lock", LOCK_EX, &lock_file);
+        if (r < 0)
+                return r;
+
         r = check_btrfs();
         if (r < 0)
                 return sd_bus_error_set_errnof(error, r, "Failed to determine whether /var/lib/machines is located on btrfs: %m");

commit 432cea008720480f6eaae7e75e6ad255e91fe2b4
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Mar 1 16:39:31 2015 +0100

    importd: split out setup logic for /var/lib/machines into its own API file

diff --git a/Makefile.am b/Makefile.am
index ee5401d..9d41a2c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -977,6 +977,8 @@ libsystemd_label_la_SOURCES = \
 	src/shared/btrfs-ctree.h \
 	src/shared/machine-image.c \
 	src/shared/machine-image.h \
+	src/shared/machine-pool.c \
+	src/shared/machine-pool.h \
 	src/shared/copy.c \
 	src/shared/copy.h
 
diff --git a/src/import/importd.c b/src/import/importd.c
index f315212..a6447e1 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -20,9 +20,6 @@
 ***/
 
 #include <sys/prctl.h>
-#include <sys/vfs.h>
-#include <sys/statvfs.h>
-#include <sys/mount.h>
 
 #include "sd-bus.h"
 #include "util.h"
@@ -34,13 +31,10 @@
 #include "mkdir.h"
 #include "def.h"
 #include "missing.h"
-#include "btrfs-util.h"
+#include "machine-pool.h"
 #include "path-util.h"
 #include "import-util.h"
 
-#define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL)
-#define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL)
-
 typedef struct Transfer Transfer;
 typedef struct Manager Manager;
 
@@ -650,261 +644,6 @@ static Transfer *manager_find(Manager *m, TransferType type, const char *dkr_ind
         return NULL;
 }
 
-static int check_btrfs(void) {
-        struct statfs sfs;
-
-        if (statfs("/var/lib/machines", &sfs) < 0) {
-                if (errno != ENOENT)
-                        return -errno;
-
-                if (statfs("/var/lib", &sfs) < 0)
-                        return -errno;
-        }
-
-        return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
-}
-
-static int setup_machine_raw(sd_bus_error *error) {
-        _cleanup_free_ char *tmp = NULL;
-        _cleanup_close_ int fd = -1;
-        struct statvfs ss;
-        pid_t pid = 0;
-        siginfo_t si;
-        int r;
-
-        /* We want to be able to make use of btrfs-specific file
-         * system features, in particular subvolumes, reflinks and
-         * quota. Hence, if we detect that /var/lib/machines.raw is
-         * not located on btrfs, let's create a loopback file, place a
-         * btrfs file system into it, and mount it to
-         * /var/lib/machines. */
-
-        fd = open("/var/lib/machines.raw", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
-        if (fd >= 0) {
-                r = fd;
-                fd = -1;
-                return r;
-        }
-
-        if (errno != ENOENT)
-                return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m");
-
-        r = tempfn_xxxxxx("/var/lib/machines.raw", &tmp);
-        if (r < 0)
-                return r;
-
-        (void) mkdir_p_label("/var/lib", 0755);
-        fd = open(tmp, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600);
-        if (fd < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to create /var/lib/machines.raw: %m");
-
-        if (fstatvfs(fd, &ss) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to determine free space on /var/lib/machines.raw: %m");
-                goto fail;
-        }
-
-        if (ss.f_bsize * ss.f_bavail < VAR_LIB_MACHINES_FREE_MIN) {
-                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Not enough free disk space to set up /var/lib/machines.");
-                goto fail;
-        }
-
-        if (ftruncate(fd, VAR_LIB_MACHINES_SIZE_START) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m");
-                goto fail;
-        }
-
-        pid = fork();
-        if (pid < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to fork mkfs.btrfs: %m");
-                goto fail;
-        }
-
-        if (pid == 0) {
-
-                /* Child */
-
-                reset_all_signal_handlers();
-                reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
-                fd = safe_close(fd);
-
-                execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
-                if (errno == ENOENT)
-                        return 99;
-
-                _exit(EXIT_FAILURE);
-        }
-
-        r = wait_for_terminate(pid, &si);
-        if (r < 0) {
-                sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m");
-                goto fail;
-        }
-
-        pid = 0;
-
-        if (si.si_code != CLD_EXITED) {
-                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs died abnormally.");
-                goto fail;
-        }
-        if (si.si_status == 99) {
-                r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
-                goto fail;
-        }
-        if (si.si_status != 0) {
-                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", si.si_status);
-                goto fail;
-        }
-
-        if (renameat2(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw", RENAME_NOREPLACE) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to move /var/lib/machines.raw into place: %m");
-                goto fail;
-        }
-
-        r = fd;
-        fd = -1;
-
-        return r;
-
-fail:
-        if (tmp)
-                unlink_noerrno(tmp);
-
-        if (pid > 1)
-                kill_and_sigcont(pid, SIGKILL);
-
-        return r;
-}
-
-static int setup_machine_directory(sd_bus_error *error) {
-        struct loop_info64 info = {
-                .lo_flags = LO_FLAGS_AUTOCLEAR,
-        };
-        _cleanup_close_ int fd = -1, control = -1, loop = -1;
-        _cleanup_free_ char* loopdev = NULL;
-        char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL;
-        bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
-        int r, nr = -1;
-
-        r = check_btrfs();
-        if (r < 0)
-                return sd_bus_error_set_errnof(error, r, "Failed to determine whether /var/lib/machines is located on btrfs: %m");
-        if (r > 0) {
-                (void) btrfs_subvol_make_label("/var/lib/machines");
-
-                r = btrfs_quota_enable("/var/lib/machines", true);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to enable quota, ignoring: %m");
-
-                return 0;
-        }
-
-        if (path_is_mount_point("/var/lib/machines", true) > 0 ||
-            dir_is_empty("/var/lib/machines") == 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems.");
-
-        fd = setup_machine_raw(error);
-        if (fd < 0)
-                return fd;
-
-        control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
-        if (control < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to open /dev/loop-control: %m");
-
-        nr = ioctl(control, LOOP_CTL_GET_FREE);
-        if (nr < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to allocate loop device: %m");
-
-        if (asprintf(&loopdev, "/dev/loop%i", nr) < 0) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        loop = open(loopdev, O_CLOEXEC|O_RDWR|O_NOCTTY|O_NONBLOCK);
-        if (loop < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to open loopback device: %m");
-                goto fail;
-        }
-
-        if (ioctl(loop, LOOP_SET_FD, fd) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to bind loopback device: %m");
-                goto fail;
-        }
-
-        if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to enable auto-clear for loopback device: %m");
-                goto fail;
-        }
-
-        /* We need to make sure the new /var/lib/machines directory
-         * has an access mode of 0700 at the time it is first made
-         * available. mkfs will create it with 0755 however. Hence,
-         * let's mount the directory into an inaccessible directory
-         * below /tmp first, fix the access mode, and move it to the
-         * public place then. */
-
-        if (!mkdtemp(tmpdir)) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount parent directory: %m");
-                goto fail;
-        }
-        tmpdir_made = true;
-
-        mntdir = strjoina(tmpdir, "/mnt");
-        if (mkdir(mntdir, 0700) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount directory: %m");
-                goto fail;
-        }
-        mntdir_made = true;
-
-        if (mount(loopdev, mntdir, "btrfs", 0, NULL) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to mount loopback device: %m");
-                goto fail;
-        }
-        mntdir_mounted = true;
-
-        r = btrfs_quota_enable(mntdir, true);
-        if (r < 0)
-                log_warning_errno(r, "Failed to enable quota, ignoring: %m");
-
-        if (chmod(mntdir, 0700) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
-                goto fail;
-        }
-
-        (void) mkdir_p_label("/var/lib/machines", 0700);
-
-        if (mount(mntdir, "/var/lib/machines", NULL, MS_BIND, NULL) < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to mount directory into right place: %m");
-                goto fail;
-        }
-
-        (void) umount2(mntdir, MNT_DETACH);
-        (void) rmdir(mntdir);
-        (void) rmdir(tmpdir);
-
-        return 0;
-
-fail:
-        if (mntdir_mounted)
-                (void) umount2(mntdir, MNT_DETACH);
-
-        if (mntdir_made)
-                (void) rmdir(mntdir);
-        if (tmpdir_made)
-                (void) rmdir(tmpdir);
-
-        if (loop >= 0) {
-                (void) ioctl(loop, LOOP_CLR_FD);
-                loop = safe_close(loop);
-        }
-
-        if (control >= 0 && nr >= 0)
-                (void) ioctl(control, LOOP_CTL_REMOVE, nr);
-
-        return r;
-}
-
 static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
         _cleanup_(transfer_unrefp) Transfer *t = NULL;
         const char *remote, *local, *verify, *object;
diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c
new file mode 100644
index 0000000..add19bb
--- /dev/null
+++ b/src/shared/machine-pool.c
@@ -0,0 +1,289 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2015 Lennart Poettering
+
+  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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/prctl.h>
+#include <sys/vfs.h>
+#include <sys/statvfs.h>
+#include <sys/mount.h>
+
+#include "util.h"
+#include "mkdir.h"
+#include "btrfs-util.h"
+#include "path-util.h"
+#include "machine-pool.h"
+
+#define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL)
+#define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL)
+
+static int check_btrfs(void) {
+        struct statfs sfs;
+
+        if (statfs("/var/lib/machines", &sfs) < 0) {
+                if (errno != ENOENT)
+                        return -errno;
+
+                if (statfs("/var/lib", &sfs) < 0)
+                        return -errno;
+        }
+
+        return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
+}
+
+static int setup_machine_raw(sd_bus_error *error) {
+        _cleanup_free_ char *tmp = NULL;
+        _cleanup_close_ int fd = -1;
+        struct statvfs ss;
+        pid_t pid = 0;
+        siginfo_t si;
+        int r;
+
+        /* We want to be able to make use of btrfs-specific file
+         * system features, in particular subvolumes, reflinks and
+         * quota. Hence, if we detect that /var/lib/machines.raw is
+         * not located on btrfs, let's create a loopback file, place a
+         * btrfs file system into it, and mount it to
+         * /var/lib/machines. */
+
+        fd = open("/var/lib/machines.raw", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+        if (fd >= 0) {
+                r = fd;
+                fd = -1;
+                return r;
+        }
+
+        if (errno != ENOENT)
+                return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m");
+
+        r = tempfn_xxxxxx("/var/lib/machines.raw", &tmp);
+        if (r < 0)
+                return r;
+
+        (void) mkdir_p_label("/var/lib", 0755);
+        fd = open(tmp, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600);
+        if (fd < 0)
+                return sd_bus_error_set_errnof(error, errno, "Failed to create /var/lib/machines.raw: %m");
+
+        if (fstatvfs(fd, &ss) < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to determine free space on /var/lib/machines.raw: %m");
+                goto fail;
+        }
+
+        if (ss.f_bsize * ss.f_bavail < VAR_LIB_MACHINES_FREE_MIN) {
+                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Not enough free disk space to set up /var/lib/machines.");
+                goto fail;
+        }
+
+        if (ftruncate(fd, VAR_LIB_MACHINES_SIZE_START) < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m");
+                goto fail;
+        }
+
+        pid = fork();
+        if (pid < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to fork mkfs.btrfs: %m");
+                goto fail;
+        }
+
+        if (pid == 0) {
+
+                /* Child */
+
+                reset_all_signal_handlers();
+                reset_signal_mask();
+                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
+
+                fd = safe_close(fd);
+
+                execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
+                if (errno == ENOENT)
+                        return 99;
+
+                _exit(EXIT_FAILURE);
+        }
+
+        r = wait_for_terminate(pid, &si);
+        if (r < 0) {
+                sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m");
+                goto fail;
+        }
+
+        pid = 0;
+
+        if (si.si_code != CLD_EXITED) {
+                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs died abnormally.");
+                goto fail;
+        }
+        if (si.si_status == 99) {
+                r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
+                goto fail;
+        }
+        if (si.si_status != 0) {
+                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", si.si_status);
+                goto fail;
+        }
+
+        if (renameat2(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw", RENAME_NOREPLACE) < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to move /var/lib/machines.raw into place: %m");
+                goto fail;
+        }
+
+        r = fd;
+        fd = -1;
+
+        return r;
+
+fail:
+        if (tmp)
+                unlink_noerrno(tmp);
+
+        if (pid > 1)
+                kill_and_sigcont(pid, SIGKILL);
+
+        return r;
+}
+
+int setup_machine_directory(sd_bus_error *error) {
+        struct loop_info64 info = {
+                .lo_flags = LO_FLAGS_AUTOCLEAR,
+        };
+        _cleanup_close_ int fd = -1, control = -1, loop = -1;
+        _cleanup_free_ char* loopdev = NULL;
+        char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL;
+        bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
+        int r, nr = -1;
+
+        r = check_btrfs();
+        if (r < 0)
+                return sd_bus_error_set_errnof(error, r, "Failed to determine whether /var/lib/machines is located on btrfs: %m");
+        if (r > 0) {
+                (void) btrfs_subvol_make_label("/var/lib/machines");
+
+                r = btrfs_quota_enable("/var/lib/machines", true);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to enable quota, ignoring: %m");
+
+                return 0;
+        }
+
+        if (path_is_mount_point("/var/lib/machines", true) > 0 ||
+            dir_is_empty("/var/lib/machines") == 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems.");
+
+        fd = setup_machine_raw(error);
+        if (fd < 0)
+                return fd;
+
+        control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+        if (control < 0)
+                return sd_bus_error_set_errnof(error, errno, "Failed to open /dev/loop-control: %m");
+
+        nr = ioctl(control, LOOP_CTL_GET_FREE);
+        if (nr < 0)
+                return sd_bus_error_set_errnof(error, errno, "Failed to allocate loop device: %m");
+
+        if (asprintf(&loopdev, "/dev/loop%i", nr) < 0) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        loop = open(loopdev, O_CLOEXEC|O_RDWR|O_NOCTTY|O_NONBLOCK);
+        if (loop < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to open loopback device: %m");
+                goto fail;
+        }
+
+        if (ioctl(loop, LOOP_SET_FD, fd) < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to bind loopback device: %m");
+                goto fail;
+        }
+
+        if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to enable auto-clear for loopback device: %m");
+                goto fail;
+        }
+
+        /* We need to make sure the new /var/lib/machines directory
+         * has an access mode of 0700 at the time it is first made
+         * available. mkfs will create it with 0755 however. Hence,
+         * let's mount the directory into an inaccessible directory
+         * below /tmp first, fix the access mode, and move it to the
+         * public place then. */
+
+        if (!mkdtemp(tmpdir)) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount parent directory: %m");
+                goto fail;
+        }
+        tmpdir_made = true;
+
+        mntdir = strjoina(tmpdir, "/mnt");
+        if (mkdir(mntdir, 0700) < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount directory: %m");
+                goto fail;
+        }
+        mntdir_made = true;
+
+        if (mount(loopdev, mntdir, "btrfs", 0, NULL) < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to mount loopback device: %m");
+                goto fail;
+        }
+        mntdir_mounted = true;
+
+        r = btrfs_quota_enable(mntdir, true);
+        if (r < 0)
+                log_warning_errno(r, "Failed to enable quota, ignoring: %m");
+
+        if (chmod(mntdir, 0700) < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
+                goto fail;
+        }
+
+        (void) mkdir_p_label("/var/lib/machines", 0700);
+
+        if (mount(mntdir, "/var/lib/machines", NULL, MS_BIND, NULL) < 0) {
+                r = sd_bus_error_set_errnof(error, errno, "Failed to mount directory into right place: %m");
+                goto fail;
+        }
+
+        (void) umount2(mntdir, MNT_DETACH);
+        (void) rmdir(mntdir);
+        (void) rmdir(tmpdir);
+
+        return 0;
+
+fail:
+        if (mntdir_mounted)
+                (void) umount2(mntdir, MNT_DETACH);
+
+        if (mntdir_made)
+                (void) rmdir(mntdir);
+        if (tmpdir_made)
+                (void) rmdir(tmpdir);
+
+        if (loop >= 0) {
+                (void) ioctl(loop, LOOP_CLR_FD);
+                loop = safe_close(loop);
+        }
+
+        if (control >= 0 && nr >= 0)
+                (void) ioctl(control, LOOP_CTL_REMOVE, nr);
+
+        return r;
+}
diff --git a/src/shared/machine-pool.h b/src/shared/machine-pool.h
new file mode 100644
index 0000000..5f7bc28
--- /dev/null
+++ b/src/shared/machine-pool.h
@@ -0,0 +1,26 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2015 Lennart Poettering
+
+  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 <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+
+int setup_machine_directory(sd_bus_error *error);

commit 5ad096b3f1331b175340129a8c9a5a9d711e5415
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Mar 1 16:24:19 2015 +0100

    core: expose consumed CPU time per unit
    
    This adds support for showing the accumulated consumed CPU time per-unit
    in the "systemctl status" output. The property is also readable via the
    bus.

diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 10fdcc9..6b8abb4 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -1029,16 +1029,100 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
         assert(cgroup);
 
         u = manager_get_unit_by_cgroup(m, cgroup);
-        if (u) {
-                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
-                if (r > 0) {
-                        if (UNIT_VTABLE(u)->notify_cgroup_empty)
-                                UNIT_VTABLE(u)->notify_cgroup_empty(u);
+        if (!u)
+                return 0;
 
-                        unit_add_to_gc_queue(u);
-                }
+        r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
+        if (r <= 0)
+                return r;
+
+        if (UNIT_VTABLE(u)->notify_cgroup_empty)
+                UNIT_VTABLE(u)->notify_cgroup_empty(u);
+
+        unit_add_to_gc_queue(u);
+        return 0;
+}
+
+int unit_get_memory_current(Unit *u, uint64_t *ret) {
+        _cleanup_free_ char *v = NULL;
+        int r;
+
+        assert(u);
+        assert(ret);
+
+        if (!u->cgroup_path)
+                return -ENODATA;
+
+        if ((u->cgroup_realized_mask & CGROUP_MEMORY) == 0)
+                return -ENODATA;
+
+        r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
+        if (r == -ENOENT)
+                return -ENODATA;
+        if (r < 0)
+                return r;
+
+        return safe_atou64(v, ret);
+}
+
+static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) {
+        _cleanup_free_ char *v = NULL;
+        uint64_t ns;
+        int r;
+
+        assert(u);
+        assert(ret);
+
+        if (!u->cgroup_path)
+                return -ENODATA;
+
+        if ((u->cgroup_realized_mask & CGROUP_CPUACCT) == 0)
+                return -ENODATA;
+
+        r = cg_get_attribute("cpuacct", u->cgroup_path, "cpuacct.usage", &v);
+        if (r == -ENOENT)
+                return -ENODATA;
+        if (r < 0)
+                return r;
+
+        r = safe_atou64(v, &ns);
+        if (r < 0)
+                return r;
+
+        *ret = ns;
+        return 0;
+}
+
+int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
+        nsec_t ns;
+        int r;
+
+        r = unit_get_cpu_usage_raw(u, &ns);
+        if (r < 0)
+                return r;
+
+        if (ns > u->cpuacct_usage_base)
+                ns -= u->cpuacct_usage_base;
+        else
+                ns = 0;
+
+        *ret = ns;
+        return 0;
+}
+
+int unit_reset_cpu_usage(Unit *u) {
+        nsec_t ns;
+        int r;
+
+        assert(u);
+
+        r = unit_get_cpu_usage_raw(u, &ns);
+        if (r < 0) {
+                u->cpuacct_usage_base = 0;
+                return r;
         }
 
+        u->cpuacct_usage_base = ns;
         return 0;
 }
 
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 993aa9d..869ddae 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -126,5 +126,9 @@ pid_t unit_search_main_pid(Unit *u);
 
 int manager_notify_cgroup_empty(Manager *m, const char *group);
 
+int unit_get_memory_current(Unit *u, uint64_t *ret);
+int unit_get_cpu_usage(Unit *u, nsec_t *ret);
+int unit_reset_cpu_usage(Unit *u);
+
 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-unit.c b/src/core/dbus-unit.c
index 0ff9a01..af7dc26 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -661,30 +661,43 @@ static int property_get_current_memory(
                 void *userdata,
                 sd_bus_error *error) {
 
-        Unit *u = userdata;
         uint64_t sz = (uint64_t) -1;
+        Unit *u = userdata;
         int r;
 
         assert(bus);
         assert(reply);
         assert(u);
 
-        if (u->cgroup_path &&
-            (u->cgroup_realized_mask & CGROUP_MEMORY)) {
-                _cleanup_free_ char *v = NULL;
+        r = unit_get_memory_current(u, &sz);
+        if (r < 0 && r != -ENODATA)
+                log_unit_warning_errno(u->id, r, "Failed to get memory.usage_in_bytes attribute: %m");
 
-                r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
-                if (r < 0 && r != -ENOENT)
-                        log_unit_warning_errno(u->id, r, "Couldn't read memory.usage_in_bytes attribute: %m");
+        return sd_bus_message_append(reply, "t", sz);
+}
 
-                if (v) {
-                        r = safe_atou64(v, &sz);
-                        if (r < 0)
-                                log_unit_warning_errno(u->id, r, "Failed to parse memory.usage_in_bytes attribute: %m");
-                }
-        }
+static int property_get_cpu_usage(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
 
-        return sd_bus_message_append(reply, "t", sz);
+        nsec_t ns = (nsec_t) -1;
+        Unit *u = userdata;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(u);
+
+        r = unit_get_cpu_usage(u, &ns);
+        if (r < 0 && r != -ENODATA)
+                log_unit_warning_errno(u->id, r, "Failed to get cpuacct.usage attribute: %m");
+
+        return sd_bus_message_append(reply, "t", ns);
 }
 
 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
@@ -692,6 +705,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
         SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
         SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
         SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
+        SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
         SD_BUS_VTABLE_END
 };
 
diff --git a/src/core/mount.c b/src/core/mount.c
index 8e4a376..5ee679d 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -706,7 +706,11 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
         assert(c);
         assert(_pid);
 
-        unit_realize_cgroup(UNIT(m));
+        (void) unit_realize_cgroup(UNIT(m));
+        if (m->reset_cpu_usage) {
+                (void) unit_reset_cpu_usage(UNIT(m));
+                m->reset_cpu_usage = false;
+        }
 
         r = unit_setup_exec_runtime(UNIT(m));
         if (r < 0)
@@ -1030,6 +1034,7 @@ static int mount_start(Unit *u) {
 
         m->result = MOUNT_SUCCESS;
         m->reload_result = MOUNT_SUCCESS;
+        m->reset_cpu_usage = true;
 
         mount_enter_mounting(m);
         return 1;
diff --git a/src/core/mount.h b/src/core/mount.h
index 76771ab..072b0e0 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -86,6 +86,8 @@ struct Mount {
         bool just_mounted:1;
         bool just_changed:1;
 
+        bool reset_cpu_usage:1;
+
         bool sloppy_options;
 
         MountResult result;
diff --git a/src/core/scope.c b/src/core/scope.c
index a0e4732..1c3c6bb 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -286,6 +286,9 @@ static int scope_start(Unit *u) {
         if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
                 return -ENOENT;
 
+        (void) unit_realize_cgroup(u);
+        (void) unit_reset_cpu_usage(u);
+
         r = unit_attach_pids_to_cgroup(u);
         if (r < 0)
                 return r;
diff --git a/src/core/service.c b/src/core/service.c
index c7b3505..a89ff3f 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1057,7 +1057,11 @@ static int service_spawn(
         assert(c);
         assert(_pid);
 
-        unit_realize_cgroup(UNIT(s));
+        (void) unit_realize_cgroup(UNIT(s));
+        if (s->reset_cpu_usage) {
+                (void) unit_reset_cpu_usage(UNIT(s));
+                s->reset_cpu_usage = false;
+        }
 
         r = unit_setup_exec_runtime(UNIT(s));
         if (r < 0)
@@ -1828,6 +1832,7 @@ static int service_start(Unit *u) {
         s->main_pid_known = false;
         s->main_pid_alien = false;
         s->forbid_restart = false;
+        s->reset_cpu_usage = true;
 
         free(s->status_text);
         s->status_text = NULL;
diff --git a/src/core/service.h b/src/core/service.h
index fe5afef..23124e8 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -189,6 +189,8 @@ struct Service {
         bool forbid_restart:1;
         bool start_timeout_defined:1;
 
+        bool reset_cpu_usage:1;
+
         char *bus_name;
 
         char *status_text;
diff --git a/src/core/slice.c b/src/core/slice.c
index 4d2eaf7..0bebdbc 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -181,7 +181,8 @@ static int slice_start(Unit *u) {
         assert(t);
         assert(t->state == SLICE_DEAD);
 
-        unit_realize_cgroup(u);
+        (void) unit_realize_cgroup(u);
+        (void) unit_reset_cpu_usage(u);
 
         slice_set_state(t, SLICE_ACTIVE);
         return 1;
diff --git a/src/core/socket.c b/src/core/socket.c
index 7d052f2..9606ac2 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1392,7 +1392,11 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
         assert(c);
         assert(_pid);
 
-        unit_realize_cgroup(UNIT(s));
+        (void) unit_realize_cgroup(UNIT(s));
+        if (s->reset_cpu_usage) {
+                (void) unit_reset_cpu_usage(UNIT(s));
+                s->reset_cpu_usage = false;
+        }
 
         r = unit_setup_exec_runtime(UNIT(s));
         if (r < 0)
@@ -1948,6 +1952,8 @@ static int socket_start(Unit *u) {
         assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
 
         s->result = SOCKET_SUCCESS;
+        s->reset_cpu_usage = true;
+
         socket_enter_start_pre(s);
 
         return 1;
diff --git a/src/core/socket.h b/src/core/socket.h
index 5acf214..fa3ebda 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -166,6 +166,8 @@ struct Socket {
         bool selinux_context_from_net;
 
         char *user, *group;
+
+        bool reset_cpu_usage:1;
 };
 
 /* Called from the service code when collecting fds */
diff --git a/src/core/swap.c b/src/core/swap.c
index de3a5d8..4dd6be8 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -604,7 +604,11 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
         assert(c);
         assert(_pid);
 
-        unit_realize_cgroup(UNIT(s));
+        (void) unit_realize_cgroup(UNIT(s));
+        if (s->reset_cpu_usage) {
+                (void) unit_reset_cpu_usage(UNIT(s));
+                s->reset_cpu_usage = false;
+        }
 
         r = unit_setup_exec_runtime(UNIT(s));
         if (r < 0)
@@ -830,6 +834,8 @@ static int swap_start(Unit *u) {
                         return -EAGAIN;
 
         s->result = SWAP_SUCCESS;
+        s->reset_cpu_usage = true;
+
         swap_enter_activating(s);
         return 1;
 }
diff --git a/src/core/swap.h b/src/core/swap.h
index 5de8c20..9136b9a 100644
--- a/src/core/swap.h
+++ b/src/core/swap.h
@@ -87,6 +87,8 @@ struct Swap {
         bool is_active:1;
         bool just_activated:1;
 
+        bool reset_cpu_usage:1;
+
         SwapResult result;
 
         usec_t timeout_usec;
diff --git a/src/core/unit.c b/src/core/unit.c
index 7cd7043..b639d68 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2602,6 +2602,7 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
                 unit_serialize_item(u, f, "assert-result", yes_no(u->assert_result));
 
         unit_serialize_item(u, f, "transient", yes_no(u->transient));
+        unit_serialize_item_format(u, f, "cpuacct-usage-base", "%" PRIu64, u->cpuacct_usage_base);
 
         if (u->cgroup_path)
                 unit_serialize_item(u, f, "cgroup", u->cgroup_path);
@@ -2776,6 +2777,12 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                                 u->transient = b;
 
                         continue;
+                } else if (streq(l, "cpuacct-usage-base")) {
+
+                        r = safe_atou64(v, &u->cpuacct_usage_base);
+                        if (r < 0)
+                                log_debug("Failed to parse CPU usage %s", v);
+
                 } else if (streq(l, "cgroup")) {
                         char *s;
 
@@ -2787,8 +2794,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                                 void *p;
 
                                 p = hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
-                                log_info("Removing cgroup_path %s from hashmap (%p)",
-                                         u->cgroup_path, p);
+                                log_info("Removing cgroup_path %s from hashmap (%p)", u->cgroup_path, p);
                                 free(u->cgroup_path);
                         }
 
diff --git a/src/core/unit.h b/src/core/unit.h
index b3775d4..ac5647a 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -176,6 +176,9 @@ struct Unit {
         UnitFileState unit_file_state;
         int unit_file_preset;
 
+        /* Where the cpuacct.usage cgroup counter was at the time the unit was started */
+        nsec_t cpuacct_usage_base;
+
         /* Counterparts in the cgroup filesystem */
         char *cgroup_path;
         CGroupControllerMask cgroup_realized_mask;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 10213af..e915f6f 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3195,6 +3195,7 @@ typedef struct UnitStatusInfo {
         /* CGroup */
         uint64_t memory_current;
         uint64_t memory_limit;
+        uint64_t cpu_usage_nsec;
 
         LIST_HEAD(ExecStatusInfo, exec);
 } UnitStatusInfo;
@@ -3465,6 +3466,11 @@ static void print_status_info(
                         printf("\n");
         }
 
+        if (i->cpu_usage_nsec != (uint64_t) -1) {
+                char buf[FORMAT_TIMESPAN_MAX];
+                printf("      CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
+        }
+
         if (i->control_group &&
             (i->main_pid > 0 || i->control_pid > 0 ||
              ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0))) {
@@ -3683,6 +3689,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
                         i->memory_current = u;
                 else if (streq(name, "MemoryLimit"))
                         i->memory_limit = u;
+                else if (streq(name, "CPUUsageNSec"))
+                        i->cpu_usage_nsec = u;
 
                 break;
         }
@@ -4156,6 +4164,7 @@ static int show_one(
         UnitStatusInfo info = {
                 .memory_current = (uint64_t) -1,
                 .memory_limit = (uint64_t) -1,
+                .cpu_usage_nsec = (uint64_t) -1,
         };
         ExecStatusInfo *p;
         int r;



More information about the systemd-commits mailing list