Report full errors from virCgroupNew*

Instead of returning raw errno values, report full libvirt
errors in virCgroupNew* functions.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2013-07-04 16:49:24 +01:00
parent f5384eed3f
commit b64dabff27
9 changed files with 418 additions and 443 deletions

View File

@ -1156,6 +1156,7 @@ virCgroupAddTaskController;
virCgroupAllowDevice; virCgroupAllowDevice;
virCgroupAllowDeviceMajor; virCgroupAllowDeviceMajor;
virCgroupAllowDevicePath; virCgroupAllowDevicePath;
virCgroupAvailable;
virCgroupControllerTypeFromString; virCgroupControllerTypeFromString;
virCgroupControllerTypeToString; virCgroupControllerTypeToString;
virCgroupDenyAllDevices; virCgroupDenyAllDevices;
@ -1188,6 +1189,7 @@ virCgroupNewDomainDriver;
virCgroupNewDomainPartition; virCgroupNewDomainPartition;
virCgroupNewDriver; virCgroupNewDriver;
virCgroupNewEmulator; virCgroupNewEmulator;
virCgroupNewIgnoreError;
virCgroupNewPartition; virCgroupNewPartition;
virCgroupNewSelf; virCgroupNewSelf;
virCgroupNewVcpu; virCgroupNewVcpu;

View File

@ -306,33 +306,29 @@ cleanup:
int virLXCCgroupGetMeminfo(virLXCMeminfoPtr meminfo) int virLXCCgroupGetMeminfo(virLXCMeminfoPtr meminfo)
{ {
int ret; int ret = -1, rc;
virCgroupPtr cgroup; virCgroupPtr cgroup;
ret = virCgroupNewSelf(&cgroup); if (virCgroupNewSelf(&cgroup) < 0)
if (ret < 0) { return -1;
virReportSystemError(-ret, "%s",
_("Unable to get cgroup for container"));
return ret;
}
ret = virLXCCgroupGetMemStat(cgroup, meminfo); rc = virLXCCgroupGetMemStat(cgroup, meminfo);
if (ret < 0) { if (rc < 0) {
virReportSystemError(-ret, "%s", virReportSystemError(-rc, "%s",
_("Unable to get memory cgroup stat info")); _("Unable to get memory cgroup stat info"));
goto cleanup; goto cleanup;
} }
ret = virLXCCgroupGetMemTotal(cgroup, meminfo); rc = virLXCCgroupGetMemTotal(cgroup, meminfo);
if (ret < 0) { if (rc < 0) {
virReportSystemError(-ret, "%s", virReportSystemError(-rc, "%s",
_("Unable to get memory cgroup total")); _("Unable to get memory cgroup total"));
goto cleanup; goto cleanup;
} }
ret = virLXCCgroupGetMemUsage(cgroup, meminfo); rc = virLXCCgroupGetMemUsage(cgroup, meminfo);
if (ret < 0) { if (rc < 0) {
virReportSystemError(-ret, "%s", virReportSystemError(-rc, "%s",
_("Unable to get memory cgroup stat usage")); _("Unable to get memory cgroup stat usage"));
goto cleanup; goto cleanup;
} }
@ -541,7 +537,6 @@ cleanup:
virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def, bool startup) virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def, bool startup)
{ {
int rc;
virCgroupPtr parent = NULL; virCgroupPtr parent = NULL;
virCgroupPtr cgroup = NULL; virCgroupPtr cgroup = NULL;
@ -569,51 +564,31 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def, bool startup)
} }
/* We only auto-create the default partition. In other /* We only auto-create the default partition. In other
* cases we expec the sysadmin/app to have done so */ * cases we expec the sysadmin/app to have done so */
rc = virCgroupNewPartition(def->resource->partition, if (virCgroupNewPartition(def->resource->partition,
STREQ(def->resource->partition, "/machine"), STREQ(def->resource->partition, "/machine"),
-1, -1,
&parent); &parent) < 0)
if (rc != 0) {
virReportSystemError(-rc,
_("Unable to initialize %s cgroup"),
def->resource->partition);
goto cleanup; goto cleanup;
}
rc = virCgroupNewDomainPartition(parent, if (virCgroupNewDomainPartition(parent,
"lxc", "lxc",
def->name, def->name,
true, true,
&cgroup); &cgroup) < 0)
if (rc != 0) {
virReportSystemError(-rc,
_("Unable to create cgroup for %s"),
def->name);
goto cleanup; goto cleanup;
}
} else { } else {
rc = virCgroupNewDriver("lxc", if (virCgroupNewDriver("lxc",
true, true,
-1, -1,
&parent); &parent) < 0)
if (rc != 0) {
virReportSystemError(-rc,
_("Unable to create cgroup for %s"),
def->name);
goto cleanup; goto cleanup;
}
rc = virCgroupNewDomainDriver(parent, if (virCgroupNewDomainDriver(parent,
def->name, def->name,
true, true,
&cgroup); &cgroup) < 0)
if (rc != 0) {
virReportSystemError(-rc,
_("Unable to create cgroup for %s"),
def->name);
goto cleanup; goto cleanup;
} }
}
cleanup: cleanup:
virCgroupFree(&parent); virCgroupFree(&parent);

View File

@ -1466,7 +1466,6 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
virSecurityManagerPtr securityDriver) virSecurityManagerPtr securityDriver)
{ {
virCgroupPtr cgroup = NULL; virCgroupPtr cgroup = NULL;
int rc;
int ret = -1; int ret = -1;
char *sec_mount_options; char *sec_mount_options;
char *stateDir = NULL; char *stateDir = NULL;
@ -1478,11 +1477,8 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
/* Before pivoting we need to identify any /* Before pivoting we need to identify any
* cgroups controllers that are mounted */ * cgroups controllers that are mounted */
if ((rc = virCgroupNewSelf(&cgroup)) != 0) { if (virCgroupNewSelf(&cgroup) < 0)
virReportSystemError(-rc, "%s",
_("Cannot identify cgroup placement"));
goto cleanup; goto cleanup;
}
if (virFileResolveAllLinks(LXC_STATE_DIR, &stateDir) < 0) if (virFileResolveAllLinks(LXC_STATE_DIR, &stateDir) < 0)
goto cleanup; goto cleanup;

View File

@ -139,8 +139,10 @@ static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def,
virBuffer buffer = VIR_BUFFER_INITIALIZER; virBuffer buffer = VIR_BUFFER_INITIALIZER;
virBufferPtr new_meminfo = &buffer; virBufferPtr new_meminfo = &buffer;
if ((res = virLXCCgroupGetMeminfo(&meminfo)) < 0) if (virLXCCgroupGetMeminfo(&meminfo) < 0) {
return res; virErrorSetErrnoFromLastError();
return -errno;
}
fd = fopen(hostpath, "r"); fd = fopen(hostpath, "r");
if (fd == NULL) { if (fd == NULL) {

View File

@ -731,6 +731,9 @@ qemuInitCgroup(virQEMUDriverPtr driver,
if (!cfg->privileged) if (!cfg->privileged)
goto done; goto done;
if (!virCgroupAvailable())
goto done;
virCgroupFree(&priv->cgroup); virCgroupFree(&priv->cgroup);
if (!vm->def->resource && startup) { if (!vm->def->resource && startup) {
@ -757,65 +760,39 @@ qemuInitCgroup(virQEMUDriverPtr driver,
} }
/* We only auto-create the default partition. In other /* We only auto-create the default partition. In other
* cases we expec the sysadmin/app to have done so */ * cases we expec the sysadmin/app to have done so */
rc = virCgroupNewPartition(vm->def->resource->partition, if (virCgroupNewPartition(vm->def->resource->partition,
STREQ(vm->def->resource->partition, "/machine"), STREQ(vm->def->resource->partition, "/machine"),
cfg->cgroupControllers, cfg->cgroupControllers,
&parent); &parent) < 0) {
if (rc != 0) { if (virCgroupNewIgnoreError())
if (rc == -ENXIO ||
rc == -EPERM ||
rc == -EACCES) { /* No cgroups mounts == success */
VIR_DEBUG("No cgroups present/configured/accessible, ignoring error");
goto done; goto done;
}
virReportSystemError(-rc,
_("Unable to initialize %s cgroup"),
vm->def->resource->partition);
goto cleanup; goto cleanup;
} }
rc = virCgroupNewDomainPartition(parent, if (virCgroupNewDomainPartition(parent,
"qemu", "qemu",
vm->def->name, vm->def->name,
true, true,
&priv->cgroup); &priv->cgroup) < 0)
if (rc != 0) {
virReportSystemError(-rc,
_("Unable to create cgroup for %s"),
vm->def->name);
goto cleanup; goto cleanup;
}
} else { } else {
rc = virCgroupNewDriver("qemu", if (virCgroupNewDriver("qemu",
true, true,
cfg->cgroupControllers, cfg->cgroupControllers,
&parent); &parent) < 0) {
if (rc != 0) { if (virCgroupNewIgnoreError())
if (rc == -ENXIO ||
rc == -EPERM ||
rc == -EACCES) { /* No cgroups mounts == success */
VIR_DEBUG("No cgroups present/configured/accessible, ignoring error");
goto done; goto done;
}
virReportSystemError(-rc,
_("Unable to create cgroup for %s"),
vm->def->name);
goto cleanup; goto cleanup;
} }
rc = virCgroupNewDomainDriver(parent, if (virCgroupNewDomainDriver(parent,
vm->def->name, vm->def->name,
true, true,
&priv->cgroup); &priv->cgroup) < 0)
if (rc != 0) {
virReportSystemError(-rc,
_("Unable to create cgroup for %s"),
vm->def->name);
goto cleanup; goto cleanup;
} }
}
done: done:
rc = 0; rc = 0;
@ -994,14 +971,8 @@ qemuSetupCgroupForVcpu(virDomainObjPtr vm)
} }
for (i = 0; i < priv->nvcpupids; i++) { for (i = 0; i < priv->nvcpupids; i++) {
rc = virCgroupNewVcpu(priv->cgroup, i, true, &cgroup_vcpu); if (virCgroupNewVcpu(priv->cgroup, i, true, &cgroup_vcpu) < 0)
if (rc < 0) {
virReportSystemError(-rc,
_("Unable to create vcpu cgroup for %s(vcpu:"
" %zu)"),
vm->def->name, i);
goto cleanup; goto cleanup;
}
/* move the thread for vcpu to sub dir */ /* move the thread for vcpu to sub dir */
rc = virCgroupAddTask(cgroup_vcpu, priv->vcpupids[i]); rc = virCgroupAddTask(cgroup_vcpu, priv->vcpupids[i]);
@ -1061,7 +1032,7 @@ qemuSetupCgroupForEmulator(virQEMUDriverPtr driver,
qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjPrivatePtr priv = vm->privateData;
unsigned long long period = vm->def->cputune.emulator_period; unsigned long long period = vm->def->cputune.emulator_period;
long long quota = vm->def->cputune.emulator_quota; long long quota = vm->def->cputune.emulator_quota;
int rc; int rc = -1;
if ((period || quota) && if ((period || quota) &&
!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) { !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
@ -1073,13 +1044,8 @@ qemuSetupCgroupForEmulator(virQEMUDriverPtr driver,
if (priv->cgroup == NULL) if (priv->cgroup == NULL)
return 0; /* Not supported, so claim success */ return 0; /* Not supported, so claim success */
rc = virCgroupNewEmulator(priv->cgroup, true, &cgroup_emulator); if (virCgroupNewEmulator(priv->cgroup, true, &cgroup_emulator) < 0)
if (rc < 0) {
virReportSystemError(-rc,
_("Unable to create emulator cgroup for %s"),
vm->def->name);
goto cleanup; goto cleanup;
}
rc = virCgroupMoveTask(priv->cgroup, cgroup_emulator); rc = virCgroupMoveTask(priv->cgroup, cgroup_emulator);
if (rc < 0) { if (rc < 0) {

View File

@ -3940,14 +3940,8 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
if (priv->cgroup) { if (priv->cgroup) {
int rv = -1; int rv = -1;
/* Create cgroup for the onlined vcpu */ /* Create cgroup for the onlined vcpu */
rv = virCgroupNewVcpu(priv->cgroup, i, true, &cgroup_vcpu); if (virCgroupNewVcpu(priv->cgroup, i, true, &cgroup_vcpu) < 0)
if (rv < 0) {
virReportSystemError(-rv,
_("Unable to create vcpu cgroup for %s(vcpu:"
" %zu)"),
vm->def->name, i);
goto cleanup; goto cleanup;
}
/* Add vcpu thread to the cgroup */ /* Add vcpu thread to the cgroup */
rv = virCgroupAddTask(cgroup_vcpu, cpupids[i]); rv = virCgroupAddTask(cgroup_vcpu, cpupids[i]);
@ -4008,16 +4002,8 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
virDomainVcpuPinDefPtr vcpupin = NULL; virDomainVcpuPinDefPtr vcpupin = NULL;
if (priv->cgroup) { if (priv->cgroup) {
int rv = -1; if (virCgroupNewVcpu(priv->cgroup, i, false, &cgroup_vcpu) < 0)
rv = virCgroupNewVcpu(priv->cgroup, i, false, &cgroup_vcpu);
if (rv < 0) {
virReportSystemError(-rv,
_("Unable to access vcpu cgroup for %s(vcpu:"
" %zu)"),
vm->def->name, i);
goto cleanup; goto cleanup;
}
/* Remove cgroup for the offlined vcpu */ /* Remove cgroup for the offlined vcpu */
virCgroupRemove(cgroup_vcpu); virCgroupRemove(cgroup_vcpu);
@ -4358,8 +4344,9 @@ qemuDomainPinVcpuFlags(virDomainPtr dom,
/* Configure the corresponding cpuset cgroup before set affinity. */ /* Configure the corresponding cpuset cgroup before set affinity. */
if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) { if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
if (virCgroupNewVcpu(priv->cgroup, vcpu, false, &cgroup_vcpu) == 0 && if (virCgroupNewVcpu(priv->cgroup, vcpu, false, &cgroup_vcpu) < 0)
qemuSetupCgroupVcpuPin(cgroup_vcpu, newVcpuPin, newVcpuPinNum, vcpu) < 0) { goto cleanup;
if (qemuSetupCgroupVcpuPin(cgroup_vcpu, newVcpuPin, newVcpuPinNum, vcpu) < 0) {
virReportError(VIR_ERR_OPERATION_INVALID, virReportError(VIR_ERR_OPERATION_INVALID,
_("failed to set cpuset.cpus in cgroup" _("failed to set cpuset.cpus in cgroup"
" for vcpu %d"), vcpu); " for vcpu %d"), vcpu);
@ -4620,9 +4607,9 @@ qemuDomainPinEmulator(virDomainPtr dom,
VIR_CGROUP_CONTROLLER_CPUSET)) { VIR_CGROUP_CONTROLLER_CPUSET)) {
/* /*
* Configure the corresponding cpuset cgroup. * Configure the corresponding cpuset cgroup.
* If no cgroup for domain or hypervisor exists, do nothing.
*/ */
if (virCgroupNewEmulator(priv->cgroup, false, &cgroup_emulator) == 0) { if (virCgroupNewEmulator(priv->cgroup, false, &cgroup_emulator) < 0)
goto cleanup;
if (qemuSetupCgroupEmulatorPin(cgroup_emulator, if (qemuSetupCgroupEmulatorPin(cgroup_emulator,
newVcpuPin[0]->cpumask) < 0) { newVcpuPin[0]->cpumask) < 0) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s", virReportError(VIR_ERR_OPERATION_INVALID, "%s",
@ -4630,7 +4617,6 @@ qemuDomainPinEmulator(virDomainPtr dom,
" for emulator threads")); " for emulator threads"));
goto cleanup; goto cleanup;
} }
}
} else { } else {
if (virProcessSetAffinity(pid, pcpumap) < 0) { if (virProcessSetAffinity(pid, pcpumap) < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR, "%s", virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
@ -8596,7 +8582,6 @@ qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
size_t i; size_t i;
qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjPrivatePtr priv = vm->privateData;
virCgroupPtr cgroup_vcpu = NULL; virCgroupPtr cgroup_vcpu = NULL;
int rc;
if (period == 0 && quota == 0) if (period == 0 && quota == 0)
return 0; return 0;
@ -8607,14 +8592,8 @@ qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
*/ */
if (priv->nvcpupids != 0 && priv->vcpupids[0] != vm->pid) { if (priv->nvcpupids != 0 && priv->vcpupids[0] != vm->pid) {
for (i = 0; i < priv->nvcpupids; i++) { for (i = 0; i < priv->nvcpupids; i++) {
rc = virCgroupNewVcpu(cgroup, i, false, &cgroup_vcpu); if (virCgroupNewVcpu(cgroup, i, false, &cgroup_vcpu) < 0)
if (rc < 0) {
virReportSystemError(-rc,
_("Unable to find vcpu cgroup for %s(vcpu:"
" %zu)"),
vm->def->name, i);
goto cleanup; goto cleanup;
}
if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0) if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0)
goto cleanup; goto cleanup;
@ -8636,7 +8615,6 @@ qemuSetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup,
{ {
qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjPrivatePtr priv = vm->privateData;
virCgroupPtr cgroup_emulator = NULL; virCgroupPtr cgroup_emulator = NULL;
int rc;
if (period == 0 && quota == 0) if (period == 0 && quota == 0)
return 0; return 0;
@ -8645,13 +8623,8 @@ qemuSetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup,
return 0; return 0;
} }
rc = virCgroupNewEmulator(cgroup, false, &cgroup_emulator); if (virCgroupNewEmulator(cgroup, false, &cgroup_emulator) < 0)
if (rc < 0) {
virReportSystemError(-rc,
_("Unable to find emulator cgroup for %s"),
vm->def->name);
goto cleanup; goto cleanup;
}
if (qemuSetupCgroupVcpuBW(cgroup_emulator, period, quota) < 0) if (qemuSetupCgroupVcpuBW(cgroup_emulator, period, quota) < 0)
goto cleanup; goto cleanup;
@ -8897,13 +8870,8 @@ qemuGetVcpusBWLive(virDomainObjPtr vm,
} }
/* get period and quota for vcpu0 */ /* get period and quota for vcpu0 */
rc = virCgroupNewVcpu(priv->cgroup, 0, false, &cgroup_vcpu); if (virCgroupNewVcpu(priv->cgroup, 0, false, &cgroup_vcpu) < 0)
if (!cgroup_vcpu) {
virReportSystemError(-rc,
_("Unable to find vcpu cgroup for %s(vcpu: 0)"),
vm->def->name);
goto cleanup; goto cleanup;
}
rc = qemuGetVcpuBWLive(cgroup_vcpu, period, quota); rc = qemuGetVcpuBWLive(cgroup_vcpu, period, quota);
if (rc < 0) if (rc < 0)
@ -8935,13 +8903,8 @@ qemuGetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup,
} }
/* get period and quota for emulator */ /* get period and quota for emulator */
rc = virCgroupNewEmulator(cgroup, false, &cgroup_emulator); if (virCgroupNewEmulator(cgroup, false, &cgroup_emulator) < 0)
if (!cgroup_emulator) {
virReportSystemError(-rc,
_("Unable to find emulator cgroup for %s"),
vm->def->name);
goto cleanup; goto cleanup;
}
rc = qemuGetVcpuBWLive(cgroup_emulator, period, quota); rc = qemuGetVcpuBWLive(cgroup_emulator, period, quota);
if (rc < 0) if (rc < 0)
@ -15537,11 +15500,8 @@ getSumVcpuPercpuStats(virDomainObjPtr vm,
unsigned long long tmp; unsigned long long tmp;
size_t j; size_t j;
if (virCgroupNewVcpu(priv->cgroup, i, false, &group_vcpu) < 0) { if (virCgroupNewVcpu(priv->cgroup, i, false, &group_vcpu) < 0)
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("error accessing cgroup cpuacct for vcpu"));
goto cleanup; goto cleanup;
}
if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0) if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0)
goto cleanup; goto cleanup;

View File

@ -67,6 +67,30 @@ typedef enum {
*/ */
} virCgroupFlags; } virCgroupFlags;
bool virCgroupAvailable(void)
{
FILE *mounts = NULL;
struct mntent entry;
bool ret = false;
char buf[CGROUP_MAX_VAL];
if (!virFileExists("/proc/cgroups"))
return false;
if (!(mounts = fopen("/proc/mounts", "r")))
return false;
while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) {
if (STREQ(entry.mnt_type, "cgroup")) {
ret = true;
break;
}
}
VIR_FORCE_FCLOSE(mounts);
return ret;
}
/** /**
* virCgroupFree: * virCgroupFree:
* *
@ -116,13 +140,13 @@ static int virCgroupCopyMounts(virCgroupPtr group,
if (!parent->controllers[i].mountPoint) if (!parent->controllers[i].mountPoint)
continue; continue;
if (VIR_STRDUP_QUIET(group->controllers[i].mountPoint, if (VIR_STRDUP(group->controllers[i].mountPoint,
parent->controllers[i].mountPoint) < 0) parent->controllers[i].mountPoint) < 0)
return -ENOMEM; return -1;
if (VIR_STRDUP_QUIET(group->controllers[i].linkPoint, if (VIR_STRDUP(group->controllers[i].linkPoint,
parent->controllers[i].linkPoint) < 0) parent->controllers[i].linkPoint) < 0)
return -ENOMEM; return -1;
} }
return 0; return 0;
} }
@ -140,8 +164,9 @@ static int virCgroupDetectMounts(virCgroupPtr group)
mounts = fopen("/proc/mounts", "r"); mounts = fopen("/proc/mounts", "r");
if (mounts == NULL) { if (mounts == NULL) {
VIR_ERROR(_("Unable to open /proc/mounts")); virReportSystemError(errno, "%s",
return -ENOENT; _("Unable to open /proc/mounts"));
return -1;
} }
while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) { while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) {
@ -171,13 +196,15 @@ static int virCgroupDetectMounts(virCgroupPtr group)
struct stat sb; struct stat sb;
char *tmp2; char *tmp2;
if (VIR_STRDUP_QUIET(group->controllers[i].mountPoint, if (VIR_STRDUP(group->controllers[i].mountPoint,
entry.mnt_dir) < 0) entry.mnt_dir) < 0)
goto error; goto error;
tmp2 = strrchr(entry.mnt_dir, '/'); tmp2 = strrchr(entry.mnt_dir, '/');
if (!tmp2) { if (!tmp2) {
errno = EINVAL; virReportError(VIR_ERR_INTERNAL_ERROR,
_("Missing '/' separator in cgroup mount '%s'"),
entry.mnt_dir);
goto error; goto error;
} }
*tmp2 = '\0'; *tmp2 = '\0';
@ -195,6 +222,8 @@ static int virCgroupDetectMounts(virCgroupPtr group)
typestr, entry.mnt_dir, linksrc); typestr, entry.mnt_dir, linksrc);
VIR_FREE(linksrc); VIR_FREE(linksrc);
} else { } else {
virReportSystemError(errno,
_("Cannot stat %s"), linksrc);
goto error; goto error;
} }
} else { } else {
@ -218,7 +247,7 @@ static int virCgroupDetectMounts(virCgroupPtr group)
error: error:
VIR_FORCE_FCLOSE(mounts); VIR_FORCE_FCLOSE(mounts);
return -errno; return -1;
} }
@ -232,8 +261,8 @@ static int virCgroupCopyPlacement(virCgroupPtr group,
continue; continue;
if (path[0] == '/') { if (path[0] == '/') {
if (VIR_STRDUP_QUIET(group->controllers[i].placement, path) < 0) if (VIR_STRDUP(group->controllers[i].placement, path) < 0)
return -ENOMEM; return -1;
} else { } else {
/* /*
* parent=="/" + path="" => "/" * parent=="/" + path="" => "/"
@ -246,7 +275,7 @@ static int virCgroupCopyPlacement(virCgroupPtr group,
(STREQ(parent->controllers[i].placement, "/") || (STREQ(parent->controllers[i].placement, "/") ||
STREQ(path, "") ? "" : "/"), STREQ(path, "") ? "" : "/"),
path) < 0) path) < 0)
return -ENOMEM; return -1;
} }
} }
@ -282,11 +311,13 @@ static int virCgroupDetectPlacement(virCgroupPtr group,
size_t i; size_t i;
FILE *mapping = NULL; FILE *mapping = NULL;
char line[1024]; char line[1024];
int ret = -1;
mapping = fopen("/proc/self/cgroup", "r"); mapping = fopen("/proc/self/cgroup", "r");
if (mapping == NULL) { if (mapping == NULL) {
VIR_ERROR(_("Unable to open /proc/self/cgroup")); virReportSystemError(errno, "%s",
return -ENOENT; _("Unable to open /proc/self/cgroup"));
return -1;
} }
while (fgets(line, sizeof(line), mapping) != NULL) { while (fgets(line, sizeof(line), mapping) != NULL) {
@ -329,7 +360,7 @@ static int virCgroupDetectPlacement(virCgroupPtr group,
(STREQ(selfpath, "/") || (STREQ(selfpath, "/") ||
STREQ(path, "") ? "" : "/"), STREQ(path, "") ? "" : "/"),
path) < 0) path) < 0)
goto no_memory; goto cleanup;
} }
tmp = next; tmp = next;
@ -337,14 +368,12 @@ static int virCgroupDetectPlacement(virCgroupPtr group,
} }
} }
ret = 0;
cleanup:
VIR_FORCE_FCLOSE(mapping); VIR_FORCE_FCLOSE(mapping);
return 0; return ret;
no_memory:
VIR_FORCE_FCLOSE(mapping);
return -ENOMEM;
} }
static int virCgroupDetect(virCgroupPtr group, static int virCgroupDetect(virCgroupPtr group,
@ -352,19 +381,17 @@ static int virCgroupDetect(virCgroupPtr group,
const char *path, const char *path,
virCgroupPtr parent) virCgroupPtr parent)
{ {
int rc;
size_t i; size_t i;
size_t j; size_t j;
VIR_DEBUG("group=%p controllers=%d path=%s parent=%p", VIR_DEBUG("group=%p controllers=%d path=%s parent=%p",
group, controllers, path, parent); group, controllers, path, parent);
if (parent) if (parent) {
rc = virCgroupCopyMounts(group, parent); if (virCgroupCopyMounts(group, parent) < 0)
else return -1;
rc = virCgroupDetectMounts(group); } else {
if (rc < 0) { if (virCgroupDetectMounts(group) < 0)
VIR_ERROR(_("Failed to detect mounts for %s"), group->path); return -1;
return rc;
} }
if (controllers >= 0) { if (controllers >= 0) {
@ -392,10 +419,11 @@ static int virCgroupDetect(virCgroupPtr group,
if (STREQ_NULLABLE(group->controllers[i].mountPoint, if (STREQ_NULLABLE(group->controllers[i].mountPoint,
group->controllers[j].mountPoint)) { group->controllers[j].mountPoint)) {
VIR_DEBUG("Controller '%s' is not wanted, but '%s' is co-mounted", virReportSystemError(EINVAL,
_("Controller '%s' is not wanted, but '%s' is co-mounted"),
virCgroupControllerTypeToString(i), virCgroupControllerTypeToString(i),
virCgroupControllerTypeToString(j)); virCgroupControllerTypeToString(j));
return -EINVAL; return -1;
} }
} }
VIR_FREE(group->controllers[i].mountPoint); VIR_FREE(group->controllers[i].mountPoint);
@ -416,27 +444,30 @@ static int virCgroupDetect(virCgroupPtr group,
/* Check that at least 1 controller is available */ /* Check that at least 1 controller is available */
if (!controllers) { if (!controllers) {
VIR_DEBUG("No controllers set"); virReportSystemError(ENXIO, "%s",
return -ENXIO; _("At least one cgroup controller is required"));
return -1;
} }
if (parent || path[0] == '/') if (parent || path[0] == '/') {
rc = virCgroupCopyPlacement(group, path, parent); if (virCgroupCopyPlacement(group, path, parent) < 0)
else return -1;
rc = virCgroupDetectPlacement(group, path); } else {
if (virCgroupDetectPlacement(group, path) < 0)
return -1;
}
if (rc == 0) {
/* Check that for every mounted controller, we found our placement */ /* Check that for every mounted controller, we found our placement */
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
if (!group->controllers[i].mountPoint) if (!group->controllers[i].mountPoint)
continue; continue;
if (!group->controllers[i].placement) { if (!group->controllers[i].placement) {
VIR_ERROR(_("Could not find placement for controller %s at %s"), virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not find placement for controller %s at %s"),
virCgroupControllerTypeToString(i), virCgroupControllerTypeToString(i),
group->controllers[i].placement); group->controllers[i].placement);
rc = -ENOENT; return -1;
break;
} }
VIR_DEBUG("Detected mount/mapping %zu:%s at %s in %s", i, VIR_DEBUG("Detected mount/mapping %zu:%s at %s in %s", i,
@ -444,11 +475,8 @@ static int virCgroupDetect(virCgroupPtr group,
group->controllers[i].mountPoint, group->controllers[i].mountPoint,
group->controllers[i].placement); group->controllers[i].placement);
} }
} else {
VIR_ERROR(_("Failed to detect mapping for %s"), group->path);
}
return rc; return 0;
} }
#endif #endif
@ -646,8 +674,9 @@ static int virCgroupCpuSetInherit(virCgroupPtr parent, virCgroupPtr group)
inherit_values[i], inherit_values[i],
&value); &value);
if (rc != 0) { if (rc != 0) {
VIR_ERROR(_("Failed to get %s %d"), inherit_values[i], rc); virReportSystemError(-rc,
break; _("Failed to get '%s'"), inherit_values[i]);
return -1;
} }
VIR_DEBUG("Inherit %s = %s", inherit_values[i], value); VIR_DEBUG("Inherit %s = %s", inherit_values[i], value);
@ -659,12 +688,13 @@ static int virCgroupCpuSetInherit(virCgroupPtr parent, virCgroupPtr group)
VIR_FREE(value); VIR_FREE(value);
if (rc != 0) { if (rc != 0) {
VIR_ERROR(_("Failed to set %s %d"), inherit_values[i], rc); virReportSystemError(-rc,
break; _("Failed to set '%s'"), inherit_values[i]);
return -1;
} }
} }
return rc; return 0;
} }
static int virCgroupSetMemoryUseHierarchy(virCgroupPtr group) static int virCgroupSetMemoryUseHierarchy(virCgroupPtr group)
@ -677,8 +707,9 @@ static int virCgroupSetMemoryUseHierarchy(virCgroupPtr group)
VIR_CGROUP_CONTROLLER_MEMORY, VIR_CGROUP_CONTROLLER_MEMORY,
filename, &value); filename, &value);
if (rc != 0) { if (rc != 0) {
VIR_ERROR(_("Failed to read %s/%s (%d)"), group->path, filename, rc); virReportSystemError(-rc,
return rc; _("Failed to get '%s'"), filename);
return -1;
} }
/* Setting twice causes error, so if already enabled, skip setting */ /* Setting twice causes error, so if already enabled, skip setting */
@ -691,10 +722,12 @@ static int virCgroupSetMemoryUseHierarchy(virCgroupPtr group)
filename, 1); filename, 1);
if (rc != 0) { if (rc != 0) {
VIR_ERROR(_("Failed to set %s/%s (%d)"), group->path, filename, rc); virReportSystemError(-rc,
_("Failed to set '%s'"), filename);
return -1;
} }
return rc; return 0;
} }
static int virCgroupMakeGroup(virCgroupPtr parent, static int virCgroupMakeGroup(virCgroupPtr parent,
@ -703,7 +736,7 @@ static int virCgroupMakeGroup(virCgroupPtr parent,
unsigned int flags) unsigned int flags)
{ {
size_t i; size_t i;
int rc = 0; int ret = -1;
VIR_DEBUG("Make group %s", group->path); VIR_DEBUG("Make group %s", group->path);
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
@ -716,11 +749,11 @@ static int virCgroupMakeGroup(virCgroupPtr parent,
continue; continue;
} }
rc = virCgroupPathOfController(group, i, "", &path); if (virCgroupPathOfController(group, i, "", &path) < 0) {
if (rc < 0) { virReportError(VIR_ERR_INTERNAL_ERROR,
VIR_DEBUG("Failed to find path of controller %s", _("Failed to find path of controller %s"),
virCgroupControllerTypeToString(i)); virCgroupControllerTypeToString(i));
return rc; return -1;
} }
/* As of Feb 2011, clang can't see that the above function /* As of Feb 2011, clang can't see that the above function
* call did not modify group. */ * call did not modify group. */
@ -736,25 +769,23 @@ static int virCgroupMakeGroup(virCgroupPtr parent,
* treat blkio as unmounted if mkdir fails. */ * treat blkio as unmounted if mkdir fails. */
if (i == VIR_CGROUP_CONTROLLER_BLKIO) { if (i == VIR_CGROUP_CONTROLLER_BLKIO) {
VIR_DEBUG("Ignoring mkdir failure with blkio controller. Kernel probably too old"); VIR_DEBUG("Ignoring mkdir failure with blkio controller. Kernel probably too old");
rc = 0;
VIR_FREE(group->controllers[i].mountPoint); VIR_FREE(group->controllers[i].mountPoint);
VIR_FREE(path); VIR_FREE(path);
continue; continue;
} else { } else {
VIR_DEBUG("Failed to create controller %s for group", virReportSystemError(errno,
_("Failed to create controller %s for group"),
virCgroupControllerTypeToString(i)); virCgroupControllerTypeToString(i));
rc = -errno;
VIR_FREE(path); VIR_FREE(path);
break; goto cleanup;
} }
} }
if (group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint != NULL && if (group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint != NULL &&
(i == VIR_CGROUP_CONTROLLER_CPUSET || (i == VIR_CGROUP_CONTROLLER_CPUSET ||
STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint))) { STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint))) {
rc = virCgroupCpuSetInherit(parent, group); if (virCgroupCpuSetInherit(parent, group) < 0) {
if (rc != 0) {
VIR_FREE(path); VIR_FREE(path);
break; goto cleanup;
} }
} }
/* /*
@ -765,10 +796,9 @@ static int virCgroupMakeGroup(virCgroupPtr parent,
(group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint != NULL) && (group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint != NULL) &&
(i == VIR_CGROUP_CONTROLLER_MEMORY || (i == VIR_CGROUP_CONTROLLER_MEMORY ||
STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint))) { STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint))) {
rc = virCgroupSetMemoryUseHierarchy(group); if (virCgroupSetMemoryUseHierarchy(group) < 0) {
if (rc != 0) {
VIR_FREE(path); VIR_FREE(path);
break; goto cleanup;
} }
} }
} }
@ -777,7 +807,10 @@ static int virCgroupMakeGroup(virCgroupPtr parent,
} }
VIR_DEBUG("Done making controllers for group"); VIR_DEBUG("Done making controllers for group");
return rc; ret = 0;
cleanup:
return ret;
} }
@ -795,51 +828,41 @@ static int virCgroupMakeGroup(virCgroupPtr parent,
* @parent is NULL, then the placement of the current * @parent is NULL, then the placement of the current
* process is used. * process is used.
* *
* Returns 0 on success, -1 on error
*/ */
static int virCgroupNew(const char *path, static int virCgroupNew(const char *path,
virCgroupPtr parent, virCgroupPtr parent,
int controllers, int controllers,
virCgroupPtr *group) virCgroupPtr *group)
{ {
int rc = 0;
char *typpath = NULL;
VIR_DEBUG("parent=%p path=%s controllers=%d", VIR_DEBUG("parent=%p path=%s controllers=%d",
parent, path, controllers); parent, path, controllers);
*group = NULL; *group = NULL;
if (VIR_ALLOC((*group)) != 0) { if (VIR_ALLOC((*group)) < 0)
rc = -ENOMEM; goto error;
goto err;
}
if (path[0] == '/' || !parent) { if (path[0] == '/' || !parent) {
if (VIR_STRDUP_QUIET((*group)->path, path) < 0) { if (VIR_STRDUP((*group)->path, path) < 0)
rc = -ENOMEM; goto error;
goto err;
}
} else { } else {
if (virAsprintf(&(*group)->path, "%s%s%s", if (virAsprintf(&(*group)->path, "%s%s%s",
parent->path, parent->path,
STREQ(parent->path, "") ? "" : "/", STREQ(parent->path, "") ? "" : "/",
path) < 0) { path) < 0)
rc = -ENOMEM; goto error;
goto err;
}
} }
rc = virCgroupDetect(*group, controllers, path, parent); if (virCgroupDetect(*group, controllers, path, parent) < 0)
if (rc < 0) goto error;
goto err;
return rc; return 0;
err:
error:
virCgroupFree(group); virCgroupFree(group);
*group = NULL; *group = NULL;
VIR_FREE(typpath); return -1;
return rc;
} }
static int virCgroupAppRoot(virCgroupPtr *group, static int virCgroupAppRoot(virCgroupPtr *group,
@ -847,22 +870,21 @@ static int virCgroupAppRoot(virCgroupPtr *group,
int controllers) int controllers)
{ {
virCgroupPtr selfgrp = NULL; virCgroupPtr selfgrp = NULL;
int rc; int ret = -1;
rc = virCgroupNewSelf(&selfgrp); if (virCgroupNewSelf(&selfgrp) < 0)
return -1;
if (rc != 0) if (virCgroupNew("libvirt", selfgrp, controllers, group) < 0)
return rc;
rc = virCgroupNew("libvirt", selfgrp, controllers, group);
if (rc != 0)
goto cleanup; goto cleanup;
rc = virCgroupMakeGroup(selfgrp, *group, create, VIR_CGROUP_NONE); if (virCgroupMakeGroup(selfgrp, *group, create, VIR_CGROUP_NONE) < 0)
goto cleanup;
ret = 0;
cleanup: cleanup:
virCgroupFree(&selfgrp); virCgroupFree(&selfgrp);
return rc; return ret;
} }
#endif #endif
@ -918,8 +940,9 @@ int virCgroupRemoveRecursively(char *grppath)
#else #else
int virCgroupRemoveRecursively(char *grppath ATTRIBUTE_UNUSED) int virCgroupRemoveRecursively(char *grppath ATTRIBUTE_UNUSED)
{ {
/* Claim no support */ virReportSystemError(ENXIO, "%s",
return -ENXIO; _("Control groups not supported on this platform"));
return -1;
} }
#endif #endif
@ -1119,7 +1142,9 @@ static int virCgroupPartitionNeedsEscaping(const char *path)
* if cgroups are not available on a host */ * if cgroups are not available on a host */
if (errno == ENOENT) if (errno == ENOENT)
errno = ENXIO; errno = ENXIO;
return -errno; virReportSystemError(errno, "%s",
_("Cannot open /proc/cgroups"));
return -1;
} }
/* /*
@ -1152,7 +1177,8 @@ static int virCgroupPartitionNeedsEscaping(const char *path)
} }
if (ferror(fp)) { if (ferror(fp)) {
ret = -EIO; virReportSystemError(errno, "%s",
_("Error while reading /proc/cgroups"));
goto cleanup; goto cleanup;
} }
@ -1172,18 +1198,18 @@ static int virCgroupPartitionEscape(char **path)
return rc; return rc;
if (VIR_INSERT_ELEMENT(*path, 0, len, escape) < 0) if (VIR_INSERT_ELEMENT(*path, 0, len, escape) < 0)
return -ENOMEM; return -1;
return 0; return 0;
} }
static int virCgroupSetPartitionSuffix(const char *path, char **res) static int virCgroupSetPartitionSuffix(const char *path, char **res)
{ {
char **tokens = virStringSplit(path, "/", 0); char **tokens;
size_t i; size_t i;
int ret = -1; int ret = -1;
if (!tokens) if (!(tokens = virStringSplit(path, "/", 0)))
return ret; return ret;
for (i = 0; tokens[i] != NULL; i++) { for (i = 0; tokens[i] != NULL; i++) {
@ -1202,23 +1228,17 @@ static int virCgroupSetPartitionSuffix(const char *path, char **res)
if (STRNEQ(tokens[i], "") && if (STRNEQ(tokens[i], "") &&
!strchr(tokens[i], '.')) { !strchr(tokens[i], '.')) {
if (VIR_REALLOC_N(tokens[i], if (VIR_REALLOC_N(tokens[i],
strlen(tokens[i]) + strlen(".partition") + 1) < 0) { strlen(tokens[i]) + strlen(".partition") + 1) < 0)
ret = -ENOMEM;
goto cleanup; goto cleanup;
}
strcat(tokens[i], ".partition"); strcat(tokens[i], ".partition");
} }
ret = virCgroupPartitionEscape(&(tokens[i])); if (virCgroupPartitionEscape(&(tokens[i])) < 0)
if (ret < 0) {
goto cleanup; goto cleanup;
} }
}
if (!(*res = virStringJoin((const char **)tokens, "/"))) { if (!(*res = virStringJoin((const char **)tokens, "/")))
ret = -ENOMEM;
goto cleanup; goto cleanup;
}
ret = 0; ret = 0;
@ -1236,64 +1256,59 @@ cleanup:
* Creates a new cgroup to represent the resource * Creates a new cgroup to represent the resource
* partition path identified by @name. * partition path identified by @name.
* *
* Returns 0 on success, -errno on failure * Returns 0 on success, -1 on failure
*/ */
int virCgroupNewPartition(const char *path, int virCgroupNewPartition(const char *path,
bool create, bool create,
int controllers, int controllers,
virCgroupPtr *group) virCgroupPtr *group)
{ {
int rc; int ret = -1;
char *parentPath = NULL; char *parentPath = NULL;
virCgroupPtr parent = NULL; virCgroupPtr parent = NULL;
char *newpath = NULL; char *newpath = NULL;
VIR_DEBUG("path=%s create=%d controllers=%x", VIR_DEBUG("path=%s create=%d controllers=%x",
path, create, controllers); path, create, controllers);
if (path[0] != '/') if (path[0] != '/') {
return -EINVAL; virReportError(VIR_ERR_INTERNAL_ERROR,
_("Partition path '%s' must start with '/'"),
/* XXX convert all cgroups APIs to use error report path);
* APIs instead of returning errno */ return -1;
rc = virCgroupSetPartitionSuffix(path, &newpath);
if (rc < 0) {
virResetLastError();
goto cleanup;
} }
rc = virCgroupNew(newpath, NULL, controllers, group); if (virCgroupSetPartitionSuffix(path, &newpath) < 0)
if (rc != 0) goto cleanup;
if (virCgroupNew(newpath, NULL, controllers, group) < 0)
goto cleanup; goto cleanup;
if (STRNEQ(newpath, "/")) { if (STRNEQ(newpath, "/")) {
char *tmp; char *tmp;
if (VIR_STRDUP_QUIET(parentPath, newpath) < 0) { if (VIR_STRDUP(parentPath, newpath) < 0)
rc = -ENOMEM;
goto cleanup; goto cleanup;
}
tmp = strrchr(parentPath, '/'); tmp = strrchr(parentPath, '/');
tmp++; tmp++;
*tmp = '\0'; *tmp = '\0';
rc = virCgroupNew(parentPath, NULL, controllers, &parent); if (virCgroupNew(parentPath, NULL, controllers, &parent) < 0)
if (rc != 0)
goto cleanup; goto cleanup;
rc = virCgroupMakeGroup(parent, *group, create, VIR_CGROUP_NONE); if (virCgroupMakeGroup(parent, *group, create, VIR_CGROUP_NONE) < 0) {
if (rc != 0) {
virCgroupRemove(*group); virCgroupRemove(*group);
goto cleanup; goto cleanup;
} }
} }
ret = 0;
cleanup: cleanup:
if (rc != 0) if (ret != 0)
virCgroupFree(group); virCgroupFree(group);
virCgroupFree(&parent); virCgroupFree(&parent);
VIR_FREE(parentPath); VIR_FREE(parentPath);
VIR_FREE(newpath); VIR_FREE(newpath);
return rc; return ret;
} }
#else #else
int virCgroupNewPartition(const char *path ATTRIBUTE_UNUSED, int virCgroupNewPartition(const char *path ATTRIBUTE_UNUSED,
@ -1301,8 +1316,9 @@ int virCgroupNewPartition(const char *path ATTRIBUTE_UNUSED,
int controllers ATTRIBUTE_UNUSED, int controllers ATTRIBUTE_UNUSED,
virCgroupPtr *group ATTRIBUTE_UNUSED) virCgroupPtr *group ATTRIBUTE_UNUSED)
{ {
/* Claim no support */ virReportSystemError(ENXIO, "%s",
return -ENXIO; _("Control groups not supported on this platform"));
return -1;
} }
#endif #endif
@ -1312,7 +1328,7 @@ int virCgroupNewPartition(const char *path ATTRIBUTE_UNUSED,
* @name: name of this driver (e.g., xen, qemu, lxc) * @name: name of this driver (e.g., xen, qemu, lxc)
* @group: Pointer to returned virCgroupPtr * @group: Pointer to returned virCgroupPtr
* *
* Returns 0 on success * Returns 0 on success, or -1 on error
*/ */
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
int virCgroupNewDriver(const char *name, int virCgroupNewDriver(const char *name,
@ -1320,26 +1336,27 @@ int virCgroupNewDriver(const char *name,
int controllers, int controllers,
virCgroupPtr *group) virCgroupPtr *group)
{ {
int rc; int ret = -1;
virCgroupPtr rootgrp = NULL; virCgroupPtr rootgrp = NULL;
rc = virCgroupAppRoot(&rootgrp, if (virCgroupAppRoot(&rootgrp,
create, controllers); create, controllers) < 0)
if (rc != 0) goto cleanup;
goto out;
rc = virCgroupNew(name, rootgrp, -1, group); if (virCgroupNew(name, rootgrp, -1, group) < 0)
if (rc == 0) { goto cleanup;
rc = virCgroupMakeGroup(rootgrp, *group, create, VIR_CGROUP_NONE);
if (rc != 0) { if (virCgroupMakeGroup(rootgrp, *group, create, VIR_CGROUP_NONE) < 0) {
virCgroupRemove(*group); virCgroupRemove(*group);
virCgroupFree(group); virCgroupFree(group);
goto cleanup;
} }
}
out:
virCgroupFree(&rootgrp);
return rc; ret = 0;
cleanup:
virCgroupFree(&rootgrp);
return ret;
} }
#else #else
int virCgroupNewDriver(const char *name ATTRIBUTE_UNUSED, int virCgroupNewDriver(const char *name ATTRIBUTE_UNUSED,
@ -1347,8 +1364,9 @@ int virCgroupNewDriver(const char *name ATTRIBUTE_UNUSED,
int controllers ATTRIBUTE_UNUSED, int controllers ATTRIBUTE_UNUSED,
virCgroupPtr *group ATTRIBUTE_UNUSED) virCgroupPtr *group ATTRIBUTE_UNUSED)
{ {
/* Claim no support */ virReportSystemError(ENXIO, "%s",
return -ENXIO; _("Control groups not supported on this platform"));
return -1;
} }
#endif #endif
@ -1360,7 +1378,7 @@ int virCgroupNewDriver(const char *name ATTRIBUTE_UNUSED,
* Obtain a cgroup representing the config of the * Obtain a cgroup representing the config of the
* current process * current process
* *
* Returns 0 on success * Returns 0 on success, or -1 on error
*/ */
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
int virCgroupNewSelf(virCgroupPtr *group) int virCgroupNewSelf(virCgroupPtr *group)
@ -1370,7 +1388,9 @@ int virCgroupNewSelf(virCgroupPtr *group)
#else #else
int virCgroupNewSelf(virCgroupPtr *group ATTRIBUTE_UNUSED) int virCgroupNewSelf(virCgroupPtr *group ATTRIBUTE_UNUSED)
{ {
return -ENXIO; virReportSystemError(ENXIO, "%s",
_("Control groups not supported on this platform"));
return -1;
} }
#endif #endif
@ -1381,7 +1401,7 @@ int virCgroupNewSelf(virCgroupPtr *group ATTRIBUTE_UNUSED)
* @name: name of the domain * @name: name of the domain
* @group: Pointer to returned virCgroupPtr * @group: Pointer to returned virCgroupPtr
* *
* Returns 0 on success * Returns 0 on success, or -1 on error
*/ */
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
int virCgroupNewDomainDriver(virCgroupPtr driver, int virCgroupNewDomainDriver(virCgroupPtr driver,
@ -1389,11 +1409,11 @@ int virCgroupNewDomainDriver(virCgroupPtr driver,
bool create, bool create,
virCgroupPtr *group) virCgroupPtr *group)
{ {
int rc; int ret = -1;
rc = virCgroupNew(name, driver, -1, group); if (virCgroupNew(name, driver, -1, group) < 0)
goto cleanup;
if (rc == 0) {
/* /*
* Create a cgroup with memory.use_hierarchy enabled to * Create a cgroup with memory.use_hierarchy enabled to
* surely account memory usage of lxc with ns subsystem * surely account memory usage of lxc with ns subsystem
@ -1404,14 +1424,15 @@ int virCgroupNewDomainDriver(virCgroupPtr driver,
* a group for driver, is to avoid overhead to track * a group for driver, is to avoid overhead to track
* cumulative usage that we don't need. * cumulative usage that we don't need.
*/ */
rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_MEM_HIERACHY); if (virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_MEM_HIERACHY) < 0) {
if (rc != 0) {
virCgroupRemove(*group); virCgroupRemove(*group);
virCgroupFree(group); virCgroupFree(group);
} goto cleanup;
} }
return rc; ret = 0;
cleanup:
return ret;
} }
#else #else
int virCgroupNewDomainDriver(virCgroupPtr driver ATTRIBUTE_UNUSED, int virCgroupNewDomainDriver(virCgroupPtr driver ATTRIBUTE_UNUSED,
@ -1419,7 +1440,9 @@ int virCgroupNewDomainDriver(virCgroupPtr driver ATTRIBUTE_UNUSED,
bool create ATTRIBUTE_UNUSED, bool create ATTRIBUTE_UNUSED,
virCgroupPtr *group ATTRIBUTE_UNUSED) virCgroupPtr *group ATTRIBUTE_UNUSED)
{ {
return -ENXIO; virReportSystemError(ENXIO, "%s",
_("Control groups not supported on this platform"));
return -1;
} }
#endif #endif
@ -1431,7 +1454,7 @@ int virCgroupNewDomainDriver(virCgroupPtr driver ATTRIBUTE_UNUSED,
* @name: name of the domain * @name: name of the domain
* @group: Pointer to returned virCgroupPtr * @group: Pointer to returned virCgroupPtr
* *
* Returns 0 on success * Returns 0 on success, or -1 on error
*/ */
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
int virCgroupNewDomainPartition(virCgroupPtr partition, int virCgroupNewDomainPartition(virCgroupPtr partition,
@ -1440,19 +1463,19 @@ int virCgroupNewDomainPartition(virCgroupPtr partition,
bool create, bool create,
virCgroupPtr *group) virCgroupPtr *group)
{ {
int rc; int ret = -1;
char *grpname = NULL; char *grpname = NULL;
if (virAsprintf(&grpname, "%s.libvirt-%s", if (virAsprintf(&grpname, "%s.libvirt-%s",
name, driver) < 0) name, driver) < 0)
return -ENOMEM; goto cleanup;
if ((rc = virCgroupPartitionEscape(&grpname)) < 0) if (virCgroupPartitionEscape(&grpname) < 0)
return rc; goto cleanup;
rc = virCgroupNew(grpname, partition, -1, group); if (virCgroupNew(grpname, partition, -1, group) < 0)
goto cleanup;
if (rc == 0) {
/* /*
* Create a cgroup with memory.use_hierarchy enabled to * Create a cgroup with memory.use_hierarchy enabled to
* surely account memory usage of lxc with ns subsystem * surely account memory usage of lxc with ns subsystem
@ -1463,15 +1486,17 @@ int virCgroupNewDomainPartition(virCgroupPtr partition,
* a group for driver, is to avoid overhead to track * a group for driver, is to avoid overhead to track
* cumulative usage that we don't need. * cumulative usage that we don't need.
*/ */
rc = virCgroupMakeGroup(partition, *group, create, VIR_CGROUP_MEM_HIERACHY); if (virCgroupMakeGroup(partition, *group, create, VIR_CGROUP_MEM_HIERACHY) < 0) {
if (rc != 0) {
virCgroupRemove(*group); virCgroupRemove(*group);
virCgroupFree(group); virCgroupFree(group);
} goto cleanup;
} }
ret = 0;
cleanup:
VIR_FREE(grpname); VIR_FREE(grpname);
return rc; return ret;
} }
#else #else
int virCgroupNewDomainPartition(virCgroupPtr partition ATTRIBUTE_UNUSED, int virCgroupNewDomainPartition(virCgroupPtr partition ATTRIBUTE_UNUSED,
@ -1480,7 +1505,9 @@ int virCgroupNewDomainPartition(virCgroupPtr partition ATTRIBUTE_UNUSED,
bool create ATTRIBUTE_UNUSED, bool create ATTRIBUTE_UNUSED,
virCgroupPtr *group ATTRIBUTE_UNUSED) virCgroupPtr *group ATTRIBUTE_UNUSED)
{ {
return -ENXIO; virReportSystemError(ENXIO, "%s",
_("Control groups not supported on this platform"));
return -1;
} }
#endif #endif
@ -1492,7 +1519,7 @@ int virCgroupNewDomainPartition(virCgroupPtr partition ATTRIBUTE_UNUSED,
* @create: true to create if not already existing * @create: true to create if not already existing
* @group: Pointer to returned virCgroupPtr * @group: Pointer to returned virCgroupPtr
* *
* Returns 0 on success * Returns 0 on success, or -1 on error
*/ */
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
int virCgroupNewVcpu(virCgroupPtr domain, int virCgroupNewVcpu(virCgroupPtr domain,
@ -1500,29 +1527,30 @@ int virCgroupNewVcpu(virCgroupPtr domain,
bool create, bool create,
virCgroupPtr *group) virCgroupPtr *group)
{ {
int rc; int ret = -1;
char *name; char *name = NULL;
int controllers; int controllers;
if (virAsprintf(&name, "vcpu%d", vcpuid) < 0) if (virAsprintf(&name, "vcpu%d", vcpuid) < 0)
return -ENOMEM; goto cleanup;
controllers = ((1 << VIR_CGROUP_CONTROLLER_CPU) | controllers = ((1 << VIR_CGROUP_CONTROLLER_CPU) |
(1 << VIR_CGROUP_CONTROLLER_CPUACCT) | (1 << VIR_CGROUP_CONTROLLER_CPUACCT) |
(1 << VIR_CGROUP_CONTROLLER_CPUSET)); (1 << VIR_CGROUP_CONTROLLER_CPUSET));
rc = virCgroupNew(name, domain, controllers, group); if (virCgroupNew(name, domain, controllers, group) < 0)
VIR_FREE(name); goto cleanup;
if (rc == 0) { if (virCgroupMakeGroup(domain, *group, create, VIR_CGROUP_NONE) < 0) {
rc = virCgroupMakeGroup(domain, *group, create, VIR_CGROUP_NONE);
if (rc != 0) {
virCgroupRemove(*group); virCgroupRemove(*group);
virCgroupFree(group); virCgroupFree(group);
} goto cleanup;
} }
return rc; ret = 0;
cleanup:
VIR_FREE(name);
return ret;
} }
#else #else
int virCgroupNewVcpu(virCgroupPtr domain ATTRIBUTE_UNUSED, int virCgroupNewVcpu(virCgroupPtr domain ATTRIBUTE_UNUSED,
@ -1530,7 +1558,9 @@ int virCgroupNewVcpu(virCgroupPtr domain ATTRIBUTE_UNUSED,
bool create ATTRIBUTE_UNUSED, bool create ATTRIBUTE_UNUSED,
virCgroupPtr *group ATTRIBUTE_UNUSED) virCgroupPtr *group ATTRIBUTE_UNUSED)
{ {
return -ENXIO; virReportSystemError(ENXIO, "%s",
_("Control groups not supported on this platform"));
return -1;
} }
#endif #endif
@ -1541,41 +1571,57 @@ int virCgroupNewVcpu(virCgroupPtr domain ATTRIBUTE_UNUSED,
* @create: true to create if not already existing * @create: true to create if not already existing
* @group: Pointer to returned virCgroupPtr * @group: Pointer to returned virCgroupPtr
* *
* Returns: 0 on success or -errno on failure * Returns: 0 on success or -1 on error
*/ */
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
int virCgroupNewEmulator(virCgroupPtr domain, int virCgroupNewEmulator(virCgroupPtr domain,
bool create, bool create,
virCgroupPtr *group) virCgroupPtr *group)
{ {
int rc; int ret = -1;
int controllers; int controllers;
controllers = ((1 << VIR_CGROUP_CONTROLLER_CPU) | controllers = ((1 << VIR_CGROUP_CONTROLLER_CPU) |
(1 << VIR_CGROUP_CONTROLLER_CPUACCT) | (1 << VIR_CGROUP_CONTROLLER_CPUACCT) |
(1 << VIR_CGROUP_CONTROLLER_CPUSET)); (1 << VIR_CGROUP_CONTROLLER_CPUSET));
rc = virCgroupNew("emulator", domain, controllers, group); if (virCgroupNew("emulator", domain, controllers, group) < 0)
goto cleanup;
if (rc == 0) { if (virCgroupMakeGroup(domain, *group, create, VIR_CGROUP_NONE) < 0) {
rc = virCgroupMakeGroup(domain, *group, create, VIR_CGROUP_NONE);
if (rc != 0) {
virCgroupRemove(*group); virCgroupRemove(*group);
virCgroupFree(group); virCgroupFree(group);
} goto cleanup;
} }
return rc; ret = 0;
cleanup:
return ret;
} }
#else #else
int virCgroupNewEmulator(virCgroupPtr domain ATTRIBUTE_UNUSED, int virCgroupNewEmulator(virCgroupPtr domain ATTRIBUTE_UNUSED,
bool create ATTRIBUTE_UNUSED, bool create ATTRIBUTE_UNUSED,
virCgroupPtr *group ATTRIBUTE_UNUSED) virCgroupPtr *group ATTRIBUTE_UNUSED)
{ {
return -ENXIO; virReportSystemError(ENXIO, "%s",
_("Control groups not supported on this platform"));
return -1;
} }
#endif #endif
bool virCgroupNewIgnoreError(void)
{
if (virLastErrorIsSystemErrno(ENXIO) ||
virLastErrorIsSystemErrno(EPERM) ||
virLastErrorIsSystemErrno(EACCES)) {
virResetLastError();
VIR_DEBUG("No cgroups present/configured/accessible, ignoring error");
return true;
}
return false;
}
/** /**
* virCgroupSetBlkioWeight: * virCgroupSetBlkioWeight:
* *
@ -2454,8 +2500,11 @@ static int virCgroupKillRecursiveInternal(virCgroupPtr group, int signum, virHas
VIR_DEBUG("Process subdir %s", ent->d_name); VIR_DEBUG("Process subdir %s", ent->d_name);
if ((rc = virCgroupNew(ent->d_name, group, -1, &subgroup)) != 0) if (virCgroupNew(ent->d_name, group, -1, &subgroup) < 0) {
virErrorSetErrnoFromLastError();
rc = -errno;
goto cleanup; goto cleanup;
}
if ((rc = virCgroupKillRecursiveInternal(subgroup, signum, pids, true)) < 0) if ((rc = virCgroupKillRecursiveInternal(subgroup, signum, pids, true)) < 0)
goto cleanup; goto cleanup;

View File

@ -46,6 +46,8 @@ enum {
VIR_ENUM_DECL(virCgroupController); VIR_ENUM_DECL(virCgroupController);
bool virCgroupAvailable(void);
int virCgroupNewPartition(const char *path, int virCgroupNewPartition(const char *path,
bool create, bool create,
int controllers, int controllers,
@ -84,6 +86,8 @@ int virCgroupNewEmulator(virCgroupPtr domain,
virCgroupPtr *group) virCgroupPtr *group)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
bool virCgroupNewIgnoreError(void);
int virCgroupPathOfController(virCgroupPtr group, int virCgroupPathOfController(virCgroupPtr group,
int controller, int controller,
const char *key, const char *key,

View File

@ -136,6 +136,18 @@ cleanup:
} }
# define ENSURE_ERRNO(en) \
do { \
if (!virLastErrorIsSystemErrno(en)) { \
virErrorPtr err = virGetLastError(); \
fprintf(stderr, "Did not get " #en " error code: %d:%d\n", \
err ? err->code : 0, err ? err->int1 : 0); \
goto cleanup; \
} } while (0)
/* Asking for impossible combination since CPU is co-mounted */
static int testCgroupNewForDriver(const void *args ATTRIBUTE_UNUSED) static int testCgroupNewForDriver(const void *args ATTRIBUTE_UNUSED)
{ {
virCgroupPtr cgroup = NULL; virCgroupPtr cgroup = NULL;
@ -160,26 +172,28 @@ static int testCgroupNewForDriver(const void *args ATTRIBUTE_UNUSED)
[VIR_CGROUP_CONTROLLER_BLKIO] = "/libvirt/lxc", [VIR_CGROUP_CONTROLLER_BLKIO] = "/libvirt/lxc",
}; };
if ((rv = virCgroupNewDriver("lxc", false, -1, &cgroup)) != -ENOENT) { if ((rv = virCgroupNewDriver("lxc", false, -1, &cgroup)) != -1) {
fprintf(stderr, "Unexpected found LXC cgroup: %d\n", -rv); fprintf(stderr, "Unexpected found LXC cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(ENOENT);
/* Asking for impossible combination since CPU is co-mounted */
if ((rv = virCgroupNewDriver("lxc", true, if ((rv = virCgroupNewDriver("lxc", true,
(1 << VIR_CGROUP_CONTROLLER_CPU), (1 << VIR_CGROUP_CONTROLLER_CPU),
&cgroup)) != -EINVAL) { &cgroup)) != -1) {
fprintf(stderr, "Should not have created LXC cgroup: %d\n", -rv); fprintf(stderr, "Should not have created LXC cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(EINVAL);
/* Asking for impossible combination since devices is not mounted */ /* Asking for impossible combination since devices is not mounted */
if ((rv = virCgroupNewDriver("lxc", true, if ((rv = virCgroupNewDriver("lxc", true,
(1 << VIR_CGROUP_CONTROLLER_DEVICES), (1 << VIR_CGROUP_CONTROLLER_DEVICES),
&cgroup)) != -ENXIO) { &cgroup)) != -1) {
fprintf(stderr, "Should not have created LXC cgroup: %d\n", -rv); fprintf(stderr, "Should not have created LXC cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(ENXIO);
/* Asking for small combination since devices is not mounted */ /* Asking for small combination since devices is not mounted */
if ((rv = virCgroupNewDriver("lxc", true, if ((rv = virCgroupNewDriver("lxc", true,
@ -264,26 +278,29 @@ static int testCgroupNewForPartition(const void *args ATTRIBUTE_UNUSED)
[VIR_CGROUP_CONTROLLER_BLKIO] = "/virtualmachines.partition", [VIR_CGROUP_CONTROLLER_BLKIO] = "/virtualmachines.partition",
}; };
if ((rv = virCgroupNewPartition("/virtualmachines", false, -1, &cgroup)) != -ENOENT) { if ((rv = virCgroupNewPartition("/virtualmachines", false, -1, &cgroup)) != -1) {
fprintf(stderr, "Unexpected found /virtualmachines cgroup: %d\n", -rv); fprintf(stderr, "Unexpected found /virtualmachines cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(ENOENT);
/* Asking for impossible combination since CPU is co-mounted */ /* Asking for impossible combination since CPU is co-mounted */
if ((rv = virCgroupNewPartition("/virtualmachines", true, if ((rv = virCgroupNewPartition("/virtualmachines", true,
(1 << VIR_CGROUP_CONTROLLER_CPU), (1 << VIR_CGROUP_CONTROLLER_CPU),
&cgroup)) != -EINVAL) { &cgroup)) != -1) {
fprintf(stderr, "Should not have created /virtualmachines cgroup: %d\n", -rv); fprintf(stderr, "Should not have created /virtualmachines cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(EINVAL);
/* Asking for impossible combination since devices is not mounted */ /* Asking for impossible combination since devices is not mounted */
if ((rv = virCgroupNewPartition("/virtualmachines", true, if ((rv = virCgroupNewPartition("/virtualmachines", true,
(1 << VIR_CGROUP_CONTROLLER_DEVICES), (1 << VIR_CGROUP_CONTROLLER_DEVICES),
&cgroup)) != -ENXIO) { &cgroup)) != -1) {
fprintf(stderr, "Should not have created /virtualmachines cgroup: %d\n", -rv); fprintf(stderr, "Should not have created /virtualmachines cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(ENXIO);
/* Asking for small combination since devices is not mounted */ /* Asking for small combination since devices is not mounted */
if ((rv = virCgroupNewPartition("/virtualmachines", true, if ((rv = virCgroupNewPartition("/virtualmachines", true,
@ -324,16 +341,18 @@ static int testCgroupNewForPartitionNested(const void *args ATTRIBUTE_UNUSED)
[VIR_CGROUP_CONTROLLER_BLKIO] = "/deployment.partition/production.partition", [VIR_CGROUP_CONTROLLER_BLKIO] = "/deployment.partition/production.partition",
}; };
if ((rv = virCgroupNewPartition("/deployment/production", false, -1, &cgroup)) != -ENOENT) { if ((rv = virCgroupNewPartition("/deployment/production", false, -1, &cgroup)) != -1) {
fprintf(stderr, "Unexpected found /deployment/production cgroup: %d\n", -rv); fprintf(stderr, "Unexpected found /deployment/production cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(ENOENT);
/* Should not work, since we require /deployment to be pre-created */ /* Should not work, since we require /deployment to be pre-created */
if ((rv = virCgroupNewPartition("/deployment/production", true, -1, &cgroup)) != -ENOENT) { if ((rv = virCgroupNewPartition("/deployment/production", true, -1, &cgroup)) != -1) {
fprintf(stderr, "Unexpected created /deployment/production cgroup: %d\n", -rv); fprintf(stderr, "Unexpected created /deployment/production cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(ENOENT);
if ((rv = virCgroupNewPartition("/deployment", true, -1, &cgroup)) != 0) { if ((rv = virCgroupNewPartition("/deployment", true, -1, &cgroup)) != 0) {
fprintf(stderr, "Failed to create /deployment cgroup: %d\n", -rv); fprintf(stderr, "Failed to create /deployment cgroup: %d\n", -rv);
@ -370,16 +389,18 @@ static int testCgroupNewForPartitionNestedDeep(const void *args ATTRIBUTE_UNUSED
[VIR_CGROUP_CONTROLLER_BLKIO] = "/user/berrange.user/production.partition", [VIR_CGROUP_CONTROLLER_BLKIO] = "/user/berrange.user/production.partition",
}; };
if ((rv = virCgroupNewPartition("/user/berrange.user/production", false, -1, &cgroup)) != -ENOENT) { if ((rv = virCgroupNewPartition("/user/berrange.user/production", false, -1, &cgroup)) != -1) {
fprintf(stderr, "Unexpected found /user/berrange.user/production cgroup: %d\n", -rv); fprintf(stderr, "Unexpected found /user/berrange.user/production cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(ENOENT);
/* Should not work, since we require /user/berrange.user to be pre-created */ /* Should not work, since we require /user/berrange.user to be pre-created */
if ((rv = virCgroupNewPartition("/user/berrange.user/production", true, -1, &cgroup)) != -ENOENT) { if ((rv = virCgroupNewPartition("/user/berrange.user/production", true, -1, &cgroup)) != -1) {
fprintf(stderr, "Unexpected created /user/berrange.user/production cgroup: %d\n", -rv); fprintf(stderr, "Unexpected created /user/berrange.user/production cgroup: %d\n", -rv);
goto cleanup; goto cleanup;
} }
ENSURE_ERRNO(ENOENT);
if ((rv = virCgroupNewPartition("/user", true, -1, &cgroup)) != 0) { if ((rv = virCgroupNewPartition("/user", true, -1, &cgroup)) != 0) {
fprintf(stderr, "Failed to create /user/berrange.user cgroup: %d\n", -rv); fprintf(stderr, "Failed to create /user/berrange.user cgroup: %d\n", -rv);