Add support for guaranteed CPU shares
Steve Muir [Fri, 17 Feb 2006 18:50:56 +0000 (18:50 +0000)]
lib/planetlab.c
python/vserver.py
python/vserverimpl.c
util-vserver.spec
util-vserver.spec.in

index 6b5d936..879cb5d 100644 (file)
@@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
 
 #include <errno.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <unistd.h>
 #include <sys/resource.h>
 
@@ -49,11 +50,14 @@ create_context(xid_t ctx, uint32_t flags, uint64_t bcaps, const rspec_t *rspec)
   struct vc_ctx_flags  vc_flags;
   struct vc_rlimit  vc_rlimit;
 
-  /* create context info */
+  /*
+   * 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.
+   */
   if (vc_ctx_create(ctx) == VC_NOCTX)
     return -1;
 
-  /* set capabilities - these don't take effect until SETUP flags 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 */
@@ -61,14 +65,9 @@ create_context(xid_t ctx, uint32_t flags, uint64_t bcaps, const rspec_t *rspec)
   if (vc_set_ccaps(ctx, &vc_caps))
     return -1;
 
-  /* ignore all flags except SETUP and scheduler flags */
-  vc_flags.mask = VC_VXF_STATE_SETUP | VC_VXF_SCHED_FLAGS;
-  /* don't let user change scheduler flags */
-  vc_flags.flagword = flags & ~VC_VXF_SCHED_FLAGS;  /* SETUP not set */
-
   /* set scheduler parameters */
-  vc_flags.flagword |= rspec->cpu_sched_flags;
-  pl_setsched(ctx, rspec->cpu_share, rspec->cpu_sched_flags);
+  if (pl_setsched(ctx, rspec->cpu_share, rspec->cpu_sched_flags))
+    return -1;
 
   /* set resource limits */
   vc_rlimit.min = VC_LIM_KEEP;
@@ -83,6 +82,9 @@ create_context(xid_t ctx, uint32_t flags, uint64_t bcaps, const rspec_t *rspec)
     return -1;
 
   /* set flags, unset SETUP flag - this allows other processes to migrate */
+  vc_flags.mask = VC_VXF_STATE_SETUP | VC_VXF_SCHED_FLAGS;
+  flags = 0;  /* XXX - ignore flags parameter */
+  vc_flags.flagword = flags | rspec->cpu_sched_flags;  /* SETUP cleared */
   if (vc_set_cflags(ctx, &vc_flags))
     return -1;
 
@@ -133,10 +135,27 @@ pl_chcontext(xid_t ctx, uint32_t flags, uint64_t bcaps, const rspec_t *rspec)
   return 0;
 }
 
+/* it's okay for a syscall to fail because the context doesn't exist */
+#define VC_SYSCALL(x)                          \
+do                                             \
+{                                              \
+  if (x)                                       \
+    return errno == ESRCH ? 0 : -1;            \
+}                                              \
+while (0)
+
+
 int
 pl_setsched(xid_t ctx, uint32_t cpu_share, uint32_t cpu_sched_flags)
 {
   struct vc_set_sched  vc_sched;
+  struct vc_ctx_flags  vc_flags;
+
+  if (cpu_sched_flags & ~VC_VXF_SCHED_FLAGS)
+    {
+      errno = EINVAL;
+      return -1;
+    }
 
   vc_sched.set_mask = (VC_VXSM_FILL_RATE | VC_VXSM_INTERVAL | VC_VXSM_TOKENS |
                       VC_VXSM_TOKENS_MIN | VC_VXSM_TOKENS_MAX);
@@ -146,5 +165,18 @@ pl_setsched(xid_t ctx, uint32_t cpu_share, uint32_t cpu_sched_flags)
   vc_sched.tokens_min = 50;  /* need this many tokens to run */
   vc_sched.tokens_max = 100;  /* max accumulated number of tokens */
 
-  return vc_set_sched(ctx, &vc_sched);
+  VC_SYSCALL(vc_set_sched(ctx, &vc_sched));
+
+  /* get current flag values */
+  VC_SYSCALL(vc_get_cflags(ctx, &vc_flags));
+
+  /* the only flag which ever changes is the SCHED_SHARE bit */
+  if ((vc_flags.flagword ^ cpu_sched_flags) & VC_VXF_SCHED_SHARE)
+    {
+      vc_flags.mask = VC_VXF_SCHED_SHARE;
+      vc_flags.flagword = cpu_sched_flags & VC_VXF_SCHED_FLAGS;
+      VC_SYSCALL(vc_set_cflags(ctx, &vc_flags));
+    }
+
+  return 0;
 }
index 8224abd..ee061bb 100644 (file)
@@ -151,9 +151,13 @@ class VServer:
 
         if cpu_share == int(self.config.get("CPULIMIT", -1)):
             return
-
-        self.__update_config_file(self.config_file, { "CPULIMIT": cpu_share })
+        # XXX - don't want to have to deal with nm_ flags here
+        cpu_guaranteed = int(self.resources.get("nm_sched_flags",
+                                                None) == "guaranteed")
+        cpu_config = { "CPULIMIT": cpu_share, "CPUGUARANTEED": cpu_guaranteed }
+        self.__update_config_file(self.config_file, cpu_config)
         if self.vm_running:
+            # caller must ensure cpu_share is consistent with self.resources
             vserverimpl.setsched(self.ctx, self.resources)
 
     def get_sched(self):
index 6b1284c..fbb94f5 100644 (file)
@@ -44,27 +44,52 @@ POSSIBILITY OF SUCH DAMAGE.
 #include "vserver.h"
 #include "vserver-internal.h"
 
+#define NONE  ({ Py_INCREF(Py_None); Py_None; })
+
 static int
 get_rspec(PyObject *resources, rspec_t *rspec)
 {
+  int  result = -1;
   PyObject  *cpu_share;
+  PyObject  *sched_flags = NULL;
 
   if (!PyMapping_Check(resources))
     {
       PyErr_SetString(PyExc_TypeError, "invalid rspec");
       return -1;
     }
-  if ((cpu_share = PyMapping_GetItemString(resources, "nm_cpu_share")))
+
+  /* get CPU share */
+  if (!(cpu_share = PyMapping_GetItemString(resources, "nm_cpu_share")))
+    return -1;
+  if (!PyInt_Check(cpu_share))
     {
-      if (PyInt_Check(cpu_share))
-       {
-         rspec->cpu_share = PyInt_AS_LONG(cpu_share);
-         return 0;
-       }
       PyErr_SetString(PyExc_TypeError, "nm_cpu_share not an integer");
+      goto out;
+    }
+  rspec->cpu_share = PyInt_AS_LONG(cpu_share);
+
+  /* check whether this share should be guaranteed */
+  rspec->cpu_sched_flags = VC_VXF_SCHED_FLAGS;
+  result = 0;
+  if ((sched_flags = PyMapping_GetItemString(resources, "nm_sched_flags")))
+    {
+      const char  *flagstr;
+
+      if (!(flagstr = PyString_AsString(sched_flags)))
+       result = -1;
+      else if (!strcmp(flagstr, "guaranteed"))
+       rspec->cpu_sched_flags &= ~VC_VXF_SCHED_SHARE;
+      Py_DECREF(sched_flags);
     }
+  else
+    /* not an error if nm_sched_flags is missing */
+    PyErr_Clear();
+
+ out:
+  Py_DECREF(cpu_share);
 
-  return -1;
+  return result;
 }
 
 /*
@@ -86,7 +111,7 @@ vserver_chcontext(PyObject *self, PyObject *args)
   if (pl_chcontext(ctx, flags, bcaps, &rspec))
     return PyErr_SetFromErrno(PyExc_OSError);
 
-  return Py_None;
+  return NONE;
 }
 
 static PyObject *
@@ -103,7 +128,6 @@ vserver_set_rlimit(PyObject *self, PyObject *args) {
        if (!PyArg_ParseTuple(args, "IiL", &xid, &resource, &limits.hard))
                return NULL;
 
-       ret = Py_None;
        if (vc_set_rlimit(xid, resource, &limits)) 
                ret = PyErr_SetFromErrno(PyExc_OSError);
        else if (vc_get_rlimit(xid, resource, &limits)==-1)
@@ -128,7 +152,6 @@ vserver_get_rlimit(PyObject *self, PyObject *args) {
        if (!PyArg_ParseTuple(args, "Ii", &xid, &resource))
                return NULL;
 
-       ret = Py_None;
        if (vc_get_rlimit(xid, resource, &limits)==-1)
                ret = PyErr_SetFromErrno(PyExc_OSError);
        else
@@ -156,7 +179,7 @@ vserver_setsched(PyObject *self, PyObject *args)
       errno != ESRCH)
     return PyErr_SetFromErrno(PyExc_OSError);
 
-  return Py_None;
+  return NONE;
 }
 
 static PyObject *
@@ -219,7 +242,7 @@ vserver_set_dlimit(PyObject *self, PyObject *args)
             vserver(VCMD_set_dlimit, xid, &data))
           return PyErr_SetFromErrno(PyExc_OSError);
 
-       return Py_None; 
+       return NONE;    
 }
 
 static PyObject *
@@ -239,7 +262,7 @@ vserver_unset_dlimit(PyObject *self, PyObject *args)
   if (vserver(VCMD_rem_dlimit, xid, &init) && errno != ESRCH)
     return PyErr_SetFromErrno(PyExc_OSError);
 
-  return Py_None;      
+  return NONE; 
 }
 
 static PyObject *
@@ -254,7 +277,7 @@ vserver_killall(PyObject *self, PyObject *args)
   if (vc_ctx_kill(ctx, 0, sig) && errno != ESRCH)
     return PyErr_SetFromErrno(PyExc_OSError);
 
-  return Py_None;
+  return NONE;
 }
 
 static PyMethodDef  methods[] = {
index 2699259..65a7eaa 100644 (file)
@@ -17,7 +17,7 @@
 
 %define name util-vserver
 %define version 0.30.208
-%define release 8%{?pldistro:.%{pldistro}}%{?date:.%{date}}
+%define release 9%{?pldistro:.%{pldistro}}%{?date:.%{date}}
 
 %define _without_dietlibc 1
 %define _without_xalan 1
@@ -384,6 +384,9 @@ done
 
 
 %changelog
+* Fri Feb 17 2006 Steve Muir <smuir@cs.princeton.edu>
+- add support for setting guaranteed CPU share flag in rspec
+
 * Fri Jan 13 2006 Steve Muir <smuir@cs.princeton.edu>
 - fix bug in python/vserverimpl.c where attempting to adjust CPU share
   for a context that didn't exist would cause an error (it should be a
index ce9c031..3f96a47 100644 (file)
@@ -17,7 +17,7 @@
 
 %define name @PACKAGE@
 %define version @VERSION@
-%define release 8%{?pldistro:.%{pldistro}}%{?date:.%{date}}
+%define release 9%{?pldistro:.%{pldistro}}%{?date:.%{date}}
 
 %define _without_dietlibc 1
 %define _without_xalan 1
@@ -384,6 +384,14 @@ done
 
 
 %changelog
+* Fri Feb 17 2006 Steve Muir <smuir@cs.princeton.edu>
+- add support for setting guaranteed CPU share flag in rspec
+
+* Fri Jan 13 2006 Steve Muir <smuir@cs.princeton.edu>
+- fix bug in python/vserverimpl.c where attempting to adjust CPU share
+  for a context that didn't exist would cause an error (it should be a
+  safe no-op)
+
 * Fri Dec  2 2005 Steve Muir <smuir@cs.princeton.edu>
 - fix bugs in python/vserverimpl.c where exceptions were not raised when
   they should be and thus occured later at unexpected times