]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: make ExecRuntime be manager managed object
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 6 Feb 2018 07:00:34 +0000 (16:00 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 6 Feb 2018 07:00:34 +0000 (16:00 +0900)
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.

src/core/execute.c
src/core/execute.h
src/core/manager.c
src/core/manager.h
src/core/mount.c
src/core/service.c
src/core/socket.c
src/core/swap.c
src/core/unit.c

index 0df3971df6730c5f2f1d5e41cc637251c51b18e9..30a608e6894a848be385e7878a4fbfdf7fb30c09 100644 (file)
@@ -82,6 +82,7 @@
 #include "label.h"
 #include "log.h"
 #include "macro.h"
+#include "manager.h"
 #include "missing.h"
 #include "mkdir.h"
 #include "namespace.h"
@@ -4523,224 +4524,432 @@ int exec_command_append(ExecCommand *c, const char *path, ...) {
         return 0;
 }
 
+static void *remove_tmpdir_thread(void *p) {
+        _cleanup_free_ char *path = p;
 
-static int exec_runtime_allocate(ExecRuntime **rt) {
+        (void) rm_rf(path, REMOVE_ROOT|REMOVE_PHYSICAL);
+        return NULL;
+}
+
+static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
+        int r;
+
+        if (!rt)
+                return NULL;
+
+        if (rt->manager)
+                (void) hashmap_remove(rt->manager->exec_runtime_by_id, rt->id);
+
+        /* When destroy is true, then rm_rf tmp_dir and var_tmp_dir. */
+        if (destroy && rt->tmp_dir) {
+                log_debug("Spawning thread to nuke %s", rt->tmp_dir);
+
+                r = asynchronous_job(remove_tmpdir_thread, rt->tmp_dir);
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to nuke %s: %m", rt->tmp_dir);
+                        free(rt->tmp_dir);
+                }
+
+                rt->tmp_dir = NULL;
+        }
 
+        if (destroy && rt->var_tmp_dir) {
+                log_debug("Spawning thread to nuke %s", rt->var_tmp_dir);
+
+                r = asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir);
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to nuke %s: %m", rt->var_tmp_dir);
+                        free(rt->var_tmp_dir);
+                }
+
+                rt->var_tmp_dir = NULL;
+        }
+
+        rt->id = mfree(rt->id);
+        rt->tmp_dir = mfree(rt->tmp_dir);
+        rt->var_tmp_dir = mfree(rt->var_tmp_dir);
+        safe_close_pair(rt->netns_storage_socket);
+        return mfree(rt);
+}
+
+static void exec_runtime_freep(ExecRuntime **rt) {
         if (*rt)
-                return 0;
+                (void) exec_runtime_free(*rt, false);
+}
+
+static int exec_runtime_allocate(ExecRuntime **rt) {
+        assert(rt);
 
         *rt = new0(ExecRuntime, 1);
         if (!*rt)
                 return -ENOMEM;
 
-        (*rt)->n_ref = 1;
         (*rt)->netns_storage_socket[0] = (*rt)->netns_storage_socket[1] = -1;
-
         return 0;
 }
 
-int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id) {
+static int exec_runtime_add(
+                Manager *m,
+                const char *id,
+                const char *tmp_dir,
+                const char *var_tmp_dir,
+                const int netns_storage_socket[2],
+                ExecRuntime **ret) {
+
+        _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
         int r;
 
-        assert(rt);
-        assert(c);
+        assert(m);
         assert(id);
 
-        if (*rt)
-                return 1;
-
-        if (!c->private_network && !c->private_tmp)
-                return 0;
+        r = hashmap_ensure_allocated(&m->exec_runtime_by_id, &string_hash_ops);
+        if (r < 0)
+                return r;
 
-        r = exec_runtime_allocate(rt);
+        r = exec_runtime_allocate(&rt);
         if (r < 0)
                 return r;
 
-        if (c->private_network && (*rt)->netns_storage_socket[0] < 0) {
-                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, (*rt)->netns_storage_socket) < 0)
-                        return -errno;
+        rt->id = strdup(id);
+        if (!rt->id)
+                return -ENOMEM;
+
+        if (tmp_dir) {
+                rt->tmp_dir = strdup(tmp_dir);
+                if (!rt->tmp_dir)
+                        return -ENOMEM;
+
+                /* When tmp_dir is set, then we require var_tmp_dir is also set. */
+                assert(var_tmp_dir);
+                rt->var_tmp_dir = strdup(var_tmp_dir);
+                if (!rt->var_tmp_dir)
+                        return -ENOMEM;
+        }
+
+        if (netns_storage_socket) {
+                rt->netns_storage_socket[0] = netns_storage_socket[0];
+                rt->netns_storage_socket[1] = netns_storage_socket[1];
         }
 
-        if (c->private_tmp && !(*rt)->tmp_dir) {
-                r = setup_tmp_dirs(id, &(*rt)->tmp_dir, &(*rt)->var_tmp_dir);
+        r = hashmap_put(m->exec_runtime_by_id, rt->id, rt);
+        if (r < 0)
+                return r;
+
+        rt->manager = m;
+
+        if (ret)
+                *ret = rt;
+
+        /* do not remove created ExecRuntime object when the operation succeeds. */
+        rt = NULL;
+        return 0;
+}
+
+static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, ExecRuntime **ret) {
+        _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
+        _cleanup_close_pair_ int netns_storage_socket[2] = {-1, -1};
+        int r;
+
+        assert(m);
+        assert(c);
+        assert(id);
+
+        /* It is not necessary to create ExecRuntime object. */
+        if (!c->private_network && !c->private_tmp)
+                return 0;
+
+        if (c->private_tmp) {
+                r = setup_tmp_dirs(id, &tmp_dir, &var_tmp_dir);
                 if (r < 0)
                         return r;
         }
 
+        if (c->private_network) {
+                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, netns_storage_socket) < 0)
+                        return -errno;
+        }
+
+        r = exec_runtime_add(m, id, tmp_dir, var_tmp_dir, netns_storage_socket, ret);
+        if (r < 0)
+                return r;
+
+        /* Avoid cleanup */
+        netns_storage_socket[0] = -1;
+        netns_storage_socket[1] = -1;
         return 1;
 }
 
-ExecRuntime *exec_runtime_ref(ExecRuntime *r) {
-        assert(r);
-        assert(r->n_ref > 0);
+int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecRuntime **ret) {
+        ExecRuntime *rt;
+        int r;
 
-        r->n_ref++;
-        return r;
-}
+        assert(m);
+        assert(id);
+        assert(ret);
+
+        rt = hashmap_get(m->exec_runtime_by_id, id);
+        if (rt)
+                /* We already have a ExecRuntime object, let's increase the ref count and reuse it */
+                goto ref;
+
+        if (!create)
+                return 0;
+
+        /* If not found, then create a new object. */
+        r = exec_runtime_make(m, c, id, &rt);
+        if (r <= 0)
+                /* When r == 0, it is not necessary to create ExecRuntime object. */
+                return r;
 
-ExecRuntime *exec_runtime_unref(ExecRuntime *r) {
+ref:
+        /* increment reference counter. */
+        rt->n_ref++;
+        *ret = rt;
+        return 1;
+}
 
-        if (!r)
+ExecRuntime *exec_runtime_unref(ExecRuntime *rt, bool destroy) {
+        if (!rt)
                 return NULL;
 
-        assert(r->n_ref > 0);
+        assert(rt->n_ref > 0);
 
-        r->n_ref--;
-        if (r->n_ref > 0)
+        rt->n_ref--;
+        if (rt->n_ref > 0)
                 return NULL;
 
-        free(r->tmp_dir);
-        free(r->var_tmp_dir);
-        safe_close_pair(r->netns_storage_socket);
-        return mfree(r);
+        return exec_runtime_free(rt, destroy);
 }
 
-int exec_runtime_serialize(Unit *u, ExecRuntime *rt, FILE *f, FDSet *fds) {
-        assert(u);
+int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
+        ExecRuntime *rt;
+        Iterator i;
+
+        assert(m);
         assert(f);
         assert(fds);
 
-        if (!rt)
-                return 0;
+        HASHMAP_FOREACH(rt, m->exec_runtime_by_id, i) {
+                fprintf(f, "exec-runtime=%s", rt->id);
 
-        if (rt->tmp_dir)
-                unit_serialize_item(u, f, "tmp-dir", rt->tmp_dir);
+                if (rt->tmp_dir)
+                        fprintf(f, " tmp-dir=%s", rt->tmp_dir);
 
-        if (rt->var_tmp_dir)
-                unit_serialize_item(u, f, "var-tmp-dir", rt->var_tmp_dir);
+                if (rt->var_tmp_dir)
+                        fprintf(f, " var-tmp-dir=%s", rt->var_tmp_dir);
 
-        if (rt->netns_storage_socket[0] >= 0) {
-                int copy;
+                if (rt->netns_storage_socket[0] >= 0) {
+                        int copy;
 
-                copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
-                if (copy < 0)
-                        return copy;
+                        copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
+                        if (copy < 0)
+                                return copy;
 
-                unit_serialize_item_format(u, f, "netns-socket-0", "%i", copy);
-        }
+                        fprintf(f, " netns-socket-0=%i", copy);
+                }
 
-        if (rt->netns_storage_socket[1] >= 0) {
-                int copy;
+                if (rt->netns_storage_socket[1] >= 0) {
+                        int copy;
 
-                copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
-                if (copy < 0)
-                        return copy;
+                        copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
+                        if (copy < 0)
+                                return copy;
 
-                unit_serialize_item_format(u, f, "netns-socket-1", "%i", copy);
+                        fprintf(f, " netns-socket-1=%i", copy);
+                }
+
+                fputc('\n', f);
         }
 
         return 0;
 }
 
-int exec_runtime_deserialize_item(Unit *u, ExecRuntime **rt, const char *key, const char *value, FDSet *fds) {
+int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
+        _cleanup_(exec_runtime_freep) ExecRuntime *rt_create = NULL;
+        ExecRuntime *rt;
         int r;
 
-        assert(rt);
+        /* This is for the migration from old (v237 or earlier) deserialization text.
+         * Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
+         * Even if the ExecRuntime object originally created by the other unit, we cannot judge
+         * so or not from the serialized text, then we always creates a new object owned by this. */
+
+        assert(u);
         assert(key);
         assert(value);
 
-        if (streq(key, "tmp-dir")) {
-                char *copy;
+        /* Manager manages ExecRuntime objects by the unit id.
+         * So, we omit the serialized text when the unit does not have id (yet?)... */
+        if (isempty(u->id)) {
+                log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.");
+                return 0;
+        }
 
-                r = exec_runtime_allocate(rt);
+        r = hashmap_ensure_allocated(&u->manager->exec_runtime_by_id, &string_hash_ops);
+        if (r < 0) {
+                log_unit_debug_errno(u, r, "Failed to allocate storage for runtime parameter: %m");
+                return 0;
+        }
+
+        rt = hashmap_get(u->manager->exec_runtime_by_id, u->id);
+        if (!rt) {
+                r = exec_runtime_allocate(&rt_create);
                 if (r < 0)
                         return log_oom();
 
+                rt_create->id = strdup(u->id);
+                if (!rt_create->id)
+                        return log_oom();
+
+                rt = rt_create;
+        }
+
+        if (streq(key, "tmp-dir")) {
+                char *copy;
+
                 copy = strdup(value);
                 if (!copy)
                         return log_oom();
 
-                free((*rt)->tmp_dir);
-                (*rt)->tmp_dir = copy;
+                free_and_replace(rt->tmp_dir, copy);
 
         } else if (streq(key, "var-tmp-dir")) {
                 char *copy;
 
-                r = exec_runtime_allocate(rt);
-                if (r < 0)
-                        return log_oom();
-
                 copy = strdup(value);
                 if (!copy)
                         return log_oom();
 
-                free((*rt)->var_tmp_dir);
-                (*rt)->var_tmp_dir = copy;
+                free_and_replace(rt->var_tmp_dir, copy);
 
         } else if (streq(key, "netns-socket-0")) {
                 int fd;
 
-                r = exec_runtime_allocate(rt);
-                if (r < 0)
-                        return log_oom();
-
-                if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
+                if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
                         log_unit_debug(u, "Failed to parse netns socket value: %s", value);
-                else {
-                        safe_close((*rt)->netns_storage_socket[0]);
-                        (*rt)->netns_storage_socket[0] = fdset_remove(fds, fd);
+                        return 0;
                 }
+
+                safe_close(rt->netns_storage_socket[0]);
+                rt->netns_storage_socket[0] = fdset_remove(fds, fd);
+
         } else if (streq(key, "netns-socket-1")) {
                 int fd;
 
-                r = exec_runtime_allocate(rt);
-                if (r < 0)
-                        return log_oom();
-
-                if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
+                if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
                         log_unit_debug(u, "Failed to parse netns socket value: %s", value);
-                else {
-                        safe_close((*rt)->netns_storage_socket[1]);
-                        (*rt)->netns_storage_socket[1] = fdset_remove(fds, fd);
+                        return 0;
                 }
+
+                safe_close(rt->netns_storage_socket[1]);
+                rt->netns_storage_socket[1] = fdset_remove(fds, fd);
         } else
                 return 0;
 
-        return 1;
-}
 
-static void *remove_tmpdir_thread(void *p) {
-        _cleanup_free_ char *path = p;
+        /* If the object is newly created, then put it to the hashmap which manages ExecRuntime objects. */
+        if (rt_create) {
+                r = hashmap_put(u->manager->exec_runtime_by_id, rt_create->id, rt_create);
+                if (r < 0) {
+                        log_unit_debug_errno(u, r, "Failed to put runtime paramter to manager's storage: %m");
+                        return 0;
+                }
 
-        (void) rm_rf(path, REMOVE_ROOT|REMOVE_PHYSICAL);
-        return NULL;
-}
+                rt_create->manager = u->manager;
 
-void exec_runtime_destroy(ExecRuntime *rt) {
-        int r;
+                /* Avoid cleanup */
+                rt_create = NULL;
+        }
 
-        if (!rt)
-                return;
+        return 1;
+}
 
-        /* If there are multiple users of this, let's leave the stuff around */
-        if (rt->n_ref > 1)
-                return;
+void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
+        char *id = NULL, *tmp_dir = NULL, *var_tmp_dir = NULL;
+        int r, fd0 = -1, fd1 = -1;
+        const char *p, *v = value;
+        size_t n;
 
-        if (rt->tmp_dir) {
-                log_debug("Spawning thread to nuke %s", rt->tmp_dir);
+        assert(m);
+        assert(value);
+        assert(fds);
 
-                r = asynchronous_job(remove_tmpdir_thread, rt->tmp_dir);
-                if (r < 0) {
-                        log_warning_errno(r, "Failed to nuke %s: %m", rt->tmp_dir);
-                        free(rt->tmp_dir);
+        n = strcspn(v, " ");
+        id = strndupa(v, n);
+        if (v[n] != ' ')
+                goto finalize;
+        p = v + n + 1;
+
+        v = startswith(p, "tmp-dir=");
+        if (v) {
+                n = strcspn(v, " ");
+                tmp_dir = strndupa(v, n);
+                if (v[n] != ' ')
+                        goto finalize;
+                p = v + n + 1;
+        }
+
+        v = startswith(p, "var-tmp-dir=");
+        if (v) {
+                n = strcspn(v, " ");
+                var_tmp_dir = strndupa(v, n);
+                if (v[n] != ' ')
+                        goto finalize;
+                p = v + n + 1;
+        }
+
+        v = startswith(p, "netns-socket-0=");
+        if (v) {
+                char *buf;
+
+                n = strcspn(v, " ");
+                buf = strndupa(v, n);
+                if (safe_atoi(buf, &fd0) < 0 || !fdset_contains(fds, fd0)) {
+                        log_debug("Unable to process exec-runtime netns fd specification.");
+                        return;
                 }
-
-                rt->tmp_dir = NULL;
+                fd0 = fdset_remove(fds, fd0);
+                if (v[n] != ' ')
+                        goto finalize;
+                p = v + n + 1;
         }
 
-        if (rt->var_tmp_dir) {
-                log_debug("Spawning thread to nuke %s", rt->var_tmp_dir);
+        v = startswith(p, "netns-socket-1=");
+        if (v) {
+                char *buf;
 
-                r = asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir);
-                if (r < 0) {
-                        log_warning_errno(r, "Failed to nuke %s: %m", rt->var_tmp_dir);
-                        free(rt->var_tmp_dir);
+                n = strcspn(v, " ");
+                buf = strndupa(v, n);
+                if (safe_atoi(buf, &fd1) < 0 || !fdset_contains(fds, fd1)) {
+                        log_debug("Unable to process exec-runtime netns fd specification.");
+                        return;
                 }
+                fd1 = fdset_remove(fds, fd1);
+        }
 
-                rt->var_tmp_dir = NULL;
+finalize:
+
+        r = exec_runtime_add(m, id, tmp_dir, var_tmp_dir, (int[]) { fd0, fd1 }, NULL);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to add exec-runtime: %m");
+                return;
         }
+}
 
-        safe_close_pair(rt->netns_storage_socket);
+void exec_runtime_vacuum(Manager *m) {
+        ExecRuntime *rt;
+        Iterator i;
+
+        assert(m);
+
+        /* Free unreferenced ExecRuntime objects. This is used after manager deserialization process. */
+
+        HASHMAP_FOREACH(rt, m->exec_runtime_by_id, i) {
+                if (rt->n_ref > 0)
+                        continue;
+
+                (void) exec_runtime_free(rt, false);
+        }
 }
 
 static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
index d04dfcf6c9d17acd67158619f7eaa8d468fa0280..90d0fc64e3e876e3d1c1bef272dd9b056248595f 100644 (file)
@@ -25,6 +25,7 @@ typedef struct ExecCommand ExecCommand;
 typedef struct ExecContext ExecContext;
 typedef struct ExecRuntime ExecRuntime;
 typedef struct ExecParameters ExecParameters;
+typedef struct Manager Manager;
 
 #include <sched.h>
 #include <stdbool.h>
@@ -120,6 +121,11 @@ struct ExecCommand {
 struct ExecRuntime {
         int n_ref;
 
+        Manager *manager;
+
+        /* unit id of the owner */
+        char *id;
+
         char *tmp_dir;
         char *var_tmp_dir;
 
@@ -374,14 +380,13 @@ void exec_status_start(ExecStatus *s, pid_t pid);
 void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
 void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
 
-int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id);
-ExecRuntime *exec_runtime_ref(ExecRuntime *r);
-ExecRuntime *exec_runtime_unref(ExecRuntime *r);
-
-int exec_runtime_serialize(Unit *unit, ExecRuntime *rt, FILE *f, FDSet *fds);
-int exec_runtime_deserialize_item(Unit *unit, ExecRuntime **rt, const char *key, const char *value, FDSet *fds);
+int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *name, bool create, ExecRuntime **ret);
+ExecRuntime *exec_runtime_unref(ExecRuntime *r, bool destroy);
 
-void exec_runtime_destroy(ExecRuntime *rt);
+int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds);
+int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds);
+void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds);
+void exec_runtime_vacuum(Manager *m);
 
 const char* exec_output_to_string(ExecOutput i) _const_;
 ExecOutput exec_output_from_string(const char *s) _pure_;
index e837a46f56aeca420c9e5fb24397be619bdb2e6d..5021e00b870e4ababc3f569bc1bebec91452facd 100644 (file)
@@ -1200,6 +1200,9 @@ Manager* manager_free(Manager *m) {
 
         bus_done(m);
 
+        exec_runtime_vacuum(m);
+        hashmap_free(m->exec_runtime_by_id);
+
         dynamic_user_vacuum(m, false);
         hashmap_free(m->dynamic_users);
 
@@ -1463,6 +1466,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
         /* Release any dynamic users no longer referenced */
         dynamic_user_vacuum(m, true);
 
+        exec_runtime_vacuum(m);
+
         /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
         manager_vacuum_uid_refs(m);
         manager_vacuum_gid_refs(m);
@@ -2800,6 +2805,10 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
         manager_serialize_uid_refs(m, f);
         manager_serialize_gid_refs(m, f);
 
+        r = exec_runtime_serialize(m, f, fds);
+        if (r < 0)
+                return r;
+
         (void) fputc('\n', f);
 
         HASHMAP_FOREACH_KEY(u, t, m->units, i) {
@@ -2978,6 +2987,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                         manager_deserialize_uid_refs_one(m, val);
                 else if ((val = startswith(l, "destroy-ipc-gid=")))
                         manager_deserialize_gid_refs_one(m, val);
+                else if ((val = startswith(l, "exec-runtime=")))
+                        exec_runtime_deserialize_one(m, val, fds);
                 else if ((val = startswith(l, "subscribed="))) {
 
                         if (strv_extend(&m->deserialized_subscribed, val) < 0)
@@ -3082,6 +3093,7 @@ int manager_reload(Manager *m) {
         manager_clear_jobs_and_units(m);
         lookup_paths_flush_generator(&m->lookup_paths);
         lookup_paths_free(&m->lookup_paths);
+        exec_runtime_vacuum(m);
         dynamic_user_vacuum(m, false);
         m->uid_refs = hashmap_free(m->uid_refs);
         m->gid_refs = hashmap_free(m->gid_refs);
@@ -3140,6 +3152,8 @@ int manager_reload(Manager *m) {
         manager_vacuum_uid_refs(m);
         manager_vacuum_gid_refs(m);
 
+        exec_runtime_vacuum(m);
+
         /* It might be safe to log to the journal now. */
         manager_recheck_journal(m);
 
index 0eed67b46a4d85a61449c1ff4371f93205009d87..c785861bfbad9ae1fbebee7a3655a9bcb6b98a8e 100644 (file)
@@ -341,6 +341,9 @@ struct Manager {
         Hashmap *uid_refs;
         Hashmap *gid_refs;
 
+        /* ExecRuntime, indexed by their owner unit id */
+        Hashmap *exec_runtime_by_id;
+
         /* When the user hits C-A-D more than 7 times per 2s, do something immediately... */
         RateLimit ctrl_alt_del_ratelimit;
         EmergencyAction cad_burst_action;
index e72d8161ed16911d27e9bbfd702f579cce1c9095..76883475a2ba09f393c331a555096bd845b16c3a 100644 (file)
@@ -241,7 +241,7 @@ static void mount_done(Unit *u) {
         mount_parameters_done(&m->parameters_proc_self_mountinfo);
         mount_parameters_done(&m->parameters_fragment);
 
-        m->exec_runtime = exec_runtime_unref(m->exec_runtime);
+        m->exec_runtime = exec_runtime_unref(m->exec_runtime, false);
         exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
         m->control_command = NULL;
 
@@ -699,8 +699,10 @@ static int mount_coldplug(Unit *u) {
                         return r;
         }
 
-        if (!IN_SET(new_state, MOUNT_DEAD, MOUNT_FAILED))
+        if (!IN_SET(new_state, MOUNT_DEAD, MOUNT_FAILED)) {
                 (void) unit_setup_dynamic_creds(u);
+                (void) unit_setup_exec_runtime(u);
+        }
 
         mount_set_state(m, new_state);
         return 0;
@@ -813,8 +815,7 @@ static void mount_enter_dead(Mount *m, MountResult f) {
 
         mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
 
-        exec_runtime_destroy(m->exec_runtime);
-        m->exec_runtime = exec_runtime_unref(m->exec_runtime);
+        m->exec_runtime = exec_runtime_unref(m->exec_runtime, true);
 
         exec_context_destroy_runtime_directory(&m->exec_context, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
 
index 0b53b1c829babe4286a92b5b7c81ca6dc0378de3..ff0a82864ffd3414322a9aa658132713c6b9ff20 100644 (file)
@@ -369,7 +369,7 @@ static void service_done(Unit *u) {
         s->pid_file = mfree(s->pid_file);
         s->status_text = mfree(s->status_text);
 
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime);
+        s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
         exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
         s->control_command = NULL;
         s->main_command = NULL;
@@ -1155,8 +1155,10 @@ static int service_coldplug(Unit *u) {
         if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
                 service_start_watchdog(s);
 
-        if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
+        if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) {
                 (void) unit_setup_dynamic_creds(u);
+                (void) unit_setup_exec_runtime(u);
+        }
 
         if (UNIT_ISSET(s->accept_socket)) {
                 Socket* socket = SOCKET(UNIT_DEREF(s->accept_socket));
@@ -1643,8 +1645,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         s->forbid_restart = false;
 
         /* We want fresh tmpdirs in case service is started again immediately */
-        exec_runtime_destroy(s->exec_runtime);
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime);
+        s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
 
         if (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_NO ||
             (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(UNIT(s))))
index 74cdebbe81041bfa49447f5899f8378f659bdff1..703f9f760fa97a0501756f4a3e18ba1fd9a27a6d 100644 (file)
@@ -164,7 +164,7 @@ static void socket_done(Unit *u) {
 
         s->peers_by_address = set_free(s->peers_by_address);
 
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime);
+        s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
         exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
         s->control_command = NULL;
 
@@ -1878,8 +1878,10 @@ static int socket_coldplug(Unit *u) {
                         return r;
         }
 
-        if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED))
+        if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED)) {
                 (void) unit_setup_dynamic_creds(u);
+                (void) unit_setup_exec_runtime(u);
+        }
 
         socket_set_state(s, s->deserialized_state);
         return 0;
@@ -2017,8 +2019,7 @@ static void socket_enter_dead(Socket *s, SocketResult f) {
 
         socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
 
-        exec_runtime_destroy(s->exec_runtime);
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime);
+        s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
 
         exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
 
index b10066db01ae2db2d57d61bd003f33bd8af15397..3b234c22123f5db045721d04c99316f7e4e5830c 100644 (file)
@@ -157,7 +157,7 @@ static void swap_done(Unit *u) {
         s->parameters_fragment.what = mfree(s->parameters_fragment.what);
         s->parameters_fragment.options = mfree(s->parameters_fragment.options);
 
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime);
+        s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
         exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
         s->control_command = NULL;
 
@@ -549,8 +549,10 @@ static int swap_coldplug(Unit *u) {
                         return r;
         }
 
-        if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED))
+        if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED)) {
                 (void) unit_setup_dynamic_creds(u);
+                (void) unit_setup_exec_runtime(u);
+        }
 
         swap_set_state(s, new_state);
         return 0;
@@ -669,8 +671,7 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
 
         swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
 
-        exec_runtime_destroy(s->exec_runtime);
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime);
+        s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
 
         exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
 
index 54e298cae417515f4d90a90eeeee8178b4b821ac..4a5fa4005cac22afdd4d5bd6e5fa2d0dda1bee7f 100644 (file)
@@ -3176,18 +3176,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
         assert(fds);
 
         if (unit_can_serialize(u)) {
-                ExecRuntime *rt;
-
                 r = UNIT_VTABLE(u)->serialize(u, f, fds);
                 if (r < 0)
                         return r;
-
-                rt = unit_get_exec_runtime(u);
-                if (rt) {
-                        r = exec_runtime_serialize(u, rt, f, fds);
-                        if (r < 0)
-                                return r;
-                }
         }
 
         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
 }
 
 int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
-        ExecRuntime **rt = NULL;
-        size_t offset;
         int r;
 
         assert(u);
         assert(f);
         assert(fds);
 
-        offset = UNIT_VTABLE(u)->exec_runtime_offset;
-        if (offset > 0)
-                rt = (ExecRuntime**) ((uint8_t*) u + offset);
-
         for (;;) {
                 char line[LINE_MAX], *l, *v;
                 CGroupIPAccountingMetric m;
@@ -3604,18 +3589,16 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                 }
 
                 if (unit_can_serialize(u)) {
-                        if (rt) {
-                                r = exec_runtime_deserialize_item(u, rt, l, v, fds);
-                                if (r < 0) {
-                                        log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
-                                        continue;
-                                }
-
-                                /* Returns positive if key was handled by the call */
-                                if (r > 0)
-                                        continue;
+                        r = exec_runtime_deserialize_compat(u, l, v, fds);
+                        if (r < 0) {
+                                log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
+                                continue;
                         }
 
+                        /* Returns positive if key was handled by the call */
+                        if (r > 0)
+                                continue;
+
                         r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
                         if (r < 0)
                                 log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
@@ -4684,6 +4667,7 @@ int unit_setup_exec_runtime(Unit *u) {
         Unit *other;
         Iterator i;
         void *v;
+        int r;
 
         offset = UNIT_VTABLE(u)->exec_runtime_offset;
         assert(offset > 0);
@@ -4695,15 +4679,12 @@ int unit_setup_exec_runtime(Unit *u) {
 
         /* Try to get it from somebody else */
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) {
-
-                *rt = unit_get_exec_runtime(other);
-                if (*rt) {
-                        exec_runtime_ref(*rt);
-                        return 0;
-                }
+                r = exec_runtime_acquire(u->manager, NULL, other->id, false, rt);
+                if (r == 1)
+                        return 1;
         }
 
-        return exec_runtime_make(rt, unit_get_exec_context(u), u->id);
+        return exec_runtime_acquire(u->manager, unit_get_exec_context(u), u->id, true, rt);
 }
 
 int unit_setup_dynamic_creds(Unit *u) {