generalized setting and getting of vserver limits
Marc Fiuczynski [Thu, 10 May 2007 15:22:08 +0000 (15:22 +0000)]
lib/planetlab.c
lib/planetlab.h

index 4d85fb9..8bef6dc 100644 (file)
@@ -31,20 +31,24 @@ POSSIBILITY OF SUCH DAMAGE.
 
 */
 
+#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, uint32_t flags, uint64_t bcaps, struct sliver_resources *slr)
 {
   struct vc_ctx_caps  vc_caps;
 
@@ -65,8 +69,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;
 }
@@ -88,7 +91,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, uint32_t flags, uint64_t bcaps, struct sliver_resources *slr)
 {
   int  retry_count = 0;
 
@@ -102,7 +105,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, flags, bcaps,slr))
            {
              if (errno == EEXIST)
                /* another process beat us in a race */
@@ -183,3 +186,219 @@ 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);
+}
+
+void
+pl_set_limits(xid_t ctx, struct sliver_resources *slr)
+{
+  struct rlimit olim; /* current limit values */
+  struct rlimit nlim; /* new limit values */
+
+  if (slr != 0) {
+    /* set memory limits */
+    getrlimit(RLIMIT_RSS,&olim);
+    if (0) /* for debugging only */
+      fprintf(stderr,"rss cur = %ld, max = %ld, vs_rss min = %ld\n",olim.rlim_cur,olim.rlim_max,slr->vs_rss.min);
+    if ((slr->vs_rss.min != VC_LIM_KEEP) && (slr->vs_rss.min > olim.rlim_cur)) {
+      nlim.rlim_cur = slr->vs_rss.min;
+      if (slr->vs_rss.min > olim.rlim_max) {
+       nlim.rlim_max = slr->vs_rss.min;
+      } else {
+       nlim.rlim_max = olim.rlim_max;
+      }
+      setrlimit(RLIMIT_RSS, &nlim);
+    }
+    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,&olim);
+    if (0) /* for debugging only */
+      fprintf(stderr,"as cur = %ld, max = %ld, vs_as min = %ld\n",olim.rlim_cur,olim.rlim_max,slr->vs_as.min);
+    if ((slr->vs_as.min != VC_LIM_KEEP) && (slr->vs_as.min > olim.rlim_cur)) {
+      nlim.rlim_cur = slr->vs_as.min;
+      if (slr->vs_as.min > olim.rlim_max) {
+       nlim.rlim_max = slr->vs_as.min;
+      } else {
+       nlim.rlim_max = olim.rlim_max;
+      }
+      setrlimit(RLIMIT_AS, &nlim);
+    }
+    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,&olim);
+    if (0) /* for debugging only */
+      fprintf(stderr,"nproc cur = %ld, max = %ld, vs_nproc min = %ld\n",olim.rlim_cur,olim.rlim_max,slr->vs_nproc.min);
+    if ((slr->vs_nproc.min != VC_LIM_KEEP) && (slr->vs_nproc.min > olim.rlim_cur)) {
+      nlim.rlim_cur = slr->vs_nproc.min;
+      if (slr->vs_nproc.min > olim.rlim_max) {
+       nlim.rlim_max = slr->vs_nproc.min;
+      } else {
+       nlim.rlim_max = olim.rlim_max;
+      }
+      setrlimit(RLIMIT_NPROC, &nlim);
+    }
+    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,&olim);
+    if (0) /* for debugging only */
+      fprintf(stderr,"NOFILE cur = %ld, max = %ld, vs_openfd min = %ld\n",olim.rlim_cur,olim.rlim_max,slr->vs_openfd.min);
+    if ((slr->vs_openfd.min != VC_LIM_KEEP) && (slr->vs_openfd.min > olim.rlim_cur)) {
+      nlim.rlim_cur = slr->vs_openfd.min;
+      if (slr->vs_openfd.min > olim.rlim_max) {
+       nlim.rlim_max = slr->vs_openfd.min;
+      } else {
+       nlim.rlim_max = olim.rlim_max;
+      }
+      setrlimit(RLIMIT_NOFILE, &nlim);
+      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);
+      }
+  }
+    
+  if (pl_setsched(ctx, slr ? slr->vs_cpu : 1, slr ? (slr->vs_cpuguaranteed & VS_SCHED_CPU_GUARANTEED) : 0 ) < 0)
+    {
+      PERROR("pl_setsched(&u)", ctx);
+      exit(1);
+    }
+}
index e4d6ae4..fe346aa 100644 (file)
@@ -36,8 +36,18 @@ 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 int vs_whitelisted;
+};
+
 int
-pl_chcontext(xid_t ctx, uint32_t flags, uint64_t bcaps);
+pl_chcontext(xid_t ctx, uint32_t flags, uint64_t bcaps, struct sliver_resources *slr);
 
 int
 pl_setup_done(xid_t ctx);
@@ -48,4 +58,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