*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/resource.h>
+#include <fcntl.h>
-#include "config.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, struct sliver_resources *slr)
+create_context(xid_t ctx, uint64_t bcaps, struct sliver_resources *slr)
{
struct vc_ctx_caps vc_caps;
+ struct vc_net_flags vc_nf;
+
+ /* Create network context */
+ if (vc_net_create(ctx) == VC_NOCTX) {
+ if (errno == EEXIST)
+ goto process;
+ return -1;
+ }
+
+ /* Make the network context persistent */
+ vc_nf.mask = vc_nf.flagword = VC_NXF_PERSISTENT;
+ if (vc_set_nflags(ctx, &vc_nf))
+ return -1;
+process:
/*
* 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 */
struct vc_ctx_flags vc_flags;
/* unset SETUP flag - this allows other processes to migrate */
- vc_flags.mask = VC_VXF_STATE_SETUP;
- vc_flags.flagword = 0;
+ /* set the PERSISTENT flag - so the context doesn't vanish */
+ /* Don't clear the STATE_INIT flag, as that would make us the init task. */
+ vc_flags.mask = VC_VXF_STATE_SETUP|VC_VXF_PERSISTENT;
+ vc_flags.flagword = VC_VXF_PERSISTENT;
if (vc_set_cflags(ctx, &vc_flags))
return -1;
#define RETRY_LIMIT 10
int
-pl_chcontext(xid_t ctx, uint32_t flags, uint64_t bcaps, struct sliver_resources *slr)
+pl_chcontext(xid_t ctx, uint64_t bcaps, struct sliver_resources *slr)
{
int retry_count = 0;
+ int net_migrated = 0;
+
+ pl_set_ulimits(slr);
for (;;)
{
return -1;
/* context doesn't exist - create it */
- if (create_context(ctx, flags, bcaps,slr))
+ if (create_context(ctx, bcaps, slr))
{
if (errno == EEXIST)
/* another process beat us in a race */
/* context has been setup */
migrate:
- if (!vc_ctx_migrate(ctx))
- break; /* done */
+ if (net_migrated || !vc_net_migrate(ctx))
+ {
+ if (!vc_ctx_migrate(ctx, 0))
+ break; /* done */
+ net_migrated = 1;
+ }
/* context disappeared - retry */
}
uint32_t new_flags;
vc_sched.set_mask = (VC_VXSM_FILL_RATE | VC_VXSM_INTERVAL | VC_VXSM_TOKENS |
- VC_VXSM_TOKENS_MIN | VC_VXSM_TOKENS_MAX);
- vc_sched.fill_rate = cpu_share; /* tokens accumulated per interval */
- vc_sched.interval = 1000; /* milliseconds */
+ VC_VXSM_TOKENS_MIN | VC_VXSM_TOKENS_MAX | VC_VXSM_MSEC |
+ VC_VXSM_FILL_RATE2 | VC_VXSM_INTERVAL2 | VC_VXSM_FORCE |
+ VC_VXSM_IDLE_TIME);
+ vc_sched.fill_rate = 0;
+ vc_sched.fill_rate2 = cpu_share; /* tokens accumulated per interval */
+ vc_sched.interval = vc_sched.interval2 = 1000; /* milliseconds */
vc_sched.tokens = 100; /* initial allocation of tokens */
vc_sched.tokens_min = 50; /* need this many tokens to run */
vc_sched.tokens_max = 100; /* max accumulated number of tokens */
- VC_SYSCALL(vc_set_sched(ctx, &vc_sched));
-
- /* get current flag values */
- VC_SYSCALL(vc_get_cflags(ctx, &vc_flags));
+ if (cpu_share == (uint32_t)VC_LIM_KEEP)
+ vc_sched.set_mask &= ~(VC_VXSM_FILL_RATE|VC_VXSM_FILL_RATE2);
/* guaranteed CPU corresponds to SCHED_SHARE flag being cleared */
- new_flags = (cpu_sched_flags & VS_SCHED_CPU_GUARANTEED
- ? 0
- : VC_VXF_SCHED_SHARE);
- if ((vc_flags.flagword & VC_VXF_SCHED_SHARE) != new_flags)
- {
- vc_flags.mask = VC_VXF_SCHED_FLAGS;
- vc_flags.flagword = new_flags | VC_VXF_SCHED_HARD;
- VC_SYSCALL(vc_set_cflags(ctx, &vc_flags));
- }
+ if (cpu_sched_flags & VS_SCHED_CPU_GUARANTEED) {
+ new_flags = 0;
+ vc_sched.fill_rate = vc_sched.fill_rate2;
+ }
+ else
+ new_flags = VC_VXF_SCHED_SHARE;
+
+ VC_SYSCALL(vc_set_sched(ctx, &vc_sched));
+
+ vc_flags.mask = VC_VXF_SCHED_FLAGS;
+ vc_flags.flagword = new_flags | VC_VXF_SCHED_HARD;
+ VC_SYSCALL(vc_set_cflags(ctx, &vc_flags));
return 0;
}
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);
+ int cwd;
+ size_t len = strlen(VSERVERCONF) + strlen(context) + NULLBYTE_SIZE;
+ char *conf = (char *)malloc(len + strlen("rlimits/openfd.hard"));
struct pl_resources *r;
struct pl_resources sliver_list[] = {
- {"CPULIMIT", &slr->vs_cpu},
- {"CPUSHARE", &slr->vs_cpu},
- {"CPUGUARANTEED", &slr->vs_cpuguaranteed},
+ {"sched/fill-rate2", &slr->vs_cpu},
+ {"sched/fill-rate", &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},
+ {"rlimits/nproc.hard", &slr->vs_nproc.hard},
+ {"rlimits/nproc.soft", &slr->vs_nproc.soft},
+ {"rlimits/nproc.min", &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},
+ {"rlimits/rss.hard", &slr->vs_rss.hard},
+ {"rlimits/rss.soft", &slr->vs_rss.soft},
+ {"rlimits/rss.min", &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},
+ {"rlimits/as.hard", &slr->vs_as.hard},
+ {"rlimits/as.soft", &slr->vs_as.soft},
+ {"rlimits/as.min", &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},
+ {"rlimits/openfd.hard", &slr->vs_openfd.hard},
+ {"rlimits/openfd.soft", &slr->vs_openfd.soft},
+ {"rlimits/openfd.min", &slr->vs_openfd.min},
- {"VS_WHITELISTED", &slr->vs_whitelisted},
+ {"bcapabilities", NULL},
{0,0}
};
- sprintf(conf, "%s%s.conf", VSERVERCONF, context);
+ sprintf(conf, "%s%s", VSERVERCONF, context);
slr->vs_cpu = VC_LIM_KEEP;
slr->vs_cpuguaranteed = 0;
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;
- }
+ slr->vs_capabilities.bcaps = 0;
+ slr->vs_capabilities.bmask = 0;
+ slr->vs_capabilities.ccaps = 0;
+ slr->vs_capabilities.cmask = 0;
+
+ cwd = open(".", O_RDONLY);
+ if (cwd == -1) {
+ perror("cannot get a handle on .");
+ goto out;
+ }
+ if (chdir(conf) == -1) {
+ fprintf(stderr, "cannot chdir to ");
+ perror(conf);
+ goto out_fd;
+ }
+
+ for (r = &sliver_list[0]; r->name; r++) {
+ char buf[1000];
+ fb = fopen(r->name, "r");
+ if (fb == NULL)
+ continue;
+ /* XXX: UGLY. */
+ if (strcmp(r->name, "bcapabilities") == 0) {
+ size_t len, i;
+ struct vc_err_listparser err;
+
+ len = fread(buf, 1, sizeof(buf), fb);
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '\n')
+ buf[i] = ',';
+ }
+ vc_list2bcap(buf, len, &err, &slr->vs_capabilities);
}
- out:
+ else
+ if (fgets(buf, sizeof(buf), fb) != NULL && isdigit(*buf))
+ *r->limit = atoi(buf);
fclose(fb);
- free(buffer);
- } else {
- fprintf(stderr,"cannot open %s\n",conf);
}
+
+ fchdir(cwd);
+out_fd:
+ close(cwd);
+out:
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;
+}
+
+static inline void
+set_one_ulimit(int resource, struct vc_rlimit *limit)
+{
+ struct rlimit lim;
+ getrlimit(resource, &lim);
+ adjust_lim(limit, &lim);
+ setrlimit(resource, &lim);
+}
+
+void
+pl_set_ulimits(struct sliver_resources *slr)
+{
+ if (!slr)
+ return;
+
+ set_one_ulimit(RLIMIT_RSS, &slr->vs_rss);
+ set_one_ulimit(RLIMIT_AS, &slr->vs_as);
+ set_one_ulimit(RLIMIT_NPROC, &slr->vs_nproc);
+ set_one_ulimit(RLIMIT_NOFILE, &slr->vs_openfd);
+}
+
void
pl_set_limits(xid_t ctx, struct sliver_resources *slr)
{
- struct rlimit olim; /* current limit values */
- struct rlimit nlim; /* new limit values */
+ unsigned long long vs_cpu;
+ uint32_t cpu_sched_flags;
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);
}
- 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);
}
- 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);
}
- 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);
- }
+ 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);
+ if (vc_set_rlimit(ctx, VC_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);
+ }
+
+ vs_cpu = slr->vs_cpu;
+ cpu_sched_flags = slr->vs_cpuguaranteed & VS_SCHED_CPU_GUARANTEED;
+
+ slr->vs_capabilities.bmask = vc_get_insecurebcaps();
+ if (vc_set_ccaps(ctx, &slr->vs_capabilities) < 0) {
+ PERROR("pl_setcaps(%u)", ctx);
exit(1);
}
+ } 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);
+ }
}