core: do BindMount/MountImage operations in async control process
These operations might require slow I/O, and thus might block PID1's main loop for an undeterminated amount of time. Instead of performing them inline, fork a worker process and stash away the D-Bus message, and reply once we get a SIGCHILD indicating they have completed. That way we don't break compatibility and callers can continue to rely on the fact that when they get the method reply the operation either succeeded or failed. To keep backward compatibility, unlike reload control processes, these are ran inside init.scope and not the target cgroup. Unlike ExecReload, this is under our control and is not defined by the unit. This is necessary because previously the operation also wasn't ran from the target cgroup, so suddenly forking a copy-on-write copy of pid1 into the target cgroup will make memory usage spike, and if there is a MemoryMax= or MemoryHigh= set and the cgroup is already close to the limit, it will cause an OOM kill, where previously it would have worked fine.
This commit is contained in:
committed by
Luca Boccassi
parent
5121f7c45b
commit
5162829ec8
+26
-38
@@ -854,11 +854,9 @@ static int mount_in_namespace_legacy(
|
||||
int pidns_fd,
|
||||
int mntns_fd,
|
||||
int root_fd,
|
||||
bool read_only,
|
||||
bool make_file_or_directory,
|
||||
MountInNamespaceFlags flags,
|
||||
const MountOptions *options,
|
||||
const ImagePolicy *image_policy,
|
||||
bool is_image) {
|
||||
const ImagePolicy *image_policy) {
|
||||
|
||||
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
|
||||
char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
|
||||
@@ -877,7 +875,7 @@ static int mount_in_namespace_legacy(
|
||||
assert(pidns_fd >= 0);
|
||||
assert(mntns_fd >= 0);
|
||||
assert(root_fd >= 0);
|
||||
assert(!options || is_image);
|
||||
assert(!options || (flags & MOUNT_IN_NAMESPACE_IS_IMAGE));
|
||||
|
||||
p = strjoina(propagate_path, "/");
|
||||
r = laccess(p, F_OK);
|
||||
@@ -910,7 +908,7 @@ static int mount_in_namespace_legacy(
|
||||
|
||||
/* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
|
||||
mount_tmp = strjoina(mount_slave, "/mount");
|
||||
if (is_image)
|
||||
if (flags & MOUNT_IN_NAMESPACE_IS_IMAGE)
|
||||
r = mkdir_p(mount_tmp, 0700);
|
||||
else
|
||||
r = make_mount_point_inode_from_stat(chased_src_st, mount_tmp, 0700);
|
||||
@@ -921,7 +919,7 @@ static int mount_in_namespace_legacy(
|
||||
|
||||
mount_tmp_created = true;
|
||||
|
||||
if (is_image)
|
||||
if (flags & MOUNT_IN_NAMESPACE_IS_IMAGE)
|
||||
r = verity_dissect_and_mount(
|
||||
chased_src_fd,
|
||||
chased_src_path,
|
||||
@@ -943,7 +941,7 @@ static int mount_in_namespace_legacy(
|
||||
mount_tmp_mounted = true;
|
||||
|
||||
/* Third, we remount the new bind mount read-only if requested. */
|
||||
if (read_only) {
|
||||
if (flags & MOUNT_IN_NAMESPACE_READ_ONLY) {
|
||||
r = mount_nofollow_verbose(LOG_DEBUG, NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
@@ -953,7 +951,7 @@ static int mount_in_namespace_legacy(
|
||||
* right-away. */
|
||||
|
||||
mount_outside = strjoina(propagate_path, "/XXXXXX");
|
||||
if (is_image || S_ISDIR(chased_src_st->st_mode))
|
||||
if ((flags & MOUNT_IN_NAMESPACE_IS_IMAGE) || S_ISDIR(chased_src_st->st_mode))
|
||||
r = mkdtemp(mount_outside) ? 0 : -errno;
|
||||
else {
|
||||
r = mkostemp_safe(mount_outside);
|
||||
@@ -973,7 +971,7 @@ static int mount_in_namespace_legacy(
|
||||
mount_outside_mounted = true;
|
||||
mount_tmp_mounted = false;
|
||||
|
||||
if (is_image || S_ISDIR(chased_src_st->st_mode))
|
||||
if ((flags & MOUNT_IN_NAMESPACE_IS_IMAGE) || S_ISDIR(chased_src_st->st_mode))
|
||||
(void) rmdir(mount_tmp);
|
||||
else
|
||||
(void) unlink(mount_tmp);
|
||||
@@ -999,8 +997,8 @@ static int mount_in_namespace_legacy(
|
||||
|
||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
||||
|
||||
if (make_file_or_directory) {
|
||||
if (!is_image) {
|
||||
if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) {
|
||||
if (!(flags & MOUNT_IN_NAMESPACE_IS_IMAGE)) {
|
||||
(void) mkdir_parents(dest, 0755);
|
||||
(void) make_mount_point_inode_from_stat(chased_src_st, dest, 0700);
|
||||
} else
|
||||
@@ -1052,7 +1050,7 @@ finish:
|
||||
if (mount_outside_mounted)
|
||||
(void) umount_verbose(LOG_DEBUG, mount_outside, UMOUNT_NOFOLLOW);
|
||||
if (mount_outside_created) {
|
||||
if (is_image || S_ISDIR(chased_src_st->st_mode))
|
||||
if ((flags & MOUNT_IN_NAMESPACE_IS_IMAGE) || S_ISDIR(chased_src_st->st_mode))
|
||||
(void) rmdir(mount_outside);
|
||||
else
|
||||
(void) unlink(mount_outside);
|
||||
@@ -1061,7 +1059,7 @@ finish:
|
||||
if (mount_tmp_mounted)
|
||||
(void) umount_verbose(LOG_DEBUG, mount_tmp, UMOUNT_NOFOLLOW);
|
||||
if (mount_tmp_created) {
|
||||
if (is_image || S_ISDIR(chased_src_st->st_mode))
|
||||
if ((flags & MOUNT_IN_NAMESPACE_IS_IMAGE) || S_ISDIR(chased_src_st->st_mode))
|
||||
(void) rmdir(mount_tmp);
|
||||
else
|
||||
(void) unlink(mount_tmp);
|
||||
@@ -1081,9 +1079,7 @@ static int mount_in_namespace(
|
||||
const char *incoming_path,
|
||||
const char *src,
|
||||
const char *dest,
|
||||
bool read_only,
|
||||
bool make_file_or_directory,
|
||||
bool is_image,
|
||||
MountInNamespaceFlags flags,
|
||||
const MountOptions *options,
|
||||
const ImagePolicy *image_policy) {
|
||||
|
||||
@@ -1096,7 +1092,7 @@ static int mount_in_namespace(
|
||||
assert(incoming_path);
|
||||
assert(src);
|
||||
assert(dest);
|
||||
assert(is_image || (!options && !image_policy));
|
||||
assert((flags & MOUNT_IN_NAMESPACE_IS_IMAGE) || (!options && !image_policy));
|
||||
|
||||
if (!pidref_is_set(target))
|
||||
return -ESRCH;
|
||||
@@ -1133,18 +1129,16 @@ static int mount_in_namespace(
|
||||
pidns_fd,
|
||||
mntns_fd,
|
||||
root_fd,
|
||||
read_only,
|
||||
make_file_or_directory,
|
||||
flags,
|
||||
options,
|
||||
image_policy,
|
||||
is_image);
|
||||
image_policy);
|
||||
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *img = NULL;
|
||||
_cleanup_close_ int new_mount_fd = -EBADF;
|
||||
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
|
||||
pid_t child;
|
||||
|
||||
if (is_image) {
|
||||
if (flags & MOUNT_IN_NAMESPACE_IS_IMAGE) {
|
||||
r = verity_dissect_and_mount(
|
||||
chased_src_fd,
|
||||
chased_src_path,
|
||||
@@ -1173,7 +1167,7 @@ static int mount_in_namespace(
|
||||
"Failed to open mount source '%s': %m",
|
||||
chased_src_path);
|
||||
|
||||
if (read_only && mount_setattr(new_mount_fd, "", AT_EMPTY_PATH,
|
||||
if ((flags & MOUNT_IN_NAMESPACE_READ_ONLY) && mount_setattr(new_mount_fd, "", AT_EMPTY_PATH,
|
||||
&(struct mount_attr) {
|
||||
.attr_set = MOUNT_ATTR_RDONLY,
|
||||
}, MOUNT_ATTR_SIZE_VER0) < 0)
|
||||
@@ -1201,7 +1195,7 @@ static int mount_in_namespace(
|
||||
if (r == 0) {
|
||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
||||
|
||||
if (make_file_or_directory)
|
||||
if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY)
|
||||
(void) mkdir_parents(dest, 0755);
|
||||
|
||||
if (img) {
|
||||
@@ -1209,10 +1203,10 @@ static int mount_in_namespace(
|
||||
DISSECT_IMAGE_TRY_ATOMIC_MOUNT_EXCHANGE |
|
||||
DISSECT_IMAGE_ALLOW_USERSPACE_VERITY;
|
||||
|
||||
if (make_file_or_directory)
|
||||
if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY)
|
||||
f |= DISSECT_IMAGE_MKDIR;
|
||||
|
||||
if (read_only)
|
||||
if (flags & MOUNT_IN_NAMESPACE_READ_ONLY)
|
||||
f |= DISSECT_IMAGE_READ_ONLY;
|
||||
|
||||
r = dissected_image_mount(
|
||||
@@ -1223,7 +1217,7 @@ static int mount_in_namespace(
|
||||
/* userns_fd= */ -EBADF,
|
||||
f);
|
||||
} else {
|
||||
if (make_file_or_directory)
|
||||
if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY)
|
||||
(void) make_mount_point_inode_from_stat(&st, dest, 0700);
|
||||
|
||||
r = mount_exchange_graceful(new_mount_fd, dest, /* mount_beneath= */ true);
|
||||
@@ -1259,17 +1253,14 @@ int bind_mount_in_namespace(
|
||||
const char *incoming_path,
|
||||
const char *src,
|
||||
const char *dest,
|
||||
bool read_only,
|
||||
bool make_file_or_directory) {
|
||||
MountInNamespaceFlags flags) {
|
||||
|
||||
return mount_in_namespace(target,
|
||||
propagate_path,
|
||||
incoming_path,
|
||||
src,
|
||||
dest,
|
||||
read_only,
|
||||
make_file_or_directory,
|
||||
/* is_image = */ false,
|
||||
flags & ~MOUNT_IN_NAMESPACE_IS_IMAGE,
|
||||
/* options = */ NULL,
|
||||
/* image_policy = */ NULL);
|
||||
}
|
||||
@@ -1280,8 +1271,7 @@ int mount_image_in_namespace(
|
||||
const char *incoming_path,
|
||||
const char *src,
|
||||
const char *dest,
|
||||
bool read_only,
|
||||
bool make_file_or_directory,
|
||||
MountInNamespaceFlags flags,
|
||||
const MountOptions *options,
|
||||
const ImagePolicy *image_policy) {
|
||||
|
||||
@@ -1290,9 +1280,7 @@ int mount_image_in_namespace(
|
||||
incoming_path,
|
||||
src,
|
||||
dest,
|
||||
read_only,
|
||||
make_file_or_directory,
|
||||
/* is_image = */ true,
|
||||
flags | MOUNT_IN_NAMESPACE_IS_IMAGE,
|
||||
options,
|
||||
image_policy);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user