/* * This function assumes that all pids inside a cgroup * belong to the same namespace, that is the container namespace. * Therefore, from the host box, any of them will do. */ pid_t get_pid_from_container(envid_t veid) { char cgrp[CT_MAX_STR_SIZE]; struct cgroup *ct; void *task_handle; void *cont_handle; struct cgroup_mount_point mnt; pid_t pid = -1; int ret; veid_to_name(cgrp, veid); ct = cgroup_new_cgroup(cgrp); ret = cgroup_get_cgroup(ct); if (ret == ECGROUPNOTEXIST) goto out_free; ret = cgroup_get_controller_begin(&cont_handle, &mnt); if (ret != 0) /* no controllers, something is wrong */ goto out_free; ret = cgroup_get_task_begin(cgrp, mnt.name, &task_handle, &pid); if (ret != 0) /* no tasks, something is also wrong */ goto out_end_cont; cgroup_get_task_end(&task_handle); out_end_cont: cgroup_get_controller_end(&cont_handle); out_free: cgroup_free(&ct); return pid; }
static int do_create_container(struct cgroup *ct, struct cgroup *parent) { struct cgroup_mount_point mnt; struct cgroup_controller *controller; void *handle; int ret; ret = cgroup_get_controller_begin(&handle, &mnt); cgroup_get_cgroup(parent); do { controller = cgroup_add_controller(ct, mnt.name); ret = controller_apply_config(ct, parent, controller, mnt.name); if (!ret) ret = cgroup_get_controller_next(&handle, &mnt); } while (!ret); cgroup_get_controller_end(&handle); if (ret == ECGEOF) ret = cgroup_create_cgroup(ct, 0); return ret; }
int container_is_running(envid_t veid) { int ret = 0; void *handle; struct cgroup_mount_point mnt; struct cgroup *ct; char cgrp[CT_MAX_STR_SIZE]; veid_to_name(cgrp, veid); ct = cgroup_new_cgroup(cgrp); ret = cgroup_get_cgroup(ct); if (ret == ECGROUPNOTEXIST) { ret = 0; goto out_free; } ret = cgroup_get_controller_begin(&handle, &mnt); do { struct cgroup_controller *controller; controller = cgroup_get_controller(ct, mnt.name); if (!controller) { logger(0, 0, "Controller %s seems to be missing!", mnt.name); continue; } if ((ret = controller_has_tasks(cgrp, mnt.name)) != 0) goto out; } while ((ret = cgroup_get_controller_next(&handle, &mnt)) == 0); if (ret != ECGEOF) ret = -ret; else ret = 0; out: cgroup_get_controller_end(&handle); out_free: cgroup_free(&ct); return ret; }
int VanillaProc::setupOOMEvent(const std::string &cgroup_string) { #if !(defined(HAVE_EVENTFD) && defined(HAVE_EXT_LIBCGROUP)) // Shut the compiler up. cgroup_string.size(); return 0; #else // Initialize the event descriptor int tmp_efd = eventfd(0, EFD_CLOEXEC); if (tmp_efd == -1) { dprintf(D_ALWAYS, "Unable to create new event FD for starter: %u %s\n", errno, strerror(errno)); return 1; } // Find the memcg location on disk void * handle = NULL; struct cgroup_mount_point mount_info; int ret = cgroup_get_controller_begin(&handle, &mount_info); std::stringstream oom_control; std::stringstream event_control; bool found_memcg = false; while (ret == 0) { if (strcmp(mount_info.name, MEMORY_CONTROLLER_STR) == 0) { found_memcg = true; oom_control << mount_info.path << "/"; event_control << mount_info.path << "/"; break; } cgroup_get_controller_next(&handle, &mount_info); } if (!found_memcg && (ret != ECGEOF)) { dprintf(D_ALWAYS, "Error while locating memcg controller for starter: %u %s\n", ret, cgroup_strerror(ret)); return 1; } cgroup_get_controller_end(&handle); if (found_memcg == false) { dprintf(D_ALWAYS, "Memcg is not available; OOM notification disabled for starter.\n"); return 1; } // Finish constructing the location of the control files oom_control << cgroup_string << "/memory.oom_control"; std::string oom_control_str = oom_control.str(); event_control << cgroup_string << "/cgroup.event_control"; std::string event_control_str = event_control.str(); // Open the oom_control and event control files TemporaryPrivSentry sentry(PRIV_ROOT); m_oom_fd = open(oom_control_str.c_str(), O_RDONLY | O_CLOEXEC); if (m_oom_fd == -1) { dprintf(D_ALWAYS, "Unable to open the OOM control file for starter: %u %s\n", errno, strerror(errno)); return 1; } int event_ctrl_fd = open(event_control_str.c_str(), O_WRONLY | O_CLOEXEC); if (event_ctrl_fd == -1) { dprintf(D_ALWAYS, "Unable to open event control for starter: %u %s\n", errno, strerror(errno)); return 1; } // Inform Linux we will be handling the OOM events for this container. int oom_fd2 = open(oom_control_str.c_str(), O_WRONLY | O_CLOEXEC); if (oom_fd2 == -1) { dprintf(D_ALWAYS, "Unable to open the OOM control file for writing for starter: %u %s\n", errno, strerror(errno)); close(event_ctrl_fd); return 1; } const char limits [] = "1"; ssize_t nwritten = full_write(oom_fd2, &limits, 1); if (nwritten < 0) { /* Newer kernels return EINVAL if you attempt to enable OOM management * on a cgroup where use_hierarchy is set to 1 and it is not the parent * cgroup. * * This is a common setup, so we log and move along. * * See also #4435. */ if (errno == EINVAL) { dprintf(D_FULLDEBUG, "Unable to setup OOM killer management because" " memory.use_hierarchy is enabled for this cgroup; consider" " disabling it for this host or set BASE_CGROUP=/. The hold" " message for an OOM event may not be reliably set.\n"); } else { dprintf(D_ALWAYS, "Failure when attempting to enable OOM killer " " management for this job (errno=%d, %s).\n", errno, strerror(errno)); close(event_ctrl_fd); close(oom_fd2); close(tmp_efd); return 1; } } close(oom_fd2); // Create the subscription string: std::stringstream sub_ss; sub_ss << tmp_efd << " " << m_oom_fd; std::string sub_str = sub_ss.str(); if ((nwritten = full_write(event_ctrl_fd, sub_str.c_str(), sub_str.size())) < 0) { dprintf(D_ALWAYS, "Unable to write into event control file for starter: %u %s\n", errno, strerror(errno)); close(event_ctrl_fd); close(tmp_efd); return 1; } close(event_ctrl_fd); // Fool DC into talking to the eventfd int pipes[2]; pipes[0] = -1; pipes[1] = -1; int fd_to_replace = -1; if (!daemonCore->Create_Pipe(pipes, true) || pipes[0] == -1) { dprintf(D_ALWAYS, "Unable to create a DC pipe\n"); close(tmp_efd); close(m_oom_fd); m_oom_fd = -1; return 1; } if (!daemonCore->Get_Pipe_FD(pipes[0], &fd_to_replace) || fd_to_replace == -1) { dprintf(D_ALWAYS, "Unable to lookup pipe's FD\n"); close(tmp_efd); close(m_oom_fd); m_oom_fd = -1; daemonCore->Close_Pipe(pipes[0]); daemonCore->Close_Pipe(pipes[1]); return 1; } dup3(tmp_efd, fd_to_replace, O_CLOEXEC); close(tmp_efd); m_oom_efd = pipes[0]; m_oom_efd2 = pipes[1]; // Inform DC we want to recieve notifications from this FD. if (-1 == daemonCore->Register_Pipe(pipes[0],"OOM event fd", static_cast<PipeHandlercpp>(&VanillaProc::outOfMemoryEvent),"OOM Event Handler",this,HANDLE_READ)) { dprintf(D_ALWAYS, "Failed to register OOM event FD pipe.\n"); daemonCore->Close_Pipe(pipes[0]); daemonCore->Close_Pipe(pipes[1]); m_oom_fd = -1; m_oom_efd = -1; m_oom_efd2 = -1; } dprintf(D_FULLDEBUG, "Subscribed the starter to OOM notification for this cgroup; jobs triggering an OOM will be put on hold.\n"); return 0; #endif }
int VanillaProc::setupOOMEvent(const std::string &cgroup_string) { #if !(defined(HAVE_EVENTFD) && defined(HAVE_EXT_LIBCGROUP)) // Shut the compiler up. cgroup_string.size(); return 0; #else // Initialize the event descriptor m_oom_efd = eventfd(0, EFD_CLOEXEC); if (m_oom_efd == -1) { dprintf(D_ALWAYS, "Unable to create new event FD for starter: %u %s\n", errno, strerror(errno)); return 1; } // Find the memcg location on disk void * handle = NULL; struct cgroup_mount_point mount_info; int ret = cgroup_get_controller_begin(&handle, &mount_info); std::stringstream oom_control; std::stringstream event_control; bool found_memcg = false; while (ret == 0) { if (strcmp(mount_info.name, MEMORY_CONTROLLER_STR) == 0) { found_memcg = true; oom_control << mount_info.path << "/"; event_control << mount_info.path << "/"; break; } cgroup_get_controller_next(&handle, &mount_info); } if (!found_memcg && (ret != ECGEOF)) { dprintf(D_ALWAYS, "Error while locating memcg controller for starter: %u %s\n", ret, cgroup_strerror(ret)); return 1; } cgroup_get_controller_end(&handle); if (found_memcg == false) { dprintf(D_ALWAYS, "Memcg is not available; OOM notification disabled for starter.\n"); return 1; } // Finish constructing the location of the control files oom_control << cgroup_string << "/memory.oom_control"; std::string oom_control_str = oom_control.str(); event_control << cgroup_string << "/cgroup.event_control"; std::string event_control_str = event_control.str(); // Open the oom_control and event control files TemporaryPrivSentry sentry(PRIV_ROOT); m_oom_fd = open(oom_control_str.c_str(), O_RDONLY | O_CLOEXEC); if (m_oom_fd == -1) { dprintf(D_ALWAYS, "Unable to open the OOM control file for starter: %u %s\n", errno, strerror(errno)); return 1; } int event_ctrl_fd = open(event_control_str.c_str(), O_WRONLY | O_CLOEXEC); if (event_ctrl_fd == -1) { dprintf(D_ALWAYS, "Unable to open event control for starter: %u %s\n", errno, strerror(errno)); return 1; } // Inform Linux we will be handling the OOM events for this container. int oom_fd2 = open(oom_control_str.c_str(), O_WRONLY | O_CLOEXEC); if (oom_fd2 == -1) { dprintf(D_ALWAYS, "Unable to open the OOM control file for writing for starter: %u %s\n", errno, strerror(errno)); close(event_ctrl_fd); return 1; } const char limits [] = "1"; ssize_t nwritten = full_write(oom_fd2, &limits, 1); if (nwritten < 0) { dprintf(D_ALWAYS, "Unable to set OOM control to %s for starter: %u %s\n", limits, errno, strerror(errno)); close(event_ctrl_fd); close(oom_fd2); return 1; } close(oom_fd2); // Create the subscription string: std::stringstream sub_ss; sub_ss << m_oom_efd << " " << m_oom_fd; std::string sub_str = sub_ss.str(); if ((nwritten = full_write(event_ctrl_fd, sub_str.c_str(), sub_str.size())) < 0) { dprintf(D_ALWAYS, "Unable to write into event control file for starter: %u %s\n", errno, strerror(errno)); close(event_ctrl_fd); return 1; } close(event_ctrl_fd); // Fool DC into talking to the eventfd int pipes[2]; pipes[0] = -1; pipes[1] = -1; int fd_to_replace = -1; if (daemonCore->Create_Pipe(pipes, true) == -1 || pipes[0] == -1) { dprintf(D_ALWAYS, "Unable to create a DC pipe\n"); close(m_oom_efd); m_oom_efd = -1; close(m_oom_fd); m_oom_fd = -1; return 1; } if ( daemonCore->Get_Pipe_FD(pipes[0], &fd_to_replace) == -1 || fd_to_replace == -1) { dprintf(D_ALWAYS, "Unable to lookup pipe's FD\n"); close(m_oom_efd); m_oom_efd = -1; close(m_oom_fd); m_oom_fd = -1; daemonCore->Close_Pipe(pipes[0]); daemonCore->Close_Pipe(pipes[1]); return 1; } dup3(m_oom_efd, fd_to_replace, O_CLOEXEC); close(m_oom_efd); m_oom_efd = pipes[0]; // Inform DC we want to recieve notifications from this FD. daemonCore->Register_Pipe(pipes[0],"OOM event fd", static_cast<PipeHandlercpp>(&VanillaProc::outOfMemoryEvent),"OOM Event Handler",this,HANDLE_READ); return 0; #endif }