From 92cce1a7b806fef7a9ec0b7cd2553cfa6f8f03b2377c70dd00899849a269ec1e Mon Sep 17 00:00:00 2001 From: OBS User unknown Date: Mon, 13 Oct 2008 15:08:24 +0000 Subject: [PATCH] OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/libvirt?expand=0&rev=22 --- cgroup.patch | 822 ++++++++++++++++++++++++++++++++++++++++++++++ cgshares.patch | 118 +++++++ libvirt.changes | 6 + libvirt.spec | 15 +- lxc_res_mem.patch | 198 +++++++++++ lxcsched.patch | 130 ++++++++ lxcvirsh.patch | 123 +++++++ 7 files changed, 1411 insertions(+), 1 deletion(-) create mode 100644 cgroup.patch create mode 100644 cgshares.patch create mode 100644 lxc_res_mem.patch create mode 100644 lxcsched.patch create mode 100644 lxcvirsh.patch diff --git a/cgroup.patch b/cgroup.patch new file mode 100644 index 0000000..a16cdfe --- /dev/null +++ b/cgroup.patch @@ -0,0 +1,822 @@ +# HG changeset patch +# User danms +# Date 1223056682 0 +# Node ID 64f19f607bc6837fe2411cfdb2942b13ce8902c1 +# Parent a28490b116b0430aa0d4f579bba57d52793312ed +[r2008-10-03 17:58:02 by danms] Add forgotten cgroup.{c,h} and ChangeLog + +Index: libvirt-0.4.6/src/cgroup.c +=================================================================== +--- /dev/null ++++ libvirt-0.4.6/src/cgroup.c +@@ -0,0 +1,762 @@ ++/* ++ * cgroup.c: Tools for managing cgroups ++ * ++ * Copyright IBM Corp. 2008 ++ * ++ * See COPYING.LIB for the License of this software ++ * ++ * Authors: ++ * Dan Smith ++ */ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "internal.h" ++#include "util.h" ++#include "memory.h" ++#include "cgroup.h" ++ ++#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__) ++#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg) ++ ++#define CGROUP_MAX_VAL 512 ++ ++struct virCgroup { ++ char *path; ++}; ++ ++const char *supported_controllers[] = { ++ "memory", ++ "devices", ++ NULL ++}; ++ ++/** ++ * virCgroupFree: ++ * ++ * @group: The group structure to free ++ */ ++void virCgroupFree(virCgroupPtr *group) ++{ ++ if (*group != NULL) { ++ VIR_FREE((*group)->path); ++ VIR_FREE(*group); ++ *group = NULL; ++ } ++} ++ ++static virCgroupPtr virCgroupGetMount(const char *controller) ++{ ++ FILE *mounts; ++ struct mntent entry; ++ char buf[CGROUP_MAX_VAL]; ++ virCgroupPtr root = NULL; ++ ++ if (VIR_ALLOC(root) != 0) ++ return NULL; ++ ++ mounts = fopen("/proc/mounts", "r"); ++ if (mounts == NULL) { ++ DEBUG0("Unable to open /proc/mounts: %m"); ++ goto err; ++ } ++ ++ while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) { ++ if (STREQ(entry.mnt_type, "cgroup") && ++ (strstr(entry.mnt_opts, controller))) { ++ root->path = strdup(entry.mnt_dir); ++ break; ++ } ++ } ++ ++ DEBUG("Mount for %s is %s\n", controller, root->path); ++ ++ if (root->path == NULL) { ++ DEBUG0("Did not find cgroup mount"); ++ goto err; ++ } ++ ++ fclose(mounts); ++ ++ return root; ++err: ++ virCgroupFree(&root); ++ ++ return NULL; ++} ++ ++/** ++ * virCgroupHaveSupport: ++ * ++ * Returns 0 if support is present, negative if not ++ */ ++int virCgroupHaveSupport(void) ++{ ++ virCgroupPtr root; ++ int i; ++ ++ for (i = 0; supported_controllers[i] != NULL; i++) { ++ root = virCgroupGetMount(supported_controllers[i]); ++ if (root == NULL) ++ return -1; ++ virCgroupFree(&root); ++ } ++ ++ return 0; ++} ++ ++static int virCgroupPathOfGroup(const char *group, ++ const char *controller, ++ char **path) ++{ ++ virCgroupPtr root = NULL; ++ int rc = 0; ++ ++ root = virCgroupGetMount(controller); ++ if (root == NULL) { ++ rc = -ENOTDIR; ++ goto out; ++ } ++ ++ if (asprintf(path, "%s/%s", root->path, group) == -1) ++ rc = -ENOMEM; ++out: ++ virCgroupFree(&root); ++ ++ return rc; ++} ++ ++static int virCgroupPathOf(const char *grppath, ++ const char *key, ++ char **path) ++{ ++ virCgroupPtr root; ++ int rc = 0; ++ char *controller = NULL; ++ ++ if (strchr(key, '.') == NULL) ++ return -EINVAL; ++ ++ if (sscanf(key, "%a[^.]", &controller) != 1) ++ return -EINVAL; ++ ++ root = virCgroupGetMount(controller); ++ if (root == NULL) { ++ rc = -ENOTDIR; ++ goto out; ++ } ++ ++ if (asprintf(path, "%s/%s/%s", root->path, grppath, key) == -1) ++ rc = -ENOMEM; ++out: ++ virCgroupFree(&root); ++ VIR_FREE(controller); ++ ++ return rc; ++} ++ ++static int virCgroupSetValueStr(virCgroupPtr group, ++ const char *key, ++ const char *value) ++{ ++ int fd = -1; ++ int rc = 0; ++ char *keypath = NULL; ++ ++ rc = virCgroupPathOf(group->path, key, &keypath); ++ if (rc != 0) ++ return rc; ++ ++ fd = open(keypath, O_WRONLY); ++ if (fd < 0) { ++ DEBUG("Unable to open %s: %m", keypath); ++ rc = -ENOENT; ++ goto out; ++ } ++ ++ DEBUG("Writing '%s' to '%s'", value, keypath); ++ ++ rc = safewrite(fd, value, strlen(value)); ++ if (rc < 0) { ++ DEBUG("Failed to write value '%s': %m", value); ++ rc = -errno; ++ goto out; ++ } else if (rc != strlen(value)) { ++ DEBUG("Short write of value '%s'", value); ++ rc = -ENOSPC; ++ goto out; ++ } ++ ++ rc = 0; ++out: ++ VIR_FREE(keypath); ++ close(fd); ++ ++ return rc; ++} ++ ++static int virCgroupSetValueU64(virCgroupPtr group, ++ const char *key, ++ uint64_t value) ++{ ++ char *strval = NULL; ++ int rc; ++ ++ if (asprintf(&strval, "%" PRIu64, value) == -1) ++ return -ENOMEM; ++ ++ rc = virCgroupSetValueStr(group, key, strval); ++ ++ VIR_FREE(strval); ++ ++ return rc; ++} ++ ++#if 0 ++/* This is included for completeness, but not yet used */ ++ ++static int virCgroupSetValueI64(virCgroupPtr group, ++ const char *key, ++ int64_t value) ++{ ++ char *strval = NULL; ++ int rc; ++ ++ if (asprintf(&strval, "%" PRIi64, value) == -1) ++ return -ENOMEM; ++ ++ rc = virCgroupSetValueStr(group, key, strval); ++ ++ VIR_FREE(strval); ++ ++ return rc; ++} ++ ++static int virCgroupGetValueStr(virCgroupPtr group, ++ const char *key, ++ char **value) ++{ ++ int fd = -1; ++ int rc; ++ char *keypath = NULL; ++ char buf[CGROUP_MAX_VAL]; ++ ++ memset(buf, 0, sizeof(buf)); ++ ++ rc = virCgroupPathOf(group->path, key, &keypath); ++ if (rc != 0) { ++ DEBUG("No path of %s, %s", group->path, key); ++ return rc; ++ } ++ ++ fd = open(keypath, O_RDONLY); ++ if (fd < 0) { ++ DEBUG("Unable to open %s: %m", keypath); ++ rc = -ENOENT; ++ goto out; ++ } ++ ++ rc = saferead(fd, buf, sizeof(buf)); ++ if (rc < 0) { ++ DEBUG("Failed to read %s: %m\n", keypath); ++ rc = -errno; ++ goto out; ++ } else if (rc == 0) { ++ DEBUG("Short read of %s\n", keypath); ++ rc = -EIO; ++ goto out; ++ } ++ ++ *value = strdup(buf); ++ if (*value == NULL) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ rc = 0; ++out: ++ VIR_FREE(keypath); ++ close(fd); ++ ++ return rc; ++} ++ ++static int virCgroupGetValueU64(virCgroupPtr group, ++ const char *key, ++ uint64_t *value) ++{ ++ char *strval = NULL; ++ int rc = 0; ++ ++ rc = virCgroupGetValueStr(group, key, &strval); ++ if (rc != 0) ++ goto out; ++ ++ if (sscanf(strval, "%" SCNu64, value) != 1) ++ rc = -EINVAL; ++out: ++ VIR_FREE(strval); ++ ++ return rc; ++} ++ ++static int virCgroupGetValueI64(virCgroupPtr group, ++ const char *key, ++ int64_t *value) ++{ ++ char *strval = NULL; ++ int rc = 0; ++ ++ rc = virCgroupGetValueStr(group, key, &strval); ++ if (rc != 0) ++ goto out; ++ ++ if (sscanf(strval, "%" SCNi64, value) != 1) ++ rc = -EINVAL; ++out: ++ VIR_FREE(strval); ++ ++ return rc; ++} ++#endif ++ ++static int _virCgroupInherit(const char *path, ++ const char *key) ++{ ++ int rc = 0; ++ int fd = -1; ++ char buf[CGROUP_MAX_VAL]; ++ char *keypath = NULL; ++ char *pkeypath = NULL; ++ ++ memset(buf, 0, sizeof(buf)); ++ ++ if (asprintf(&keypath, "%s/%s", path, key) == -1) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ if (access(keypath, F_OK) != 0) { ++ DEBUG("Group %s has no key %s\n", path, key); ++ goto out; ++ } ++ ++ if (asprintf(&pkeypath, "%s/../%s", path, key) == -1) { ++ rc = -ENOMEM; ++ VIR_FREE(keypath); ++ goto out; ++ } ++ ++ fd = open(pkeypath, O_RDONLY); ++ if (fd < 0) { ++ rc = -errno; ++ goto out; ++ } ++ ++ if (saferead(fd, buf, sizeof(buf)) <= 0) { ++ rc = -errno; ++ goto out; ++ } ++ ++ close(fd); ++ ++ fd = open(keypath, O_WRONLY); ++ if (fd < 0) { ++ rc = -errno; ++ goto out; ++ } ++ ++ if (safewrite(fd, buf, strlen(buf)) != strlen(buf)) { ++ rc = -errno; ++ goto out; ++ } ++ ++out: ++ VIR_FREE(keypath); ++ VIR_FREE(pkeypath); ++ close(fd); ++ ++ return rc; ++} ++ ++static int virCgroupInherit(const char *grppath) ++{ ++ int i; ++ int rc = 0; ++ const char *inherit_values[] = { ++ "cpuset.cpus", ++ "cpuset.mems", ++ NULL ++ }; ++ ++ for (i = 0; inherit_values[i] != NULL; i++) { ++ const char *key = inherit_values[i]; ++ ++ rc = _virCgroupInherit(grppath, key); ++ if (rc != 0) { ++ DEBUG("inherit of %s failed\n", key); ++ break; ++ } ++ } ++ ++ return rc; ++} ++ ++static int virCgroupMakeGroup(const char *name) ++{ ++ int i; ++ int rc = 0; ++ ++ for (i = 0; supported_controllers[i] != NULL; i++) { ++ char *path = NULL; ++ virCgroupPtr root; ++ ++ root = virCgroupGetMount(supported_controllers[i]); ++ if (root == NULL) ++ continue; ++ ++ rc = virCgroupPathOfGroup(name, supported_controllers[i], &path); ++ if (rc != 0) { ++ virCgroupFree(&root); ++ break; ++ } ++ ++ virCgroupFree(&root); ++ ++ if (access(path, F_OK) != 0) { ++ if (mkdir(path, 0655) < 0) { ++ rc = -errno; ++ VIR_FREE(path); ++ break; ++ } ++ virCgroupInherit(path); ++ } ++ ++ VIR_FREE(path); ++ } ++ ++ return rc; ++} ++ ++static int virCgroupRoot(virCgroupPtr *root) ++{ ++ int rc = 0; ++ char *grppath = NULL; ++ ++ if (VIR_ALLOC((*root)) != 0) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ (*root)->path = strdup("libvirt"); ++ if ((*root)->path == NULL) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ rc = virCgroupMakeGroup((*root)->path); ++out: ++ if (rc != 0) ++ virCgroupFree(root); ++ VIR_FREE(grppath); ++ ++ return rc; ++} ++ ++static int virCgroupNew(virCgroupPtr *parent, ++ const char *group, ++ virCgroupPtr *newgroup) ++{ ++ int rc = 0; ++ char *typpath = NULL; ++ ++ *newgroup = NULL; ++ ++ if (*parent == NULL) { ++ rc = virCgroupRoot(parent); ++ if (rc != 0) ++ goto err; ++ } ++ ++ if (VIR_ALLOC((*newgroup)) != 0) { ++ rc = -ENOMEM; ++ goto err; ++ } ++ ++ rc = asprintf(&((*newgroup)->path), ++ "%s/%s", ++ (*parent)->path, ++ group); ++ if (rc == -1) { ++ rc = -ENOMEM; ++ goto err; ++ } ++ ++ rc = 0; ++ ++ return rc; ++err: ++ virCgroupFree(newgroup); ++ *newgroup = NULL; ++ ++ VIR_FREE(typpath); ++ ++ return rc; ++} ++ ++static int virCgroupOpen(virCgroupPtr parent, ++ const char *group, ++ virCgroupPtr *newgroup) ++{ ++ int rc = 0; ++ char *grppath = NULL; ++ bool free_parent = (parent == NULL); ++ ++ rc = virCgroupNew(&parent, group, newgroup); ++ if (rc != 0) ++ goto err; ++ ++ if (free_parent) ++ virCgroupFree(&parent); ++ ++ rc = virCgroupPathOfGroup((*newgroup)->path, ++ supported_controllers[0], ++ &grppath); ++ if (rc != 0) ++ goto err; ++ ++ if (access(grppath, F_OK) != 0) { ++ rc = -ENOENT; ++ goto err; ++ } ++ ++ return rc; ++err: ++ virCgroupFree(newgroup); ++ *newgroup = NULL; ++ ++ return rc; ++} ++ ++static int virCgroupCreate(virCgroupPtr parent, ++ const char *group, ++ virCgroupPtr *newgroup) ++{ ++ int rc = 0; ++ bool free_parent = (parent == NULL); ++ ++ rc = virCgroupNew(&parent, group, newgroup); ++ if (rc != 0) { ++ DEBUG0("Unable to allocate new virCgroup structure"); ++ goto err; ++ } ++ ++ rc = virCgroupMakeGroup((*newgroup)->path); ++ if (rc != 0) ++ goto err; ++ ++ if (free_parent) ++ virCgroupFree(&parent); ++ ++ return rc; ++err: ++ virCgroupFree(newgroup); ++ *newgroup = NULL; ++ ++ if (free_parent) ++ virCgroupFree(&parent); ++ ++ return rc; ++} ++ ++/** ++ * virCgroupRemove: ++ * ++ * @group: The group to be removed ++ * ++ * Returns: 0 on success ++ */ ++int virCgroupRemove(virCgroupPtr group) ++{ ++ int rc = 0; ++ int i; ++ char *grppath = NULL; ++ ++ for (i = 0; supported_controllers[i] != NULL; i++) { ++ if (virCgroupPathOfGroup(group->path, ++ supported_controllers[i], ++ &grppath) != 0) ++ continue; ++ ++ if (rmdir(grppath) != 0) ++ rc = -errno; ++ ++ VIR_FREE(grppath); ++ } ++ ++ return rc; ++} ++ ++/** ++ * virCgroupAddTask: ++ * ++ * @group: The cgroup to add a task to ++ * @pid: The pid of the task to add ++ * ++ * Returns: 0 on success ++ */ ++int virCgroupAddTask(virCgroupPtr group, pid_t pid) ++{ ++ int rc = 0; ++ int fd = -1; ++ int i; ++ char *grppath = NULL; ++ char *taskpath = NULL; ++ char *pidstr = NULL; ++ ++ for (i = 0; supported_controllers[i] != NULL; i++) { ++ rc = virCgroupPathOfGroup(group->path, ++ supported_controllers[i], ++ &grppath); ++ if (rc != 0) ++ goto done; ++ ++ if (asprintf(&taskpath, "%s/tasks", grppath) == -1) { ++ rc = -ENOMEM; ++ goto done; ++ } ++ ++ fd = open(taskpath, O_WRONLY); ++ if (fd < 0) { ++ rc = -errno; ++ goto done; ++ } ++ ++ if (asprintf(&pidstr, "%lu", (unsigned long)pid) == -1) { ++ rc = -ENOMEM; ++ goto done; ++ } ++ ++ if (write(fd, pidstr, strlen(pidstr)) <= 0) { ++ rc = -errno; ++ goto done; ++ } ++ ++ done: ++ VIR_FREE(grppath); ++ VIR_FREE(taskpath); ++ VIR_FREE(pidstr); ++ close(fd); ++ ++ if (rc != 0) ++ break; ++ } ++ ++ return rc; ++} ++ ++/** ++ * virCgroupForDomain: ++ * ++ * @def: Domain definition to create cgroup for ++ * @driverName: Classification of this domain type (e.g., xen, qemu, lxc) ++ * @group: Pointer to returned virCgroupPtr ++ * ++ * Returns 0 on success ++ */ ++int virCgroupForDomain(virDomainDefPtr def, ++ const char *driverName, ++ virCgroupPtr *group) ++{ ++ int rc; ++ virCgroupPtr typegrp = NULL; ++ ++ rc = virCgroupOpen(NULL, driverName, &typegrp); ++ if (rc == -ENOENT) { ++ rc = virCgroupCreate(NULL, driverName, &typegrp); ++ if (rc != 0) ++ goto out; ++ } else if (rc != 0) ++ goto out; ++ ++ rc = virCgroupOpen(typegrp, def->name, group); ++ if (rc == -ENOENT) ++ rc = virCgroupCreate(typegrp, def->name, group); ++out: ++ virCgroupFree(&typegrp); ++ ++ return rc; ++} ++ ++/** ++ * virCgroupSetMemory: ++ * ++ * @group: The cgroup to change memory for ++ * @kb: The memory amount in kilobytes ++ * ++ * Returns: 0 on success ++ */ ++int virCgroupSetMemory(virCgroupPtr group, unsigned long kb) ++{ ++ return virCgroupSetValueU64(group, ++ "memory.limit_in_bytes", ++ kb << 10); ++} ++ ++/** ++ * virCgroupDenyAllDevices: ++ * ++ * @group: The cgroup to deny devices for ++ * ++ * Returns: 0 on success ++ */ ++int virCgroupDenyAllDevices(virCgroupPtr group) ++{ ++ return virCgroupSetValueStr(group, ++ "devices.deny", ++ "a"); ++} ++ ++/** ++ * virCgroupAllowDevice: ++ * ++ * @group: The cgroup to allow a device for ++ * @type: The device type (i.e., 'c' or 'b') ++ * @major: The major number of the device ++ * @minor: The minor number of the device ++ * ++ * Returns: 0 on success ++ */ ++int virCgroupAllowDevice(virCgroupPtr group, ++ char type, ++ int major, ++ int minor) ++{ ++ int rc; ++ char *devstr = NULL; ++ ++ if (asprintf(&devstr, "%c %i:%i rwm", type, major, minor) == -1) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ rc = virCgroupSetValueStr(group, ++ "devices.allow", ++ devstr); ++out: ++ VIR_FREE(devstr); ++ ++ return rc; ++} +Index: libvirt-0.4.6/src/cgroup.h +=================================================================== +--- /dev/null ++++ libvirt-0.4.6/src/cgroup.h +@@ -0,0 +1,43 @@ ++/* ++ * cgroup.h: Interface to tools for managing cgroups ++ * ++ * Copyright IBM Corp. 2008 ++ * ++ * See COPYING.LIB for the License of this software ++ * ++ * Authors: ++ * Dan Smith ++ */ ++ ++#ifndef CGROUP_H ++#define CGROUP_H ++ ++#include ++ ++struct virCgroup; ++typedef struct virCgroup *virCgroupPtr; ++ ++#include "domain_conf.h" ++ ++int virCgroupHaveSupport(void); ++ ++int virCgroupForDomain(virDomainDefPtr def, ++ const char *driverName, ++ virCgroupPtr *group); ++ ++int virCgroupAddTask(virCgroupPtr group, pid_t pid); ++ ++int virCgroupSetMemory(virCgroupPtr group, unsigned long kb); ++ ++int virCgroupDenyAllDevices(virCgroupPtr group); ++ ++int virCgroupAllowDevice(virCgroupPtr group, ++ char type, ++ int major, ++ int minor); ++ ++int virCgroupRemove(virCgroupPtr group); ++ ++void virCgroupFree(virCgroupPtr *group); ++ ++#endif /* CGROUP_H */ diff --git a/cgshares.patch b/cgshares.patch new file mode 100644 index 0000000..59dd8cc --- /dev/null +++ b/cgshares.patch @@ -0,0 +1,118 @@ +Add get/set of cpu.shares to cgroup implementation + +This brings get/set of U64 out of the #if 0, which looks messier than it is. + +diff -r d18631472325 src/cgroup.c +--- a/src/cgroup.c Tue Oct 07 08:19:56 2008 -0700 ++++ b/src/cgroup.c Tue Oct 07 08:20:56 2008 -0700 +@@ -224,26 +224,6 @@ + return rc; + } + +-#if 0 +-/* This is included for completeness, but not yet used */ +- +-static int virCgroupSetValueI64(virCgroupPtr group, +- const char *key, +- int64_t value) +-{ +- char *strval = NULL; +- int rc; +- +- if (asprintf(&strval, "%" PRIi64, value) == -1) +- return -ENOMEM; +- +- rc = virCgroupSetValueStr(group, key, strval); +- +- VIR_FREE(strval); +- +- return rc; +-} +- + static int virCgroupGetValueStr(virCgroupPtr group, + const char *key, + char **value) +@@ -293,20 +273,21 @@ + return rc; + } + +-static int virCgroupGetValueU64(virCgroupPtr group, ++#if 0 ++/* This is included for completeness, but not yet used */ ++ ++static int virCgroupSetValueI64(virCgroupPtr group, + const char *key, +- uint64_t *value) ++ int64_t value) + { + char *strval = NULL; +- int rc = 0; ++ int rc; + +- rc = virCgroupGetValueStr(group, key, &strval); +- if (rc != 0) +- goto out; ++ if (asprintf(&strval, "%" PRIi64, value) == -1) ++ return -ENOMEM; + +- if (sscanf(strval, "%" SCNu64, value) != 1) +- rc = -EINVAL; +-out: ++ rc = virCgroupSetValueStr(group, key, strval); ++ + VIR_FREE(strval); + + return rc; +@@ -331,6 +312,25 @@ + return rc; + } + #endif ++ ++static int virCgroupGetValueU64(virCgroupPtr group, ++ const char *key, ++ uint64_t *value) ++{ ++ char *strval = NULL; ++ int rc = 0; ++ ++ rc = virCgroupGetValueStr(group, key, &strval); ++ if (rc != 0) ++ goto out; ++ ++ if (sscanf(strval, "%" SCNu64, value) != 1) ++ rc = -EINVAL; ++out: ++ VIR_FREE(strval); ++ ++ return rc; ++} + + static int _virCgroupInherit(const char *path, + const char *key) +@@ -760,3 +760,13 @@ + + return rc; + } ++ ++int virCgroupSetCpuShares(virCgroupPtr group, unsigned long shares) ++{ ++ return virCgroupSetValueU64(group, "cpu.shares", (uint64_t)shares); ++} ++ ++int virCgroupGetCpuShares(virCgroupPtr group, unsigned long *shares) ++{ ++ return virCgroupGetValueU64(group, "cpu.shares", (uint64_t *)shares); ++} +diff -r d18631472325 src/cgroup.h +--- a/src/cgroup.h Tue Oct 07 08:19:56 2008 -0700 ++++ b/src/cgroup.h Tue Oct 07 08:20:56 2008 -0700 +@@ -36,6 +36,9 @@ + int major, + int minor); + ++int virCgroupSetCpuShares(virCgroupPtr group, unsigned long shares); ++int virCgroupGetCpuShares(virCgroupPtr group, unsigned long *shares); ++ + int virCgroupRemove(virCgroupPtr group); + + void virCgroupFree(virCgroupPtr *group); diff --git a/libvirt.changes b/libvirt.changes index 61b5ba8..ac42872 100644 --- a/libvirt.changes +++ b/libvirt.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Oct 10 10:48:19 MDT 2008 - jfehlig@novell.com + +- Added upstream patches providing additional LXC support + bnc#433881 + ------------------------------------------------------------------- Mon Oct 6 15:36:17 MDT 2008 - jfehlig@novell.com diff --git a/libvirt.spec b/libvirt.spec index 4b21c53..e8ec52b 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -49,7 +49,7 @@ License: LGPL v2.1 or later Group: Development/Libraries/C and C++ AutoReqProv: yes Version: 0.4.6 -Release: 1 +Release: 2 Summary: A C toolkit to interract with the virtualization capabilities of Linux Requires: readline Requires: ncurses @@ -72,6 +72,11 @@ Patch2: fs-storage-driver.patch Patch3: snapshots.patch Patch4: vif-parsing.patch Patch5: xen-maxmem.patch +Patch6: cgroup.patch +Patch7: lxc_res_mem.patch +Patch8: cgshares.patch +Patch9: lxcsched.patch +Patch10: lxcvirsh.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -168,6 +173,11 @@ Authors: %patch3 -p1 %patch4 -p1 %patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 rm po/no.* %build @@ -300,6 +310,9 @@ rm -rf $RPM_BUILD_ROOT %{py_sitedir}/libvirtmod* %changelog +* Fri Oct 10 2008 jfehlig@novell.com +- Added upstream patches providing additional LXC support + bnc#433881 * Mon Oct 06 2008 jfehlig@novell.com - Use xend vs hypercall interface to change max mem setting bnc#431766 diff --git a/lxc_res_mem.patch b/lxc_res_mem.patch new file mode 100644 index 0000000..1bd457c --- /dev/null +++ b/lxc_res_mem.patch @@ -0,0 +1,198 @@ +# HG changeset patch +# User danms +# Date 1223052361 0 +# Node ID a28490b116b0430aa0d4f579bba57d52793312ed +# Parent 47378698026980b5734c81f9480b50c783dde68a +[r2008-10-03 16:46:01 by danms] Add cgroup manipulation and LXC driver + +diff -r 473786980269 -r a28490b116b0 src/Makefile.am +--- a/src/Makefile.am Thu Oct 02 15:04:11 2008 +0000 ++++ b/src/Makefile.am Fri Oct 03 16:46:01 2008 +0000 +@@ -90,13 +90,15 @@ + lxc_conf.c lxc_conf.h \ + lxc_container.c lxc_container.h \ + lxc_driver.c lxc_driver.h \ +- veth.c veth.h ++ veth.c veth.h \ ++ cgroup.c cgroup.h + + LXC_CONTROLLER_SOURCES = \ + lxc_conf.c lxc_conf.h \ + lxc_container.c lxc_container.h \ + lxc_controller.c \ +- veth.c veth.h ++ veth.c veth.h \ ++ cgroup.c cgroup.h + + OPENVZ_DRIVER_SOURCES = \ + openvz_conf.c openvz_conf.h \ +diff -r 473786980269 -r a28490b116b0 src/lxc_container.c +--- a/src/lxc_container.c Thu Oct 02 15:04:11 2008 +0000 ++++ b/src/lxc_container.c Fri Oct 03 16:46:01 2008 +0000 +@@ -320,12 +320,12 @@ + mode_t mode; + const char *path; + } devs[] = { +- { 1, 3, 0666, "/dev/null" }, +- { 1, 5, 0666, "/dev/zero" }, +- { 1, 7, 0666, "/dev/full" }, +- { 5, 1, 0600, "/dev/console" }, +- { 1, 8, 0666, "/dev/random" }, +- { 1, 9, 0666, "/dev/urandom" }, ++ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL, 0666, "/dev/null" }, ++ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO, 0666, "/dev/zero" }, ++ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL, 0666, "/dev/full" }, ++ { LXC_DEV_MAJ_TTY, LXC_DEV_MIN_CONSOLE, 0600, "/dev/console" }, ++ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM, 0666, "/dev/random" }, ++ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM, 0666, "/dev/urandom" }, + }; + + if (virFileMakePath("/dev") < 0 || +diff -r 473786980269 -r a28490b116b0 src/lxc_container.h +--- a/src/lxc_container.h Thu Oct 02 15:04:11 2008 +0000 ++++ b/src/lxc_container.h Fri Oct 03 16:46:01 2008 +0000 +@@ -30,6 +30,16 @@ + LXC_CONTAINER_FEATURE_NET = (1 << 0), + }; + ++#define LXC_DEV_MAJ_MEMORY 1 ++#define LXC_DEV_MIN_NULL 3 ++#define LXC_DEV_MIN_ZERO 5 ++#define LXC_DEV_MIN_FULL 7 ++#define LXC_DEV_MIN_RANDOM 8 ++#define LXC_DEV_MIN_URANDOM 9 ++ ++#define LXC_DEV_MAJ_TTY 5 ++#define LXC_DEV_MIN_CONSOLE 1 ++ + int lxcContainerSendContinue(int control); + + int lxcContainerStart(virDomainDefPtr def, +diff -r 473786980269 -r a28490b116b0 src/lxc_controller.c +--- a/src/lxc_controller.c Thu Oct 02 15:04:11 2008 +0000 ++++ b/src/lxc_controller.c Fri Oct 03 16:46:01 2008 +0000 +@@ -42,12 +42,82 @@ + #include "veth.h" + #include "memory.h" + #include "util.h" +- ++#include "cgroup.h" + + #define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__) + #define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg) + + int debugFlag = 0; ++ ++struct cgroup_device_policy { ++ char type; ++ int major; ++ int minor; ++}; ++ ++/** ++ * lxcSetContainerResources ++ * @def: pointer to virtual machine structure ++ * ++ * Creates a cgroup for the container, moves the task inside, ++ * and sets resource limits ++ * ++ * Returns 0 on success or -1 in case of error ++ */ ++static int lxcSetContainerResources(virDomainDefPtr def) ++{ ++ virCgroupPtr cgroup; ++ int rc = -1; ++ int i; ++ struct cgroup_device_policy devices[] = { ++ {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL}, ++ {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO}, ++ {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL}, ++ {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM}, ++ {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM}, ++ {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_CONSOLE}, ++ {0, 0, 0}}; ++ ++ if (virCgroupHaveSupport() != 0) ++ return 0; /* Not supported, so claim success */ ++ ++ rc = virCgroupForDomain(def, "lxc", &cgroup); ++ if (rc != 0) { ++ lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, ++ _("Unable to create cgroup for %s\n"), def->name); ++ return rc; ++ } ++ ++ rc = virCgroupSetMemory(cgroup, def->maxmem); ++ if (rc != 0) ++ goto out; ++ ++ rc = virCgroupDenyAllDevices(cgroup); ++ if (rc != 0) ++ goto out; ++ ++ for (i = 0; devices[i].type != 0; i++) { ++ struct cgroup_device_policy *dev = &devices[i]; ++ rc = virCgroupAllowDevice(cgroup, ++ dev->type, ++ dev->major, ++ dev->minor); ++ if (rc != 0) ++ goto out; ++ } ++ ++ rc = virCgroupAddTask(cgroup, getpid()); ++out: ++ if (rc != 0) { ++ lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, ++ _("Failed to set lxc resources: %s\n"), strerror(-rc)); ++ virCgroupRemove(cgroup); ++ } ++ ++ virCgroupFree(&cgroup); ++ ++ return rc; ++} + + static char*lxcMonitorPath(virDomainDefPtr def) + { +@@ -394,6 +464,9 @@ + if (lxcControllerMoveInterfaces(nveths, veths, container) < 0) + goto cleanup; + ++ if (lxcSetContainerResources(def) < 0) ++ goto cleanup; ++ + if (lxcContainerSendContinue(control[0]) < 0) + goto cleanup; + +diff -r 473786980269 -r a28490b116b0 src/lxc_driver.c +--- a/src/lxc_driver.c Thu Oct 02 15:04:11 2008 +0000 ++++ b/src/lxc_driver.c Fri Oct 03 16:46:01 2008 +0000 +@@ -43,6 +43,7 @@ + #include "bridge.h" + #include "veth.h" + #include "event.h" ++#include "cgroup.h" + + + /* debug macros */ +@@ -376,6 +377,7 @@ + int waitRc; + int childStatus = -1; + virDomainNetDefPtr net; ++ virCgroupPtr cgroup; + + while (((waitRc = waitpid(vm->pid, &childStatus, 0)) == -1) && + errno == EINTR) +@@ -408,6 +410,11 @@ + for (net = vm->def->nets; net; net = net->next) { + vethInterfaceUpOrDown(net->ifname, 0); + vethDelete(net->ifname); ++ } ++ ++ if (virCgroupForDomain(vm->def, "lxc", &cgroup) == 0) { ++ virCgroupRemove(cgroup); ++ virCgroupFree(&cgroup); + } + + return rc; diff --git a/lxcsched.patch b/lxcsched.patch new file mode 100644 index 0000000..150428b --- /dev/null +++ b/lxcsched.patch @@ -0,0 +1,130 @@ +Add scheduling parameter support for LXC domains + +Index: libvirt-0.4.6/src/lxc_driver.c +=================================================================== +--- libvirt-0.4.6.orig/src/lxc_driver.c ++++ libvirt-0.4.6/src/lxc_driver.c +@@ -35,6 +35,7 @@ + #include + #include + ++#include "internal.h" + #include "lxc_conf.h" + #include "lxc_container.h" + #include "lxc_driver.h" +@@ -1149,6 +1150,94 @@ static int lxcVersion(virConnectPtr conn + return 0; + } + ++static char *lxcGetSchedulerType(virDomainPtr domain, int *nparams) ++{ ++ if (nparams) ++ *nparams = 1; ++ ++ return strdup("posix"); ++} ++ ++static int lxcSetSchedulerParameters(virDomainPtr _domain, ++ virSchedParameterPtr params, ++ int nparams) ++{ ++ int i; ++ int rc; ++ virCgroupPtr group; ++ virDomainObjPtr domain; ++ ++ if (virCgroupHaveSupport() != 0) ++ return 0; ++ ++ domain = virDomainFindByUUID(lxc_driver->domains, _domain->uuid); ++ if (domain == NULL) { ++ lxcError(NULL, _domain, VIR_ERR_INTERNAL_ERROR, ++ _("No such domain %s"), _domain->uuid); ++ return -EINVAL; ++ } ++ ++ rc = virCgroupForDomain(domain->def, "lxc", &group); ++ if (rc != 0) ++ return rc; ++ ++ for (i = 0; i < nparams; i++) { ++ virSchedParameterPtr param = ¶ms[i]; ++ ++ if (STREQ(param->field, "cpu_shares")) { ++ rc = virCgroupSetCpuShares(group, params[i].value.ui); ++ } else { ++ lxcError(NULL, _domain, VIR_ERR_INVALID_ARG, ++ _("Invalid parameter `%s'"), param->field); ++ rc = -ENOENT; ++ goto out; ++ } ++ } ++ ++ rc = 0; ++out: ++ virCgroupFree(&group); ++ ++ return rc; ++} ++ ++static int lxcGetSchedulerParameters(virDomainPtr _domain, ++ virSchedParameterPtr params, ++ int *nparams) ++{ ++ int rc = 0; ++ virCgroupPtr group; ++ virDomainObjPtr domain; ++ ++ if (virCgroupHaveSupport() != 0) ++ return 0; ++ ++ if ((*nparams) != 1) { ++ lxcError(NULL, _domain, VIR_ERR_INVALID_ARG, ++ _("Invalid parameter count")); ++ return -1; ++ } ++ ++ domain = virDomainFindByUUID(lxc_driver->domains, _domain->uuid); ++ if (domain == NULL) { ++ lxcError(NULL, _domain, VIR_ERR_INTERNAL_ERROR, ++ _("No such domain %s"), _domain->uuid); ++ return -ENOENT; ++ } ++ ++ rc = virCgroupForDomain(domain->def, "lxc", &group); ++ if (rc != 0) ++ return rc; ++ ++ rc = virCgroupGetCpuShares(group, (unsigned long *)¶ms[0].value.ul); ++ strncpy(params[0].field, "cpu_shares", sizeof(params[0].field)); ++ params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG; ++ ++ virCgroupFree(&group); ++ ++ return rc; ++} ++ + /* Function Tables */ + static virDriver lxcDriver = { + VIR_DRV_LXC, /* the number virDrvNo */ +@@ -1198,9 +1287,9 @@ static virDriver lxcDriver = { + NULL, /* domainDetachDevice */ + NULL, /* domainGetAutostart */ + NULL, /* domainSetAutostart */ +- NULL, /* domainGetSchedulerType */ +- NULL, /* domainGetSchedulerParameters */ +- NULL, /* domainSetSchedulerParameters */ ++ lxcGetSchedulerType, /* domainGetSchedulerType */ ++ lxcGetSchedulerParameters, /* domainGetSchedulerParameters */ ++ lxcSetSchedulerParameters, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePrepare */ + NULL, /* domainMigratePerform */ + NULL, /* domainMigrateFinish */ +@@ -1217,7 +1306,6 @@ static virDriver lxcDriver = { + NULL, /* domainListSnapshots */ + }; + +- + static virStateDriver lxcStateDriver = { + lxcStartup, + lxcShutdown, diff --git a/lxcvirsh.patch b/lxcvirsh.patch new file mode 100644 index 0000000..df0ceb2 --- /dev/null +++ b/lxcvirsh.patch @@ -0,0 +1,123 @@ +Add generic parameter=value support for virsh's schedinfo command + +This patch maintains the two Xen-specific --weight and --cap options, +but adds support for setting arbitrary parameters by specifying them in +param=value syntax. + +Changes to the virsh manual are included. + +Changes: + - Replace use of 'a' conversion modifier with pre-alloc + +Index: libvirt-0.4.6/docs/virsh.pod +=================================================================== +--- libvirt-0.4.6.orig/docs/virsh.pod ++++ libvirt-0.4.6/docs/virsh.pod +@@ -322,12 +322,14 @@ This is roughly equivalent to doing a hi + with all the same limitations. Open network connections may be + severed upon restore, as TCP timeouts may have expired. + ++=item B optional I<--set> B I ++ + =item B optional I<--weight> B optional I<--cap> B I + +-Allows to show (and set) the domain scheduler parameters. This is currently +-only defined for XEN_CREDIT scheduler, and the optional weight and cap +-arguments allows to set the associated parameters in that scheduler if +-provided. ++Allows to show (and set) the domain scheduler parameters. ++ ++B: The weight and cap parameters are defined only for the ++XEN_CREDIT scheduler and are now I. + + =item B I B + +Index: libvirt-0.4.6/src/virsh.c +=================================================================== +--- libvirt-0.4.6.orig/src/virsh.c ++++ libvirt-0.4.6/src/virsh.c +@@ -1295,6 +1295,7 @@ static const vshCmdInfo info_schedinfo[] + + static const vshCmdOptDef opts_schedinfo[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, ++ {"set", VSH_OT_STRING, VSH_OFLAG_NONE, gettext_noop("parameter=value")}, + {"weight", VSH_OT_INT, VSH_OFLAG_NONE, gettext_noop("weight for XEN_CREDIT")}, + {"cap", VSH_OT_INT, VSH_OFLAG_NONE, gettext_noop("cap for XEN_CREDIT")}, + {NULL, 0, 0, NULL} +@@ -1304,6 +1305,9 @@ static int + cmdSchedinfo(vshControl *ctl, const vshCmd *cmd) + { + char *schedulertype; ++ char *set; ++ char *param_name = NULL; ++ long long int param_value = 0; + virDomainPtr dom; + virSchedParameterPtr params = NULL; + int i, ret; +@@ -1311,6 +1315,7 @@ cmdSchedinfo(vshControl *ctl, const vshC + int nr_inputparams = 0; + int inputparams = 0; + int weightfound = 0; ++ int setfound = 0; + int weight = 0; + int capfound = 0; + int cap = 0; +@@ -1324,7 +1329,7 @@ cmdSchedinfo(vshControl *ctl, const vshC + if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL))) + return FALSE; + +- /* Currently supports Xen Credit only */ ++ /* Deprecated Xen-only options */ + if(vshCommandOptBool(cmd, "weight")) { + weight = vshCommandOptInt(cmd, "weight", &weightfound); + if (!weightfound) { +@@ -1345,6 +1350,25 @@ cmdSchedinfo(vshControl *ctl, const vshC + } + } + ++ if(vshCommandOptBool(cmd, "set")) { ++ set = vshCommandOptString(cmd, "set", &setfound); ++ if (!setfound) { ++ vshError(ctl, FALSE, "%s", _("Error getting param")); ++ goto cleanup; ++ } ++ ++ param_name = vshMalloc(ctl, strlen(set) + 1); ++ if (param_name == NULL) ++ goto cleanup; ++ ++ if (sscanf(set, "%[^=]=%i", param_name, ¶m_value) != 2) { ++ vshError(ctl, FALSE, "%s", _("Invalid value of param")); ++ goto cleanup; ++ } ++ ++ nr_inputparams++; ++ } ++ + params = vshMalloc(ctl, sizeof (virSchedParameter) * nr_inputparams); + if (params == NULL) { + goto cleanup; +@@ -1363,7 +1387,14 @@ cmdSchedinfo(vshControl *ctl, const vshC + params[inputparams].value.ui = cap; + inputparams++; + } +- /* End Currently supports Xen Credit only */ ++ /* End Deprecated Xen-only options */ ++ ++ if (setfound) { ++ strncpy(params[inputparams].field,param_name,sizeof(params[0].field)); ++ params[inputparams].type = VIR_DOMAIN_SCHED_FIELD_LLONG; ++ params[inputparams].value.l = param_value; ++ inputparams++; ++ } + + assert (inputparams == nr_inputparams); + +@@ -1430,6 +1461,7 @@ cmdSchedinfo(vshControl *ctl, const vshC + } + cleanup: + free(params); ++ free(param_name); + virDomainFree(dom); + return ret_val; + }