*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include <stdint.h>
-#include <stdio.h>
+#include <stdarg.h>
#include <unistd.h>
+#include <ctype.h>
#include <sys/resource.h>
#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 */
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;
}
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))
#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;
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 */
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);
+ }
+}
#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);
/* 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
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
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'),
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
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):
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:
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:
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"):
([], 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")
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:
# 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:])
return size
def stop(self, signal = signal.SIGKILL):
-
vserverimpl.killall(self.ctx, signal)
self.vm_running = False
+ self.rlimits_changed = False
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
#include <errno.h>
#include <stdint.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#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; })
/*
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 *
}
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;
}
/*
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 *
"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 }
};
/* 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,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdlib.h>
#include <errno.h>
+#include <limits.h>
#include <pwd.h>
#include <unistd.h>
#include <syscall.h>
#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()
{
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
}
#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
-# $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
%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
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 || :
%files python
%{_datadir}/%{name}
%{_sbindir}/bwlimit
+%{_sbindir}/disklimit
%changelog
-# $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
%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
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 || :
%files python
%{_datadir}/%{name}
%{_sbindir}/bwlimit
+%{_sbindir}/disklimit
%changelog