`shrink-and-grown` the home area is also shrunk to the minimal size possible
(as dictated by used disk space and file system constraints) on logout.
+`rebalanceWeight` → An unsigned integer, `null` or a boolean. Configures the
+free disk space rebalancing weight for the home area. The integer must be in
+the range 1…10000 to configure an explicit weight. If unset, or set to `null`
+or `true` the default weight of 100 is implied. If set to 0 or `false`
+rebalancing is turned off for this home area.
+
`service` → A string declaring the service that defines or manages this user
record. It is recommended to use reverse domain name notation for this. For
example, if `systemd-homed` manages a user a string of `io.systemd.Home` is
`fileSystemUuid`, `luksDiscard`, `luksOfflineDiscard`, `luksCipher`,
`luksCipherMode`, `luksVolumeKeySize`, `luksPbkdfHashAlgorithm`,
`luksPbkdfType`, `luksPbkdfTimeCostUSec`, `luksPbkdfMemoryCost`,
-`luksPbkdfParallelThreads`, `rateLimitIntervalUSec`, `rateLimitBurst`,
-`enforcePasswordPolicy`, `autoLogin`, `stopDelayUSec`, `killProcesses`,
-`passwordChangeMinUSec`, `passwordChangeMaxUSec`, `passwordChangeWarnUSec`,
+`luksPbkdfParallelThreads`, `autoResizeMode`, `rebalanceWeight`,
+`rateLimitIntervalUSec`, `rateLimitBurst`, `enforcePasswordPolicy`,
+`autoLogin`, `stopDelayUSec`, `killProcesses`, `passwordChangeMinUSec`,
+`passwordChangeMaxUSec`, `passwordChangeWarnUSec`,
`passwordChangeInactiveUSec`, `passwordChangeNow`, `pkcs11TokenUri`,
`fido2HmacCredential`.
.fido2_user_verification_permitted = -1,
.drop_caches = -1,
.auto_resize_mode = _AUTO_RESIZE_MODE_INVALID,
+ .rebalance_weight = REBALANCE_WEIGHT_UNSET,
};
return h;
return 0;
}
+static int dispatch_rebalance_weight(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
+ uint64_t *rebalance_weight = userdata;
+ uintmax_t u;
+
+ assert_se(rebalance_weight);
+
+ if (json_variant_is_null(variant)) {
+ *rebalance_weight = REBALANCE_WEIGHT_UNSET;
+ return 0;
+ }
+
+ if (json_variant_is_boolean(variant)) {
+ *rebalance_weight = json_variant_boolean(variant) ? REBALANCE_WEIGHT_DEFAULT : REBALANCE_WEIGHT_OFF;
+ return 0;
+ }
+
+ if (!json_variant_is_unsigned(variant))
+ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an unsigned integer, boolean or null.", strna(name));
+
+ u = json_variant_unsigned(variant);
+ if (u >= REBALANCE_WEIGHT_MIN && u <= REBALANCE_WEIGHT_MAX)
+ *rebalance_weight = (uint64_t) u;
+ else if (u == 0)
+ *rebalance_weight = REBALANCE_WEIGHT_OFF;
+ else
+ return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "Rebalance weight is out of valid range %" PRIu64 "…%" PRIu64 ".", REBALANCE_WEIGHT_MIN, REBALANCE_WEIGHT_MAX);
+
+ return 0;
+}
+
static int dispatch_privileged(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
static const JsonDispatch privileged_dispatch_table[] = {
{ "luksExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_extra_mount_options), 0 },
{ "dropCaches", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, drop_caches), 0 },
{ "autoResizeMode", _JSON_VARIANT_TYPE_INVALID, dispatch_auto_resize_mode, offsetof(UserRecord, auto_resize_mode), 0 },
+ { "rebalanceWeight", _JSON_VARIANT_TYPE_INVALID, dispatch_rebalance_weight, offsetof(UserRecord, rebalance_weight), 0 },
{ "rateLimitIntervalUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_interval_usec), 0 },
{ "rateLimitBurst", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_burst), 0 },
{ "enforcePasswordPolicy", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, enforce_password_policy), 0 },
{ "luksExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_extra_mount_options), 0 },
{ "dropCaches", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, drop_caches), 0 },
{ "autoResizeMode", _JSON_VARIANT_TYPE_INVALID, dispatch_auto_resize_mode, offsetof(UserRecord, auto_resize_mode), 0 },
+ { "rebalanceWeight", _JSON_VARIANT_TYPE_INVALID, dispatch_rebalance_weight, offsetof(UserRecord, rebalance_weight), 0 },
{ "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
{ "rateLimitIntervalUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_interval_usec), 0 },
{ "rateLimitBurst", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_burst), 0 },
return user_record_storage(h) == USER_LUKS ? AUTO_RESIZE_SHRINK_AND_GROW : AUTO_RESIZE_OFF;
}
+uint64_t user_record_rebalance_weight(UserRecord *h) {
+ assert(h);
+
+ if (h->rebalance_weight == REBALANCE_WEIGHT_UNSET)
+ return REBALANCE_WEIGHT_DEFAULT;
+
+ return h->rebalance_weight;
+}
+
uint64_t user_record_ratelimit_next_try(UserRecord *h) {
assert(h);
_AUTO_RESIZE_MODE_INVALID = -EINVAL,
} AutoResizeMode;
+#define REBALANCE_WEIGHT_OFF UINT64_C(0)
+#define REBALANCE_WEIGHT_DEFAULT UINT64_C(100)
+#define REBALANCE_WEIGHT_MIN UINT64_C(1)
+#define REBALANCE_WEIGHT_MAX UINT64_C(10000)
+#define REBALANCE_WEIGHT_UNSET UINT64_MAX
+
typedef struct UserRecord {
/* The following three fields are not part of the JSON record */
unsigned n_ref;
char *skeleton_directory;
mode_t access_mode;
AutoResizeMode auto_resize_mode;
+ uint64_t rebalance_weight;
uint64_t tasks_max;
uint64_t memory_high;
bool user_record_can_authenticate(UserRecord *h);
bool user_record_drop_caches(UserRecord *h);
AutoResizeMode user_record_auto_resize_mode(UserRecord *h);
+uint64_t user_record_rebalance_weight(UserRecord *h);
int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret);