示例#1
0
文件: cgroup.c 项目: avagin/vzctl
/*
 * 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;
}
示例#2
0
文件: cgroup.c 项目: avagin/vzctl
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;

}
示例#3
0
文件: cgroup.c 项目: avagin/vzctl
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;
}
示例#4
0
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
}
示例#5
0
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
}