X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Fmachine-pool.c;h=8af78f47d5e3775de87065a6a3cb7e86dbd1ea08;hp=7b17395d212b2bff7a82bd93b41f6c244739154f;hb=fb047e8edd9fc19b4a65f2656df494a12add1d31;hpb=403e5b32301cab098151814acbd08821475c00c3 diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index 7b17395d2..8af78f47d 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -25,9 +25,12 @@ #include #include "util.h" +#include "process-util.h" +#include "lockfile-util.h" #include "mkdir.h" #include "btrfs-util.h" #include "path-util.h" +#include "signal-util.h" #include "machine-pool.h" #define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL) @@ -47,7 +50,7 @@ static int check_btrfs(void) { return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC); } -static int setup_machine_raw(sd_bus_error *error) { +static int setup_machine_raw(uint64_t size, sd_bus_error *error) { _cleanup_free_ char *tmp = NULL; _cleanup_close_ int fd = -1; struct statvfs ss; @@ -72,7 +75,7 @@ static int setup_machine_raw(sd_bus_error *error) { 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); + r = tempfn_xxxxxx("/var/lib/machines.raw", NULL, &tmp); if (r < 0) return r; @@ -91,7 +94,7 @@ static int setup_machine_raw(sd_bus_error *error) { goto fail; } - if (ftruncate(fd, VAR_LIB_MACHINES_SIZE_START) < 0) { + if (ftruncate(fd, size) < 0) { r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m"); goto fail; } @@ -106,8 +109,8 @@ static int setup_machine_raw(sd_bus_error *error) { /* Child */ - reset_all_signal_handlers(); - reset_signal_mask(); + (void) reset_all_signal_handlers(); + (void) reset_signal_mask(); assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); fd = safe_close(fd); @@ -140,8 +143,9 @@ static int setup_machine_raw(sd_bus_error *error) { 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"); + r = rename_noreplace(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw"); + if (r < 0) { + sd_bus_error_set_errnof(error, r, "Failed to move /var/lib/machines.raw into place: %m"); goto fail; } @@ -151,8 +155,7 @@ static int setup_machine_raw(sd_bus_error *error) { return r; fail: - if (tmp) - unlink_noerrno(tmp); + unlink_noerrno(tmp); if (pid > 1) kill_and_sigcont(pid, SIGKILL); @@ -160,7 +163,7 @@ fail: return r; } -int setup_machine_directory(sd_bus_error *error) { +int setup_machine_directory(uint64_t size, sd_bus_error *error) { _cleanup_release_lock_file_ LockFile lock_file = LOCK_FILE_INIT; struct loop_info64 info = { .lo_flags = LO_FLAGS_AUTOCLEAR, @@ -169,8 +172,15 @@ int setup_machine_directory(sd_bus_error *error) { _cleanup_free_ char* loopdev = NULL; char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL; bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false; + char buf[FORMAT_BYTES_MAX]; int r, nr = -1; + /* btrfs cannot handle file systems < 16M, hence use this as minimum */ + if (size == (uint64_t) -1) + size = VAR_LIB_MACHINES_SIZE_START; + else if (size < 16*1024*1024) + size = 16*1024*1024; + /* 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) @@ -189,11 +199,11 @@ int setup_machine_directory(sd_bus_error *error) { return 0; } - if (path_is_mount_point("/var/lib/machines", true) > 0 || + if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 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); + fd = setup_machine_raw(size, error); if (fd < 0) return fd; @@ -268,6 +278,10 @@ int setup_machine_directory(sd_bus_error *error) { goto fail; } + (void) syncfs(fd); + + log_info("Set up /var/lib/machines as btrfs loopback file system of size %s mounted on /var/lib/machines.raw.", format_bytes(buf, sizeof(buf), size)); + (void) umount2(mntdir, MNT_DETACH); (void) rmdir(mntdir); (void) rmdir(tmpdir); @@ -293,3 +307,73 @@ fail: return r; } + +static int sync_path(const char *p) { + _cleanup_close_ int fd = -1; + + fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + if (syncfs(fd) < 0) + return -errno; + + return 0; +} + +int grow_machine_directory(void) { + char buf[FORMAT_BYTES_MAX]; + struct statvfs a, b; + uint64_t old_size, new_size, max_add; + int r; + + /* Ensure the disk space data is accurate */ + sync_path("/var/lib/machines"); + sync_path("/var/lib/machines.raw"); + + if (statvfs("/var/lib/machines.raw", &a) < 0) + return -errno; + + if (statvfs("/var/lib/machines", &b) < 0) + return -errno; + + /* Don't grow if not enough disk space is available on the host */ + if (((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) <= VAR_LIB_MACHINES_FREE_MIN) + return 0; + + /* Don't grow if at least 1/3th of the fs is still free */ + if (b.f_bavail > b.f_blocks / 3) + return 0; + + /* Calculate how much we are willing to add at maximum */ + max_add = ((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) - VAR_LIB_MACHINES_FREE_MIN; + + /* Calculate the old size */ + old_size = (uint64_t) b.f_blocks * (uint64_t) b.f_bsize; + + /* Calculate the new size as three times the size of what is used right now */ + new_size = ((uint64_t) b.f_blocks - (uint64_t) b.f_bavail) * (uint64_t) b.f_bsize * 3; + + /* Always, grow at least to the start size */ + if (new_size < VAR_LIB_MACHINES_SIZE_START) + new_size = VAR_LIB_MACHINES_SIZE_START; + + /* If the new size is smaller than the old size, don't grow */ + if (new_size < old_size) + return 0; + + /* Ensure we never add more than the maximum */ + if (new_size > old_size + max_add) + new_size = old_size + max_add; + + r = btrfs_resize_loopback("/var/lib/machines", new_size, true); + if (r <= 0) + return r; + + r = btrfs_quota_limit("/var/lib/machines", new_size); + if (r < 0) + return r; + + log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size)); + return 1; +}