Merge pull request #21440 from poettering/homed-initial-fs-size
homed: also support minimizing/maximizing home dirs when creating them
This commit is contained in:
+7
-4
@@ -504,10 +504,13 @@
|
||||
<varlistentry>
|
||||
<term><option>--disk-size=</option><replaceable>BYTES</replaceable></term>
|
||||
<listitem><para>Either takes a size in bytes as argument (possibly using the usual K, M, G, …
|
||||
suffixes for 1024 base values), or a percentage value and configures the disk space to assign to the
|
||||
user. If a percentage value is specified (i.e. the argument suffixed with <literal>%</literal>) it is
|
||||
taken relative to the available disk space of the backing file system. If the LUKS2 backend is used
|
||||
this configures the size of the loopback file and file system contained therein. For the other
|
||||
suffixes for 1024 base values), a percentage value, or the special strings <literal>min</literal> or
|
||||
<literal>max</literal>, and configures the disk space to assign to the user. If a percentage value is
|
||||
specified (i.e. the argument suffixed with <literal>%</literal>) it is taken relative to the
|
||||
available disk space of the backing file system. If specified as <literal>min</literal> assigns the
|
||||
minimal disk space permitted by the constraints of the backing file system and other limits, when
|
||||
specified as <literal>max</literal> assigns the maximum disk space available. If the LUKS2 backend is
|
||||
used this configures the size of the loopback file and file system contained therein. For the other
|
||||
storage backends configures disk quota using the filesystem's native quota logic, if available. If
|
||||
not specified, defaults to 85% of the available disk space for the LUKS2 backend and to no quota for
|
||||
the others.</para></listitem>
|
||||
|
||||
+41
-34
@@ -64,6 +64,11 @@
|
||||
_x > UINT64_MAX - 4095U ? UINT64_MAX : (_x + 4095U) & ~UINT64_C(4095); \
|
||||
})
|
||||
|
||||
/* How much larger will the image on disk be than the fs inside it, i.e. the space we pay for the GPT and
|
||||
* LUKS2 envelope. (As measured on cryptsetup 2.4.1) */
|
||||
#define GPT_LUKS2_OVERHEAD UINT64_C(18874368)
|
||||
|
||||
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';
|
||||
@@ -1891,6 +1896,8 @@ static int make_partition_table(
|
||||
assert(first_lba <= UINT64_MAX/512);
|
||||
start = DISK_SIZE_ROUND_UP(first_lba * 512); /* Round up to multiple of 4K */
|
||||
|
||||
log_debug("Starting partition at offset %" PRIu64, start);
|
||||
|
||||
if (start == UINT64_MAX)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Overflow while rounding up start LBA.");
|
||||
|
||||
@@ -2024,36 +2031,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 (fstatfs(image_fd, &sfs) < 0)
|
||||
return log_error_errno(errno, "statfs() on image failed: %m");
|
||||
|
||||
if (statfs(parent_dir, &sfs) < 0)
|
||||
return log_error_errno(errno, "statfs() on %s failed: %m", parent_dir);
|
||||
upper_boundary = DISK_SIZE_ROUND_DOWN((uint64_t) sfs.f_bsize * sfs.f_bavail);
|
||||
|
||||
m = sfs.f_bsize * sfs.f_bavail;
|
||||
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 (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,
|
||||
@@ -2061,8 +2065,16 @@ 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) {
|
||||
assert(GPT_LUKS2_OVERHEAD < UINT64_MAX - lower_boundary);
|
||||
lower_boundary += GPT_LUKS2_OVERHEAD;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -2231,7 +2243,7 @@ int home_create_luks(
|
||||
else
|
||||
host_size = DISK_SIZE_ROUND_DOWN(h->disk_size);
|
||||
|
||||
if (!supported_fs_size(fstype, host_size))
|
||||
if (!supported_fs_size(fstype, LESS_BY(host_size, GPT_LUKS2_OVERHEAD)))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
|
||||
"Selected file system size too small for %s.", fstype);
|
||||
|
||||
@@ -2251,22 +2263,11 @@ int home_create_luks(
|
||||
log_info("Full device discard completed.");
|
||||
}
|
||||
} else {
|
||||
_cleanup_free_ char *parent = NULL, *t = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
parent = dirname_malloc(ip);
|
||||
if (!parent)
|
||||
return log_oom();
|
||||
|
||||
r = mkdir_p(parent, 0755);
|
||||
r = mkdir_parents(ip, 0755);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create parent directory %s: %m", parent);
|
||||
|
||||
r = calculate_disk_size(h, parent, &host_size);
|
||||
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)
|
||||
@@ -2283,7 +2284,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;
|
||||
|
||||
@@ -2461,10 +2466,12 @@ 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);
|
||||
|
||||
log_debug("GPT + LUKS2 overhead is %" PRIu64 " (expected %" PRIu64 ")", host_size - encrypted_size, GPT_LUKS2_OVERHEAD);
|
||||
|
||||
*ret_home = TAKE_PTR(new_home);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ mount -t tmpfs tmpfs /home-pool -o size=290M
|
||||
# needlessly pressure for storage. We also set the cheapest KDF, since we don't
|
||||
# want to waste CI CPU cycles on it.
|
||||
NEWPASSWORD=xEhErW0ndafV4s homectl create test-user \
|
||||
--disk-size=256M \
|
||||
--disk-size=min \
|
||||
--luks-discard=yes \
|
||||
--image-path=/home-pool/test-user.home \
|
||||
--luks-pbkdf-type=pbkdf2 \
|
||||
|
||||
Reference in New Issue
Block a user