int CgroupLimits::set_cpu_shares(uint64_t shares) { if (!m_cgroup.isValid() || !CgroupManager::getInstance().isMounted(CgroupManager::CPU_CONTROLLER)) { dprintf(D_ALWAYS, "Unable to set CPU shares because cgroup is invalid.\n"); return 1; } int err; struct cgroup *cpucg = &m_cgroup.getCgroup(); struct cgroup_controller *cpu_controller; if ((cpu_controller = cgroup_get_controller(cpucg, CPU_CONTROLLER_STR)) == NULL) { dprintf(D_ALWAYS, "Unable to add cgroup CPU controller for %s.\n", m_cgroup_string.c_str()); return 1; } else if ((err = cgroup_set_value_uint64(cpu_controller, "cpu.shares", shares))) { dprintf(D_ALWAYS, "Unable to set CPU shares for %s: %u %s\n", m_cgroup_string.c_str(), err, cgroup_strerror(err)); return 1; } else { TemporaryPrivSentry sentry(PRIV_ROOT); if ((err = cgroup_modify_cgroup(cpucg))) { dprintf(D_ALWAYS, "Unable to commit CPU shares for %s" ": %u %s\n", m_cgroup_string.c_str(), err, cgroup_strerror(err)); return 1; } } return 0; }
int CgroupLimits::set_blockio_weight(uint64_t weight) { if (!m_cgroup.isValid() || !CgroupManager::getInstance().isMounted(CgroupManager::BLOCK_CONTROLLER)) { dprintf(D_ALWAYS, "Unable to set blockio weight because cgroup is invalid.\n"); return 1; } int err; struct cgroup *blkiocg = &m_cgroup.getCgroup(); struct cgroup_controller *blkio_controller; if ((blkio_controller = cgroup_get_controller(blkiocg, BLOCK_CONTROLLER_STR)) == NULL) { dprintf(D_ALWAYS, "Unable to get cgroup block IO controller for %s.\n", m_cgroup_string.c_str()); return 1; } else if ((err = cgroup_set_value_uint64(blkio_controller, "blkio.weight", weight))) { dprintf(D_ALWAYS, "Unable to set block IO weight for %s: %u %s\n", m_cgroup_string.c_str(), err, cgroup_strerror(err)); return 1; } else { TemporaryPrivSentry sentry(PRIV_ROOT); if ((err = cgroup_modify_cgroup(blkiocg))) { dprintf(D_ALWAYS, "Unable to commit block IO weight for %s" ": %u %s\n", m_cgroup_string.c_str(), err, cgroup_strerror(err)); return 1; } } return 0; }
int CgroupLimits::set_memory_limit_bytes(uint64_t mem_bytes, bool soft) { if (!m_cgroup.isValid() || !CgroupManager::getInstance().isMounted(CgroupManager::MEMORY_CONTROLLER)) { dprintf(D_ALWAYS, "Unable to set memory limit because cgroup is invalid.\n"); return 1; } int err; struct cgroup_controller * mem_controller; const char * limit = soft ? mem_soft_limit : mem_hard_limit; dprintf(D_ALWAYS, "Limitting memory usage to %ld bytes\n", mem_bytes); struct cgroup *memcg = &m_cgroup.getCgroup(); if ((mem_controller = cgroup_get_controller(memcg, MEMORY_CONTROLLER_STR)) == NULL) { dprintf(D_ALWAYS, "Unable to get cgroup memory controller for %s.\n", m_cgroup_string.c_str()); return 1; } else if ((err = cgroup_set_value_uint64(mem_controller, limit, mem_bytes))) { dprintf(D_ALWAYS, "Unable to set memory soft limit for %s: %u %s\n", m_cgroup_string.c_str(), err, cgroup_strerror(err)); return 1; } else { TemporaryPrivSentry sentry(PRIV_ROOT); if ((err = cgroup_modify_cgroup(memcg))) { dprintf(D_ALWAYS, "Unable to commit memory soft limit for %s " ": %u %s\n", m_cgroup_string.c_str(), err, cgroup_strerror(err)); return 1; } } return 0; }
int container_apply_config(envid_t veid, enum conf_files c, void *_val) { struct cgroup *ct; char cgrp[CT_MAX_STR_SIZE]; struct cgroup_controller *mem, *cpu, *cpuset; int ret = -EINVAL; unsigned long *val = _val; veid_to_name(cgrp, veid); ct = cgroup_new_cgroup(cgrp); /* * We should really be doing some thing like: * * ret = cgroup_get_cgroup(ct); * * and then doing cgroup_get_controller. However, libcgroup has * a very nasty bug that make it sometimes fail. adding a controller * to a newly "created" cgroup structure and then setting the value * is a workaround that seems to work on various versions of the * library */ switch (c) { case MEMORY: if ((mem = cgroup_add_controller(ct, "memory"))) ret = cgroup_set_value_uint64(mem, MEMLIMIT, *val); break; case SWAP: /* Unlike kmem, this must always be greater than mem */ if ((mem = cgroup_add_controller(ct, "memory"))) { u_int64_t mval; if (!cgroup_get_value_uint64(mem, MEMLIMIT, &mval)) ret = cgroup_set_value_uint64(mem, SWAPLIMIT, mval + *val); } break; case KMEMORY: if ((mem = cgroup_add_controller(ct, "memory"))) ret = cgroup_set_value_uint64(mem, KMEMLIMIT, *val); break; case TCP: if ((mem = cgroup_add_controller(ct, "memory"))) ret = cgroup_set_value_uint64(mem, TCPLIMIT, *val); break; case CPULIMIT: { u_int64_t period; u_int64_t quota; if ((cpu = cgroup_add_controller(ct, "cpu")) == NULL) break; /* Should be 100000, but be safe. It may fail on some versions * of libcgroup, so if it fails, just assume the default */ ret = cgroup_get_value_uint64(cpu, "cpu.cfs_period_us", &period); if (ret) period = 100000; /* val will contain an integer percentage, like 223% */ quota = (period * (*val)) / 100; ret = cgroup_set_value_uint64(cpu, "cpu.cfs_quota_us", quota); break; } case CPUSHARES: if ((cpu = cgroup_add_controller(ct, "cpu")) == NULL) break; ret = cgroup_set_value_uint64(cpu, "cpu.shares", *val); break; case CPUMASK: { struct cgroup_controller *pcont; struct cgroup *parent; char *ptr = NULL; char cpusetstr[2 * CPUMASK_NBITS]; unsigned int i; if ((cpuset = cgroup_add_controller(ct, "cpuset")) == NULL) break; /* * Having all bits set is a bit different, bitmap_snprintf will * return a bad string. (From the PoV of the cpuset cgroup). We * actually need to copy the parent's mask in that case. */ for (i = 0; i < CPUMASK_NBYTES; i++) { if (val[i] != (~0UL)) { bitmap_snprintf(cpusetstr, CPUMASK_NBITS * 2, val, CPUMASK_NBITS); goto string_ok; } } parent = cgroup_new_cgroup(CT_BASE_STRING); cgroup_get_cgroup(parent); pcont = cgroup_get_controller(parent, "cpuset"); ret = cgroup_get_value_string(pcont, "cpuset.cpus", &ptr); if (ptr) { strncpy(cpusetstr, ptr, CPUMASK_NBITS *2); free(ptr); } cgroup_free(&parent); string_ok: ret = cgroup_set_value_string(cpuset, "cpuset.cpus", cpusetstr); break; } case DEVICES_DENY: { struct cgroup_controller *dev; if ((dev = cgroup_add_controller(ct, "devices")) == NULL) break; ret = cgroup_set_value_string(dev, "devices.deny", (char *)_val); break; } case DEVICES_ALLOW: { struct cgroup_controller *dev; if ((dev = cgroup_add_controller(ct, "devices")) == NULL) break; ret = cgroup_set_value_string(dev, "devices.allow", (char *)_val); break; } default: ret = -EINVAL; break; } if (ret) goto out; if ((ret = cgroup_modify_cgroup(ct))) logger(-1, 0, "Failed to set limits for %s (%s)", conf_names[c], cgroup_strerror(ret)); out: cgroup_free(&ct); return ret; }