From: Marc Fiuczynski <mef@cs.princeton.edu>
Date: Thu, 10 May 2007 15:22:08 +0000 (+0000)
Subject: generalized setting and getting of vserver limits
X-Git-Tag: after-util-vserver-0_30_213-merge~20
X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=6471cae28b5b32ff2d425b3d103a4ceac7550125;p=util-vserver.git

generalized setting and getting of vserver limits
---

diff --git a/lib/planetlab.c b/lib/planetlab.c
index 4d85fb9..8bef6dc 100644
--- a/lib/planetlab.c
+++ b/lib/planetlab.c
@@ -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);
+    }
+}
diff --git a/lib/planetlab.h b/lib/planetlab.h
index e4d6ae4..fe346aa 100644
--- a/lib/planetlab.h
+++ b/lib/planetlab.h
@@ -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