summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-11-04 21:54:46 +0100
committerLennart Poettering <lennart@poettering.net>2021-11-23 10:02:35 +0100
commit716bc20034bb54a0c1b1dd5125929d900026670b (patch)
treee917c2be7eb47d1f080a230327d02b4d851a55da
parent7c5cef22115c1898cce8d501d912e2685c83e16e (diff)
downloadsystemd-716bc20034bb54a0c1b1dd5125929d900026670b.tar.gz
homework: when creating home dir also treat specified size as hint
The resize logic is now able to handle resize requests that cannot be fulfilled in full gracefully. Let's do the same when allocating new home directories. This means "homectl create foo --disk-size=min" and "homectl create foo --disk-size=max" may now be used to create the smallest or largest home directory we support.
-rw-r--r--src/home/homework-luks.c61
1 files changed, 28 insertions, 33 deletions
diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c
index 57b41d26b8..0beee8ecfd 100644
--- a/src/home/homework-luks.c
+++ b/src/home/homework-luks.c
@@ -63,6 +63,7 @@
_x > UINT64_MAX - 4095U ? UINT64_MAX : (_x + 4095U) & ~UINT64_C(4095); \
})
+static int resize_image_loop(UserRecord *h, HomeSetup *setup, uint64_t old_image_size, uint64_t new_image_size, uint64_t *ret_image_size);
int run_mark_dirty(int fd, bool b) {
char x = '1';
@@ -1914,36 +1915,33 @@ static int wait_for_devlink(const char *path) {
}
}
-static int calculate_disk_size(UserRecord *h, const char *parent_dir, uint64_t *ret) {
+static int calculate_initial_image_size(UserRecord *h, int image_fd, const char *fstype, uint64_t *ret) {
+ uint64_t upper_boundary, lower_boundary;
struct statfs sfs;
- uint64_t m;
assert(h);
- assert(parent_dir);
+ assert(image_fd >= 0);
assert(ret);
- if (h->disk_size != UINT64_MAX) {
- *ret = DISK_SIZE_ROUND_DOWN(h->disk_size);
- return 0;
- }
-
- if (statfs(parent_dir, &sfs) < 0)
- return log_error_errno(errno, "statfs() on %s failed: %m", parent_dir);
+ if (fstatfs(image_fd, &sfs) < 0)
+ return log_error_errno(errno, "statfs() on image failed: %m");
- m = sfs.f_bsize * sfs.f_bavail;
+ upper_boundary = DISK_SIZE_ROUND_DOWN((uint64_t) sfs.f_bsize * sfs.f_bavail);
- if (h->disk_size_relative == UINT64_MAX) {
+ if (h->disk_size != UINT64_MAX)
+ *ret = MIN(DISK_SIZE_ROUND_DOWN(h->disk_size), upper_boundary);
+ else if (h->disk_size_relative == UINT64_MAX) {
- if (m > UINT64_MAX / USER_DISK_SIZE_DEFAULT_PERCENT)
+ if (upper_boundary > UINT64_MAX / USER_DISK_SIZE_DEFAULT_PERCENT)
return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "Disk size too large.");
- *ret = DISK_SIZE_ROUND_DOWN(m * USER_DISK_SIZE_DEFAULT_PERCENT / 100);
+ *ret = DISK_SIZE_ROUND_DOWN(upper_boundary * USER_DISK_SIZE_DEFAULT_PERCENT / 100);
log_info("Sizing home to %u%% of available disk space, which is %s.",
USER_DISK_SIZE_DEFAULT_PERCENT,
FORMAT_BYTES(*ret));
} else {
- *ret = DISK_SIZE_ROUND_DOWN((uint64_t) ((double) m * (double) h->disk_size_relative / (double) UINT32_MAX));
+ *ret = DISK_SIZE_ROUND_DOWN((uint64_t) ((double) upper_boundary * (double) CLAMP(h->disk_size_relative, 0U, UINT32_MAX) / (double) UINT32_MAX));
log_info("Sizing home to %" PRIu64 ".%01" PRIu64 "%% of available disk space, which is %s.",
(h->disk_size_relative * 100) / UINT32_MAX,
@@ -1951,8 +1949,12 @@ static int calculate_disk_size(UserRecord *h, const char *parent_dir, uint64_t *
FORMAT_BYTES(*ret));
}
- if (*ret < USER_DISK_SIZE_MIN)
- *ret = USER_DISK_SIZE_MIN;
+ lower_boundary = minimal_size_by_fs_name(fstype);
+ if (lower_boundary == UINT64_MAX || lower_boundary < USER_DISK_SIZE_MIN)
+ lower_boundary = USER_DISK_SIZE_MIN;
+
+ if (*ret < lower_boundary)
+ *ret = lower_boundary;
return 0;
}
@@ -2141,22 +2143,11 @@ int home_create_luks(
log_info("Full device discard completed.");
}
} else {
- _cleanup_free_ char *parent = NULL, *t = NULL;
-
- parent = dirname_malloc(ip);
- if (!parent)
- return log_oom();
-
- r = mkdir_p(parent, 0755);
- if (r < 0)
- return log_error_errno(r, "Failed to create parent directory %s: %m", parent);
+ _cleanup_free_ char *t = NULL;
- r = calculate_disk_size(h, parent, &host_size);
+ r = mkdir_parents(ip, 0755);
if (r < 0)
- return r;
-
- if (!supported_fs_size(fstype, host_size))
- return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Selected file system size too small for %s.", fstype);
+ return log_error_errno(r, "Failed to create parent directory of %s: %m", ip);
r = tempfn_random(ip, "homework", &t);
if (r < 0)
@@ -2173,7 +2164,11 @@ int home_create_luks(
log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set file attributes on %s, ignoring: %m", setup->temporary_image_path);
- r = home_truncate(h, setup->image_fd, host_size);
+ r = calculate_initial_image_size(h, setup->image_fd, fstype, &host_size);
+ if (r < 0)
+ return r;
+
+ r = resize_image_loop(h, setup, 0, host_size, &host_size);
if (r < 0)
return r;
@@ -2351,7 +2346,7 @@ int home_create_luks(
if (disk_uuid_path)
(void) wait_for_devlink(disk_uuid_path);
- log_info("Everything completed.");
+ log_info("Creation completed.");
print_size_summary(host_size, encrypted_size, &sfs);