Refactor cgroups to allow a group per driver to be managed directly

Allow the driver level cgroup to be managed explicitly by the
hypervisor drivers, in order to detect whether to enable or
disable cgroup support for domains. Provides better error
reporting of failures. Also allow for creation of cgroups for
unprivileged drivers if controller is accessible by the user.

* src/cgroup.c, src/cgroup.h: Add an API to obtain a driver cgroup
* src/lxc_conf.h, src/lxc_controller.c, src/lxc_driver.c:
  Obtain a driver cgroup at startup and use that instead of
  re-creating everytime.
* src/util.c, src/util.h, src/libvirt_private.syms: Add a
  virGetUserName() helper
This commit is contained in:
Daniel P. Berrange 2009-07-10 11:40:04 +01:00
parent de1ecd5302
commit 946c489c68
8 changed files with 153 additions and 107 deletions

View File

@ -484,36 +484,6 @@ static int virCgroupMakeGroup(virCgroupPtr parent, virCgroupPtr group)
} }
static int virCgroupRoot(virCgroupPtr *group);
/**
* virCgroupHaveSupport:
*
* Returns 0 if support is present, negative if not
*/
int virCgroupHaveSupport(void)
{
virCgroupPtr root;
int i;
int rc;
int any = 0;
rc = virCgroupRoot(&root);
if (rc < 0)
return rc;
for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
if (root->controllers[i].mountPoint != NULL)
any = 1;
}
virCgroupFree(&root);
if (any)
return 0;
return -ENOENT;
}
static int virCgroupNew(const char *path, static int virCgroupNew(const char *path,
virCgroupPtr *group) virCgroupPtr *group)
{ {
@ -547,47 +517,47 @@ err:
return rc; return rc;
} }
static int virCgroupRoot(virCgroupPtr *group) static int virCgroupAppRoot(int privileged,
virCgroupPtr *group)
{ {
return virCgroupNew("/", group); virCgroupPtr rootgrp = NULL;
} int rc;
static int virCgroupCreate(virCgroupPtr parent, rc = virCgroupNew("/", &rootgrp);
const char *name,
virCgroupPtr *group)
{
int rc = 0;
char *path;
VIR_DEBUG("Creating %s under %s", name, parent->path);
rc = virAsprintf(&path, "%s/%s",
STREQ(parent->path, "/") ?
"" : parent->path,
name);
if (rc < 0) {
rc = -ENOMEM;
goto err;
}
rc = virCgroupNew(path, group);
if (rc != 0) {
DEBUG0("Unable to allocate new virCgroup structure");
goto err;
}
rc = virCgroupMakeGroup(parent, *group);
if (rc != 0) if (rc != 0)
goto err; return rc;
return rc; if (privileged) {
err: rc = virCgroupNew("/libvirt", group);
virCgroupFree(group); } else {
*group = NULL; char *rootname;
char *username;
username = virGetUserName(NULL, getuid());
if (!username) {
rc = -ENOMEM;
goto cleanup;
}
rc = virAsprintf(&rootname, "/libvirt-%s", username);
VIR_FREE(username);
if (rc < 0) {
rc = -ENOMEM;
goto cleanup;
}
rc = virCgroupNew(rootname, group);
VIR_FREE(rootname);
}
if (rc != 0)
goto cleanup;
rc = virCgroupMakeGroup(rootgrp, *group);
cleanup:
virCgroupFree(&rootgrp);
return rc; return rc;
} }
/** /**
* virCgroupRemove: * virCgroupRemove:
* *
@ -648,45 +618,83 @@ int virCgroupAddTask(virCgroupPtr group, pid_t pid)
return rc; return rc;
} }
/** /**
* virCgroupForDomain: * virCgroupForDriver:
* *
* @def: Domain definition to create cgroup for * @name: name of this driver (e.g., xen, qemu, lxc)
* @driverName: Classification of this domain type (e.g., xen, qemu, lxc)
* @group: Pointer to returned virCgroupPtr * @group: Pointer to returned virCgroupPtr
* *
* Returns 0 on success * Returns 0 on success
*/ */
int virCgroupForDomain(virDomainDefPtr def, int virCgroupForDriver(const char *name,
const char *driverName, virCgroupPtr *group,
virCgroupPtr *group) int privileged,
int create)
{ {
int rc; int rc;
char *path = NULL;
virCgroupPtr rootgrp = NULL; virCgroupPtr rootgrp = NULL;
virCgroupPtr daemongrp = NULL;
virCgroupPtr typegrp = NULL;
rc = virCgroupRoot(&rootgrp); rc = virCgroupAppRoot(privileged, &rootgrp);
if (rc != 0) if (rc != 0)
goto out; goto out;
rc = virCgroupCreate(rootgrp, "libvirt", &daemongrp); if (virAsprintf(&path, "%s/%s", rootgrp->path, name) < 0) {
if (rc != 0) rc = -ENOMEM;
goto out; goto out;
}
rc = virCgroupCreate(daemongrp, driverName, &typegrp); rc = virCgroupNew(path, group);
if (rc != 0) VIR_FREE(path);
goto out;
if (rc == 0 &&
create) {
rc = virCgroupMakeGroup(rootgrp, *group);
if (rc != 0)
virCgroupFree(group);
}
rc = virCgroupCreate(typegrp, def->name, group);
out: out:
virCgroupFree(&typegrp);
virCgroupFree(&daemongrp);
virCgroupFree(&rootgrp); virCgroupFree(&rootgrp);
return rc; return rc;
} }
/**
* virCgroupForDomain:
*
* @driver: group for driver owning the domain
* @name: name of the domain
* @group: Pointer to returned virCgroupPtr
*
* Returns 0 on success
*/
int virCgroupForDomain(virCgroupPtr driver,
const char *name,
virCgroupPtr *group,
int create)
{
int rc;
char *path;
if (virAsprintf(&path, "%s/%s", driver->path, name) < 0)
return -ENOMEM;
rc = virCgroupNew(path, group);
VIR_FREE(path);
if (rc == 0 &&
create) {
rc = virCgroupMakeGroup(driver, *group);
if (rc != 0)
virCgroupFree(group);
}
return rc;
}
/** /**
* virCgroupSetMemory: * virCgroupSetMemory:
* *

View File

@ -12,18 +12,18 @@
#ifndef CGROUP_H #ifndef CGROUP_H
#define CGROUP_H #define CGROUP_H
#include <stdint.h>
struct virCgroup; struct virCgroup;
typedef struct virCgroup *virCgroupPtr; typedef struct virCgroup *virCgroupPtr;
#include "domain_conf.h" int virCgroupForDriver(const char *name,
virCgroupPtr *group,
int privileged,
int create);
int virCgroupHaveSupport(void); int virCgroupForDomain(virCgroupPtr driver,
const char *name,
int virCgroupForDomain(virDomainDefPtr def, virCgroupPtr *group,
const char *driverName, int create);
virCgroupPtr *group);
int virCgroupAddTask(virCgroupPtr group, pid_t pid); int virCgroupAddTask(virCgroupPtr group, pid_t pid);

View File

@ -382,6 +382,7 @@ virRun;
virSkipSpaces; virSkipSpaces;
virKillProcess; virKillProcess;
virGetUserDirectory; virGetUserDirectory;
virGetUserName;
virGetUserID; virGetUserID;
virGetGroupID; virGetGroupID;

View File

@ -31,6 +31,7 @@
#include "domain_event.h" #include "domain_event.h"
#include "capabilities.h" #include "capabilities.h"
#include "threads.h" #include "threads.h"
#include "cgroup.h"
#define LXC_CONFIG_DIR SYSCONF_DIR "/libvirt/lxc" #define LXC_CONFIG_DIR SYSCONF_DIR "/libvirt/lxc"
#define LXC_STATE_DIR LOCAL_STATE_DIR "/run/libvirt/lxc" #define LXC_STATE_DIR LOCAL_STATE_DIR "/run/libvirt/lxc"
@ -42,6 +43,7 @@ struct __lxc_driver {
virCapsPtr caps; virCapsPtr caps;
virCgroupPtr cgroup;
virDomainObjList domains; virDomainObjList domains;
char *configDir; char *configDir;
char *autostartDir; char *autostartDir;

View File

@ -48,7 +48,6 @@
#include "veth.h" #include "veth.h"
#include "memory.h" #include "memory.h"
#include "util.h" #include "util.h"
#include "cgroup.h"
#define VIR_FROM_THIS VIR_FROM_LXC #define VIR_FROM_THIS VIR_FROM_LXC
@ -69,6 +68,7 @@ struct cgroup_device_policy {
*/ */
static int lxcSetContainerResources(virDomainDefPtr def) static int lxcSetContainerResources(virDomainDefPtr def)
{ {
virCgroupPtr driver;
virCgroupPtr cgroup; virCgroupPtr cgroup;
int rc = -1; int rc = -1;
int i; int i;
@ -82,14 +82,18 @@ static int lxcSetContainerResources(virDomainDefPtr def)
{'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_PTMX}, {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_PTMX},
{0, 0, 0}}; {0, 0, 0}};
if (virCgroupHaveSupport() != 0) rc = virCgroupForDriver("lxc", &driver, 1, 0);
return 0; /* Not supported, so claim success */ if (rc != 0) {
lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to get cgroup for driver"));
return rc;
}
rc = virCgroupForDomain(def, "lxc", &cgroup); rc = virCgroupForDomain(driver, def->name, &cgroup, 1);
if (rc != 0) { if (rc != 0) {
lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("Unable to create cgroup for %s\n"), def->name); _("Unable to create cgroup for domain %s"), def->name);
return rc; goto cleanup;
} }
rc = virCgroupSetMemory(cgroup, def->maxmem); rc = virCgroupSetMemory(cgroup, def->maxmem);
@ -119,9 +123,10 @@ out:
if (rc != 0) { if (rc != 0) {
virReportSystemError(NULL, -rc, "%s", virReportSystemError(NULL, -rc, "%s",
_("Failed to set lxc resources")); _("Failed to set lxc resources"));
virCgroupRemove(cgroup);
} }
cleanup:
virCgroupFree(&driver);
virCgroupFree(&cgroup); virCgroupFree(&cgroup);
return rc; return rc;

View File

@ -46,7 +46,6 @@
#include "bridge.h" #include "bridge.h"
#include "veth.h" #include "veth.h"
#include "event.h" #include "event.h"
#include "cgroup.h"
#include "nodeinfo.h" #include "nodeinfo.h"
#include "uuid.h" #include "uuid.h"
@ -421,10 +420,10 @@ static int lxcDomainGetInfo(virDomainPtr dom,
info->state = vm->state; info->state = vm->state;
if (!virDomainIsActive(vm) || virCgroupHaveSupport() != 0) { if (!virDomainIsActive(vm) || driver->cgroup == NULL) {
info->cpuTime = 0; info->cpuTime = 0;
} else { } else {
if (virCgroupForDomain(vm->def, "lxc", &cgroup) != 0) { if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR, lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
_("Unable to get cgroup for %s\n"), vm->def->name); _("Unable to get cgroup for %s\n"), vm->def->name);
goto cleanup; goto cleanup;
@ -555,7 +554,8 @@ static int lxcVMCleanup(virConnectPtr conn,
vethDelete(vm->def->nets[i]->ifname); vethDelete(vm->def->nets[i]->ifname);
} }
if (virCgroupForDomain(vm->def, "lxc", &cgroup) == 0) { if (driver->cgroup &&
virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0) {
virCgroupRemove(cgroup); virCgroupRemove(cgroup);
virCgroupFree(&cgroup); virCgroupFree(&cgroup);
} }
@ -1348,6 +1348,7 @@ static int lxcStartup(int privileged)
{ {
unsigned int i; unsigned int i;
char *ld; char *ld;
int rc;
/* Valgrind gets very annoyed when we clone containers, so /* Valgrind gets very annoyed when we clone containers, so
* disable LXC when under valgrind * disable LXC when under valgrind
@ -1386,6 +1387,13 @@ static int lxcStartup(int privileged)
lxc_driver->have_netns = lxcCheckNetNsSupport(); lxc_driver->have_netns = lxcCheckNetNsSupport();
rc = virCgroupForDriver("lxc", &lxc_driver->cgroup, privileged, 1);
if (rc < 0) {
char buf[1024];
VIR_WARN("Unable to create cgroup for driver: %s",
virStrerror(-rc, buf, sizeof(buf)));
}
/* Call function to load lxc driver configuration information */ /* Call function to load lxc driver configuration information */
if (lxcLoadDriverConfig(lxc_driver) < 0) if (lxcLoadDriverConfig(lxc_driver) < 0)
goto cleanup; goto cleanup;
@ -1405,7 +1413,6 @@ static int lxcStartup(int privileged)
virDomainObjPtr vm = lxc_driver->domains.objs[i]; virDomainObjPtr vm = lxc_driver->domains.objs[i];
char *config = NULL; char *config = NULL;
virDomainDefPtr tmp; virDomainDefPtr tmp;
int rc;
virDomainObjLock(vm); virDomainObjLock(vm);
if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0) { if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0) {
@ -1587,7 +1594,7 @@ static int lxcSetSchedulerParameters(virDomainPtr domain,
virDomainObjPtr vm = NULL; virDomainObjPtr vm = NULL;
int ret = -1; int ret = -1;
if (virCgroupHaveSupport() != 0) if (driver->cgroup == NULL)
return -1; return -1;
lxcDriverLock(driver); lxcDriverLock(driver);
@ -1600,7 +1607,7 @@ static int lxcSetSchedulerParameters(virDomainPtr domain,
goto cleanup; goto cleanup;
} }
if (virCgroupForDomain(vm->def, "lxc", &group) != 0) if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
goto cleanup; goto cleanup;
for (i = 0; i < nparams; i++) { for (i = 0; i < nparams; i++) {
@ -1634,7 +1641,7 @@ static int lxcGetSchedulerParameters(virDomainPtr domain,
unsigned long val; unsigned long val;
int ret = -1; int ret = -1;
if (virCgroupHaveSupport() != 0) if (driver->cgroup == NULL)
return -1; return -1;
if ((*nparams) != 1) { if ((*nparams) != 1) {
@ -1653,7 +1660,7 @@ static int lxcGetSchedulerParameters(virDomainPtr domain,
goto cleanup; goto cleanup;
} }
if (virCgroupForDomain(vm->def, "lxc", &group) != 0) if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
goto cleanup; goto cleanup;
if (virCgroupGetCpuShares(group, &val) != 0) if (virCgroupGetCpuShares(group, &val) != 0)

View File

@ -1826,8 +1826,14 @@ int virRandom(int max)
#ifdef HAVE_GETPWUID_R #ifdef HAVE_GETPWUID_R
char *virGetUserDirectory(virConnectPtr conn, enum {
uid_t uid) VIR_USER_ENT_DIRECTORY,
VIR_USER_ENT_NAME,
};
static char *virGetUserEnt(virConnectPtr conn,
uid_t uid,
int field)
{ {
char *strbuf; char *strbuf;
char *ret; char *ret;
@ -1855,7 +1861,10 @@ char *virGetUserDirectory(virConnectPtr conn,
return NULL; return NULL;
} }
ret = strdup(pw->pw_dir); if (field == VIR_USER_ENT_DIRECTORY)
ret = strdup(pw->pw_dir);
else
ret = strdup(pw->pw_name);
VIR_FREE(strbuf); VIR_FREE(strbuf);
if (!ret) if (!ret)
@ -1864,6 +1873,18 @@ char *virGetUserDirectory(virConnectPtr conn,
return ret; return ret;
} }
char *virGetUserDirectory(virConnectPtr conn,
uid_t uid)
{
return virGetUserEnt(conn, uid, VIR_USER_ENT_DIRECTORY);
}
char *virGetUserName(virConnectPtr conn,
uid_t uid)
{
return virGetUserEnt(conn, uid, VIR_USER_ENT_NAME);
}
int virGetUserID(virConnectPtr conn, int virGetUserID(virConnectPtr conn,
const char *name, const char *name,

View File

@ -217,6 +217,8 @@ int virKillProcess(pid_t pid, int sig);
#ifdef HAVE_GETPWUID_R #ifdef HAVE_GETPWUID_R
char *virGetUserDirectory(virConnectPtr conn, char *virGetUserDirectory(virConnectPtr conn,
uid_t uid); uid_t uid);
char *virGetUserName(virConnectPtr conn,
uid_t uid);
int virGetUserID(virConnectPtr conn, int virGetUserID(virConnectPtr conn,
const char *name, const char *name,
uid_t *uid); uid_t *uid);