summaryrefslogtreecommitdiff
path: root/src/systemctl
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2019-07-18 13:11:28 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2019-07-30 14:01:46 +0200
commite8630e695232bdfcd16b55f3faafb4329c961104 (patch)
treedce17c3db55aa13c5f64ed6f8a415e6eea3db7fd /src/systemctl
parent7d1e91d1a9504ab1bc03894038f90a8e87a4e982 (diff)
downloadsystemd-e8630e695232bdfcd16b55f3faafb4329c961104.tar.gz
pid1: use a cache for all unit aliases
This reworks how we load units from disk. Instead of chasing symlinks every time we are asked to load a unit by name, we slurp all symlinks from disk and build two hashmaps: 1. from unit name to either alias target, or fragment on disk (if an alias, we put just the target name in the hashmap, if a fragment we put an absolute path, so we can distinguish both). 2. from a unit name to all aliases Reading all this data can be pretty costly (40 ms) on my machine, so we keep it around for reuse. The advantage is that we can reliably know what all the aliases of a given unit are. This means we can reliably load dropins under all names. This fixes #11972.
Diffstat (limited to 'src/systemctl')
-rw-r--r--src/systemctl/systemctl.c47
1 files changed, 20 insertions, 27 deletions
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 97f3176cc5..31d364cefe 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -33,6 +33,7 @@
#include "cgroup-util.h"
#include "copy.h"
#include "cpu-set-util.h"
+#include "dirent-util.h"
#include "dropin.h"
#include "efivars.h"
#include "env-util.h"
@@ -165,12 +166,18 @@ static bool arg_jobs_before = false;
static bool arg_jobs_after = false;
static char **arg_clean_what = NULL;
+/* This is a global cache that will be constructed on first use. */
+static Hashmap *cached_id_map = NULL;
+static Hashmap *cached_name_map = NULL;
+
STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(cached_id_map, hashmap_freep);
+STATIC_DESTRUCTOR_REGISTER(cached_name_map, hashmap_freep);
static int daemon_reload(int argc, char *argv[], void* userdata);
static int trivial_method(int argc, char *argv[], void *userdata);
@@ -2582,38 +2589,24 @@ static int unit_find_paths(
return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
}
} else {
- _cleanup_set_free_ Set *names = NULL;
- _cleanup_free_ char *template = NULL;
+ const char *_path;
+ _cleanup_set_free_free_ Set *names = NULL;
- names = set_new(NULL);
- if (!names)
- return log_oom();
+ if (!cached_name_map) {
+ r = unit_file_build_name_map(lp, &cached_id_map, &cached_name_map, NULL);
+ if (r < 0)
+ return r;
+ }
- r = unit_find_template_path(unit_name, lp, &path, &template);
+ r = unit_file_find_fragment(cached_id_map, cached_name_map, unit_name, &_path, &names);
if (r < 0)
return r;
- if (r > 0) {
- if (null_or_empty_path(path))
- /* The template is masked. Let's cut the process short. */
- return -ERFKILL;
-
- /* We found the unit file. If we followed symlinks, this name might be
- * different then the unit_name with started with. Look for dropins matching
- * that "final" name. */
- r = set_put(names, basename(path));
- } else if (!template)
- /* No unit file, let's look for dropins matching the original name.
- * systemd has fairly complicated rules (based on unit type and provenience),
- * which units are allowed not to have the main unit file. We err on the
- * side of including too many files, and always try to load dropins. */
- r = set_put(names, unit_name);
- else
- /* The cases where we allow a unit to exist without the main file are
- * never valid for templates. Don't try to load dropins in this case. */
- goto not_found;
- if (r < 0)
- return log_error_errno(r, "Failed to add unit name: %m");
+ if (_path) {
+ path = strdup(_path);
+ if (!path)
+ return log_oom();
+ }
if (ret_dropin_paths) {
r = unit_file_find_dropin_paths(arg_root, lp->search_path, NULL,