Provisioning syscall and helper program (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 27 Feb 2013 20:55:53 +0000 (12:55 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 27 Feb 2013 20:55:53 +0000 (12:55 -0800)
Basic syscall for resource provisioning.  It only handles cores, does no
permissions checks, and is basically a syscall wrapper around
provision_core().

To use it, check out the test program 'prov'.  For now, it will operate
on a PID like so:

$ prov --help
$ prov -t c -p PID -v 4  (provision pcore 4 to PID)
$ prov -t c -p PID -m    (provision all pcores to PID)
$ prov -s (ghetto interface to tell the kernel to print the prov map)

Reinstall your kernel headers.

kern/include/ros/bits/syscall.h
kern/include/schedule.h
kern/src/schedule.c
kern/src/syscall.c
tests/prov.c [new file with mode: 0644]
user/parlib/include/parlib.h
user/parlib/syscall.c

index 7d6c3ba..3e1dc04 100644 (file)
@@ -33,7 +33,7 @@
 /* sys_brk removed */
 #define SYS_shared_page_alloc          22
 #define SYS_shared_page_free           23
-/* sys_resource_req removed */
+#define SYS_provision                          24
 #define SYS_notify                                     25
 #define SYS_self_notify                                26
 #define SYS_halt_core                          27
index 55fbf51..2aee5e5 100644 (file)
@@ -86,12 +86,13 @@ uint32_t max_vcores(struct proc *p);
 /* This section is specific to a provisioning ksched.  Careful calling any of
  * this from generic kernel code, since it might not be present in all kernel
  * schedulers. */
-void provision_core(struct proc *p, uint32_t pcoreid);
+int provision_core(struct proc *p, uint32_t pcoreid);
 
 /************** Debugging **************/
 void sched_diag(void);
 void print_idlecoremap(void);
 void print_resources(struct proc *p);
 void print_all_resources(void);
+void print_prov_map(void);
 
 #endif /* ROS_KERN_SCHEDULE_H */
index 94049f7..417c239 100644 (file)
@@ -753,17 +753,21 @@ static void __prov_track_dealloc_bulk(struct proc *p, uint32_t *pc_arr,
 }
 
 /* P will get pcore if it needs more cores next time we look at it */
-void provision_core(struct proc *p, uint32_t pcoreid)
+int provision_core(struct proc *p, uint32_t pcoreid)
 {
        struct sched_pcore *spc;
        struct sched_pcore_tailq *prov_list;
        /* Make sure we aren't asking for something that doesn't exist (bounds check
         * on the pcore array) */
-       if (!(pcoreid < num_cpus))
-               return; /* could do an error code */
+       if (!(pcoreid < num_cpus)) {
+               set_errno(ENXIO);
+               return -1;
+       }
        /* Don't allow the provisioning of LL cores */
-       if (is_ll_core(pcoreid))
-               return;
+       if (is_ll_core(pcoreid)) {
+               set_errno(EBUSY);
+               return -1;
+       }
        spc = pcoreid2spc(pcoreid);
        /* Note the sched lock protects the spc tailqs for all procs in this code.
         * If we need a finer grained sched lock, this is one place where we could
@@ -793,6 +797,7 @@ void provision_core(struct proc *p, uint32_t pcoreid)
        }
        spc->prov_proc = p;
        spin_unlock(&sched_lock);
+       return 0;
 }
 
 /************** Debugging **************/
index 2fa8eb4..34ada5f 100644 (file)
@@ -755,6 +755,43 @@ static int sys_shared_page_free(env_t* p1, void*DANGEROUS addr, pid_t p2)
        return -1;
 }
 
+/* Helper, to do the actual provisioning of a resource to a proc */
+static int prov_resource(struct proc *target, unsigned int res_type,
+                         long res_val)
+{
+       switch (res_type) {
+               case (RES_CORES):
+                       /* in the off chance we have a kernel scheduler that can't
+                        * provision, we'll need to change this. */
+                       return provision_core(target, res_val);
+               default:
+                       printk("[kernel] received provisioning for unknown resource %d\n",
+                              res_type);
+                       set_errno(ENOENT);      /* or EINVAL? */
+                       return -1;
+       }
+}
+
+/* Rough syscall to provision res_val of type res_type to target_pid */
+static int sys_provision(struct proc *p, int target_pid,
+                         unsigned int res_type, long res_val)
+{
+       struct proc *target = pid2proc(target_pid);
+       int retval;
+       if (!target) {
+               if (target_pid == 0)
+                       return prov_resource(0, res_type, res_val);
+               /* debugging interface */
+               if (target_pid == -1)
+                       print_prov_map();
+               set_errno(ESRCH);
+               return -1;
+       }
+       retval = prov_resource(target, res_type, res_val);
+       proc_decref(target);
+       return retval;
+}
+
 /* Untested.  Will notify the target on the given vcore, if the caller controls
  * the target.  Will honor the target's wanted/vcoreid.  u_ne can be NULL. */
 static int sys_notify(struct proc *p, int target_pid, unsigned int ev_type,
@@ -1499,6 +1536,7 @@ const static struct sys_table_entry syscall_table[] = {
        [SYS_mprotect] = {(syscall_t)sys_mprotect, "mprotect"},
        [SYS_shared_page_alloc] = {(syscall_t)sys_shared_page_alloc, "pa"},
        [SYS_shared_page_free] = {(syscall_t)sys_shared_page_free, "pf"},
+       [SYS_provision] = {(syscall_t)sys_provision, "provision"},
        [SYS_notify] = {(syscall_t)sys_notify, "notify"},
        [SYS_self_notify] = {(syscall_t)sys_self_notify, "self_notify"},
        [SYS_halt_core] = {(syscall_t)sys_halt_core, "halt_core"},
diff --git a/tests/prov.c b/tests/prov.c
new file mode 100644 (file)
index 0000000..8b3ca32
--- /dev/null
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <argp.h>
+
+#include <parlib.h>
+#include <vcore.h>
+
+const char *argp_program_version = "prov v0.1475263";
+const char *argp_program_bug_address = "<akaros@lists.eecs.berkeley.edu>";
+
+static char doc[] = "prov -- control for provisioning resources";
+static char args_doc[] = "-p PID\nPROGRAM [ARGS]\n-- PROGRAM [ARGS]\n-s";
+
+static struct argp_option options[] = {
+       {"type",                't', "TYPE",0, "Type of resource to provision"},
+       {"Possible types:", 0, 0, OPTION_DOC, "c = cores\nm = ram"},
+       {0, 0, 0, 0, "Call with exactly one of these, or with a program and args:"},
+       {"pid",                 'p', "PID",     0, "Pid of process to provision resources to"},
+       {"show",                's', 0,         0, "Show current resource provisioning"},
+       {"command",             'c', "PROG",0, "Launch a program and provision (alternate)"},
+       {0, 0, 0, OPTION_DOC, "If your command has arguments that conflict with prov, then put them after -- to keep prov from interpretting them."},
+       {0, 0, 0, 0, "Call with exactly one of these when changing a provision:"},
+       {"value",               'v', "VAL",     0, "Type-specific value, passed to the kernel"},
+       {"max",                 'm', 0,         0, "Provision all resources of the given type"},
+       {0, 0, 0, OPTION_DOC, "Cores are provisioned to processes, so the value is a specific pcore id.  To undo a core's provisioning, pass in pid=0."},
+
+       { 0 }
+};
+
+#define PROV_MODE_PID                  1
+#define PROV_MODE_CMD                  2
+#define PROV_MODE_SHOW                 3
+
+struct prog_args {
+       char                                            *cmd;
+       char                                            **cmd_args;
+       int                                                     mode;           /* PROV_MODE_ETC */
+       pid_t                                           pid;
+       char                                            res_type;       /* cores (c), ram (m), etc */
+       long                                            res_val;        /* type-specific value */
+       int                                                     max;
+       int                                                     dummy_val_flag;
+};
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state)
+{
+       struct prog_args *pargs = state->input;
+       switch (key) {
+               case 't':
+                       pargs->res_type = arg[0];
+                       if (arg[1] != '\0')
+                               printf("Warning, extra letters detected for -t's argument\n");
+                       break;
+               case 'p':
+                       if (pargs->mode) {
+                               printf("Too many modes given (-p, -s, COMMAND, etc)\n\n");
+                               argp_usage(state);
+                       }
+                       pargs->mode = PROV_MODE_PID;
+                       pargs->pid = atoi(arg);
+                       break;
+               case 's':
+                       if (pargs->mode) {
+                               printf("Too many modes given (-p, -s, COMMAND, etc)\n\n");
+                               argp_usage(state);
+                       }
+                       pargs->mode = PROV_MODE_SHOW;
+                       break;
+               case 'c':
+               case ARGP_KEY_ARG:
+                       if (pargs->mode) {
+                               printf("Too many modes given (-p, -s, COMMAND, etc)\n\n");
+                               argp_usage(state);
+                       }
+                       pargs->mode = PROV_MODE_CMD;
+                       pargs->cmd = arg;
+                       /* Point to the next arg.  We can also check state->arg_num, which
+                        * is how many non-arpg arguments there are */
+                       pargs->cmd_args = &state->argv[state->next];
+                       /* Consume all args (it's done when next == argc) */
+                       state->next = state->argc;
+                       break;
+               case 'v':
+                       /* could also check to make sure we're not -s (and vice versa) */
+                       if (pargs->dummy_val_flag) {
+                               printf("Provide only -v or -m, not both\n\n");
+                               argp_usage(state);
+                       }
+                       pargs->dummy_val_flag = 1;
+                       pargs->res_val = atol(arg);
+                       break;
+               case 'm':
+                       if (pargs->dummy_val_flag) {
+                               printf("Provide only -v or -m, not both\n\n");
+                               argp_usage(state);
+                       }
+                       pargs->dummy_val_flag = 1;
+                       pargs->max = 1;
+                       break;
+               case ARGP_KEY_END:
+                       /* Make sure we selected a mode */
+                       if (!pargs->mode) {
+                               printf("No mode selected (-p, -s, etc).\n\n");
+                               argp_usage(state);
+                       }
+                       break;
+               default:
+                       return ARGP_ERR_UNKNOWN;
+       }
+       return 0;
+}
+
+static struct argp argp = {options, parse_opt, args_doc, doc};
+
+/* Used by both -p and -c modes (-c will use it after creating pid) */
+static int prov_pid(pid_t pid, struct prog_args *pargs)
+{
+       int retval = 0;
+       switch (pargs->res_type) {
+               case ('c'):
+                       if (pargs->max) {
+                               /* TODO: don't guess the LL/CG layout and num pcores */
+                               for (int i = 1; i < max_vcores() + 1; i++) {
+                                       if (retval = sys_provision(pid, RES_CORES, i)) {
+                                               perror("Failed max provisioning");
+                                               return retval;
+                                       }
+                               }
+                       } else {
+                               if (retval = sys_provision(pid, RES_CORES, pargs->res_val)) {
+                                       perror("Failed single provision");
+                                       return retval;
+                               }
+                       }
+                       break;
+               case ('m'):
+                       printf("Provisioning memory is not supported yet\n");
+                       break;
+               default:
+                       if (!pargs->res_type)
+                               printf("No resource type selected.  Use -t\n");
+                       else
+                               printf("Unsupported resource type %c\n", pargs->res_type);
+                       return -1;
+       }
+       return retval;
+}
+
+int main(int argc, char **argv)
+{
+
+       struct prog_args pargs = {0};
+
+       argp_parse(&argp, argc, argv, 0, 0, &pargs);
+
+       switch (pargs.mode) {
+               case (PROV_MODE_PID):
+                       return prov_pid(pargs.pid, &pargs);
+                       break;
+               case (PROV_MODE_CMD):
+                       printf("Launching programs not supported yet\n");
+                       printf("Would have launched %s with args:", pargs.cmd);
+                       if (pargs.cmd_args)
+                               for (int i = 0; pargs.cmd_args[i]; i++)
+                                       printf(" %s", pargs.cmd_args[i]);
+                       printf("\n");
+                       return 0;
+                       break;
+               case (PROV_MODE_SHOW):
+                       printf("Show mode not supported yet, using ghetto interface\n\n");
+                       sys_provision(-1, 0, 0);
+                       return 0;
+                       break;
+               default:
+                       return -1;
+       }
+}
index 95f9f44..3e075a7 100644 (file)
@@ -47,6 +47,7 @@ ssize_t     sys_shared_page_free(void *COUNT(PGSIZE) addr, pid_t p2);
 void        sys_reboot();
 void *COUNT(length) sys_mmap(void *SNT addr, size_t length, int prot, int flags,
                              int fd, size_t offset);
+int                    sys_provision(int pid, unsigned int res_type, long res_val);
 int         sys_notify(int pid, unsigned int ev_type, struct event_msg *u_msg);
 int         sys_self_notify(uint32_t vcoreid, unsigned int ev_type,
                             struct event_msg *u_msg, bool priv);
index 10f46bb..0672623 100644 (file)
@@ -107,6 +107,11 @@ void *CT(length) sys_mmap(void *SNT addr, size_t length, int prot, int flags,
        return (void*)ros_syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
 }
 
+int sys_provision(int pid, unsigned int res_type, long res_val)
+{
+       return ros_syscall(SYS_provision, pid, res_type, res_val, 0, 0, 0);
+}
+
 int sys_notify(int pid, unsigned int ev_type, struct event_msg *u_msg)
 {
        return ros_syscall(SYS_notify, pid, ev_type, u_msg, 0, 0, 0);