From 4165a2fa18581291fc84ffd2832d84ebe6122b5f Mon Sep 17 00:00:00 2001 From: Faiyaz Ahmed Date: Mon, 25 Jun 2007 18:33:01 +0000 Subject: [PATCH] Merge from head. --- lib/planetlab.c | 252 +++++++++++++++++++++++++++++++++++++-- lib/planetlab.h | 37 +++++- python/vserver.py | 154 +++++++++++++++++------- python/vserverimpl.c | 278 +++++++++++++++++++++++++++---------------- src/vsh.c | 148 ++++------------------- util-vserver.spec | 6 +- util-vserver.spec.in | 6 +- 7 files changed, 597 insertions(+), 284 deletions(-) diff --git a/lib/planetlab.c b/lib/planetlab.c index 4d85fb9..adf6083 100644 --- a/lib/planetlab.c +++ b/lib/planetlab.c @@ -31,33 +31,34 @@ POSSIBILITY OF SUCH DAMAGE. */ +#include +#include +#include #include #include -#include +#include #include +#include #include #include "config.h" -#include "planetlab.h" #include "sched_cmd.h" #include "virtual.h" #include "vserver.h" +#include "planetlab.h" static int -create_context(xid_t ctx, uint32_t flags, uint64_t bcaps) +create_context(xid_t ctx, uint64_t bcaps, struct sliver_resources *slr) { struct vc_ctx_caps vc_caps; /* * Create context info - this sets the STATE_SETUP and STATE_INIT flags. - * Don't ever clear the STATE_INIT flag, that makes us the init task. - * - * XXX - the kernel code allows initial flags to be passed as an arg. */ if (vc_ctx_create(ctx) == VC_NOCTX) return -1; - /* set capabilities - these don't take effect until SETUP flag is unset */ + /* Set capabilities - these don't take effect until SETUP flag is unset */ vc_caps.bcaps = bcaps; vc_caps.bmask = ~0ULL; /* currently unused */ vc_caps.ccaps = 0; /* don't want any of these */ @@ -65,8 +66,7 @@ create_context(xid_t ctx, uint32_t flags, uint64_t bcaps) if (vc_set_ccaps(ctx, &vc_caps)) return -1; - /* set default scheduling parameters */ - pl_setsched(ctx, 1, 0); + pl_set_limits(ctx, slr); return 0; } @@ -77,6 +77,8 @@ pl_setup_done(xid_t ctx) struct vc_ctx_flags vc_flags; /* unset SETUP flag - this allows other processes to migrate */ + + /* Don't clear the STATE_INIT flag, as that would make us the init task. */ vc_flags.mask = VC_VXF_STATE_SETUP; vc_flags.flagword = 0; if (vc_set_cflags(ctx, &vc_flags)) @@ -88,7 +90,7 @@ pl_setup_done(xid_t ctx) #define RETRY_LIMIT 10 int -pl_chcontext(xid_t ctx, uint32_t flags, uint64_t bcaps) +pl_chcontext(xid_t ctx, uint64_t bcaps, struct sliver_resources *slr) { int retry_count = 0; @@ -102,7 +104,7 @@ pl_chcontext(xid_t ctx, uint32_t flags, uint64_t bcaps) return -1; /* context doesn't exist - create it */ - if (create_context(ctx, flags, bcaps)) + if (create_context(ctx, bcaps,slr)) { if (errno == EEXIST) /* another process beat us in a race */ @@ -183,3 +185,231 @@ pl_setsched(xid_t ctx, uint32_t cpu_share, uint32_t cpu_sched_flags) return 0; } + +struct pl_resources { + char *name; + unsigned long long *limit; +}; + +#define WHITESPACE(buffer,index,len) \ + while(isspace((int)buffer[index])) \ + if (index < len) index++; else goto out; + +#define VSERVERCONF "/etc/vservers/" +void +pl_get_limits(char *context, struct sliver_resources *slr) +{ + FILE *fb; + size_t len = strlen(VSERVERCONF) + strlen(context) + strlen(".conf") + NULLBYTE_SIZE; + char *conf = (char *)malloc(len); + struct pl_resources *r; + struct pl_resources sliver_list[] = { + {"CPULIMIT", &slr->vs_cpu}, + {"CPUSHARE", &slr->vs_cpu}, + {"CPUGUARANTEED", &slr->vs_cpuguaranteed}, + + {"TASKLIMIT", &slr->vs_nproc.hard}, /* backwards compatible */ + {"VS_NPROC_HARD", &slr->vs_nproc.hard}, + {"VS_NPROC_SOFT", &slr->vs_nproc.soft}, + {"VS_NPROC_MINIMUM", &slr->vs_nproc.min}, + + {"MEMLIMIT", &slr->vs_rss.hard}, /* backwards compatible */ + {"VS_RSS_HARD", &slr->vs_rss.hard}, + {"VS_RSS_SOFT", &slr->vs_rss.soft}, + {"VS_RSS_MINIMUM", &slr->vs_rss.min}, + + {"VS_AS_HARD", &slr->vs_as.hard}, + {"VS_AS_SOFT", &slr->vs_as.soft}, + {"VS_AS_MINIMUM", &slr->vs_as.min}, + + {"VS_OPENFD_HARD", &slr->vs_openfd.hard}, + {"VS_OPENFD_SOFT", &slr->vs_openfd.soft}, + {"VS_OPENFD_MINIMUM", &slr->vs_openfd.min}, + + {"VS_WHITELISTED", &slr->vs_whitelisted}, + {0,0} + }; + + sprintf(conf, "%s%s.conf", VSERVERCONF, context); + + slr->vs_cpu = VC_LIM_KEEP; + slr->vs_cpuguaranteed = 0; + + slr->vs_rss.hard = VC_LIM_KEEP; + slr->vs_rss.soft = VC_LIM_KEEP; + slr->vs_rss.min = VC_LIM_KEEP; + + slr->vs_as.hard = VC_LIM_KEEP; + slr->vs_as.soft = VC_LIM_KEEP; + slr->vs_as.min = VC_LIM_KEEP; + + + slr->vs_nproc.hard = VC_LIM_KEEP; + slr->vs_nproc.soft = VC_LIM_KEEP; + slr->vs_nproc.min = VC_LIM_KEEP; + + slr->vs_openfd.hard = VC_LIM_KEEP; + slr->vs_openfd.soft = VC_LIM_KEEP; + slr->vs_openfd.min = VC_LIM_KEEP; + + slr->vs_whitelisted = 1; + + /* open the conf file for reading */ + fb = fopen(conf,"r"); + if (fb != NULL) { + size_t index; + char *buffer = malloc(1000); + char *p; + + /* the conf file exist */ + while((p=fgets(buffer,1000-1,fb))!=NULL) { + index = 0; + len = strnlen(buffer,1000); + WHITESPACE(buffer,index,len); + if (buffer[index] == '#') + continue; + + for (r=&sliver_list[0]; r->name; r++) + if ((p=strstr(&buffer[index],r->name))!=NULL) { + /* adjust index into buffer */ + index+= (p-&buffer[index])+strlen(r->name); + + /* skip over whitespace */ + WHITESPACE(buffer,index,len); + + /* expecting to see = sign */ + if (buffer[index++]!='=') goto out; + + /* skip over whitespace */ + WHITESPACE(buffer,index,len); + + /* expecting to see a digit for number */ + if (!isdigit((int)buffer[index])) goto out; + + *r->limit = atoi(&buffer[index]); + if (0) /* for debugging only */ + fprintf(stderr,"pl_get_limits found %s=%ld\n", + r->name,*r->limit); + break; + } + } + out: + fclose(fb); + free(buffer); + } else { + fprintf(stderr,"cannot open %s\n",conf); + } + free(conf); +} + +int +adjust_lim(struct vc_rlimit *vcr, struct rlimit *lim) +{ + int adjusted = 0; + if (vcr->min != VC_LIM_KEEP) { + if (vcr->min > lim->rlim_cur) { + lim->rlim_cur = vcr->min; + adjusted = 1; + } + if (vcr->min > lim->rlim_max) { + lim->rlim_max = vcr->min; + adjusted = 1; + } + } + + if (vcr->soft != VC_LIM_KEEP) { + switch (vcr->min != VC_LIM_KEEP) { + case 1: + if (vcr->soft < vcr->min) + break; + case 0: + lim->rlim_cur = vcr->soft; + adjusted = 1; + } + } + + if (vcr->hard != VC_LIM_KEEP) { + switch (vcr->min != VC_LIM_KEEP) { + case 1: + if (vcr->hard < vcr->min) + break; + case 0: + lim->rlim_cur = vcr->hard; + adjusted = 1; + } + } + return adjusted; +} + + +void +pl_set_limits(xid_t ctx, struct sliver_resources *slr) +{ + struct rlimit lim; /* getrlimit values */ + unsigned long long vs_cpu; + uint32_t cpu_sched_flags; + + if (slr != 0) { + /* set memory limits */ + getrlimit(RLIMIT_RSS,&lim); + if (adjust_lim(&slr->vs_rss, &lim)) { + setrlimit(RLIMIT_RSS, &lim); + if (vc_set_rlimit(ctx, RLIMIT_RSS, &slr->vs_rss)) + { + PERROR("pl_setrlimit(%u, RLIMIT_RSS)", ctx); + exit(1); + } + } + + /* set address space limits */ + getrlimit(RLIMIT_AS,&lim); + if (adjust_lim(&slr->vs_as, &lim)) { + setrlimit(RLIMIT_AS, &lim); + if (vc_set_rlimit(ctx, RLIMIT_AS, &slr->vs_as)) + { + PERROR("pl_setrlimit(%u, RLIMIT_AS)", ctx); + exit(1); + } + } + /* set nrpoc limit */ + getrlimit(RLIMIT_NPROC,&lim); + if (adjust_lim(&slr->vs_nproc, &lim)) { + setrlimit(RLIMIT_NPROC, &lim); + if (vc_set_rlimit(ctx, RLIMIT_NPROC, &slr->vs_nproc)) + { + PERROR("pl_setrlimit(%u, RLIMIT_NPROC)", ctx); + exit(1); + } + } + + /* set openfd limit */ + getrlimit(RLIMIT_NOFILE,&lim); + if (adjust_lim(&slr->vs_openfd, &lim)) { + setrlimit(RLIMIT_NOFILE, &lim); + if (vc_set_rlimit(ctx, RLIMIT_NOFILE, &slr->vs_openfd)) + { + PERROR("pl_setrlimit(%u, RLIMIT_NOFILE)", ctx); + exit(1); + } +#ifndef VLIMIT_OPENFD +#warning VLIMIT_OPENFD should be defined from standard header +#define VLIMIT_OPENFD 17 +#endif + if (vc_set_rlimit(ctx, VLIMIT_OPENFD, &slr->vs_openfd)) + { + PERROR("pl_setrlimit(%u, VLIMIT_OPENFD)", ctx); + exit(1); + } + } + vs_cpu = slr->vs_cpu; + cpu_sched_flags = slr->vs_cpuguaranteed & VS_SCHED_CPU_GUARANTEED; + } else { + vs_cpu = 1; + cpu_sched_flags = 0; + } + + if (pl_setsched(ctx, vs_cpu, cpu_sched_flags) < 0) { + PERROR("pl_setsched(&u)", ctx); + exit(1); + } +} diff --git a/lib/planetlab.h b/lib/planetlab.h index e4d6ae4..739bac6 100644 --- a/lib/planetlab.h +++ b/lib/planetlab.h @@ -36,8 +36,20 @@ POSSIBILITY OF SUCH DAMAGE. #define VC_VXF_SCHED_FLAGS (VC_VXF_SCHED_HARD | VC_VXF_SCHED_SHARE) +struct sliver_resources { + unsigned long long vs_cpu; + unsigned long long vs_cpuguaranteed; + struct vc_rlimit vs_rss; + struct vc_rlimit vs_as; + struct vc_rlimit vs_nproc; + struct vc_rlimit vs_openfd; + unsigned long long vs_whitelisted; +}; + +int adjust_lim(struct vc_rlimit *vcr, struct rlimit *lim); + int -pl_chcontext(xid_t ctx, uint32_t flags, uint64_t bcaps); +pl_chcontext(xid_t ctx, uint64_t bcaps, struct sliver_resources *slr); int pl_setup_done(xid_t ctx); @@ -48,4 +60,27 @@ pl_setsched(xid_t ctx, uint32_t cpu_share, uint32_t cpu_sched_flags); /* scheduler flags */ #define VS_SCHED_CPU_GUARANTEED 1 +/* Null byte made explicit */ +#define NULLBYTE_SIZE 1 + +void pl_get_limits(char *, struct sliver_resources *); +void pl_set_limits(xid_t, struct sliver_resources *); + +static int +_PERROR(const char *format, char *file, int line, int _errno, ...) +{ + va_list ap; + + va_start(ap, _errno); + fprintf(stderr, "%s:%d: ", file, line); + vfprintf(stderr, format, ap); + if (_errno) + fprintf(stderr, ": %s (%d)", strerror(_errno), _errno); + fputs("\n", stderr); + fflush(stderr); + + return _errno; +} + +#define PERROR(format, args...) _PERROR(format, __FILE__, __LINE__, errno, ## args) #endif diff --git a/python/vserver.py b/python/vserver.py index fd1431d..cf0b84e 100644 --- a/python/vserver.py +++ b/python/vserver.py @@ -18,8 +18,21 @@ import cpulimit, bwlimit from vserverimpl import VS_SCHED_CPU_GUARANTEED as SCHED_CPU_GUARANTEED from vserverimpl import DLIMIT_INF - - +from vserverimpl import VC_LIM_KEEP + +from vserverimpl import RLIMIT_CPU +from vserverimpl import RLIMIT_RSS +from vserverimpl import RLIMIT_NPROC +from vserverimpl import RLIMIT_NOFILE +from vserverimpl import RLIMIT_MEMLOCK +from vserverimpl import RLIMIT_AS +from vserverimpl import RLIMIT_LOCKS +from vserverimpl import RLIMIT_SIGPENDING +from vserverimpl import RLIMIT_MSGQUEUE +from vserverimpl import VLIMIT_NSOCK +from vserverimpl import VLIMIT_OPENFD +from vserverimpl import VLIMIT_ANON +from vserverimpl import VLIMIT_SHMEM # # these are the flags taken from the kernel linux/vserver/legacy.h @@ -33,12 +46,23 @@ FLAGS_HIDEINFO = 32 FLAGS_ULIMIT = 64 FLAGS_NAMESPACE = 128 - +RLIMITS = {"CPU": RLIMIT_CPU, + "RSS": RLIMIT_RSS, + "NPROC": RLIMIT_NPROC, + "NOFILE": RLIMIT_NOFILE, + "MEMLOCK": RLIMIT_MEMLOCK, + "AS": RLIMIT_AS, + "LOCKS": RLIMIT_LOCKS, + "SIGPENDING": RLIMIT_SIGPENDING, + "MSGQUEUE": RLIMIT_MSGQUEUE, + "NSOCK": VLIMIT_NSOCK, + "OPENFD": VLIMIT_OPENFD, + "ANON": VLIMIT_ANON, + "SHMEM": VLIMIT_SHMEM} class NoSuchVServer(Exception): pass - class VServer: INITSCRIPTS = [('/etc/rc.vinit', 'start'), @@ -47,6 +71,7 @@ class VServer: def __init__(self, name, vm_id = None, vm_running = False): self.name = name + self.rlimits_changed = False self.config_file = "/etc/vservers/%s.conf" % name self.dir = "%s/%s" % (vserverimpl.VSERVER_BASEDIR, name) if not (os.path.isdir(self.dir) and @@ -65,6 +90,63 @@ class VServer: self.ctx = vm_id self.vm_running = vm_running + def have_limits_changed(self): + return self.rlimits_changed + + def set_rlimit_limit(self,type,hard,soft,minimum): + """Generic set resource limit function for vserver""" + global RLIMITS + changed = False + try: + old_hard, old_soft, old_minimum = self.get_rlimit_limit(type) + if old_hard != VC_LIM_KEEP and old_hard <> hard: changed = True + if old_soft != VC_LIM_KEEP and old_soft <> soft: changed = True + if old_minimum != VC_LIM_KEEP and old_minimum <> minimum: changed = True + self.rlimits_changed = self.rlimits_changed or changed + except OSError, e: + if self.is_running(): print "Unexpected error with getrlimit for running context %d" % self.ctx + + resource_type = RLIMITS[type] + try: + ret = vserverimpl.setrlimit(self.ctx,resource_type,hard,soft,minimum) + except OSError, e: + if self.is_running(): print "Unexpected error with setrlimit for running context %d" % self.ctx + + def set_rlimit_config(self,type,hard,soft,minimum): + """Generic set resource limit function for vserver""" + resources = {} + if hard <> VC_LIM_KEEP: + resources["VS_%s_HARD"%type] = hard + if soft <> VC_LIM_KEEP: + resources["VS_%s_SOFT"%type] = soft + if minimum <> VC_LIM_KEEP: + resources["VS_%s_MINIMUM"%type] = minimum + if len(resources)>0: + self.update_resources(resources) + self.set_rlimit_limit(type,hard,soft,minimum) + + def get_rlimit_limit(self,type): + """Generic get resource configuration function for vserver""" + global RLIMITS + resource_type = RLIMITS[type] + try: + ret = vserverimpl.getrlimit(self.ctx,resource_type) + except OSError, e: + print "Unexpected error with getrlimit for context %d" % self.ctx + ret = self.get_rlimit_config(type) + return ret + + def get_rlimit_config(self,type): + """Generic get resource configuration function for vserver""" + hard = int(self.config.get("VS_%s_HARD"%type,VC_LIM_KEEP)) + soft = int(self.config.get("VS_%s_SOFT"%type,VC_LIM_KEEP)) + minimum = int(self.config.get("VS_%s_MINIMUM"%type,VC_LIM_KEEP)) + return (hard,soft,minimum) + + def set_WHITELISTED_config(self,whitelisted): + resources = {'VS_WHITELISTED': whitelisted} + self.update_resources(resources) + config_var_re = re.compile(r"^ *([A-Z_]+)=(.*)\n?$", re.MULTILINE) def __read_config_file(self, filename): @@ -133,10 +215,12 @@ class VServer: return result def set_disklimit(self, block_limit): - # block_limit is in kB if block_limit == 0: - vserverimpl.unsetdlimit(self.dir, self.ctx) + try: + vserverimpl.unsetdlimit(self.dir, self.ctx) + except OSError, e: + print "Unexpected error with unsetdlimit for context %d" % self.ctx return if self.vm_running: @@ -147,14 +231,25 @@ class VServer: block_usage = self.disk_blocks inode_usage = self.disk_inodes - vserverimpl.setdlimit(self.dir, - self.ctx, - block_usage, - block_limit, - inode_usage, - vserverimpl.DLIMIT_INF, # inode limit - 2) # %age reserved for root + try: + vserverimpl.setdlimit(self.dir, + self.ctx, + block_usage, + block_limit, + inode_usage, + vserverimpl.DLIMIT_INF, # inode limit + 2) # %age reserved for root + except OSError, e: + print "Unexpected error with setdlimit for context %d" % self.ctx + + + resources = {'VS_DISK_MAX': block_limit} + self.update_resources(resources) + + def is_running(self): + return vserverimpl.isrunning(self.ctx) + def get_disklimit(self): try: @@ -183,31 +278,13 @@ class VServer: self.set_sched(cpu_share, sched_flags) def set_sched(self, cpu_share, sched_flags = 0): - """ Update kernel CPU scheduling parameters for this context. """ - vserverimpl.setsched(self.ctx, cpu_share, sched_flags) def get_sched(self): # have no way of querying scheduler right now on a per vserver basis return (-1, False) - def set_memlimit(self, limit): - ret = vserverimpl.setrlimit(self.ctx,5,limit) - return ret - - def get_memlimit(self): - ret = vserverimpl.getrlimit(self.ctx,5) - return ret - - def set_tasklimit(self, limit): - ret = vserverimpl.setrlimit(self.ctx,6,limit) - return ret - - def get_tasklimit(self): - ret = vserverimpl.getrlimit(self.ctx,6) - return ret - def set_bwlimit(self, minrate = bwlimit.bwmin, maxrate = None, exempt_min = None, exempt_max = None, share = None, dev = "eth0"): @@ -258,8 +335,9 @@ class VServer: ([], filter_fn))[0] garbage += filter(os.path.isfile, map((LOCKDIR + "/").__add__, os.listdir(LOCKDIR))) - for f in garbage: - os.unlink(f) + if False: + for f in garbage: + os.unlink(f) # set the initial runlevel f = open(RUNDIR + "/utmp", "w") @@ -288,8 +366,8 @@ class VServer: self.__do_chcontext(state_file) def start(self, wait, runlevel = 3): - self.vm_running = True + self.rlimits_changed = False child_pid = os.fork() if child_pid == 0: @@ -317,14 +395,10 @@ class VServer: # execute each init script in turn # XXX - we don't support all scripts that vserver script does - cmd_pid = 0 - first_child = True - self.__do_chcontext(state_file) - for cmd in self.INITSCRIPTS + [None]: try: - # enter vserver context + # enter vserver context arg_subst = { 'runlevel': runlevel } cmd_args = [cmd[0]] + map(lambda x: x % arg_subst, cmd[1:]) @@ -363,9 +437,9 @@ class VServer: return size def stop(self, signal = signal.SIGKILL): - vserverimpl.killall(self.ctx, signal) self.vm_running = False + self.rlimits_changed = False diff --git a/python/vserverimpl.c b/python/vserverimpl.c index d5f018d..4afba2a 100644 --- a/python/vserverimpl.c +++ b/python/vserverimpl.c @@ -4,17 +4,17 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials provided +with the distribution. - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. +* Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived +from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -35,15 +35,23 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include +#include #include #include "config.h" #include "pathconfig.h" -#include "planetlab.h" #include "virtual.h" #include "vserver.h" +#include "planetlab.h" #include "vserver-internal.h" +/* I don't like needing to define __KERNEL__ -- mef */ +#define __KERNEL__ +#include "kernel/limit.h" +#undef __KERNEL__ + #define NONE ({ Py_INCREF(Py_None); Py_None; }) /* @@ -52,18 +60,17 @@ POSSIBILITY OF SUCH DAMAGE. static PyObject * vserver_chcontext(PyObject *self, PyObject *args) { - int result; + int ctx_is_new; xid_t ctx; - uint32_t flags = 0; - uint32_t bcaps = ~vc_get_insecurebcaps(); + uint_least64_t bcaps = ~vc_get_insecurebcaps(); - if (!PyArg_ParseTuple(args, "I|K", &ctx, &flags)) + if (!PyArg_ParseTuple(args, "I", &ctx)) return NULL; - if ((result = pl_chcontext(ctx, flags, bcaps)) < 0) + if ((ctx_is_new = pl_chcontext(ctx, bcaps, 0)) < 0) return PyErr_SetFromErrno(PyExc_OSError); - return PyBool_FromLong(result); + return PyBool_FromLong(ctx_is_new); } static PyObject * @@ -81,49 +88,95 @@ vserver_setup_done(PyObject *self, PyObject *args) } static PyObject * -vserver_set_rlimit(PyObject *self, PyObject *args) { - struct vc_rlimit limits; - xid_t xid; - int resource; - PyObject *ret; - - limits.min = VC_LIM_KEEP; - limits.soft = VC_LIM_KEEP; - limits.hard = VC_LIM_KEEP; - - if (!PyArg_ParseTuple(args, "IiL", &xid, &resource, &limits.hard)) - return NULL; - - if (vc_set_rlimit(xid, resource, &limits)) - ret = PyErr_SetFromErrno(PyExc_OSError); - else if (vc_get_rlimit(xid, resource, &limits)==-1) - ret = PyErr_SetFromErrno(PyExc_OSError); - else - ret = Py_BuildValue("L",limits.hard); - - return ret; +vserver_isrunning(PyObject *self, PyObject *args) +{ + xid_t ctx; + PyObject *ret; + struct stat statbuf; + char fname[64]; + + if (!PyArg_ParseTuple(args, "I", &ctx)) + return NULL; + + sprintf(fname,"/proc/virtual/%d", ctx); + + if(stat(&fname[0],&statbuf)==0) + ret = PyBool_FromLong(1); + else + ret = PyBool_FromLong(0); + + return ret; +} + +static PyObject * +__vserver_get_rlimit(xid_t xid, int resource) { + struct vc_rlimit limits; + PyObject *ret; + + errno = 0; + if (vc_get_rlimit(xid, resource, &limits)==-1) + ret = PyErr_SetFromErrno(PyExc_OSError); + else + ret = Py_BuildValue("LLL",limits.hard, limits.soft, limits.min); + + return ret; } static PyObject * vserver_get_rlimit(PyObject *self, PyObject *args) { - struct vc_rlimit limits; - xid_t xid; - int resource; - PyObject *ret; + xid_t xid; + int resource; + PyObject *ret; - limits.min = VC_LIM_KEEP; - limits.soft = VC_LIM_KEEP; - limits.hard = VC_LIM_KEEP; + if (!PyArg_ParseTuple(args, "Ii", &xid, &resource)) + ret = NULL; + else + ret = __vserver_get_rlimit(xid, resource); - if (!PyArg_ParseTuple(args, "Ii", &xid, &resource)) - return NULL; + return ret; +} - if (vc_get_rlimit(xid, resource, &limits)==-1) - ret = PyErr_SetFromErrno(PyExc_OSError); - else - ret = Py_BuildValue("L",limits.hard); +static PyObject * +vserver_set_rlimit(PyObject *self, PyObject *args) { + struct vc_rlimit limits; + struct rlimit lim; + xid_t xid; + int resource, lresource; + PyObject *ret; + + limits.min = VC_LIM_KEEP; + limits.soft = VC_LIM_KEEP; + limits.hard = VC_LIM_KEEP; + + if (!PyArg_ParseTuple(args, "IiLLL", &xid, &resource, &limits.hard, &limits.soft, &limits.min)) + return NULL; - return ret; + lresource = resource; + switch (resource) { + case VLIMIT_NSOCK: + case VLIMIT_ANON: + case VLIMIT_SHMEM: + goto do_vc_set_rlimit; + case VLIMIT_OPENFD: + lresource = RLIMIT_NOFILE; + break; + default: + break; + } + + getrlimit(lresource,&lim); + if (adjust_lim(&limits,&lim)) { + setrlimit(lresource, &lim); + } + + do_vc_set_rlimit: + errno = 0; + if (vc_set_rlimit(xid, resource, &limits)==-1) + ret = PyErr_SetFromErrno(PyExc_OSError); + else + ret = __vserver_get_rlimit(xid, resource); + + return ret; } /* @@ -150,64 +203,64 @@ vserver_setsched(PyObject *self, PyObject *args) static PyObject * vserver_get_dlimit(PyObject *self, PyObject *args) { - PyObject *res; - char* path; - unsigned xid; - struct vcmd_ctx_dlimit_v0 data; - int r; - - if (!PyArg_ParseTuple(args, "si", &path,&xid)) - return NULL; - - memset(&data, 0, sizeof(data)); - data.name = path; - data.flags = 0; - r = vserver(VCMD_get_dlimit, xid, &data); - if (r>=0) { - res = Py_BuildValue("(i,i,i,i,i)", - data.space_used, - data.space_total, - data.inodes_used, - data.inodes_total, - data.reserved); - } else { - res = PyErr_SetFromErrno(PyExc_OSError); - } - - return res; + PyObject *res; + char* path; + unsigned xid; + struct vcmd_ctx_dlimit_v0 data; + int r; + + if (!PyArg_ParseTuple(args, "si", &path,&xid)) + return NULL; + + memset(&data, 0, sizeof(data)); + data.name = path; + data.flags = 0; + r = vserver(VCMD_get_dlimit, xid, &data); + if (r>=0) { + res = Py_BuildValue("(i,i,i,i,i)", + data.space_used, + data.space_total, + data.inodes_used, + data.inodes_total, + data.reserved); + } else { + res = PyErr_SetFromErrno(PyExc_OSError); + } + + return res; } static PyObject * vserver_set_dlimit(PyObject *self, PyObject *args) { - char* path; - unsigned xid; - struct vcmd_ctx_dlimit_base_v0 init; - struct vcmd_ctx_dlimit_v0 data; - - memset(&data,0,sizeof(data)); - if (!PyArg_ParseTuple(args, "siiiiii", &path, - &xid, - &data.space_used, - &data.space_total, - &data.inodes_used, - &data.inodes_total, - &data.reserved)) - return NULL; - - data.name = path; - data.flags = 0; - - memset(&init, 0, sizeof(init)); - init.name = path; - init.flags = 0; - - if ((vserver(VCMD_add_dlimit, xid, &init) && errno != EEXIST) || - vserver(VCMD_set_dlimit, xid, &data)) - return PyErr_SetFromErrno(PyExc_OSError); - - return NONE; + char* path; + unsigned xid; + struct vcmd_ctx_dlimit_base_v0 init; + struct vcmd_ctx_dlimit_v0 data; + + memset(&data,0,sizeof(data)); + if (!PyArg_ParseTuple(args, "siiiiii", &path, + &xid, + &data.space_used, + &data.space_total, + &data.inodes_used, + &data.inodes_total, + &data.reserved)) + return NULL; + + data.name = path; + data.flags = 0; + + memset(&init, 0, sizeof(init)); + init.name = path; + init.flags = 0; + + if ((vserver(VCMD_add_dlimit, xid, &init) && errno != EEXIST) || + vserver(VCMD_set_dlimit, xid, &data)) + return PyErr_SetFromErrno(PyExc_OSError); + + return NONE; } static PyObject * @@ -264,6 +317,8 @@ static PyMethodDef methods[] = { "Get resource limits for given resource of a vserver context" }, { "killall", vserver_killall, METH_VARARGS, "Send signal to all processes in vserver context" }, + { "isrunning", vserver_isrunning, METH_VARARGS, + "Check if vserver is running"}, { NULL, NULL, 0, NULL } }; @@ -283,6 +338,23 @@ initvserverimpl(void) /* export limit-related constants */ PyModule_AddIntConstant(mod, "DLIMIT_KEEP", (int)CDLIM_KEEP); PyModule_AddIntConstant(mod, "DLIMIT_INF", (int)CDLIM_INFINITY); + PyModule_AddIntConstant(mod, "VC_LIM_KEEP", (int)VC_LIM_KEEP); + + PyModule_AddIntConstant(mod, "RLIMIT_CPU", (int)RLIMIT_CPU); + PyModule_AddIntConstant(mod, "RLIMIT_RSS", (int)RLIMIT_RSS); + PyModule_AddIntConstant(mod, "RLIMIT_NPROC", (int)RLIMIT_NPROC); + PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", (int)RLIMIT_NOFILE); + PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", (int)RLIMIT_MEMLOCK); + PyModule_AddIntConstant(mod, "RLIMIT_AS", (int)RLIMIT_AS); + PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", (int)RLIMIT_LOCKS); + + PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", (int)RLIMIT_SIGPENDING); + PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", (int)RLIMIT_MSGQUEUE); + + PyModule_AddIntConstant(mod, "VLIMIT_NSOCK", (int)VLIMIT_NSOCK); + PyModule_AddIntConstant(mod, "VLIMIT_OPENFD", (int)VLIMIT_OPENFD); + PyModule_AddIntConstant(mod, "VLIMIT_ANON", (int)VLIMIT_ANON); + PyModule_AddIntConstant(mod, "VLIMIT_SHMEM", (int)VLIMIT_SHMEM); /* scheduler flags */ PyModule_AddIntConstant(mod, diff --git a/src/vsh.c b/src/vsh.c index 7d28bf4..ee6ba76 100644 --- a/src/vsh.c +++ b/src/vsh.c @@ -27,8 +27,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -48,30 +48,9 @@ #undef CONFIG_VSERVER_LEGACY -/* Null byte made explicit */ -#define NULLBYTE_SIZE 1 - /* Base for all vserver roots for chroot */ #define VSERVER_ROOT_BASE "/vservers" -static int -_PERROR(const char *format, char *file, int line, int _errno, ...) -{ - va_list ap; - - va_start(ap, _errno); - fprintf(stderr, "%s:%d: ", file, line); - vfprintf(stderr, format, ap); - if (_errno) - fprintf(stderr, ": %s (%d)", strerror(_errno), _errno); - fputs("\n", stderr); - fflush(stderr); - - return _errno; -} - -#define PERROR(format, args...) _PERROR(format, __FILE__, __LINE__, errno, ## args) - /* Change to root:root (before entering new context) */ static int setuidgid_root() { @@ -200,69 +179,6 @@ static int sandbox_chroot(uid_t uid) return 0; } -#define WHITESPACE(buffer,index,len) \ - while(isspace((int)buffer[index])) \ - if (index < len) index++; else goto out; - -struct resources { - char *name; - unsigned long long *limit; -}; - -#define VSERVERCONF "/etc/vservers/" -static void get_limits(char *context, struct resources *list){ - FILE *fb; - size_t len = strlen(VSERVERCONF) + strlen(context) + strlen(".conf") + NULLBYTE_SIZE; - char *conf = (char *)malloc(len); - struct resources *r; - - sprintf(conf, "%s%s.conf", VSERVERCONF, context); - - /* open the conf file for reading */ - fb = fopen(conf,"r"); - if (fb != NULL) { - size_t index; - char *buffer = malloc(1000); - char *p; - - /* the conf file exist */ - while((p=fgets(buffer,1000-1,fb))!=NULL) { - index = 0; - len = strnlen(buffer,1000); - WHITESPACE(buffer,index,len); - if (buffer[index] == '#') - continue; - - for (r=list; r->name; r++) - if ((p=strstr(&buffer[index],r->name))!=NULL) { - /* adjust index into buffer */ - index+= (p-&buffer[index])+strlen(r->name); - - /* skip over whitespace */ - WHITESPACE(buffer,index,len); - - /* expecting to see = sign */ - if (buffer[index++]!='=') goto out; - - /* skip over whitespace */ - WHITESPACE(buffer,index,len); - - /* expecting to see a digit for number */ - if (!isdigit((int)buffer[index])) goto out; - - *r->limit = atoi(&buffer[index]); - break; - } - } - out: - free(buffer); - } else { - fprintf(stderr,"cannot open %s\n",conf); - } - free(conf); -} - - static int sandbox_processes(xid_t ctx, char *context) { #ifdef CONFIG_VSERVER_LEGACY @@ -282,58 +198,40 @@ static int sandbox_processes(xid_t ctx, char *context) } #else int ctx_is_new; - unsigned long long cpu = VC_LIM_KEEP; - unsigned long long mem = VC_LIM_KEEP; - unsigned long long task = VC_LIM_KEEP; - unsigned long long cpuguaranteed = 0; - struct resources list[] = - {{"MEMLIMIT", &mem}, - {"CPULIMIT", &cpu}, - {"CPUGUARANTEED", &cpuguaranteed}, - {"TASKLIMIT", &task}, - {0,0}}; - - get_limits(context,list); - - /* check whether the slice has been disabled */ - if (!cpu) + struct sliver_resources slr; + char hostname[HOST_NAME_MAX+1]; + pl_get_limits(context,&slr); + + if (gethostname(hostname, sizeof hostname) == -1) { - fprintf(stderr, "*** this slice has been suspended ***\n"); + PERROR("gethostname(...)"); + exit(1); + } + + /* check whether the slice has been taken off of the whitelist */ + if (slr.vs_whitelisted==0) + { + fprintf(stderr, "*** %s: %s has not been allocated resources on this node ***\n", hostname, context); + exit(0); + } + + /* check whether the slice has been suspended */ + if (slr.vs_cpu==0) + { + fprintf(stderr, "*** %s: %s has zero cpu resources and presumably it has been disabled/suspended ***\n", hostname, context); exit(0); } (void) (sandbox_chroot(ctx)); - if ((ctx_is_new = pl_chcontext(ctx, 0, ~vc_get_insecurebcaps())) < 0) + if ((ctx_is_new = pl_chcontext(ctx, ~vc_get_insecurebcaps(),&slr)) < 0) { PERROR("pl_chcontext(%u)", ctx); exit(1); } if (ctx_is_new) { - /* set resources */ - struct vc_rlimit limits; - - limits.min = VC_LIM_KEEP; - limits.soft = VC_LIM_KEEP; - limits.hard = mem; - if (vc_set_rlimit(ctx, RLIMIT_RSS, &limits)) - { - PERROR("pl_setrlimit(%u, RLIMIT_RSS)", ctx); - exit(1); - } - limits.hard = task; - if (vc_set_rlimit(ctx, RLIMIT_NPROC, &limits)) - { - PERROR("pl_setrlimit(%u, RLIMIT_NPROC)", ctx); - exit(1); - } - cpuguaranteed &= VS_SCHED_CPU_GUARANTEED; - if (pl_setsched(ctx, cpu, cpuguaranteed) < 0) - { - PERROR("pl_setsched(&u)", ctx); - exit(1); - } + pl_set_limits(ctx,&slr); pl_setup_done(ctx); } #endif diff --git a/util-vserver.spec b/util-vserver.spec index 7373d5b..4b4bb4b 100644 --- a/util-vserver.spec +++ b/util-vserver.spec @@ -1,4 +1,4 @@ -# $Id: util-vserver.spec.in,v 1.49 2005/07/15 19:06:58 ensc Exp $ +# $Id$ ## This package understands the following switches: ## --without dietlibc ... disable usage of dietlibc @@ -17,7 +17,7 @@ %define name util-vserver %define version 0.30.208 -%define release 15%{?pldistro:.%{pldistro}}%{?date:.%{date}} +%define release 17%{?pldistro:.%{pldistro}}%{?date:.%{date}} %define _without_dietlibc 1 %define _without_xalan 1 @@ -215,6 +215,7 @@ contrib/make-manifest %name $RPM_BUILD_ROOT contrib/manifest.dat install -d $RPM_BUILD_ROOT/%{_datadir}/%{name} install tmp/usr/lib/python*/site-packages/*.{py,so} $RPM_BUILD_ROOT/%{_datadir}/%{name}/ install -D -m 755 python/bwlimit $RPM_BUILD_ROOT/%{_sbindir}/bwlimit +install -D -m 755 python/disklimit $RPM_BUILD_ROOT/%{_sbindir}/disklimit %check || : @@ -442,6 +443,7 @@ fi %files python %{_datadir}/%{name} %{_sbindir}/bwlimit +%{_sbindir}/disklimit %changelog diff --git a/util-vserver.spec.in b/util-vserver.spec.in index 38f2669..de5fd0c 100644 --- a/util-vserver.spec.in +++ b/util-vserver.spec.in @@ -1,4 +1,4 @@ -# $Id: util-vserver.spec.in,v 1.49 2005/07/15 19:06:58 ensc Exp $ +# $Id$ ## This package understands the following switches: ## --without dietlibc ... disable usage of dietlibc @@ -17,7 +17,7 @@ %define name @PACKAGE@ %define version @VERSION@ -%define release 15%{?pldistro:.%{pldistro}}%{?date:.%{date}} +%define release 16%{?pldistro:.%{pldistro}}%{?date:.%{date}} %define _without_dietlibc 1 %define _without_xalan 1 @@ -215,6 +215,7 @@ contrib/make-manifest %name $RPM_BUILD_ROOT contrib/manifest.dat install -d $RPM_BUILD_ROOT/%{_datadir}/%{name} install tmp/usr/lib/python*/site-packages/*.{py,so} $RPM_BUILD_ROOT/%{_datadir}/%{name}/ install -D -m 755 python/bwlimit $RPM_BUILD_ROOT/%{_sbindir}/bwlimit +install -D -m 755 python/disklimit $RPM_BUILD_ROOT/%{_sbindir}/disklimit %check || : @@ -442,6 +443,7 @@ fi %files python %{_datadir}/%{name} %{_sbindir}/bwlimit +%{_sbindir}/disklimit %changelog -- 2.43.0