Skip to content

Commit e8a565c

Browse files
committed
core: make ExecRuntime be manager managed object
Before this, each ExecRuntime object is owned by a unit. However, it may be shared with other units which enable JoinsNamespaceOf=. Thus, by the serialization/deserialization process, its sharing information, more specifically, reference counter is lost, and causes issue #7790. This makes ExecRuntime objects be managed by manager, and changes the serialization/deserialization process. Fixes #7790.
1 parent 960c7c2 commit e8a565c

9 files changed

Lines changed: 384 additions & 168 deletions

File tree

src/core/execute.c

Lines changed: 322 additions & 113 deletions
Large diffs are not rendered by default.

src/core/execute.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ typedef struct ExecCommand ExecCommand;
2525
typedef struct ExecContext ExecContext;
2626
typedef struct ExecRuntime ExecRuntime;
2727
typedef struct ExecParameters ExecParameters;
28+
typedef struct Manager Manager;
2829

2930
#include <sched.h>
3031
#include <stdbool.h>
@@ -120,6 +121,11 @@ struct ExecCommand {
120121
struct ExecRuntime {
121122
int n_ref;
122123

124+
Manager *manager;
125+
126+
/* unit id of the owner */
127+
char *id;
128+
123129
char *tmp_dir;
124130
char *var_tmp_dir;
125131

@@ -374,14 +380,13 @@ void exec_status_start(ExecStatus *s, pid_t pid);
374380
void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
375381
void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
376382

377-
int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id);
378-
ExecRuntime *exec_runtime_ref(ExecRuntime *r);
379-
ExecRuntime *exec_runtime_unref(ExecRuntime *r);
380-
381-
int exec_runtime_serialize(Unit *unit, ExecRuntime *rt, FILE *f, FDSet *fds);
382-
int exec_runtime_deserialize_item(Unit *unit, ExecRuntime **rt, const char *key, const char *value, FDSet *fds);
383+
int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *name, bool create, ExecRuntime **ret);
384+
ExecRuntime *exec_runtime_unref(ExecRuntime *r, bool destroy);
383385

384-
void exec_runtime_destroy(ExecRuntime *rt);
386+
int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds);
387+
int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds);
388+
void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds);
389+
void exec_runtime_vacuum(Manager *m);
385390

386391
const char* exec_output_to_string(ExecOutput i) _const_;
387392
ExecOutput exec_output_from_string(const char *s) _pure_;

src/core/manager.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,9 @@ Manager* manager_free(Manager *m) {
12001200

12011201
bus_done(m);
12021202

1203+
exec_runtime_vacuum(m);
1204+
hashmap_free(m->exec_runtime_by_id);
1205+
12031206
dynamic_user_vacuum(m, false);
12041207
hashmap_free(m->dynamic_users);
12051208

@@ -1463,6 +1466,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
14631466
/* Release any dynamic users no longer referenced */
14641467
dynamic_user_vacuum(m, true);
14651468

1469+
exec_runtime_vacuum(m);
1470+
14661471
/* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
14671472
manager_vacuum_uid_refs(m);
14681473
manager_vacuum_gid_refs(m);
@@ -2800,6 +2805,10 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
28002805
manager_serialize_uid_refs(m, f);
28012806
manager_serialize_gid_refs(m, f);
28022807

2808+
r = exec_runtime_serialize(m, f, fds);
2809+
if (r < 0)
2810+
return r;
2811+
28032812
(void) fputc('\n', f);
28042813

28052814
HASHMAP_FOREACH_KEY(u, t, m->units, i) {
@@ -2978,6 +2987,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
29782987
manager_deserialize_uid_refs_one(m, val);
29792988
else if ((val = startswith(l, "destroy-ipc-gid=")))
29802989
manager_deserialize_gid_refs_one(m, val);
2990+
else if ((val = startswith(l, "exec-runtime=")))
2991+
exec_runtime_deserialize_one(m, val, fds);
29812992
else if ((val = startswith(l, "subscribed="))) {
29822993

29832994
if (strv_extend(&m->deserialized_subscribed, val) < 0)
@@ -3082,6 +3093,7 @@ int manager_reload(Manager *m) {
30823093
manager_clear_jobs_and_units(m);
30833094
lookup_paths_flush_generator(&m->lookup_paths);
30843095
lookup_paths_free(&m->lookup_paths);
3096+
exec_runtime_vacuum(m);
30853097
dynamic_user_vacuum(m, false);
30863098
m->uid_refs = hashmap_free(m->uid_refs);
30873099
m->gid_refs = hashmap_free(m->gid_refs);
@@ -3140,6 +3152,8 @@ int manager_reload(Manager *m) {
31403152
manager_vacuum_uid_refs(m);
31413153
manager_vacuum_gid_refs(m);
31423154

3155+
exec_runtime_vacuum(m);
3156+
31433157
/* It might be safe to log to the journal now. */
31443158
manager_recheck_journal(m);
31453159

src/core/manager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ struct Manager {
341341
Hashmap *uid_refs;
342342
Hashmap *gid_refs;
343343

344+
/* ExecRuntime, indexed by their owner unit id */
345+
Hashmap *exec_runtime_by_id;
346+
344347
/* When the user hits C-A-D more than 7 times per 2s, do something immediately... */
345348
RateLimit ctrl_alt_del_ratelimit;
346349
EmergencyAction cad_burst_action;

src/core/mount.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ static void mount_done(Unit *u) {
241241
mount_parameters_done(&m->parameters_proc_self_mountinfo);
242242
mount_parameters_done(&m->parameters_fragment);
243243

244-
m->exec_runtime = exec_runtime_unref(m->exec_runtime);
244+
m->exec_runtime = exec_runtime_unref(m->exec_runtime, false);
245245
exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
246246
m->control_command = NULL;
247247

@@ -699,8 +699,10 @@ static int mount_coldplug(Unit *u) {
699699
return r;
700700
}
701701

702-
if (!IN_SET(new_state, MOUNT_DEAD, MOUNT_FAILED))
702+
if (!IN_SET(new_state, MOUNT_DEAD, MOUNT_FAILED)) {
703703
(void) unit_setup_dynamic_creds(u);
704+
(void) unit_setup_exec_runtime(u);
705+
}
704706

705707
mount_set_state(m, new_state);
706708
return 0;
@@ -813,8 +815,7 @@ static void mount_enter_dead(Mount *m, MountResult f) {
813815

814816
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
815817

816-
exec_runtime_destroy(m->exec_runtime);
817-
m->exec_runtime = exec_runtime_unref(m->exec_runtime);
818+
m->exec_runtime = exec_runtime_unref(m->exec_runtime, true);
818819

819820
exec_context_destroy_runtime_directory(&m->exec_context, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
820821

src/core/service.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ static void service_done(Unit *u) {
369369
s->pid_file = mfree(s->pid_file);
370370
s->status_text = mfree(s->status_text);
371371

372-
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
372+
s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
373373
exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
374374
s->control_command = NULL;
375375
s->main_command = NULL;
@@ -1155,8 +1155,10 @@ static int service_coldplug(Unit *u) {
11551155
if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
11561156
service_start_watchdog(s);
11571157

1158-
if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
1158+
if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) {
11591159
(void) unit_setup_dynamic_creds(u);
1160+
(void) unit_setup_exec_runtime(u);
1161+
}
11601162

11611163
if (UNIT_ISSET(s->accept_socket)) {
11621164
Socket* socket = SOCKET(UNIT_DEREF(s->accept_socket));
@@ -1643,8 +1645,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
16431645
s->forbid_restart = false;
16441646

16451647
/* We want fresh tmpdirs in case service is started again immediately */
1646-
exec_runtime_destroy(s->exec_runtime);
1647-
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
1648+
s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
16481649

16491650
if (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_NO ||
16501651
(s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(UNIT(s))))

src/core/socket.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ static void socket_done(Unit *u) {
164164

165165
s->peers_by_address = set_free(s->peers_by_address);
166166

167-
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
167+
s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
168168
exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
169169
s->control_command = NULL;
170170

@@ -1878,8 +1878,10 @@ static int socket_coldplug(Unit *u) {
18781878
return r;
18791879
}
18801880

1881-
if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED))
1881+
if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED)) {
18821882
(void) unit_setup_dynamic_creds(u);
1883+
(void) unit_setup_exec_runtime(u);
1884+
}
18831885

18841886
socket_set_state(s, s->deserialized_state);
18851887
return 0;
@@ -2017,8 +2019,7 @@ static void socket_enter_dead(Socket *s, SocketResult f) {
20172019

20182020
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
20192021

2020-
exec_runtime_destroy(s->exec_runtime);
2021-
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
2022+
s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
20222023

20232024
exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
20242025

src/core/swap.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ static void swap_done(Unit *u) {
157157
s->parameters_fragment.what = mfree(s->parameters_fragment.what);
158158
s->parameters_fragment.options = mfree(s->parameters_fragment.options);
159159

160-
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
160+
s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
161161
exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
162162
s->control_command = NULL;
163163

@@ -549,8 +549,10 @@ static int swap_coldplug(Unit *u) {
549549
return r;
550550
}
551551

552-
if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED))
552+
if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED)) {
553553
(void) unit_setup_dynamic_creds(u);
554+
(void) unit_setup_exec_runtime(u);
555+
}
554556

555557
swap_set_state(s, new_state);
556558
return 0;
@@ -669,8 +671,7 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
669671

670672
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
671673

672-
exec_runtime_destroy(s->exec_runtime);
673-
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
674+
s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
674675

675676
exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
676677

src/core/unit.c

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3176,18 +3176,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
31763176
assert(fds);
31773177

31783178
if (unit_can_serialize(u)) {
3179-
ExecRuntime *rt;
3180-
31813179
r = UNIT_VTABLE(u)->serialize(u, f, fds);
31823180
if (r < 0)
31833181
return r;
3184-
3185-
rt = unit_get_exec_runtime(u);
3186-
if (rt) {
3187-
r = exec_runtime_serialize(u, rt, f, fds);
3188-
if (r < 0)
3189-
return r;
3190-
}
31913182
}
31923183

31933184
dual_timestamp_serialize(f, "state-change-timestamp", &u->state_change_timestamp);
@@ -3333,18 +3324,12 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f
33333324
}
33343325

33353326
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
3336-
ExecRuntime **rt = NULL;
3337-
size_t offset;
33383327
int r;
33393328

33403329
assert(u);
33413330
assert(f);
33423331
assert(fds);
33433332

3344-
offset = UNIT_VTABLE(u)->exec_runtime_offset;
3345-
if (offset > 0)
3346-
rt = (ExecRuntime**) ((uint8_t*) u + offset);
3347-
33483333
for (;;) {
33493334
char line[LINE_MAX], *l, *v;
33503335
CGroupIPAccountingMetric m;
@@ -3604,18 +3589,16 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
36043589
}
36053590

36063591
if (unit_can_serialize(u)) {
3607-
if (rt) {
3608-
r = exec_runtime_deserialize_item(u, rt, l, v, fds);
3609-
if (r < 0) {
3610-
log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
3611-
continue;
3612-
}
3613-
3614-
/* Returns positive if key was handled by the call */
3615-
if (r > 0)
3616-
continue;
3592+
r = exec_runtime_deserialize_compat(u, l, v, fds);
3593+
if (r < 0) {
3594+
log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
3595+
continue;
36173596
}
36183597

3598+
/* Returns positive if key was handled by the call */
3599+
if (r > 0)
3600+
continue;
3601+
36193602
r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
36203603
if (r < 0)
36213604
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
@@ -4684,6 +4667,7 @@ int unit_setup_exec_runtime(Unit *u) {
46844667
Unit *other;
46854668
Iterator i;
46864669
void *v;
4670+
int r;
46874671

46884672
offset = UNIT_VTABLE(u)->exec_runtime_offset;
46894673
assert(offset > 0);
@@ -4695,15 +4679,12 @@ int unit_setup_exec_runtime(Unit *u) {
46954679

46964680
/* Try to get it from somebody else */
46974681
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) {
4698-
4699-
*rt = unit_get_exec_runtime(other);
4700-
if (*rt) {
4701-
exec_runtime_ref(*rt);
4702-
return 0;
4703-
}
4682+
r = exec_runtime_acquire(u->manager, NULL, other->id, false, rt);
4683+
if (r == 1)
4684+
return 1;
47044685
}
47054686

4706-
return exec_runtime_make(rt, unit_get_exec_context(u), u->id);
4687+
return exec_runtime_acquire(u->manager, unit_get_exec_context(u), u->id, true, rt);
47074688
}
47084689

47094690
int unit_setup_dynamic_creds(Unit *u) {

0 commit comments

Comments
 (0)