diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-11-02 23:11:59 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-11-25 18:28:44 +0100 |
commit | d357b80d331ebed709b7a9d71e014c319ba5bd79 (patch) | |
tree | 8b063226969c9f982f8d7baff2b849c67c8568ae /src/home/homed-home.c | |
parent | 21505c937ce3bcb90aae85366a262462ec8fb6b2 (diff) | |
download | systemd-d357b80d331ebed709b7a9d71e014c319ba5bd79.tar.gz |
homed: add automatic grow/shrink ("rebalancing")
Diffstat (limited to 'src/home/homed-home.c')
-rw-r--r-- | src/home/homed-home.c | 67 |
1 files changed, 65 insertions, 2 deletions
diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 2cc1f8b384..470c7f07f6 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -161,6 +161,7 @@ int home_new(Manager *m, UserRecord *hr, const char *sysfs, Home **ret) { (void) bus_manager_emit_auto_login_changed(m); (void) bus_home_emit_change(home); + (void) manager_schedule_rebalance(m, /* immediately= */ false); if (ret) *ret = TAKE_PTR(home); @@ -193,6 +194,8 @@ Home *home_free(Home *h) { if (h->manager->gc_focus == h) h->manager->gc_focus = NULL; + + (void) manager_schedule_rebalance(h->manager, /* immediately= */ false); } user_record_unref(h->record); @@ -489,6 +492,7 @@ static void home_set_state(Home *h, HomeState state) { * enqueue it for GC too. */ home_schedule_operation(h, NULL, NULL); + manager_reschedule_rebalance(h->manager); manager_enqueue_gc(h->manager, h); } } @@ -727,6 +731,7 @@ static void home_fixate_finish(Home *h, int ret, UserRecord *hr) { /* Reset the state to "invalid", which makes home_get_state() test if the image exists and returns * HOME_ABSENT vs. HOME_INACTIVE as necessary. */ home_set_state(h, _HOME_STATE_INVALID); + (void) manager_schedule_rebalance(h->manager, /* immediately= */ false); return; fail: @@ -781,6 +786,9 @@ static void home_activate_finish(Home *h, int ret, UserRecord *hr) { finish: h->current_operation = operation_result_unref(h->current_operation, r, &error); home_set_state(h, _HOME_STATE_INVALID); + + if (r >= 0) + (void) manager_schedule_rebalance(h->manager, /* immediately= */ true); } static void home_deactivate_finish(Home *h, int ret, UserRecord *hr) { @@ -803,6 +811,9 @@ static void home_deactivate_finish(Home *h, int ret, UserRecord *hr) { finish: h->current_operation = operation_result_unref(h->current_operation, r, &error); home_set_state(h, _HOME_STATE_INVALID); + + if (r >= 0) + (void) manager_schedule_rebalance(h->manager, /* immediately= */ true); } static void home_remove_finish(Home *h, int ret, UserRecord *hr) { @@ -841,6 +852,8 @@ static void home_remove_finish(Home *h, int ret, UserRecord *hr) { /* Unload this record from memory too now. */ h = home_free(h); + + (void) manager_schedule_rebalance(m, /* immediately= */ true); return; fail: @@ -885,6 +898,8 @@ static void home_create_finish(Home *h, int ret, UserRecord *hr) { h->current_operation = operation_result_unref(h->current_operation, 0, NULL); home_set_state(h, _HOME_STATE_INVALID); + + (void) manager_schedule_rebalance(h->manager, /* immediately= */ true); } static void home_change_finish(Home *h, int ret, UserRecord *hr) { @@ -918,6 +933,7 @@ static void home_change_finish(Home *h, int ret, UserRecord *hr) { } log_debug("Change operation of %s completed.", h->user_name); + (void) manager_schedule_rebalance(h->manager, /* immediately= */ false); r = 0; finish: @@ -1683,7 +1699,12 @@ int home_update(Home *h, UserRecord *hr, sd_bus_error *error) { return 0; } -int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *error) { +int home_resize(Home *h, + uint64_t disk_size, + UserRecord *secret, + bool automatic, + sd_bus_error *error) { + _cleanup_(user_record_unrefp) UserRecord *c = NULL; HomeState state; int r; @@ -1711,6 +1732,12 @@ int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *e if (r < 0) return r; + /* If the user didn't specify any size explicitly and rebalancing is on, then the disk size is + * determined by automatic rebalancing and hence not user configured but determined by us and thus + * applied anyway. */ + if (disk_size == UINT64_MAX && h->record->rebalance_weight != REBALANCE_WEIGHT_OFF) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Disk size is being determined by automatic disk space rebalancing."); + if (disk_size == UINT64_MAX || disk_size == h->record->disk_size) { if (h->record->disk_size == UINT64_MAX) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "No disk size to resize to specified."); @@ -1732,6 +1759,11 @@ int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *e if (r < 0) return r; + /* If user picked an explicit size, then turn off rebalancing, so that we don't undo what user chose */ + r = user_record_set_rebalance_weight(c, REBALANCE_WEIGHT_OFF); + if (r < 0) + return r; + r = user_record_update_last_changed(c, false); if (r == -ECHRNG) return sd_bus_error_setf(error, BUS_ERROR_HOME_RECORD_MISMATCH, "Record last change time of %s is newer than current time, cannot update.", h->user_name); @@ -1746,7 +1778,7 @@ int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *e c = TAKE_PTR(signed_c); } - r = home_update_internal(h, "resize", c, secret, error); + r = home_update_internal(h, automatic ? "resize-auto" : "resize", c, secret, error); if (r < 0) return r; @@ -2965,6 +2997,8 @@ static int on_pending(sd_event_source *s, void *userdata) { if (r < 0) return log_error_errno(r, "Failed to disable event source: %m"); + /* No operations pending anymore, maybe this is a good time to trigger a rebalancing */ + manager_reschedule_rebalance(h->manager); return 0; } @@ -3121,6 +3155,35 @@ int home_wait_for_worker(Home *h) { return 1; } +bool home_shall_rebalance(Home *h) { + HomeState state; + + assert(h); + + /* Determines if the home directory is a candidate for rebalancing */ + + if (!user_record_shall_rebalance(h->record)) + return false; + + state = home_get_state(h); + if (!HOME_STATE_SHALL_REBALANCE(state)) + return false; + + return true; +} + +bool home_is_busy(Home *h) { + assert(h); + + if (h->current_operation) + return true; + + if (!ordered_set_isempty(h->pending_operations)) + return true; + + return HOME_STATE_IS_EXECUTING_OPERATION(home_get_state(h)); +} + static const char* const home_state_table[_HOME_STATE_MAX] = { [HOME_UNFIXATED] = "unfixated", [HOME_ABSENT] = "absent", |