set_cgroup_item takes a pointer to a running container, a cgroup subsystem name, and a char *value and it mimicks 'lxc-cgroup -n containername subsys value' get_cgroup_item takes a pointer to a running container, a a cgroup subsystem name, a destination value * and the length of the value being sent in, and returns the length of what was read from the cgroup file. If a 0 len is passed in, then the length of the file is returned. So you can do
len = c->get_cgroup_item(c, "devices.list", NULL, 0); v = malloc(len+1); ret = c->get_cgroup_item(c, "devices.list", v, len); to read the whole file. This patch also disables the lxc-init part of the startone test, which was failing because lxc-init has been moved due to multiarch issues. The test is salvagable, but saving it was beyond this effort. Signed-off-by: Serge Hallyn <serge.hal...@ubuntu.com> --- src/lxc/cgroup.c | 20 ++++++++++++++++++- src/lxc/lxccontainer.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxccontainer.h | 9 +++++++++ src/tests/startone.c | 47 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 1 deletion(-) diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c index 532d638..b6c948b 100644 --- a/src/lxc/cgroup.c +++ b/src/lxc/cgroup.c @@ -789,6 +789,13 @@ out: return ret; } +/* + * If you pass in NULL value or 0 len, then you are asking for the size + * of the file. Note that we can't get the file size quickly through stat + * or lseek. Therefore if you pass in len > 0 but less than the file size, + * your only indication will be that the return value will be equal to the + * passed-in ret. We will not return the actual full file size. + */ int lxc_cgroup_get(const char *name, const char *filename, char *value, size_t len) { @@ -813,7 +820,18 @@ int lxc_cgroup_get(const char *name, const char *filename, return -1; } - ret = read(fd, value, len); + if (!len || !value) { + char buf[100]; + int count = 0; + while ((ret = read(fd, buf, 100)) > 0) + count += ret; + if (ret >= 0) + ret = count; + } else { + memset(value, 0, len); + ret = read(fd, value, len); + } + if (ret < 0) ERROR("read %s : %s", path, strerror(errno)); diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index d25b848..1345ab5 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -163,6 +163,13 @@ static const char *lxcapi_state(struct lxc_container *c) return ret; } +static bool is_stopped_nolock(struct lxc_container *c) +{ + lxc_state_t s; + s = lxc_getstate(c->name); + return (s == STOPPED); +} + static bool lxcapi_is_running(struct lxc_container *c) { const char *s; @@ -850,6 +857,49 @@ static char *lxcapi_config_file_name(struct lxc_container *c) return strdup(c->configfile); } +static bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value) +{ + int ret; + bool b = false; + + if (!c) + return false; + + if (lxclock(c->privlock, 0)) + return false; + + if (is_stopped_nolock(c)) + goto err; + + ret = lxc_cgroup_set(c->name, subsys, value); + if (!ret) + b = true; +err: + lxcunlock(c->privlock); + return b; +} + +static int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen) +{ + int ret = -1; + + if (!c || !c->lxc_conf) + return -1; + + if (lxclock(c->privlock, 0)) + return -1; + + if (is_stopped_nolock(c)) + goto out; + + ret = lxc_cgroup_get(c->name, subsys, retv, inlen); + +out: + lxcunlock(c->privlock); + return ret; +} + + struct lxc_container *lxc_container_new(const char *name) { struct lxc_container *c; @@ -920,6 +970,8 @@ struct lxc_container *lxc_container_new(const char *name) c->shutdown = lxcapi_shutdown; c->clear_config_item = lxcapi_clear_config_item; c->get_config_item = lxcapi_get_config_item; + c->get_cgroup_item = lxcapi_get_cgroup_item; + c->set_cgroup_item = lxcapi_set_cgroup_item; /* we'll allow the caller to update these later */ if (lxc_log_init(NULL, NULL, "lxc_container", 0)) { diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 9c9296c..a6fdb2b 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -48,6 +48,15 @@ struct lxc_container { * the length which was our would be printed. */ int (*get_config_item)(struct lxc_container *c, const char *key, char *retv, int inlen); int (*get_keys)(struct lxc_container *c, const char *key, char *retv, int inlen); + /* + * get_cgroup_item returns the number of bytes read, or an error (<0). + * If retv NULL or inlen 0 is passed in, then the length of the cgroup + * file will be returned. * Otherwise it will return the # of bytes read. + * If inlen is less than the number of bytes available, then the returned + * value will be inlen, not the full available size of the file. + */ + int (*get_cgroup_item)(struct lxc_container *c, const char *subsys, char *retv, int inlen); + bool (*set_cgroup_item)(struct lxc_container *c, const char *subsys, const char *value); #if 0 bool (*commit_cgroups)(struct lxc_container *c); diff --git a/src/tests/startone.c b/src/tests/startone.c index 81a6bfb..325942e 100644 --- a/src/tests/startone.c +++ b/src/tests/startone.c @@ -98,6 +98,8 @@ int main(int argc, char *argv[]) int ret = 0; const char *s; bool b; + char buf[201]; + int len; ret = 1; /* test a real container */ @@ -125,6 +127,19 @@ int main(int argc, char *argv[]) goto out; } + len = c->get_cgroup_item(c, "cpuset.cpus", buf, 200); + if (len >= 0) { + fprintf(stderr, "%d: %s not running but had cgroup settings\n", __LINE__, MYNAME); + goto out; + } + + sprintf(buf, "0"); + b = c->set_cgroup_item(c, "cpuset.cpus", buf); + if (b) { + fprintf(stderr, "%d: %s not running but coudl set cgroup settings\n", __LINE__, MYNAME); + goto out; + } + s = c->state(c); if (!s || strcmp(s, "STOPPED")) { fprintf(stderr, "%d: %s is in state %s, not in STOPPED.\n", __LINE__, c->name, s ? s : "undefined"); @@ -172,12 +187,43 @@ int main(int argc, char *argv[]) goto out; } + len = c->get_cgroup_item(c, "cpuset.cpus", buf, 0); + if (len <= 0) { + fprintf(stderr, "%d: not able to get length of cpuset.cpus (ret %d)\n", __LINE__, len); + goto out; + } + + len = c->get_cgroup_item(c, "cpuset.cpus", buf, 200); + if (len <= 0 || strcmp(buf, "0\n")) { + fprintf(stderr, "%d: not able to get cpuset.cpus (len %d buf %s)\n", __LINE__, len, buf); + goto out; + } + + sprintf(buf, "FROZEN"); + b = c->set_cgroup_item(c, "freezer.state", buf); + if (!b) { + fprintf(stderr, "%d: not able to set freezer.state.\n", __LINE__); + goto out; + } + + sprintf(buf, "XXX"); + len = c->get_cgroup_item(c, "freezer.state", buf, 200); + if (len <= 0 || (strcmp(buf, "FREEZING\n") && strcmp(buf, "FROZEN\n"))) { + fprintf(stderr, "%d: not able to get freezer.state (len %d buf %s)\n", __LINE__, len, buf); + goto out; + } + + c->set_cgroup_item(c, "freezer.state", "THAWED"); + printf("hit return to finish"); ret = scanf("%c", &mychar); if (ret < 0) goto out; c->stop(c); + /* feh - multilib has moved the lxc-init crap */ + goto ok; + ret = system("mkdir -p " LXCPATH "/lxctest1/rootfs//usr/local/libexec/lxc"); if (!ret) ret = system("mkdir -p " LXCPATH "/lxctest1/rootfs/usr/lib/lxc/"); @@ -204,6 +250,7 @@ int main(int argc, char *argv[]) } // auto-check result? ('bobo' is printed on stdout) +ok: fprintf(stderr, "all lxc_container tests passed for %s\n", c->name); ret = 0; -- 1.7.10.4 ------------------------------------------------------------------------------ LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial Remotely access PCs and mobile devices and provide instant support Improve your efficiency, and focus on delivering more value-add services Discover what IT Professionals Know. Rescue delivers http://p.sf.net/sfu/logmein_12329d2d _______________________________________________ Lxc-devel mailing list Lxc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-devel