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.
+
+
BOOLBOOL
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;