int ProcFamily::set_cgroup(const std::string &cgroup_string) { if (cgroup_string == "/") { dprintf(D_ALWAYS, "Cowardly refusing to monitor the root cgroup out " "of security concerns.\n"); return 1; } // Ignore this command if we've done this before. if (m_cgroup.isValid()) { if (cgroup_string == m_cgroup.getCgroupString()) { return 0; } else { m_cgroup.destroy(); } } dprintf(D_PROCFAMILY, "Setting cgroup to %s for ProcFamily %u.\n", cgroup_string.c_str(), m_root_pid); m_cm.create(cgroup_string, m_cgroup, CgroupManager::ALL_CONTROLLERS, CgroupManager::NO_CONTROLLERS); m_cgroup_string = m_cgroup.getCgroupString(); if (!m_cgroup.isValid()) { return 1; } // Now that we have a cgroup, let's move all the existing processes to it ProcFamilyMember* member = m_member_list; while (member != NULL) { migrate_to_cgroup(member->get_proc_info()->pid); member = member->m_next; } // Record the amount of pre-existing CPU usage here. m_initial_user_cpu = 0; m_initial_sys_cpu = 0; get_cpu_usage_cgroup(m_initial_user_cpu, m_initial_sys_cpu); // Reset block IO controller if (m_cm.isMounted(CgroupManager::BLOCK_CONTROLLER)) { struct cgroup *tmp_cgroup = cgroup_new_cgroup(m_cgroup_string.c_str()); struct cgroup_controller *blkio_controller = cgroup_add_controller(tmp_cgroup, BLOCK_CONTROLLER_STR); ASSERT (blkio_controller != NULL); // Block IO controller should already exist. cgroup_add_value_uint64(blkio_controller, "blkio.reset_stats", 0); int err; if ((err = cgroup_modify_cgroup(tmp_cgroup))) { // Not allowed to reset stats? dprintf(D_ALWAYS, "Unable to reset cgroup %s block IO statistics. " "Some block IO accounting will be inaccurate (ProcFamily %u): %u %s\n", m_cgroup_string.c_str(), m_root_pid, err, cgroup_strerror(err)); } cgroup_free(&tmp_cgroup); } return 0; }
/** * Adds the control value to a controller using wrapper apis * @param newcontroller the controller to be added the value to * @param control_file name of the control file of the controller * @param wr the name of wrapper api * @param value_type which value out of four types * @param struct cval the control value structure */ int add_control_value(struct cgroup_controller *newcontroller, char *control_file, char *wr, int value_type, struct cntl_val_t cval) { int retval; switch (value_type) { case BOOL: retval = cgroup_add_value_bool(newcontroller, control_file, cval.val_bool); snprintf(wr, SIZE, "add_value_bool()"); break; case INT64: retval = cgroup_add_value_int64(newcontroller, control_file, cval.val_int64); snprintf(wr, SIZE, "add_value_int64()"); break; case UINT64: retval = cgroup_add_value_uint64(newcontroller, control_file, cval.val_uint64); snprintf(wr, SIZE, "add_value_uint64()"); break; case STRING: retval = cgroup_add_value_string(newcontroller, control_file, cval.val_string); snprintf(wr, SIZE, "add_value_string()"); break; default: printf("ERROR: wrong value in add_control_value()\n"); return 1; break; } return retval; }
int ProcFamily::migrate_to_cgroup(pid_t pid) { // Attempt to migrate a given process to a cgroup. // This can be done without regards to whether the // process is already in the cgroup if (!m_cgroup.isValid()) { return 1; } // We want to make sure task migration is turned on for the // associated memory controller. So, we get to look up the original cgroup. // // If there is no memory controller present, we skip all this and just attempt a migrate int err; u_int64_t orig_migrate; bool changed_orig = false; char * orig_cgroup_string = NULL; struct cgroup * orig_cgroup; struct cgroup_controller * memory_controller; if (m_cm.isMounted(CgroupManager::MEMORY_CONTROLLER) && (err = cgroup_get_current_controller_path(pid, MEMORY_CONTROLLER_STR, &orig_cgroup_string))) { dprintf(D_PROCFAMILY, "Unable to determine current memory cgroup for PID %u (ProcFamily %u): %u %s\n", pid, m_root_pid, err, cgroup_strerror(err)); return 1; } // We will migrate the PID to the new cgroup even if it is in the proper memory controller cgroup // It is possible for the task to be in multiple cgroups. if (m_cm.isMounted(CgroupManager::MEMORY_CONTROLLER) && (orig_cgroup_string != NULL) && (strcmp(m_cgroup_string.c_str(), orig_cgroup_string))) { // Yes, there are race conditions here - can't really avoid this. // Throughout this block, we can assume memory controller exists. // Get original value of migrate. orig_cgroup = cgroup_new_cgroup(orig_cgroup_string); ASSERT (orig_cgroup != NULL); if ((err = cgroup_get_cgroup(orig_cgroup))) { dprintf(D_PROCFAMILY, "Unable to read original cgroup %s (ProcFamily %u): %u %s\n", orig_cgroup_string, m_root_pid, err, cgroup_strerror(err)); goto after_migrate; } if ((memory_controller = cgroup_get_controller(orig_cgroup, MEMORY_CONTROLLER_STR)) == NULL) { cgroup_free(&orig_cgroup); goto after_migrate; } if ((err = cgroup_get_value_uint64(memory_controller, "memory.move_charge_at_immigrate", &orig_migrate))) { if (err == ECGROUPVALUENOTEXIST) { // Older kernels don't have the ability to migrate memory accounting to the new cgroup. dprintf(D_PROCFAMILY, "This kernel does not support memory usage migration; cgroup %s memory statistics" " will be slightly incorrect (ProcFamily %u)\n", m_cgroup_string.c_str(), m_root_pid); } else { dprintf(D_PROCFAMILY, "Unable to read cgroup %s memory controller settings for " "migration (ProcFamily %u): %u %s\n", orig_cgroup_string, m_root_pid, err, cgroup_strerror(err)); } cgroup_free(&orig_cgroup); goto after_migrate; } if (orig_migrate != 3) { orig_cgroup = cgroup_new_cgroup(orig_cgroup_string); memory_controller = cgroup_add_controller(orig_cgroup, MEMORY_CONTROLLER_STR); ASSERT (memory_controller != NULL); // Memory controller must already exist cgroup_add_value_uint64(memory_controller, "memory.move_charge_at_immigrate", 3); if ((err = cgroup_modify_cgroup(orig_cgroup))) { // Not allowed to change settings dprintf(D_ALWAYS, "Unable to change cgroup %s memory controller settings for migration. " "Some memory accounting will be inaccurate (ProcFamily %u): %u %s\n", orig_cgroup_string, m_root_pid, err, cgroup_strerror(err)); } else { changed_orig = true; } } cgroup_free(&orig_cgroup); } after_migrate: orig_cgroup = NULL; err = cgroup_attach_task_pid(& const_cast<struct cgroup &>(m_cgroup.getCgroup()), pid); if (err) { dprintf(D_PROCFAMILY, "Cannot attach pid %u to cgroup %s for ProcFamily %u: %u %s\n", pid, m_cgroup_string.c_str(), m_root_pid, err, cgroup_strerror(err)); } if (changed_orig) { if ((orig_cgroup = cgroup_new_cgroup(orig_cgroup_string))) { goto after_restore; } if (((memory_controller = cgroup_add_controller(orig_cgroup, MEMORY_CONTROLLER_STR)) != NULL) && (!cgroup_add_value_uint64(memory_controller, "memory.move_charge_at_immigrate", orig_migrate))) { cgroup_modify_cgroup(orig_cgroup); } cgroup_free(&orig_cgroup); } after_restore: if (orig_cgroup_string != NULL) { free(orig_cgroup_string); } return err; }