1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

Merge pull request #33092 from YHNdnzj/freezer-cleanup

UnitFreezer: several cleanups
This commit is contained in:
Mike Yuan 2024-07-17 23:45:32 +02:00 committed by GitHub
commit bbddfe5249
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 147 additions and 149 deletions

View File

@ -140,7 +140,9 @@ static const FreezerState freezer_state_finish_table[_FREEZER_STATE_MAX] = {
};
FreezerState freezer_state_finish(FreezerState state) {
assert(state >= 0 && state < _FREEZER_STATE_MAX);
assert(state >= 0);
assert(state < _FREEZER_STATE_MAX);
return freezer_state_finish_table[state];
}

View File

@ -4044,12 +4044,8 @@ static int unit_check_cgroup_events(Unit *u) {
/* Disregard freezer state changes due to operations not initiated by us.
* See: https://github.com/systemd/systemd/pull/13512/files#r416469963 and
* https://github.com/systemd/systemd/pull/13512#issuecomment-573007207 */
if (values[1] && IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_FREEZING_BY_PARENT, FREEZER_THAWING)) {
if (streq(values[1], "0"))
unit_thawed(u);
else
unit_frozen(u);
}
if (values[1] && IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_FREEZING_BY_PARENT, FREEZER_THAWING))
unit_freezer_complete(u, streq(values[1], "0") ? FREEZER_RUNNING : FREEZER_FROZEN);
free(values[0]);
free(values[1]);
@ -5106,35 +5102,35 @@ static int unit_cgroup_freezer_kernel_state(Unit *u, FreezerState *ret) {
int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
_cleanup_free_ char *path = NULL;
FreezerState target, current, next;
FreezerState current, next, objective;
int r;
assert(u);
assert(IN_SET(action, FREEZER_FREEZE, FREEZER_PARENT_FREEZE,
FREEZER_THAW, FREEZER_PARENT_THAW));
assert(action >= 0);
assert(action < _FREEZER_ACTION_MAX);
if (!cg_freezer_supported())
return 0;
unit_next_freezer_state(u, action, &next, &target);
unit_next_freezer_state(u, action, &next, &objective);
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
if (!crt || !crt->cgroup_path) {
if (!crt || !crt->cgroup_path)
/* No realized cgroup = nothing to freeze */
u->freezer_state = freezer_state_finish(next);
return 0;
}
goto skip;
r = unit_cgroup_freezer_kernel_state(u, &current);
if (r < 0)
return r;
if (current == target)
next = freezer_state_finish(next);
else if (IN_SET(next, FREEZER_FROZEN, FREEZER_FROZEN_BY_PARENT, FREEZER_RUNNING)) {
/* We're transitioning into a finished state, which implies that the cgroup's
* current state already matches the target and thus we'd return 0. But, reality
* shows otherwise. This indicates that our freezer_state tracking has diverged
if (current == objective)
goto skip;
if (next == freezer_state_finish(next)) {
/* We're directly transitioning into a finished state, which in theory means that
* the cgroup's current state already matches the objective and thus we'd return 0.
* But, reality shows otherwise (such case would have been handled by current == objective
* branch above). This indicates that our freezer_state tracking has diverged
* from the real state of the cgroup, which can happen if someone meddles with the
* cgroup from underneath us. This really shouldn't happen during normal operation,
* though. So, let's warn about it and fix up the state to be valid */
@ -5148,22 +5144,24 @@ int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
next = FREEZER_FREEZING_BY_PARENT;
else if (next == FREEZER_RUNNING)
next = FREEZER_THAWING;
else
assert_not_reached();
}
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, crt->cgroup_path, "cgroup.freeze", &path);
if (r < 0)
return r;
log_unit_debug(u, "Unit freezer state was %s, now %s.",
freezer_state_to_string(u->freezer_state),
freezer_state_to_string(next));
r = write_string_file(path, one_zero(target == FREEZER_FROZEN), WRITE_STRING_FILE_DISABLE_BUFFER);
r = write_string_file(path, one_zero(objective == FREEZER_FROZEN), WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return r;
u->freezer_state = next;
return target != current;
unit_set_freezer_state(u, next);
return 1; /* Wait for cgroup event before replying */
skip:
unit_set_freezer_state(u, freezer_state_finish(next));
return 0;
}
int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) {

View File

@ -60,7 +60,6 @@ typedef enum FreezerAction {
FREEZER_PARENT_FREEZE,
FREEZER_THAW,
FREEZER_PARENT_THAW,
_FREEZER_ACTION_MAX,
_FREEZER_ACTION_INVALID = -EINVAL,
} FreezerAction;
@ -514,6 +513,7 @@ void unit_cgroup_catchup(Unit *u);
bool unit_cgroup_delegate(Unit *u);
int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name);
int unit_cgroup_freezer_action(Unit *u, FreezerAction action);
const char* freezer_action_to_string(FreezerAction a) _const_;

View File

@ -34,9 +34,9 @@
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_collect_mode, collect_mode, CollectMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_freezer_state, freezer_state, FreezerState);
static BUS_DEFINE_PROPERTY_GET(property_get_description, "s", Unit, unit_description);
static BUS_DEFINE_PROPERTY_GET2(property_get_active_state, "s", Unit, unit_active_state, unit_active_state_to_string);
static BUS_DEFINE_PROPERTY_GET2(property_get_freezer_state, "s", Unit, unit_freezer_state, freezer_state_to_string);
static BUS_DEFINE_PROPERTY_GET(property_get_sub_state, "s", Unit, unit_sub_state_to_string);
static BUS_DEFINE_PROPERTY_GET2(property_get_unit_file_state, "s", Unit, unit_get_unit_file_state, unit_file_state_to_string);
static BUS_DEFINE_PROPERTY_GET(property_get_can_reload, "b", Unit, unit_can_reload);
@ -755,8 +755,8 @@ static int bus_unit_method_freezer_generic(sd_bus_message *message, void *userda
return sd_bus_error_set(error, BUS_ERROR_UNIT_INACTIVE, "Unit is not active");
if (r == -EALREADY)
return sd_bus_error_set(error, BUS_ERROR_UNIT_BUSY, "Previously requested freezer operation for unit is still in progress");
if (r == -ECHILD)
return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Unit is frozen by a parent slice");
if (r == -EDEADLK)
return sd_bus_error_set(error, BUS_ERROR_FROZEN_BY_PARENT, "Unit is frozen by a parent slice");
if (r < 0)
return r;
@ -864,7 +864,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("AccessSELinuxContext", "s", NULL, offsetof(Unit, access_selinux_context), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("FreezerState", "s", property_get_freezer_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("FreezerState", "s", property_get_freezer_state, offsetof(Unit, freezer_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
@ -1807,9 +1807,7 @@ int bus_unit_queue_job_one(
type = JOB_TRY_RELOAD;
}
if (type == JOB_STOP &&
IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR, UNIT_BAD_SETTING) &&
unit_active_state(u) == UNIT_INACTIVE)
if (type == JOB_STOP && UNIT_IS_LOAD_ERROR(u->load_state) && unit_active_state(u) == UNIT_INACTIVE)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
if ((type == JOB_START && u->refuse_manual_start) ||

View File

@ -339,32 +339,31 @@ static void slice_enumerate_perpetual(Manager *m) {
(void) slice_make_perpetual(m, SPECIAL_SYSTEM_SLICE, NULL);
}
static bool slice_can_freeze(Unit *s) {
static bool slice_can_freeze(const Unit *u) {
assert(u);
Unit *member;
assert(s);
UNIT_FOREACH_DEPENDENCY(member, s, UNIT_ATOM_SLICE_OF)
UNIT_FOREACH_DEPENDENCY(member, u, UNIT_ATOM_SLICE_OF)
if (!unit_can_freeze(member))
return false;
return true;
}
static int slice_freezer_action(Unit *s, FreezerAction action) {
FreezerAction child_action;
Unit *member;
int r;
assert(s);
assert(IN_SET(action, FREEZER_FREEZE, FREEZER_PARENT_FREEZE,
FREEZER_THAW, FREEZER_PARENT_THAW));
assert(action >= 0);
assert(action < _FREEZER_ACTION_MAX);
if (action == FREEZER_FREEZE && !slice_can_freeze(s)) {
/* We're intentionally only checking for FREEZER_FREEZE here and ignoring the
* _BY_PARENT variant. If we're being frozen by parent, that means someone has
* already checked if we can be frozen further up the call stack. No point to
* redo that work */
log_unit_warning(s, "Requested freezer operation is not supported by all children of the slice");
log_unit_warning(s, "Requested freezer operation is not supported by all children of the slice.");
return 0;
}
@ -375,15 +374,13 @@ static int slice_freezer_action(Unit *s, FreezerAction action) {
else
child_action = action;
UNIT_FOREACH_DEPENDENCY(member, s, UNIT_ATOM_SLICE_OF) {
if (UNIT_VTABLE(member)->freezer_action)
Unit *member;
UNIT_FOREACH_DEPENDENCY(member, s, UNIT_ATOM_SLICE_OF)
if (UNIT_VTABLE(member)->freezer_action) {
r = UNIT_VTABLE(member)->freezer_action(member, child_action);
else
/* Only thawing will reach here, since freezing checks for a method in can_freeze */
r = 0;
if (r < 0)
return r;
}
if (r < 0)
return r;
}
return unit_cgroup_freezer_action(s, action);
}

View File

@ -117,7 +117,8 @@ int unit_serialize_state(Unit *u, FILE *f, FDSet *fds, bool switching_root) {
if (!sd_id128_is_null(u->invocation_id))
(void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
(void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
(void) serialize_item(f, "freezer-state", freezer_state_to_string(u->freezer_state));
(void) serialize_markers(f, u->markers);
bus_track_serialize(u->bus_track, f, "ref");

View File

@ -864,12 +864,6 @@ Unit* unit_free(Unit *u) {
return mfree(u);
}
FreezerState unit_freezer_state(Unit *u) {
assert(u);
return u->freezer_state;
}
UnitActiveState unit_active_state(Unit *u) {
assert(u);
@ -6162,79 +6156,90 @@ bool unit_can_isolate_refuse_manual(Unit *u) {
return unit_can_isolate(u) && !u->refuse_manual_start;
}
void unit_next_freezer_state(Unit *u, FreezerAction action, FreezerState *ret, FreezerState *ret_target) {
Unit *slice;
FreezerState curr, parent, next, tgt;
void unit_next_freezer_state(Unit *u, FreezerAction action, FreezerState *ret_next, FreezerState *ret_objective) {
FreezerState current, parent, next, objective;
assert(u);
assert(IN_SET(action, FREEZER_FREEZE, FREEZER_PARENT_FREEZE,
FREEZER_THAW, FREEZER_PARENT_THAW));
assert(ret);
assert(ret_target);
assert(action >= 0);
assert(action < _FREEZER_ACTION_MAX);
assert(ret_next);
assert(ret_objective);
/* This function determines the correct freezer state transitions for a unit
* given the action being requested. It returns the next state, and also the "target",
* given the action being requested. It returns the next state, and also the "objective",
* which is either FREEZER_FROZEN or FREEZER_RUNNING, depending on what actual state we
* ultimately want to achieve. */
curr = u->freezer_state;
slice = UNIT_GET_SLICE(u);
if (slice)
current = u->freezer_state;
Unit *slice = UNIT_GET_SLICE(u);
if (slice)
parent = slice->freezer_state;
else
else
parent = FREEZER_RUNNING;
if (action == FREEZER_FREEZE) {
switch (action) {
case FREEZER_FREEZE:
/* We always "promote" a freeze initiated by parent into a normal freeze */
if (IN_SET(curr, FREEZER_FROZEN, FREEZER_FROZEN_BY_PARENT))
if (IN_SET(current, FREEZER_FROZEN, FREEZER_FROZEN_BY_PARENT))
next = FREEZER_FROZEN;
else
next = FREEZER_FREEZING;
} else if (action == FREEZER_THAW) {
break;
case FREEZER_THAW:
/* Thawing is the most complicated operation here, because we can't thaw a unit
* if its parent is frozen. So we instead "demote" a normal freeze into a freeze
* initiated by parent if the parent is frozen */
if (IN_SET(curr, FREEZER_RUNNING, FREEZER_THAWING, FREEZER_FREEZING_BY_PARENT, FREEZER_FROZEN_BY_PARENT))
next = curr;
else if (curr == FREEZER_FREEZING) {
if (IN_SET(current, FREEZER_RUNNING, FREEZER_THAWING,
FREEZER_FREEZING_BY_PARENT, FREEZER_FROZEN_BY_PARENT)) /* Should usually be refused by unit_freezer_action */
next = current;
else if (current == FREEZER_FREEZING) {
if (IN_SET(parent, FREEZER_RUNNING, FREEZER_THAWING))
next = FREEZER_THAWING;
else
next = FREEZER_FREEZING_BY_PARENT;
} else {
assert(curr == FREEZER_FROZEN);
} else if (current == FREEZER_FROZEN) {
if (IN_SET(parent, FREEZER_RUNNING, FREEZER_THAWING))
next = FREEZER_THAWING;
else
next = FREEZER_FROZEN_BY_PARENT;
}
} else if (action == FREEZER_PARENT_FREEZE) {
} else
assert_not_reached();
break;
case FREEZER_PARENT_FREEZE:
/* We need to avoid accidentally demoting units frozen manually */
if (IN_SET(curr, FREEZER_FREEZING, FREEZER_FROZEN, FREEZER_FROZEN_BY_PARENT))
next = curr;
if (IN_SET(current, FREEZER_FREEZING, FREEZER_FROZEN, FREEZER_FROZEN_BY_PARENT))
next = current;
else
next = FREEZER_FREEZING_BY_PARENT;
} else {
assert(action == FREEZER_PARENT_THAW);
break;
case FREEZER_PARENT_THAW:
/* We don't want to thaw units from a parent if they were frozen
* manually, so for such units this action is a no-op */
if (IN_SET(curr, FREEZER_RUNNING, FREEZER_FREEZING, FREEZER_FROZEN))
next = curr;
if (IN_SET(current, FREEZER_RUNNING, FREEZER_FREEZING, FREEZER_FROZEN))
next = current;
else
next = FREEZER_THAWING;
break;
default:
assert_not_reached();
}
tgt = freezer_state_finish(next);
if (tgt == FREEZER_FROZEN_BY_PARENT)
tgt = FREEZER_FROZEN;
assert(IN_SET(tgt, FREEZER_RUNNING, FREEZER_FROZEN));
objective = freezer_state_finish(next);
if (objective == FREEZER_FROZEN_BY_PARENT)
objective = FREEZER_FROZEN;
assert(IN_SET(objective, FREEZER_RUNNING, FREEZER_FROZEN));
*ret = next;
*ret_target = tgt;
*ret_next = next;
*ret_objective = objective;
}
bool unit_can_freeze(Unit *u) {
bool unit_can_freeze(const Unit *u) {
assert(u);
if (unit_has_name(u, SPECIAL_ROOT_SLICE) || unit_has_name(u, SPECIAL_INIT_SCOPE))
@ -6246,26 +6251,36 @@ bool unit_can_freeze(Unit *u) {
return UNIT_VTABLE(u)->freezer_action;
}
void unit_frozen(Unit *u) {
void unit_set_freezer_state(Unit *u, FreezerState state) {
assert(u);
assert(state >= 0);
assert(state < _FREEZER_STATE_MAX);
u->freezer_state = u->freezer_state == FREEZER_FREEZING_BY_PARENT
? FREEZER_FROZEN_BY_PARENT
: FREEZER_FROZEN;
if (u->freezer_state == state)
return;
log_unit_debug(u, "Unit now %s.", freezer_state_to_string(u->freezer_state));
log_unit_debug(u, "Freezer state changed %s -> %s",
freezer_state_to_string(u->freezer_state), freezer_state_to_string(state));
bus_unit_send_pending_freezer_message(u, false);
u->freezer_state = state;
unit_add_to_dbus_queue(u);
}
void unit_thawed(Unit *u) {
void unit_freezer_complete(Unit *u, FreezerState kernel_state) {
bool expected;
assert(u);
assert(IN_SET(kernel_state, FREEZER_RUNNING, FREEZER_FROZEN));
u->freezer_state = FREEZER_RUNNING;
expected = IN_SET(u->freezer_state, FREEZER_RUNNING, FREEZER_THAWING) == (kernel_state == FREEZER_RUNNING);
log_unit_debug(u, "Unit thawed.");
unit_set_freezer_state(u, expected ? freezer_state_finish(u->freezer_state) : kernel_state);
log_unit_info(u, "Unit now %s.", u->freezer_state == FREEZER_RUNNING ? "thawed" :
freezer_state_to_string(u->freezer_state));
bus_unit_send_pending_freezer_message(u, false);
/* If the cgroup's final state is against what's requested by us, report as canceled. */
bus_unit_send_pending_freezer_message(u, /* canceled = */ !expected);
}
int unit_freezer_action(Unit *u, FreezerAction action) {
@ -6293,7 +6308,7 @@ int unit_freezer_action(Unit *u, FreezerAction action) {
if (action == FREEZER_THAW && u->freezer_state == FREEZER_THAWING)
return -EALREADY;
if (action == FREEZER_THAW && IN_SET(u->freezer_state, FREEZER_FREEZING_BY_PARENT, FREEZER_FROZEN_BY_PARENT))
return -ECHILD;
return -EDEADLK;
r = UNIT_VTABLE(u)->freezer_action(u, action);
if (r <= 0)

View File

@ -577,7 +577,7 @@ typedef struct UnitVTable {
/* Freeze or thaw the unit. Returns > 0 to indicate that the request will be handled asynchronously; unit_frozen
* or unit_thawed should be called once the operation is done. Returns 0 if done successfully, or < 0 on error. */
int (*freezer_action)(Unit *u, FreezerAction a);
bool (*can_freeze)(Unit *u);
bool (*can_freeze)(const Unit *u);
/* Return which kind of data can be cleaned */
int (*can_clean)(Unit *u, ExecCleanMask *ret);
@ -849,7 +849,6 @@ const char* unit_status_string(Unit *u, char **combined);
bool unit_has_name(const Unit *u, const char *name);
UnitActiveState unit_active_state(Unit *u);
FreezerState unit_freezer_state(Unit *u);
const char* unit_sub_state_to_string(Unit *u);
@ -1037,11 +1036,11 @@ bool unit_can_start_refuse_manual(Unit *u);
bool unit_can_stop_refuse_manual(Unit *u);
bool unit_can_isolate_refuse_manual(Unit *u);
bool unit_can_freeze(Unit *u);
bool unit_can_freeze(const Unit *u);
int unit_freezer_action(Unit *u, FreezerAction action);
void unit_next_freezer_state(Unit *u, FreezerAction a, FreezerState *ret, FreezerState *ret_tgt);
void unit_frozen(Unit *u);
void unit_thawed(Unit *u);
void unit_next_freezer_state(Unit *u, FreezerAction action, FreezerState *ret_next, FreezerState *ret_objective);
void unit_set_freezer_state(Unit *u, FreezerState state);
void unit_freezer_complete(Unit *u, FreezerState kernel_state);
Condition *unit_find_failed_condition(Unit *u);

View File

@ -1870,7 +1870,7 @@ static int home_inspect(UserRecord *h, UserRecord **ret_home) {
return 1;
}
static int user_session_freezer(uid_t uid, bool freeze_now, UnitFreezer **ret) {
static int user_session_freezer_new(uid_t uid, UnitFreezer **ret) {
_cleanup_free_ char *unit = NULL;
int r;
@ -1881,10 +1881,6 @@ static int user_session_freezer(uid_t uid, bool freeze_now, UnitFreezer **ret) {
if (r < 0 && r != -ENXIO)
log_warning_errno(r, "Cannot parse value of $SYSTEMD_HOME_LOCK_FREEZE_SESSION, ignoring: %m");
else if (r == 0) {
if (freeze_now)
log_notice("Session remains unfrozen on explicit request ($SYSTEMD_HOME_LOCK_FREEZE_SESSION=0).\n"
"This is not recommended, and might result in unexpected behavior including data loss!");
*ret = NULL;
return 0;
}
@ -1892,10 +1888,7 @@ static int user_session_freezer(uid_t uid, bool freeze_now, UnitFreezer **ret) {
if (asprintf(&unit, "user-" UID_FMT ".slice", uid) < 0)
return log_oom();
if (freeze_now)
r = unit_freezer_new_freeze(unit, ret);
else
r = unit_freezer_new(unit, ret);
r = unit_freezer_new(unit, ret);
if (r < 0)
return r;
@ -1921,9 +1914,16 @@ static int home_lock(UserRecord *h) {
_cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
r = user_session_freezer(h->uid, /* freeze_now= */ true, &f);
r = user_session_freezer_new(h->uid, &f);
if (r < 0)
return r;
if (r > 0) {
r = unit_freezer_freeze(f);
if (r < 0)
return r;
} else
log_notice("Session remains unfrozen on explicit request ($SYSTEMD_HOME_LOCK_FREEZE_SESSION=0).\n"
"This is not recommended, and might result in unexpected behavior including data loss!");
r = home_lock_luks(h, &setup);
if (r < 0) {
@ -1966,7 +1966,7 @@ static int home_unlock(UserRecord *h) {
_cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
/* We want to thaw the session only after it's safe to access $HOME */
r = user_session_freezer(h->uid, /* freeze_now= */ false, &f);
r = user_session_freezer_new(h->uid, &f);
if (r > 0)
r = unit_freezer_thaw(f);
if (r < 0)

View File

@ -34,6 +34,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_DISK_FULL, ENOSPC),
SD_BUS_ERROR_MAP(BUS_ERROR_FILE_DESCRIPTOR_STORE_DISABLED,
EHOSTDOWN),
SD_BUS_ERROR_MAP(BUS_ERROR_FROZEN_BY_PARENT, EDEADLK),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_MACHINE, ENXIO),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_IMAGE, ENOENT),

View File

@ -34,6 +34,7 @@
#define BUS_ERROR_FREEZE_CANCELLED "org.freedesktop.systemd1.FreezeCancelled"
#define BUS_ERROR_FILE_DESCRIPTOR_STORE_DISABLED \
"org.freedesktop.systemd1.FileDescriptorStoreDisabled"
#define BUS_ERROR_FROZEN_BY_PARENT "org.freedesktop.systemd1.FrozenByParent"
#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine"
#define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage"

View File

@ -3025,22 +3025,3 @@ int unit_freezer_freeze(UnitFreezer *f) {
int unit_freezer_thaw(UnitFreezer *f) {
return unit_freezer_action(f, false);
}
int unit_freezer_new_freeze(const char *name, UnitFreezer **ret) {
_cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
int r;
assert(name);
assert(ret);
r = unit_freezer_new(name, &f);
if (r < 0)
return r;
r = unit_freezer_freeze(f);
if (r < 0)
return r;
*ret = TAKE_PTR(f);
return 0;
}

View File

@ -45,5 +45,3 @@ int unit_freezer_new(const char *name, UnitFreezer **ret);
int unit_freezer_freeze(UnitFreezer *f);
int unit_freezer_thaw(UnitFreezer *f);
int unit_freezer_new_freeze(const char *name, UnitFreezer **ret);

View File

@ -603,10 +603,14 @@ static int run(int argc, char *argv[]) {
/* Freeze the user sessions */
r = getenv_bool("SYSTEMD_SLEEP_FREEZE_USER_SESSIONS");
if (r < 0 && r != -ENXIO)
log_warning_errno(r, "Cannot parse value of $SYSTEMD_SLEEP_FREEZE_USER_SESSIONS, ignoring.");
if (r != 0)
(void) unit_freezer_new_freeze(SPECIAL_USER_SLICE, &user_slice_freezer);
else
log_warning_errno(r, "Cannot parse value of $SYSTEMD_SLEEP_FREEZE_USER_SESSIONS, ignoring: %m");
if (r != 0) {
r = unit_freezer_new(SPECIAL_USER_SLICE, &user_slice_freezer);
if (r < 0)
return r;
(void) unit_freezer_freeze(user_slice_freezer);
} else
log_notice("User sessions remain unfrozen on explicit request ($SYSTEMD_SLEEP_FREEZE_USER_SESSIONS=0).\n"
"This is not recommended, and might result in unexpected behavior, particularly\n"
"in suspend-then-hibernate operations or setups with encrypted home directories.");
@ -631,10 +635,13 @@ static int run(int argc, char *argv[]) {
break;
default:
case SLEEP_SUSPEND:
case SLEEP_HIBERNATE:
r = execute(sleep_config, arg_operation, NULL);
break;
default:
assert_not_reached();
}
if (user_slice_freezer)