diff options
author | Lennart Poettering <lennart@poettering.net> | 2016-12-14 00:51:37 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2016-12-14 00:51:37 +0100 |
commit | 8fceda937f3a177d9e27b403fb5e1b34138b05f5 (patch) | |
tree | 6453f86079b33adf50355f3c01c0314dce443be1 | |
parent | 34de407a4fca46cdb5e45aae149604fe10102ecf (diff) |
namespace: instead of chasing mount symlinks a priori, do so as-we-go
This is relevant as many of the mounts we try to establish only can be followed
when some other prior mount that is a prefix of it is established. Hence: move
the symlink chasing into the actual mount functions, so that we do it as late
as possibly but as early as necessary.
Fixes: #4588
-rw-r--r-- | src/core/namespace.c | 86 |
1 files changed, 34 insertions, 52 deletions
diff --git a/src/core/namespace.c b/src/core/namespace.c index 1b4bcd5ba4..746ebc45b0 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -568,7 +568,33 @@ fail: return r; } +static int mount_entry_chase(MountEntry *m, const char *root_directory) { + char *chased; + int r; + + assert(m); + + /* Since mount() will always follow symlinks and we need to take the different root directory into account we + * chase the symlinks on our own first. */ + + r = chase_symlinks(mount_entry_path(m), root_directory, 0, &chased); + if (r == -ENOENT && m->ignore) { + log_debug_errno(r, "Path %s does not exist, ignoring.", mount_entry_path(m)); + return 0; + } + if (r < 0) + return log_debug_errno(r, "Failed to follow symlinks on %s: %m", mount_entry_path(m)); + + log_debug("Followed symlinks %s → %s.", mount_entry_path(m), chased); + + free(m->path_malloc); + m->path_malloc = chased; + + return 1; +} + static int apply_mount( + const char *root_directory, MountEntry *m, const char *tmp_dir, const char *var_tmp_dir) { @@ -578,6 +604,10 @@ static int apply_mount( assert(m); + r = mount_entry_chase(m, root_directory); + if (r <= 0) + return r; + log_debug("Applying namespace mount on %s", mount_entry_path(m)); switch (m->mode) { @@ -604,7 +634,7 @@ static int apply_mount( case READONLY: case READWRITE: - r = path_is_mount_point(mount_entry_path(m), NULL, 0); + r = path_is_mount_point(mount_entry_path(m), root_directory, 0); if (r < 0) return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", mount_entry_path(m)); if (r > 0) /* Nothing to do here, it is already a mount. We just later toggle the MS_RDONLY bit for the mount point if needed. */ @@ -654,50 +684,9 @@ static int make_read_only(MountEntry *m, char **blacklist) { * already stays this way. This improves compatibility with container managers, where we won't attempt to undo * read-only mounts already applied. */ - return r; -} - -/* Chase symlinks and remove failed paths from mounts */ -static int chase_all_symlinks(const char *root_directory, MountEntry *m, unsigned *n) { - MountEntry *f, *t; - int r = 0; - - assert(m); - assert(n); - - /* Since mount() will always follow symlinks and we need to take the different root directory into account we - * chase the symlinks on our own first. This call wil do so for all entries and remove all entries where we - * can't resolve the path, and which have been marked for such removal. */ - - for (f = m, t = m; f < m + *n; f++) { - _cleanup_free_ char *chased = NULL; - int k; - - k = chase_symlinks(mount_entry_path(f), root_directory, 0, &chased); - if (k < 0) { - /* Get only real errors */ - if (r >= 0 && (k != -ENOENT || !f->ignore)) - r = k; - - /* Doesn't exist or failed? Then remove it and continue! */ - log_debug_errno(k, "Failed to chase symlinks for %s: %m", mount_entry_path(f)); - f->path_malloc = mfree(f->path_malloc); - continue; - } - - if (!path_equal(mount_entry_path(f), chased)) { - log_debug("Chased %s → %s", mount_entry_path(f), chased); - - free(f->path_malloc); - f->path_malloc = chased; - chased = NULL; - } - - *t = *f; - t++; - } + if (r == -ENOENT && m->ignore) + r = 0; - *n = t - m; return r; } @@ -838,13 +827,6 @@ int setup_namespace( if (r < 0) goto finish; - /* Resolve symlinks manually first, as mount() will always follow them relative to the host's - * root. Moreover we want to suppress duplicates based on the resolved paths. This of course is a bit - * racy. */ - r = chase_all_symlinks(root_directory, mounts, &n_mounts); - if (r < 0) - goto finish; - qsort(mounts, n_mounts, sizeof(MountEntry), mount_path_compare); drop_duplicates(mounts, &n_mounts); @@ -886,7 +868,7 @@ int setup_namespace( /* First round, add in all special mounts we need */ for (m = mounts; m < mounts + n_mounts; ++m) { - r = apply_mount(m, tmp_dir, var_tmp_dir); + r = apply_mount(root_directory, m, tmp_dir, var_tmp_dir); if (r < 0) goto finish; } |