core: rework how we match mount units against each other

Previously to automatically create dependencies between mount units we
matched every mount unit agains all others resulting in O(n^2)
complexity. On setups with large amounts of mount units this might make
things slow.

This change replaces the matching code to use a hashtable that is keyed
by a path prefix, and points to a set of units that require that path to
be around. When a new mount unit is installed it is hence sufficient to
simply look up this set of units via its own file system paths to know
which units to order after itself.

This patch also changes all unit types to only create automatic mount
dependencies via the RequiresMountsFor= logic, and this is exposed to
the outside to make things more transparent.

With this change we still have some O(n) complexities in place when
handling mounts, but that's currently unavoidable due to kernel APIs,
and still substantially better than O(n^2) as before.

https://bugs.freedesktop.org/show_bug.cgi?id=69740
This commit is contained in:
Lennart Poettering 2013-09-26 20:14:24 +02:00
parent 6270c1bd8f
commit a57f7e2c82
17 changed files with 321 additions and 407 deletions

View File

@ -117,42 +117,17 @@ static void automount_done(Unit *u) {
a->tokens = NULL;
}
int automount_add_one_mount_link(Automount *a, Mount *m) {
static int automount_add_mount_links(Automount *a) {
_cleanup_free_ char *parent = NULL;
int r;
assert(a);
assert(m);
if (UNIT(a)->load_state != UNIT_LOADED ||
UNIT(m)->load_state != UNIT_LOADED)
return 0;
if (!path_startswith(a->where, m->where))
return 0;
if (path_equal(a->where, m->where))
return 0;
r = unit_add_two_dependencies(UNIT(a), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
r = path_get_parent(a->where, &parent);
if (r < 0)
return r;
return 0;
}
static int automount_add_mount_links(Automount *a) {
Unit *other;
int r;
assert(a);
LIST_FOREACH(units_by_type, other, UNIT(a)->manager->units_by_type[UNIT_MOUNT]) {
r = automount_add_one_mount_link(a, MOUNT(other));
if (r < 0)
return r;
}
return 0;
return unit_require_mounts_for(UNIT(a), parent);
}
static int automount_add_default_dependencies(Automount *a) {

View File

@ -62,8 +62,6 @@ extern const UnitVTable automount_vtable;
int automount_send_ready(Automount *a, int status);
int automount_add_one_mount_link(Automount *a, Mount *m);
const char* automount_state_to_string(AutomountState i) _const_;
AutomountState automount_state_from_string(const char *s) _pure_;

View File

@ -116,7 +116,7 @@ Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAG
Unit.ReloadPropagatedFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0
Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0
Unit.PartOf, config_parse_unit_deps, UNIT_PART_OF, 0
Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, offsetof(Unit, requires_mounts_for)
Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, 0
Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded)
Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start)
Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop)

View File

@ -1773,33 +1773,48 @@ int config_parse_unit_condition_null(const char *unit,
DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
int config_parse_unit_requires_mounts_for(const char *unit,
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
int config_parse_unit_requires_mounts_for(
const char *unit,
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Unit *u = userdata;
char *state;
size_t l;
char *w;
int r;
bool empty_before;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
empty_before = !u->requires_mounts_for;
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
_cleanup_free_ char *n;
r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
rvalue, data, userdata);
n = strndup(w, l);
if (!n)
return log_oom();
/* Make it easy to find units with requires_mounts set */
if (empty_before && u->requires_mounts_for)
LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
if (!utf8_is_valid(n)) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
continue;
}
r = unit_require_mounts_for(u, n);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to add required mount for, ignoring: %s", rvalue);
continue;
}
}
return r;
}

View File

@ -770,6 +770,9 @@ void manager_free(Manager *m) {
for (i = 0; i < RLIMIT_NLIMITS; i++)
free(m->rlimit[i]);
assert(hashmap_isempty(m->units_requiring_mounts_for));
hashmap_free(m->units_requiring_mounts_for);
free(m);
}
@ -782,9 +785,11 @@ int manager_enumerate(Manager *m) {
/* Let's ask every type to load all units from disk/kernel
* that it might know */
for (c = 0; c < _UNIT_TYPE_MAX; c++)
if (unit_vtable[c]->enumerate)
if ((q = unit_vtable[c]->enumerate(m)) < 0)
if (unit_vtable[c]->enumerate) {
q = unit_vtable[c]->enumerate(m);
if (q < 0)
r = q;
}
manager_dispatch_load_queue(m);
return r;
@ -2764,6 +2769,41 @@ void manager_status_printf(Manager *m, bool ephemeral, const char *status, const
va_end(ap);
}
int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) {
_cleanup_free_ char *p = NULL;
Unit *found;
assert(m);
assert(path);
assert(suffix);
assert(_found);
p = unit_name_from_path(path, suffix);
if (!p)
return -ENOMEM;
found = manager_get_unit(m, p);
if (!found) {
*_found = NULL;
return 0;
}
*_found = found;
return 1;
}
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
char p[strlen(path)+1];
assert(m);
assert(path);
strcpy(p, path);
path_kill_slashes(p);
return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p);
}
void watch_init(Watch *w) {
assert(w);

View File

@ -103,9 +103,6 @@ struct Manager {
* type we maintain a per type linked list */
LIST_HEAD(Unit, units_by_type[_UNIT_TYPE_MAX]);
/* To optimize iteration of units that have requires_mounts_for set */
LIST_HEAD(Unit, has_requires_mounts_for);
/* Units that need to be loaded */
LIST_HEAD(Unit, load_queue); /* this is actually more a stack than a queue, but uh. */
@ -251,6 +248,11 @@ struct Manager {
char *switch_root;
char *switch_root_init;
/* This maps all possible path prefixes to the units needing
* them. It's a hashmap with a path string as key and a Set as
* value where Unit objects are contained. */
Hashmap *units_requiring_mounts_for;
};
int manager_new(SystemdRunningAs running_as, bool reexecuting, Manager **m);
@ -263,6 +265,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
Job *manager_get_job(Manager *m, uint32_t id);
Unit *manager_get_unit(Manager *m, const char *name);
int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found);
int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j);
int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret);
@ -316,4 +320,6 @@ void manager_recheck_journal(Manager *m);
void manager_set_show_status(Manager *m, bool b);
void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) _printf_attr_(4,5);
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
void watch_init(Watch *w);

View File

@ -157,61 +157,56 @@ _pure_ static MountParameters* get_mount_parameters(Mount *m) {
}
static int mount_add_mount_links(Mount *m) {
Unit *other;
int r;
_cleanup_free_ char *parent = NULL;
MountParameters *pm;
Unit *other;
Iterator i;
Set *s;
int r;
assert(m);
if (!path_equal(m->where, "/")) {
/* Adds in links to other mount points that might lie further
* up in the hierarchy */
r = path_get_parent(m->where, &parent);
if (r < 0)
return r;
r = unit_require_mounts_for(UNIT(m), parent);
if (r < 0)
return r;
}
/* Adds in links to other mount points that might be needed
* for the source path (if this is a bind mount) to be
* available. */
pm = get_mount_parameters_fragment(m);
if (pm && path_is_absolute(pm->what)) {
r = unit_require_mounts_for(UNIT(m), pm->what);
if (r < 0)
return r;
}
/* Adds in links to other mount points that might lie below or
* above us in the hierarchy */
/* Adds in links to other units that use this path or paths
* further down in the hierarchy */
s = manager_get_units_requiring_mounts_for(UNIT(m)->manager, m->where);
SET_FOREACH(other, s, i) {
LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_MOUNT]) {
Mount *n = MOUNT(other);
MountParameters *pn;
if (n == m)
if (other->load_state != UNIT_LOADED)
continue;
if (UNIT(n)->load_state != UNIT_LOADED)
if (other == UNIT(m))
continue;
pn = get_mount_parameters_fragment(n);
r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true);
if (r < 0)
return r;
if (path_startswith(m->where, n->where)) {
if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
return r;
if (pn)
if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
return r;
} else if (path_startswith(n->where, m->where)) {
if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
return r;
if (pm)
if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
return r;
} else if (pm && pm->what && path_startswith(pm->what, n->where)) {
if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
return r;
if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
return r;
} else if (pn && pn->what && path_startswith(pn->what, m->where)) {
if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
return r;
if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
if (UNIT(m)->fragment_path) {
/* If we have fragment configuration, then make this dependency required */
r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true);
if (r < 0)
return r;
}
}
@ -219,81 +214,6 @@ static int mount_add_mount_links(Mount *m) {
return 0;
}
static int mount_add_swap_links(Mount *m) {
Unit *other;
int r;
assert(m);
LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SWAP]) {
r = swap_add_one_mount_link(SWAP(other), m);
if (r < 0)
return r;
}
return 0;
}
static int mount_add_path_links(Mount *m) {
Unit *other;
int r;
assert(m);
LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_PATH]) {
r = path_add_one_mount_link(PATH(other), m);
if (r < 0)
return r;
}
return 0;
}
static int mount_add_automount_links(Mount *m) {
Unit *other;
int r;
assert(m);
LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_AUTOMOUNT]) {
r = automount_add_one_mount_link(AUTOMOUNT(other), m);
if (r < 0)
return r;
}
return 0;
}
static int mount_add_socket_links(Mount *m) {
Unit *other;
int r;
assert(m);
LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SOCKET]) {
r = socket_add_one_mount_link(SOCKET(other), m);
if (r < 0)
return r;
}
return 0;
}
static int mount_add_requires_mounts_links(Mount *m) {
Unit *other;
int r;
assert(m);
LIST_FOREACH(has_requires_mounts_for, other, UNIT(m)->manager->has_requires_mounts_for) {
r = unit_add_one_mount_link(other, m);
if (r < 0)
return r;
}
return 0;
}
static char* mount_test_option(const char *haystack, const char *needle) {
struct mntent me = { .mnt_opts = (char*) haystack };
@ -567,8 +487,9 @@ static int mount_fix_timeouts(Mount *m) {
}
static int mount_verify(Mount *m) {
_cleanup_free_ char *e = NULL;
bool b;
char *e;
assert(m);
if (UNIT(m)->load_state != UNIT_LOADED)
@ -577,12 +498,11 @@ static int mount_verify(Mount *m) {
if (!m->from_fragment && !m->from_proc_self_mountinfo)
return -ENOENT;
if (!(e = unit_name_from_path(m->where, ".mount")))
e = unit_name_from_path(m->where, ".mount");
if (!e)
return -ENOMEM;
b = unit_has_name(UNIT(m), e);
free(e);
if (!b) {
log_error_unit(UNIT(m)->id,
"%s's Where setting doesn't match unit name. Refusing.",
@ -646,26 +566,6 @@ static int mount_add_extras(Mount *m) {
if (r < 0)
return r;
r = mount_add_socket_links(m);
if (r < 0)
return r;
r = mount_add_swap_links(m);
if (r < 0)
return r;
r = mount_add_path_links(m);
if (r < 0)
return r;
r = mount_add_requires_mounts_links(m);
if (r < 0)
return r;
r = mount_add_automount_links(m);
if (r < 0)
return r;
r = mount_add_quota_links(m);
if (r < 0)
return r;
@ -1650,79 +1550,56 @@ fail:
static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
int r = 0;
unsigned i;
char *device, *path, *options, *options2, *fstype, *d, *p, *o;
assert(m);
rewind(m->proc_self_mountinfo);
for (i = 1;; i++) {
_cleanup_free_ char *device = NULL, *path = NULL, *options = NULL, *options2 = NULL, *fstype = NULL, *d = NULL, *p = NULL, *o = NULL;
int k;
device = path = options = options2 = fstype = d = p = o = NULL;
k = fscanf(m->proc_self_mountinfo,
"%*s " /* (1) mount id */
"%*s " /* (2) parent id */
"%*s " /* (3) major:minor */
"%*s " /* (4) root */
"%ms " /* (5) mount point */
"%ms" /* (6) mount options */
"%*[^-]" /* (7) optional fields */
"- " /* (8) separator */
"%ms " /* (9) file system type */
"%ms" /* (10) mount source */
"%ms" /* (11) mount options 2 */
"%*[^\n]", /* some rubbish at the end */
&path,
&options,
&fstype,
&device,
&options2);
if ((k = fscanf(m->proc_self_mountinfo,
"%*s " /* (1) mount id */
"%*s " /* (2) parent id */
"%*s " /* (3) major:minor */
"%*s " /* (4) root */
"%ms " /* (5) mount point */
"%ms" /* (6) mount options */
"%*[^-]" /* (7) optional fields */
"- " /* (8) separator */
"%ms " /* (9) file system type */
"%ms" /* (10) mount source */
"%ms" /* (11) mount options 2 */
"%*[^\n]", /* some rubbish at the end */
&path,
&options,
&fstype,
&device,
&options2)) != 5) {
if (k == EOF)
break;
if (k == EOF)
break;
if (k != 5) {
log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
goto clean_up;
continue;
}
o = strjoin(options, ",", options2, NULL);
if (!o) {
r = -ENOMEM;
goto finish;
}
if (!o)
return log_oom();
if (!(d = cunescape(device)) ||
!(p = cunescape(path))) {
r = -ENOMEM;
goto finish;
}
d = cunescape(device);
p = cunescape(path);
if (!d || !p)
return log_oom();
if ((k = mount_add_one(m, d, p, o, fstype, 0, set_flags)) < 0)
k = mount_add_one(m, d, p, o, fstype, 0, set_flags);
if (k < 0)
r = k;
clean_up:
free(device);
free(path);
free(options);
free(options2);
free(fstype);
free(d);
free(p);
free(o);
}
finish:
free(device);
free(path);
free(options);
free(options2);
free(fstype);
free(d);
free(p);
free(o);
return r;
}

View File

@ -241,10 +241,6 @@ static bool path_spec_check_good(PathSpec *s, bool initial) {
return good;
}
static bool path_spec_startswith(PathSpec *s, const char *what) {
return path_startswith(s->path, what);
}
static void path_spec_mkdir(PathSpec *s, mode_t mode) {
int r;
@ -301,38 +297,14 @@ static void path_done(Unit *u) {
path_free_specs(p);
}
int path_add_one_mount_link(Path *p, Mount *m) {
static int path_add_mount_links(Path *p) {
PathSpec *s;
int r;
assert(p);
assert(m);
if (UNIT(p)->load_state != UNIT_LOADED ||
UNIT(m)->load_state != UNIT_LOADED)
return 0;
LIST_FOREACH(spec, s, p->specs) {
if (!path_spec_startswith(s, m->where))
continue;
r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
UNIT(m), true);
if (r < 0)
return r;
}
return 0;
}
static int path_add_mount_links(Path *p) {
Unit *other;
int r;
assert(p);
LIST_FOREACH(units_by_type, other, UNIT(p)->manager->units_by_type[UNIT_MOUNT]) {
r = path_add_one_mount_link(p, MOUNT(other));
r = unit_require_mounts_for(UNIT(p), s->path);
if (r < 0)
return r;
}

View File

@ -90,10 +90,6 @@ struct Path {
PathResult result;
};
/* Called from the mount code figure out if a mount is a dependency of
* any of the paths of this path object */
int path_add_one_mount_link(Path *p, Mount *m);
void path_free_specs(Path *p);
extern const UnitVTable path_vtable;

View File

@ -258,53 +258,24 @@ static int socket_verify(Socket *s) {
return 0;
}
static bool socket_needs_mount(Socket *s, const char *prefix) {
static int socket_add_mount_links(Socket *s) {
SocketPort *p;
int r;
assert(s);
LIST_FOREACH(port, p, s->ports) {
const char *path = NULL;
if (p->type == SOCKET_SOCKET) {
if (socket_address_needs_mount(&p->address, prefix))
return true;
} else if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL) {
if (path_startswith(p->path, prefix))
return true;
}
}
if (p->type == SOCKET_SOCKET)
path = socket_address_get_path(&p->address);
else if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL)
path = p->path;
return false;
}
if (!path)
continue;
int socket_add_one_mount_link(Socket *s, Mount *m) {
int r;
assert(s);
assert(m);
if (UNIT(s)->load_state != UNIT_LOADED ||
UNIT(m)->load_state != UNIT_LOADED)
return 0;
if (!socket_needs_mount(s, m->where))
return 0;
r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
if (r < 0)
return r;
return 0;
}
static int socket_add_mount_links(Socket *s) {
Unit *other;
int r;
assert(s);
LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_MOUNT]) {
r = socket_add_one_mount_link(s, MOUNT(other));
r = unit_require_mounts_for(UNIT(s), path);
if (r < 0)
return r;
}

View File

@ -156,10 +156,6 @@ struct Socket {
/* Called from the service code when collecting fds */
int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
/* Called from the mount code figure out if a mount is a dependency of
* any of the sockets of this socket */
int socket_add_one_mount_link(Socket *s, Mount *m);
/* Called from the service code when a per-connection service ended */
void socket_connection_unref(Socket *s);

View File

@ -137,42 +137,6 @@ static void swap_done(Unit *u) {
unit_unwatch_timer(u, &s->timer_watch);
}
int swap_add_one_mount_link(Swap *s, Mount *m) {
int r;
assert(s);
assert(m);
if (UNIT(s)->load_state != UNIT_LOADED ||
UNIT(m)->load_state != UNIT_LOADED)
return 0;
if (is_device_path(s->what))
return 0;
if (!path_startswith(s->what, m->where))
return 0;
r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
if (r < 0)
return r;
return 0;
}
static int swap_add_mount_links(Swap *s) {
Unit *other;
int r;
assert(s);
LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_MOUNT])
if ((r = swap_add_one_mount_link(s, MOUNT(other))) < 0)
return r;
return 0;
}
static int swap_add_device_links(Swap *s) {
SwapParameters *p;
@ -300,11 +264,11 @@ static int swap_load(Unit *u) {
if ((r = unit_set_description(u, s->what)) < 0)
return r;
r = swap_add_device_links(s);
r = unit_require_mounts_for(UNIT(s), s->what);
if (r < 0)
return r;
r = swap_add_mount_links(s);
r = swap_add_device_links(s);
if (r < 0)
return r;

View File

@ -107,8 +107,6 @@ struct Swap {
extern const UnitVTable swap_vtable;
int swap_add_one_mount_link(Swap *s, Mount *m);
int swap_dispatch_reload(Manager *m);
int swap_fd_event(Manager *m, int events);

View File

@ -374,6 +374,34 @@ static void unit_remove_transient(Unit *u) {
}
}
static void unit_free_requires_mounts_for(Unit *u) {
char **j;
STRV_FOREACH(j, u->requires_mounts_for) {
char s[strlen(*j) + 1];
PATH_FOREACH_PREFIX_MORE(s, *j) {
char *y;
Set *x;
x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y);
if (!x)
continue;
set_remove(x, u);
if (set_isempty(x)) {
hashmap_remove(u->manager->units_requiring_mounts_for, y);
free(y);
set_free(x);
}
}
}
strv_free(u->requires_mounts_for);
u->requires_mounts_for = NULL;
}
void unit_free(Unit *u) {
UnitDependency d;
Iterator i;
@ -390,6 +418,8 @@ void unit_free(Unit *u) {
if (UNIT_VTABLE(u)->done)
UNIT_VTABLE(u)->done(u);
unit_free_requires_mounts_for(u);
SET_FOREACH(t, u->names, i)
hashmap_remove_value(u->manager->units, t, u);
@ -408,11 +438,6 @@ void unit_free(Unit *u) {
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
bidi_set_free(u, u->dependencies[d]);
if (u->requires_mounts_for) {
LIST_REMOVE(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
strv_free(u->requires_mounts_for);
}
if (u->type != _UNIT_TYPE_INVALID)
LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u);
@ -2659,40 +2684,39 @@ void unit_ref_unset(UnitRef *ref) {
ref->unit = NULL;
}
int unit_add_one_mount_link(Unit *u, Mount *m) {
char **i;
assert(u);
assert(m);
if (u->load_state != UNIT_LOADED ||
UNIT(m)->load_state != UNIT_LOADED)
return 0;
STRV_FOREACH(i, u->requires_mounts_for) {
if (UNIT(m) == u)
continue;
if (!path_startswith(*i, m->where))
continue;
return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
}
return 0;
}
int unit_add_mount_links(Unit *u) {
Unit *other;
char **i;
int r;
assert(u);
LIST_FOREACH(units_by_type, other, u->manager->units_by_type[UNIT_MOUNT]) {
r = unit_add_one_mount_link(u, MOUNT(other));
if (r < 0)
return r;
STRV_FOREACH(i, u->requires_mounts_for) {
char prefix[strlen(*i) + 1];
PATH_FOREACH_PREFIX_MORE(prefix, *i) {
Unit *m;
r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m);
if (r < 0)
return r;
if (r == 0)
continue;
if (m == u)
continue;
if (m->load_state != UNIT_LOADED)
continue;
r = unit_add_dependency(u, UNIT_AFTER, m, true);
if (r < 0)
return r;
if (m->fragment_path) {
r = unit_add_dependency(u, UNIT_REQUIRES, m, true);
if (r < 0)
return r;
}
}
}
return 0;
@ -3012,6 +3036,86 @@ int unit_kill_context(
return wait_for_exit;
}
int unit_require_mounts_for(Unit *u, const char *path) {
char prefix[strlen(path) + 1], *p;
int r;
assert(u);
assert(path);
/* Registers a unit for requiring a certain path and all its
* prefixes. We keep a simple array of these paths in the
* unit, since its usually short. However, we build a prefix
* table for all possible prefixes so that new appearing mount
* units can easily determine which units to make themselves a
* dependency of. */
p = strdup(path);
if (!p)
return -ENOMEM;
path_kill_slashes(p);
if (!path_is_absolute(p)) {
free(p);
return -EINVAL;
}
if (!path_is_safe(p)) {
free(p);
return -EPERM;
}
if (strv_contains(u->requires_mounts_for, p)) {
free(p);
return 0;
}
r = strv_push(&u->requires_mounts_for, p);
if (r < 0) {
free(p);
return r;
}
PATH_FOREACH_PREFIX_MORE(prefix, p) {
Set *x;
x = hashmap_get(u->manager->units_requiring_mounts_for, prefix);
if (!x) {
char *q;
if (!u->manager->units_requiring_mounts_for) {
u->manager->units_requiring_mounts_for = hashmap_new(string_hash_func, string_compare_func);
if (!u->manager->units_requiring_mounts_for)
return -ENOMEM;
}
q = strdup(prefix);
if (!q)
return -ENOMEM;
x = set_new(NULL, NULL);
if (!x) {
free(q);
return -ENOMEM;
}
r = hashmap_put(u->manager->units_requiring_mounts_for, q, x);
if (r < 0) {
free(q);
set_free(x);
return r;
}
}
r = set_put(x, u);
if (r < 0)
return r;
}
return 0;
}
static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
[UNIT_ACTIVE] = "active",
[UNIT_RELOADING] = "reloading",

View File

@ -173,7 +173,6 @@ struct Unit {
/* Counterparts in the cgroup filesystem */
char *cgroup_path;
bool cgroup_realized;
CGroupControllerMask cgroup_mask;
UnitRef slice;
@ -255,6 +254,8 @@ struct Unit {
bool no_gc:1;
bool in_audit:1;
bool cgroup_realized:1;
};
struct UnitStatusMessageFormats {
@ -589,7 +590,6 @@ void unit_ref_unset(UnitRef *ref);
#define UNIT_DEREF(ref) ((ref).unit)
#define UNIT_ISSET(ref) (!!(ref).unit)
int unit_add_one_mount_link(Unit *u, Mount *m);
int unit_add_mount_links(Unit *u);
int unit_exec_context_defaults(Unit *u, ExecContext *c);
@ -609,6 +609,8 @@ int unit_kill_context(Unit *u, KillContext *c, bool sigkill, pid_t main_pid, pid
int unit_make_transient(Unit *u);
int unit_require_mounts_for(Unit *u, const char *path);
const char *unit_active_state_to_string(UnitActiveState i) _const_;
UnitActiveState unit_active_state_from_string(const char *s) _pure_;

View File

@ -486,16 +486,16 @@ bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
return socket_address_equal(a, &b);
}
bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
const char* socket_address_get_path(const SocketAddress *a) {
assert(a);
if (socket_address_family(a) != AF_UNIX)
return false;
return NULL;
if (a->sockaddr.un.sun_path[0] == 0)
return false;
return NULL;
return path_startswith(a->sockaddr.un.sun_path, prefix);
return a->sockaddr.un.sun_path;
}
bool socket_ipv6_is_supported(void) {

View File

@ -92,7 +92,7 @@ int make_socket_fd(const char* address, int flags);
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_;
bool socket_address_needs_mount(const SocketAddress *a, const char *prefix);
const char* socket_address_get_path(const SocketAddress *a);
const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_;
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_;