diff --git a/man/homectl.xml b/man/homectl.xml index 5ba93bbe136..ca9225a1e0d 100644 --- a/man/homectl.xml +++ b/man/homectl.xml @@ -376,8 +376,8 @@ Note that FIDO2 devices suitable for this option must implement the hmac-secret extension. Most current devices (such as the YubiKey 5 series) do. If the extension is not implemented the device cannot be used for unlocking home directories. - - The FIDO2 device may be subsequently removed by setting the device path to an empty string + + The FIDO2 device may be subsequently removed by setting the device path to an empty string (e.g. homectl update $USER --fido2-device=""). Note that many hardware security tokens implement both FIDO2 and PKCS#11/PIV (and thus may be @@ -706,6 +706,24 @@ again. + + + + Configures the weight parameter for the free disk space rebalancing logic. Only + applies to the LUKS2 backend (since for the LUKS2 backend disk space is allocated from a per-user + loopback file system instead of immediately from a common pool like the other backends do it). In + regular intervals free disk space in the active home areas and their backing storage is redistributed + among them, taking the weight value configured here into account. Expects an integer in the range + 1…10000, or the special string off. If not specified defaults to 100. The weight + is used to scale free space made available to the home areas: a home area with a weight of 200 will + get twice the free space as one with a weight of 100; a home area with a weight of 50 will get half + of that. The backing file system will be assigned space for a weight of 20. If set to + off no automatic free space distribution is done for this home area. Note that + resizing the home area explicitly (with homectl resize see below) will implicitly + turn off the automatic rebalancing. To reenable the automatic rebalancing use + with an empty parameter. + + BOOL BOOL diff --git a/src/home/homectl.c b/src/home/homectl.c index 706ce75dfb0..0c69299c84f 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -2270,6 +2270,7 @@ static int help(int argc, char *argv[], void *userdata) { " --luks-extra-mount-options=OPTIONS\n" " LUKS extra mount options\n" " --auto-resize-mode=MODE Automatically grow/shrink home on login/logout\n" + " --rebalance-weight=WEIGHT Weight while rebalancing\n" "\n%4$sMounting User Record Properties:%5$s\n" " --nosuid=BOOL Control the 'nosuid' flag of the home mount\n" " --nodev=BOOL Control the 'nodev' flag of the home mount\n" @@ -2370,6 +2371,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_DROP_CACHES, ARG_LUKS_EXTRA_MOUNT_OPTIONS, ARG_AUTO_RESIZE_MODE, + ARG_REBALANCE_WEIGHT, }; static const struct option options[] = { @@ -2456,6 +2458,7 @@ static int parse_argv(int argc, char *argv[]) { { "drop-caches", required_argument, NULL, ARG_DROP_CACHES }, { "luks-extra-mount-options", required_argument, NULL, ARG_LUKS_EXTRA_MOUNT_OPTIONS }, { "auto-resize-mode", required_argument, NULL, ARG_AUTO_RESIZE_MODE }, + { "rebalance-weight", required_argument, NULL, ARG_REBALANCE_WEIGHT }, {} }; @@ -2931,13 +2934,13 @@ static int parse_argv(int argc, char *argv[]) { case ARG_DISK_SIZE: if (isempty(optarg)) { - r = drop_from_identity("diskSize"); - if (r < 0) - return r; + const char *prop; - r = drop_from_identity("diskSizeRelative"); - if (r < 0) - return r; + FOREACH_STRING(prop, "diskSize", "diskSizeRelative", "rebalanceWeight") { + r = drop_from_identity(prop); + if (r < 0) + return r; + } arg_disk_size = arg_disk_size_relative = UINT64_MAX; break; @@ -2973,6 +2976,11 @@ static int parse_argv(int argc, char *argv[]) { arg_disk_size = UINT64_MAX; } + /* Automatically turn off the rebalance logic if user configured a size explicitly */ + r = json_variant_set_field_unsigned(&arg_identity_extra_this_machine, "rebalanceWeight", REBALANCE_WEIGHT_OFF); + if (r < 0) + return log_error_errno(r, "Failed to set rebalanceWeight field: %m"); + break; case ARG_ACCESS_MODE: { @@ -3571,6 +3579,40 @@ static int parse_argv(int argc, char *argv[]) { break; + case ARG_REBALANCE_WEIGHT: { + uint64_t u; + + if (isempty(optarg)) { + r = drop_from_identity("rebalanceWeight"); + if (r < 0) + return r; + } + + if (streq(optarg, "off")) + u = REBALANCE_WEIGHT_OFF; + else { + r = safe_atou64(optarg, &u); + if (r < 0) + return log_error_errno(r, "Failed to parse --rebalance-weight= argument: %s", optarg); + + if (u < REBALANCE_WEIGHT_MIN || u > REBALANCE_WEIGHT_MAX) + return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Rebalancing weight out of valid range %" PRIu64 "…%" PRIu64 ": %s", + REBALANCE_WEIGHT_MIN, REBALANCE_WEIGHT_MAX, optarg); + } + + /* Drop from per machine stuff and everywhere */ + r = drop_from_identity("rebalanceWeight"); + if (r < 0) + return r; + + /* Add to main identity */ + r = json_variant_set_field_unsigned(&arg_identity_extra, "rebalanceWeight", u); + if (r < 0) + return log_error_errno(r, "Failed to set rebalanceWeight field: %m"); + + break; + } + case 'j': arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO; break;