Add support for guaranteed CPU shares
[util-vserver.git] / lib / planetlab.c
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;
 }