Skip to content

Commit d357b80

Browse files
committed
homed: add automatic grow/shrink ("rebalancing")
1 parent 21505c9 commit d357b80

File tree

11 files changed

+668
-14
lines changed

11 files changed

+668
-14
lines changed

meson.build

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2387,7 +2387,8 @@ if conf.get('ENABLE_HOMED') == 1
23872387
link_with : [libshared],
23882388
dependencies : [threads,
23892389
libcrypt,
2390-
libopenssl],
2390+
libopenssl,
2391+
libm],
23912392
install_rpath : rootlibexecdir,
23922393
install : true,
23932394
install_dir : rootlibexecdir)

src/home/home-util.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,13 @@
1616
#define USER_DISK_SIZE_MIN (UINT64_C(5)*1024*1024)
1717
#define USER_DISK_SIZE_MAX (UINT64_C(5)*1024*1024*1024*1024)
1818

19-
/* The default disk size to use when nothing else is specified, relative to free disk space */
20-
#define USER_DISK_SIZE_DEFAULT_PERCENT 85
19+
/* The default disk size to use when nothing else is specified, relative to free disk space. We calculate
20+
* this from the default rebalancing weights, so that what we create initially doesn't immediately require
21+
* rebalancing. */
22+
#define USER_DISK_SIZE_DEFAULT_PERCENT ((unsigned) ((100 * REBALANCE_WEIGHT_DEFAULT) / (REBALANCE_WEIGHT_DEFAULT + REBALANCE_WEIGHT_BACKING)))
23+
24+
/* This should be 83% right now, i.e. 100 of (100 + 20). Let's protect us against accidental changes. */
25+
assert_cc(USER_DISK_SIZE_DEFAULT_PERCENT == 83U);
2126

2227
bool suitable_user_name(const char *name);
2328
int suitable_realm(const char *realm);

src/home/homed-home-bus.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ int bus_home_method_resize(
485485
if (r == 0)
486486
return 1; /* Will call us back */
487487

488-
r = home_resize(h, sz, secret, error);
488+
r = home_resize(h, sz, secret, /* automatic= */ false, error);
489489
if (r < 0)
490490
return r;
491491

src/home/homed-home.c

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ int home_new(Manager *m, UserRecord *hr, const char *sysfs, Home **ret) {
161161

162162
(void) bus_manager_emit_auto_login_changed(m);
163163
(void) bus_home_emit_change(home);
164+
(void) manager_schedule_rebalance(m, /* immediately= */ false);
164165

165166
if (ret)
166167
*ret = TAKE_PTR(home);
@@ -193,6 +194,8 @@ Home *home_free(Home *h) {
193194

194195
if (h->manager->gc_focus == h)
195196
h->manager->gc_focus = NULL;
197+
198+
(void) manager_schedule_rebalance(h->manager, /* immediately= */ false);
196199
}
197200

198201
user_record_unref(h->record);
@@ -489,6 +492,7 @@ static void home_set_state(Home *h, HomeState state) {
489492
* enqueue it for GC too. */
490493

491494
home_schedule_operation(h, NULL, NULL);
495+
manager_reschedule_rebalance(h->manager);
492496
manager_enqueue_gc(h->manager, h);
493497
}
494498
}
@@ -727,6 +731,7 @@ static void home_fixate_finish(Home *h, int ret, UserRecord *hr) {
727731
/* Reset the state to "invalid", which makes home_get_state() test if the image exists and returns
728732
* HOME_ABSENT vs. HOME_INACTIVE as necessary. */
729733
home_set_state(h, _HOME_STATE_INVALID);
734+
(void) manager_schedule_rebalance(h->manager, /* immediately= */ false);
730735
return;
731736

732737
fail:
@@ -781,6 +786,9 @@ static void home_activate_finish(Home *h, int ret, UserRecord *hr) {
781786
finish:
782787
h->current_operation = operation_result_unref(h->current_operation, r, &error);
783788
home_set_state(h, _HOME_STATE_INVALID);
789+
790+
if (r >= 0)
791+
(void) manager_schedule_rebalance(h->manager, /* immediately= */ true);
784792
}
785793

786794
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) {
803811
finish:
804812
h->current_operation = operation_result_unref(h->current_operation, r, &error);
805813
home_set_state(h, _HOME_STATE_INVALID);
814+
815+
if (r >= 0)
816+
(void) manager_schedule_rebalance(h->manager, /* immediately= */ true);
806817
}
807818

808819
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) {
841852

842853
/* Unload this record from memory too now. */
843854
h = home_free(h);
855+
856+
(void) manager_schedule_rebalance(m, /* immediately= */ true);
844857
return;
845858

846859
fail:
@@ -885,6 +898,8 @@ static void home_create_finish(Home *h, int ret, UserRecord *hr) {
885898

886899
h->current_operation = operation_result_unref(h->current_operation, 0, NULL);
887900
home_set_state(h, _HOME_STATE_INVALID);
901+
902+
(void) manager_schedule_rebalance(h->manager, /* immediately= */ true);
888903
}
889904

890905
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) {
918933
}
919934

920935
log_debug("Change operation of %s completed.", h->user_name);
936+
(void) manager_schedule_rebalance(h->manager, /* immediately= */ false);
921937
r = 0;
922938

923939
finish:
@@ -1683,7 +1699,12 @@ int home_update(Home *h, UserRecord *hr, sd_bus_error *error) {
16831699
return 0;
16841700
}
16851701

1686-
int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *error) {
1702+
int home_resize(Home *h,
1703+
uint64_t disk_size,
1704+
UserRecord *secret,
1705+
bool automatic,
1706+
sd_bus_error *error) {
1707+
16871708
_cleanup_(user_record_unrefp) UserRecord *c = NULL;
16881709
HomeState state;
16891710
int r;
@@ -1711,6 +1732,12 @@ int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *e
17111732
if (r < 0)
17121733
return r;
17131734

1735+
/* If the user didn't specify any size explicitly and rebalancing is on, then the disk size is
1736+
* determined by automatic rebalancing and hence not user configured but determined by us and thus
1737+
* applied anyway. */
1738+
if (disk_size == UINT64_MAX && h->record->rebalance_weight != REBALANCE_WEIGHT_OFF)
1739+
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Disk size is being determined by automatic disk space rebalancing.");
1740+
17141741
if (disk_size == UINT64_MAX || disk_size == h->record->disk_size) {
17151742
if (h->record->disk_size == UINT64_MAX)
17161743
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
17321759
if (r < 0)
17331760
return r;
17341761

1762+
/* If user picked an explicit size, then turn off rebalancing, so that we don't undo what user chose */
1763+
r = user_record_set_rebalance_weight(c, REBALANCE_WEIGHT_OFF);
1764+
if (r < 0)
1765+
return r;
1766+
17351767
r = user_record_update_last_changed(c, false);
17361768
if (r == -ECHRNG)
17371769
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
17461778
c = TAKE_PTR(signed_c);
17471779
}
17481780

1749-
r = home_update_internal(h, "resize", c, secret, error);
1781+
r = home_update_internal(h, automatic ? "resize-auto" : "resize", c, secret, error);
17501782
if (r < 0)
17511783
return r;
17521784

@@ -2965,6 +2997,8 @@ static int on_pending(sd_event_source *s, void *userdata) {
29652997
if (r < 0)
29662998
return log_error_errno(r, "Failed to disable event source: %m");
29672999

3000+
/* No operations pending anymore, maybe this is a good time to trigger a rebalancing */
3001+
manager_reschedule_rebalance(h->manager);
29683002
return 0;
29693003
}
29703004

@@ -3121,6 +3155,35 @@ int home_wait_for_worker(Home *h) {
31213155
return 1;
31223156
}
31233157

3158+
bool home_shall_rebalance(Home *h) {
3159+
HomeState state;
3160+
3161+
assert(h);
3162+
3163+
/* Determines if the home directory is a candidate for rebalancing */
3164+
3165+
if (!user_record_shall_rebalance(h->record))
3166+
return false;
3167+
3168+
state = home_get_state(h);
3169+
if (!HOME_STATE_SHALL_REBALANCE(state))
3170+
return false;
3171+
3172+
return true;
3173+
}
3174+
3175+
bool home_is_busy(Home *h) {
3176+
assert(h);
3177+
3178+
if (h->current_operation)
3179+
return true;
3180+
3181+
if (!ordered_set_isempty(h->pending_operations))
3182+
return true;
3183+
3184+
return HOME_STATE_IS_EXECUTING_OPERATION(home_get_state(h));
3185+
}
3186+
31243187
static const char* const home_state_table[_HOME_STATE_MAX] = {
31253188
[HOME_UNFIXATED] = "unfixated",
31263189
[HOME_ABSENT] = "absent",

src/home/homed-home.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ static inline bool HOME_STATE_SHALL_PIN(HomeState state) {
8888
HOME_AUTHENTICATING_FOR_ACQUIRE);
8989
}
9090

91+
#define HOME_STATE_SHALL_REBALANCE(state) HOME_STATE_SHALL_PIN(state)
92+
9193
static inline bool HOME_STATE_MAY_RETRY_DEACTIVATE(HomeState state) {
9294
/* Indicates when to leave the deactivate retry timer active */
9395
return IN_SET(state,
@@ -165,6 +167,12 @@ struct Home {
165167

166168
/* An fd that locks the backing file of LUKS home dirs with a BSD lock. */
167169
int luks_lock_fd;
170+
171+
/* Space metrics during rebalancing */
172+
uint64_t rebalance_size, rebalance_usage, rebalance_free, rebalance_min, rebalance_weight, rebalance_goal;
173+
174+
/* Whether a rebalance operation is pending */
175+
bool rebalance_pending;
168176
};
169177

170178
int home_new(Manager *m, UserRecord *hr, const char *sysfs, Home **ret);
@@ -183,7 +191,7 @@ int home_deactivate(Home *h, bool force, sd_bus_error *error);
183191
int home_create(Home *h, UserRecord *secret, sd_bus_error *error);
184192
int home_remove(Home *h, sd_bus_error *error);
185193
int home_update(Home *h, UserRecord *new_record, sd_bus_error *error);
186-
int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *error);
194+
int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, bool automatic, sd_bus_error *error);
187195
int home_passwd(Home *h, UserRecord *new_secret, UserRecord *old_secret, sd_bus_error *error);
188196
int home_unregister(Home *h, sd_bus_error *error);
189197
int home_lock(Home *h, sd_bus_error *error);
@@ -208,5 +216,9 @@ int home_set_current_message(Home *h, sd_bus_message *m);
208216

209217
int home_wait_for_worker(Home *h);
210218

219+
bool home_shall_rebalance(Home *h);
220+
221+
bool home_is_busy(Home *h);
222+
211223
const char *home_state_to_string(HomeState state);
212224
HomeState home_state_from_string(const char *s);

0 commit comments

Comments
 (0)