diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/btrfs-util.c | 17 | ||||
-rw-r--r-- | src/shared/btrfs-util.h | 4 | ||||
-rw-r--r-- | src/shared/machine-pool.c | 75 | ||||
-rw-r--r-- | src/shared/machine-pool.h | 1 |
4 files changed, 91 insertions, 6 deletions
diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index 52fc5f4a17..256c5a6995 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -705,7 +705,7 @@ int btrfs_quota_limit(const char *path, uint64_t referred_max) { return btrfs_quota_limit_fd(fd, referred_max); } -int btrfs_resize_loopback_fd(int fd, uint64_t new_size) { +int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) { struct btrfs_ioctl_vol_args args = {}; _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL; _cleanup_close_ int loop_fd = -1, backing_fd = -1; @@ -726,6 +726,8 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size) { if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0) return -ENOMEM; r = read_one_line_file(p, &backing); + if (r == -ENOENT) + return -ENODEV; if (r < 0) return r; if (isempty(backing) || !path_is_absolute(backing)) @@ -743,6 +745,9 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size) { if (new_size == (uint64_t) st.st_size) return 0; + if (grow_only && new_size < (uint64_t) st.st_size) + return -EINVAL; + if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0) return -ENOMEM; loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY); @@ -770,15 +775,19 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size) { return -errno; } - return 0; + /* Make sure the free disk space is correctly updated for both file systems */ + (void) fsync(fd); + (void) fsync(backing_fd); + + return 1; } -int btrfs_resize_loopback(const char *p, uint64_t new_size) { +int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) { _cleanup_close_ int fd = -1; fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) return -errno; - return btrfs_resize_loopback_fd(fd, new_size); + return btrfs_resize_loopback_fd(fd, new_size, grow_only); } diff --git a/src/shared/btrfs-util.h b/src/shared/btrfs-util.h index e654a3fea1..a2c246b8d6 100644 --- a/src/shared/btrfs-util.h +++ b/src/shared/btrfs-util.h @@ -72,5 +72,5 @@ int btrfs_quota_enable(const char *path, bool b); int btrfs_quota_limit_fd(int fd, uint64_t referred_max); int btrfs_quota_limit(const char *path, uint64_t referred_max); -int btrfs_resize_loopback_fd(int fd, uint64_t size); -int btrfs_resize_loopback(const char *path, uint64_t size); +int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only); +int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only); diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index b74252dbc8..3eafb9443a 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -169,6 +169,7 @@ int setup_machine_directory(uint64_t size, 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 */ @@ -274,6 +275,10 @@ int setup_machine_directory(uint64_t size, 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); @@ -299,3 +304,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; +} diff --git a/src/shared/machine-pool.h b/src/shared/machine-pool.h index 9c9849f618..06c5d40583 100644 --- a/src/shared/machine-pool.h +++ b/src/shared/machine-pool.h @@ -24,3 +24,4 @@ #include "sd-bus.h" int setup_machine_directory(uint64_t size, sd_bus_error *error); +int grow_machine_directory(void); |