diff --git a/TODO b/TODO index ae1bedcd29..d8d120d66a 100644 --- a/TODO +++ b/TODO @@ -235,8 +235,7 @@ Features: the runtime dir as we maintain for the fdstore: i.e. keep it around as long as the unit is running or has a job queued. -* support projid-based quota in machinectl for containers, and then drop - implicit btrfs loopback magic in machined +* support projid-based quota in machinectl for containers * Add NetworkNamespacePath= to specify a path to a network namespace @@ -883,9 +882,6 @@ Features: - "machinectl commit" that takes a writable snapshot of a tree, invokes a shell in it, and marks it read-only after use -* importd: - - generate a nice warning if mkfs.btrfs is missing - * cryptsetup: - cryptsetup-generator: allow specification of passwords in crypttab itself - support rd.luks.allow-discards= kernel cmdline params in cryptsetup generator diff --git a/man/machinectl.xml b/man/machinectl.xml index e403c51e28..95823eb413 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -650,22 +650,7 @@ units. If the size limit shall be disabled, specify - as size. - Note that per-container size limits are only supported - on btrfs file systems. Also note that, if - set-limit is invoked without an image - parameter, and /var/lib/machines is - empty, and the directory is not located on btrfs, a btrfs - loopback file is implicitly created as - /var/lib/machines.raw with the given - size, and mounted to - /var/lib/machines. The size of the - loopback may later be readjusted with - set-limit, as well. If such a - loopback-mounted /var/lib/machines - directory is used, set-limit without an image - name alters both the quota setting within the file system as - well as the loopback file and file system size - itself. + Note that per-container size limits are only supported on btrfs file systems. @@ -803,12 +788,8 @@ image is read from standard input, in which case the second argument is mandatory. - Both pull-tar and pull-raw - will resize /var/lib/machines.raw and the - filesystem therein as necessary. Optionally, the - switch may be used to create a - read-only container or VM image. No cryptographic validation - is done when importing the images. + Optionally, the switch may be used to create a read-only container or VM + image. No cryptographic validation is done when importing the images. Much like image downloads, ongoing imports may be listed with list-transfers and aborted with @@ -920,18 +901,7 @@ /var/lib/machines/ to make them available for control with machinectl. - Note that some image operations are only supported, - efficient or atomic on btrfs file systems. Due to this, if the - pull-tar, pull-raw, - import-tar, import-raw and - set-limit commands notice that - /var/lib/machines is empty and not located on - btrfs, they will implicitly set up a loopback file - /var/lib/machines.raw containing a btrfs file - system that is mounted to - /var/lib/machines. The size of this loopback - file may be controlled dynamically with - set-limit. + Note that some image operations are only supported, efficient or atomic on btrfs file systems. Disk images are understood by systemd-nspawn1 diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 3252b75802..cedce84e9c 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -870,96 +870,6 @@ int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, u return btrfs_subvol_set_subtree_quota_limit_fd(fd, subvol_id, referenced_max); } -int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) { - struct btrfs_ioctl_vol_args args = {}; - char p[SYS_BLOCK_PATH_MAX("/loop/backing_file")], q[DEV_NUM_PATH_MAX]; - _cleanup_free_ char *backing = NULL; - _cleanup_close_ int loop_fd = -1, backing_fd = -1; - struct stat st; - dev_t dev = 0; - int r; - - /* In contrast to btrfs quota ioctls ftruncate() cannot make sense of "infinity" or file sizes > 2^31 */ - if (!FILE_SIZE_VALID(new_size)) - return -EINVAL; - - /* btrfs cannot handle file systems < 16M, hence use this as minimum */ - if (new_size < 16*1024*1024) - new_size = 16*1024*1024; - - r = btrfs_get_block_device_fd(fd, &dev); - if (r < 0) - return r; - if (r == 0) - return -ENODEV; - - xsprintf_sys_block_path(p, "/loop/backing_file", dev); - r = read_one_line_file(p, &backing); - if (r == -ENOENT) - return -ENODEV; - if (r < 0) - return r; - if (isempty(backing) || !path_is_absolute(backing)) - return -ENODEV; - - backing_fd = open(backing, O_RDWR|O_CLOEXEC|O_NOCTTY); - if (backing_fd < 0) - return -errno; - - if (fstat(backing_fd, &st) < 0) - return -errno; - if (!S_ISREG(st.st_mode)) - return -ENODEV; - - if (new_size == (uint64_t) st.st_size) - return 0; - - if (grow_only && new_size < (uint64_t) st.st_size) - return -EINVAL; - - xsprintf_dev_num_path(q, "block", dev); - loop_fd = open(q, O_RDWR|O_CLOEXEC|O_NOCTTY); - if (loop_fd < 0) - return -errno; - - if (snprintf(args.name, sizeof(args.name), "%" PRIu64, new_size) >= (int) sizeof(args.name)) - return -EINVAL; - - if (new_size < (uint64_t) st.st_size) { - /* Decrease size: first decrease btrfs size, then shorten loopback */ - if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0) - return -errno; - } - - if (ftruncate(backing_fd, new_size) < 0) - return -errno; - - if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0) - return -errno; - - if (new_size > (uint64_t) st.st_size) { - /* Increase size: first enlarge loopback, then increase btrfs size */ - if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0) - return -errno; - } - - /* 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, 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, grow_only); -} - int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret) { assert(ret); diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 3adb51e02d..085aca4dbc 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -62,9 +62,6 @@ int btrfs_quota_scan_start(int fd); int btrfs_quota_scan_wait(int fd); int btrfs_quota_scan_ongoing(int fd); -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); - int btrfs_subvol_make(const char *path); int btrfs_subvol_make_fd(int fd, const char *subvolume); diff --git a/src/import/import-raw.c b/src/import/import-raw.c index e8adaae740..2b96330c14 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -37,7 +37,6 @@ struct RawImport { char *local; bool force_local; bool read_only; - bool grow_machine_directory; char *temp_path; char *final_path; @@ -47,8 +46,6 @@ struct RawImport { ImportCompress compress; - uint64_t written_since_last_grow; - sd_event_source *input_event_source; uint8_t buffer[16*1024]; @@ -95,7 +92,6 @@ int raw_import_new( _cleanup_(raw_import_unrefp) RawImport *i = NULL; _cleanup_free_ char *root = NULL; - bool grow; int r; assert(ret); @@ -104,8 +100,6 @@ int raw_import_new( if (!root) return -ENOMEM; - grow = path_startswith(root, "/var/lib/machines"); - i = new(RawImport, 1); if (!i) return -ENOMEM; @@ -117,7 +111,6 @@ int raw_import_new( .userdata = userdata, .last_percent = (unsigned) -1, .image_root = TAKE_PTR(root), - .grow_machine_directory = grow, }; RATELIMIT_INIT(i->progress_rate_limit, 100 * USEC_PER_MSEC, 1); @@ -307,11 +300,6 @@ static int raw_import_write(const void *p, size_t sz, void *userdata) { RawImport *i = userdata; ssize_t n; - if (i->grow_machine_directory && i->written_since_last_grow >= GROW_INTERVAL_BYTES) { - i->written_since_last_grow = 0; - grow_machine_directory(); - } - n = sparse_write(i->output_fd, p, sz, 64); if (n < 0) return (int) n; @@ -319,7 +307,6 @@ static int raw_import_write(const void *p, size_t sz, void *userdata) { return -EIO; i->written_uncompressed += sz; - i->written_since_last_grow += sz; return 0; } diff --git a/src/import/import-tar.c b/src/import/import-tar.c index a164417de0..896effab77 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -37,7 +37,6 @@ struct TarImport { char *local; bool force_local; bool read_only; - bool grow_machine_directory; char *temp_path; char *final_path; @@ -47,8 +46,6 @@ struct TarImport { ImportCompress compress; - uint64_t written_since_last_grow; - sd_event_source *input_event_source; uint8_t buffer[16*1024]; @@ -102,7 +99,6 @@ int tar_import_new( _cleanup_(tar_import_unrefp) TarImport *i = NULL; _cleanup_free_ char *root = NULL; - bool grow; int r; assert(ret); @@ -111,8 +107,6 @@ int tar_import_new( if (!root) return -ENOMEM; - grow = path_startswith(root, "/var/lib/machines"); - i = new(TarImport, 1); if (!i) return -ENOMEM; @@ -124,7 +118,6 @@ int tar_import_new( .userdata = userdata, .last_percent = (unsigned) -1, .image_root = TAKE_PTR(root), - .grow_machine_directory = grow, }; RATELIMIT_INIT(i->progress_rate_limit, 100 * USEC_PER_MSEC, 1); @@ -245,17 +238,11 @@ static int tar_import_write(const void *p, size_t sz, void *userdata) { TarImport *i = userdata; int r; - if (i->grow_machine_directory && i->written_since_last_grow >= GROW_INTERVAL_BYTES) { - i->written_since_last_grow = 0; - grow_machine_directory(); - } - r = loop_write(i->tar_fd, p, sz, false); if (r < 0) return r; i->written_uncompressed += sz; - i->written_since_last_grow += sz; return 0; } diff --git a/src/import/importd.c b/src/import/importd.c index 6fa8342172..83f186f66e 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -719,7 +719,7 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (!machine_name_is_valid(local)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); - r = setup_machine_directory((uint64_t) -1, error); + r = setup_machine_directory(error); if (r < 0) return r; @@ -783,7 +783,7 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e if (!machine_name_is_valid(local)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); - r = setup_machine_directory((uint64_t) -1, error); + r = setup_machine_directory(error); if (r < 0) return r; @@ -924,7 +924,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er if (v < 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify); - r = setup_machine_directory((uint64_t) -1, error); + r = setup_machine_directory(error); if (r < 0) return r; diff --git a/src/import/pull-job.c b/src/import/pull-job.c index 0b7d9df32d..a44e0a7eda 100644 --- a/src/import/pull-job.c +++ b/src/import/pull-job.c @@ -74,7 +74,6 @@ static int pull_job_restart(PullJob *j) { j->payload_allocated = 0; j->written_compressed = 0; j->written_uncompressed = 0; - j->written_since_last_grow = 0; r = pull_job_begin(j); if (r < 0) @@ -224,11 +223,6 @@ static int pull_job_write_uncompressed(const void *p, size_t sz, void *userdata) if (j->disk_fd >= 0) { - if (j->grow_machine_directory && j->written_since_last_grow >= GROW_INTERVAL_BYTES) { - j->written_since_last_grow = 0; - grow_machine_directory(); - } - if (j->allow_sparse) n = sparse_write(j->disk_fd, p, sz, 64); else { @@ -250,7 +244,6 @@ static int pull_job_write_uncompressed(const void *p, size_t sz, void *userdata) } j->written_uncompressed += sz; - j->written_since_last_grow += sz; return 0; } @@ -577,9 +570,6 @@ int pull_job_begin(PullJob *j) { if (j->state != PULL_JOB_INIT) return -EBUSY; - if (j->grow_machine_directory) - grow_machine_directory(); - r = curl_glue_make(&j->curl, j->url, j); if (r < 0) return r; diff --git a/src/import/pull-job.h b/src/import/pull-job.h index 0c104af758..c907e74060 100644 --- a/src/import/pull-job.h +++ b/src/import/pull-job.h @@ -80,9 +80,6 @@ struct PullJob { char *checksum; - bool grow_machine_directory; - uint64_t written_since_last_grow; - VerificationStyle style; }; diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index 2ceca68c07..39d1747f7d 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -56,7 +56,6 @@ struct RawPull { char *local; bool force_local; - bool grow_machine_directory; bool settings; bool roothash; @@ -119,7 +118,6 @@ int raw_pull_new( _cleanup_(sd_event_unrefp) sd_event *e = NULL; _cleanup_(raw_pull_unrefp) RawPull *i = NULL; _cleanup_free_ char *root = NULL; - bool grow; int r; assert(ret); @@ -128,8 +126,6 @@ int raw_pull_new( if (!root) return -ENOMEM; - grow = path_startswith(root, "/var/lib/machines"); - if (event) e = sd_event_ref(event); else { @@ -150,7 +146,6 @@ int raw_pull_new( .on_finished = on_finished, .userdata = userdata, .image_root = TAKE_PTR(root), - .grow_machine_directory = grow, .event = TAKE_PTR(e), .glue = TAKE_PTR(g), }; @@ -689,7 +684,6 @@ int raw_pull_start( i->raw_job->on_open_disk = raw_pull_job_on_open_disk_raw; i->raw_job->on_progress = raw_pull_job_on_progress; i->raw_job->calc_checksum = verify != IMPORT_VERIFY_NO; - i->raw_job->grow_machine_directory = i->grow_machine_directory; r = pull_find_old_etags(url, i->image_root, DT_REG, ".raw-", ".raw", &i->raw_job->old_etags); if (r < 0) diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 67ea8813e1..b19d4ea391 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -52,7 +52,6 @@ struct TarPull { char *local; bool force_local; - bool grow_machine_directory; bool settings; pid_t tar_pid; @@ -112,7 +111,6 @@ int tar_pull_new( _cleanup_(sd_event_unrefp) sd_event *e = NULL; _cleanup_(tar_pull_unrefp) TarPull *i = NULL; _cleanup_free_ char *root = NULL; - bool grow; int r; assert(ret); @@ -121,8 +119,6 @@ int tar_pull_new( if (!root) return -ENOMEM; - grow = path_startswith(root, "/var/lib/machines"); - if (event) e = sd_event_ref(event); else { @@ -143,7 +139,6 @@ int tar_pull_new( .on_finished = on_finished, .userdata = userdata, .image_root = TAKE_PTR(root), - .grow_machine_directory = grow, .event = TAKE_PTR(e), .glue = TAKE_PTR(g), }; @@ -512,7 +507,6 @@ int tar_pull_start( i->tar_job->on_open_disk = tar_pull_job_on_open_disk_tar; i->tar_job->on_progress = tar_pull_job_on_progress; i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO; - i->tar_job->grow_machine_directory = i->grow_machine_directory; r = pull_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags); if (r < 0) diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 87e6298c78..453ca30b64 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -41,15 +41,10 @@ static int property_get_pool_usage( _cleanup_close_ int fd = -1; uint64_t usage = (uint64_t) -1; - struct stat st; assert(bus); assert(reply); - /* We try to read the quota info from /var/lib/machines, as - * well as the usage of the loopback file - * /var/lib/machines.raw, and pick the larger value. */ - fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY); if (fd >= 0) { BtrfsQuotaInfo q; @@ -58,11 +53,6 @@ static int property_get_pool_usage( usage = q.referenced; } - if (stat("/var/lib/machines.raw", &st) >= 0) { - if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage) - usage = st.st_blocks * 512ULL; - } - return sd_bus_message_append(reply, "t", usage); } @@ -77,15 +67,10 @@ static int property_get_pool_limit( _cleanup_close_ int fd = -1; uint64_t size = (uint64_t) -1; - struct stat st; assert(bus); assert(reply); - /* We try to read the quota limit from /var/lib/machines, as - * well as the size of the loopback file - * /var/lib/machines.raw, and pick the smaller value. */ - fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY); if (fd >= 0) { BtrfsQuotaInfo q; @@ -94,11 +79,6 @@ static int property_get_pool_limit( size = q.referenced_max; } - if (stat("/var/lib/machines.raw", &st) >= 0) { - if (size == (uint64_t) -1 || (uint64_t) st.st_size < size) - size = st.st_size; - } - return sd_bus_message_append(reply, "t", size); } @@ -877,19 +857,10 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus return 1; /* Will call us back */ /* Set up the machine directory if necessary */ - r = setup_machine_directory(limit, error); + r = setup_machine_directory(error); if (r < 0) return r; - /* Resize the backing loopback device, if there is one, except if we asked to drop any limit */ - if (limit != (uint64_t) -1) { - r = btrfs_resize_loopback("/var/lib/machines", limit, false); - if (r == -ENOTTY) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs."); - if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */ - return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m"); - } - (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit); r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit); diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index df56492e7b..de4f704252 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -1,46 +1,13 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include "sd-bus-protocol.h" -#include "sd-bus.h" - -#include "alloc-util.h" #include "btrfs-util.h" -#include "fd-util.h" -#include "fileio.h" -#include "fs-util.h" #include "label.h" -#include "lockfile-util.h" -#include "log.h" #include "machine-pool.h" -#include "macro.h" #include "missing.h" -#include "mkdir.h" -#include "mount-util.h" -#include "parse-util.h" -#include "path-util.h" -#include "process-util.h" -#include "signal-util.h" #include "stat-util.h" -#include "string-util.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; @@ -56,344 +23,24 @@ static int check_btrfs(void) { return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC); } -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; - pid_t pid = 0; +int setup_machine_directory(sd_bus_error *error) { 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) - return TAKE_FD(fd); - - 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", NULL, &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, size) < 0) { - r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m"); - goto fail; - } - - r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid); - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Failed to fork mkfs.btrfs: %m"); - goto fail; - } - if (r == 0) { - - /* Child */ - - fd = safe_close(fd); - - execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL); - if (errno == ENOENT) - _exit(99); - - _exit(EXIT_FAILURE); - } - - r = wait_for_terminate_and_check("mkfs", pid, 0); - pid = 0; - - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m"); - goto fail; - } - if (r == 99) { - r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing"); - goto fail; - } - if (r != EXIT_SUCCESS) { - r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", r); - goto fail; - } - - 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; - } - - return TAKE_FD(fd); - -fail: - unlink_noerrno(tmp); - - if (pid > 1) - kill_and_sigcont(pid, SIGKILL); - - return r; -} - -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, - }; - _cleanup_close_ int fd = -1, control = -1, loop = -1; - _cleanup_free_ char* loopdev = NULL; - char tmpdir[] = "/tmp/machine-pool.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) - 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"); - 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 for /var/lib/machines, ignoring: %m"); - - r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true); - if (r < 0) - log_warning_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, ignoring: %m"); - - return 1; - } - - if (path_is_mount_point("/var/lib/machines", NULL, AT_SYMLINK_FOLLOW) > 0) { - log_debug("/var/lib/machines is already a mount point, not creating loopback file for it."); - return 0; - } - - r = dir_is_populated("/var/lib/machines"); - if (r < 0 && r != -ENOENT) - return r; - if (r > 0) { - log_debug("/var/log/machines is already populated, not creating loopback file for it."); - return 0; - } - - r = mkfs_exists("btrfs"); - if (r == 0) - return sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing"); - if (r < 0) - return r; - - fd = setup_machine_raw(size, 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"); - - r = btrfs_subvol_auto_qgroup(mntdir, 0, true); - if (r < 0) - log_warning_errno(r, "Failed to set up default quota hierarchy, 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) 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); - - return 1; - -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); - } - - (void) ioctl(control, LOOP_CTL_REMOVE, nr); - - 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 most */ - 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 log_debug_errno(r, "Failed to resize loopback: %m"); if (r == 0) return 0; - /* Also bump the quota, of both the subvolume leaf qgroup, as - * well as of any subtree quota group by the same id but a - * higher level, if it exists. */ - r = btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size); - if (r < 0) - log_debug_errno(r, "Failed to set btrfs limit: %m"); + (void) btrfs_subvol_make_label("/var/lib/machines"); - r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size); + r = btrfs_quota_enable("/var/lib/machines", true); if (r < 0) - log_debug_errno(r, "Failed to set btrfs subtree limit: %m"); + log_warning_errno(r, "Failed to enable quota for /var/lib/machines, ignoring: %m"); + + r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true); + if (r < 0) + log_warning_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, ignoring: %m"); - 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 fd09296f23..6f59a18fb6 100644 --- a/src/shared/machine-pool.h +++ b/src/shared/machine-pool.h @@ -5,8 +5,4 @@ #include "sd-bus.h" -/* Grow the /var/lib/machines directory after each 10MiB written */ -#define GROW_INTERVAL_BYTES (UINT64_C(10) * UINT64_C(1024) * UINT64_C(1024)) - -int setup_machine_directory(uint64_t size, sd_bus_error *error); -int grow_machine_directory(void); +int setup_machine_directory(sd_bus_error *error); diff --git a/units/var-lib-machines.mount b/units/var-lib-machines.mount index 5da0c6fa32..3658199cc7 100644 --- a/units/var-lib-machines.mount +++ b/units/var-lib-machines.mount @@ -7,8 +7,13 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. +# This unit is required for pre-240 versions of systemd that automatically set +# up /var/lib/machines.raw as loopback-mounted btrfs file system. Later +# versions don't do that anymore, but let's keep minimal compatibility by +# mounting the image still, if it exists. + [Unit] -Description=Virtual Machine and Container Storage +Description=Virtual Machine and Container Storage (Compatibility) ConditionPathExists=/var/lib/machines.raw [Mount]