BNX2X: spatch signed typedefs
[akaros.git] / kern / src / syscall.c
index ae17b0c..7f9e80a 100644 (file)
@@ -35,6 +35,7 @@
 #include <arsc_server.h>
 #include <event.h>
 #include <termios.h>
+#include <manager.h>
 
 /* Tracing Globals */
 int systrace_flags = 0;
@@ -44,6 +45,9 @@ size_t systrace_bufsize = 0;
 struct proc *systrace_procs[MAX_NUM_TRACED] = {0};
 spinlock_t systrace_lock = SPINLOCK_INITIALIZER_IRQSAVE;
 
+// for now, only want this visible here.
+void kprof_write_sysrecord(char *pretty_buf, size_t len);
+
 /* Not enforcing the packing of systrace_procs yet, but don't rely on that */
 static bool proc_is_traced(struct proc *p)
 {
@@ -53,11 +57,114 @@ static bool proc_is_traced(struct proc *p)
        return false;
 }
 
+static bool __trace_this_proc(struct proc *p)
+{
+       return (systrace_flags & SYSTRACE_ON) &&
+              ((systrace_flags & SYSTRACE_ALLPROC) || (proc_is_traced(p)));
+}
+
+static size_t systrace_fill_pretty_buf(struct systrace_record *trace)
+{
+       size_t len = 0;
+       struct timespec ts_start;
+       struct timespec ts_end;
+       tsc2timespec(trace->start_timestamp, &ts_start);
+       tsc2timespec(trace->end_timestamp, &ts_end);
+
+       len = snprintf(trace->pretty_buf, SYSTR_PRETTY_BUF_SZ - len,
+                  "[%7d.%09d]-[%7d.%09d] Syscall %3d (%12s):(0x%llx, 0x%llx, "
+                  "0x%llx, 0x%llx, 0x%llx, 0x%llx) ret: 0x%llx proc: %d core: %d "
+                  "vcore: %d data: ",
+                  ts_start.tv_sec,
+                  ts_start.tv_nsec,
+                  ts_end.tv_sec,
+                  ts_end.tv_nsec,
+                  trace->syscallno,
+                  syscall_table[trace->syscallno].name,
+                  trace->arg0,
+                  trace->arg1,
+                  trace->arg2,
+                  trace->arg3,
+                  trace->arg4,
+                  trace->arg5,
+                  trace->retval,
+                  trace->pid,
+                  trace->coreid,
+                  trace->vcoreid);
+       /* if we have extra data, print it out on the next line, lined up nicely.
+        * this is only useful for looking at the dump in certain terminals.  if we
+        * have a tool that processes the info, we shouldn't do this. */
+       if (trace->datalen)
+               len += snprintf(trace->pretty_buf + len, SYSTR_PRETTY_BUF_SZ - len,
+                               "\n%67s", "");
+       len += printdump(trace->pretty_buf + len,
+                        MIN(trace->datalen, SYSTR_PRETTY_BUF_SZ - len - 1),
+                        trace->data);
+       len += snprintf(trace->pretty_buf + len, SYSTR_PRETTY_BUF_SZ - len, "\n");
+       return len;
+}
+
+static void systrace_start_trace(struct kthread *kthread, struct syscall *sysc)
+{
+       struct systrace_record *trace;
+       int coreid, vcoreid;
+       struct proc *p = current;
+
+       if (!__trace_this_proc(p))
+               return;
+       assert(!kthread->trace);        /* catch memory leaks */
+       coreid = core_id();
+       vcoreid = proc_get_vcoreid(p);
+       if (systrace_flags & SYSTRACE_LOUD) {
+               printk("ENTER [%16llu] Syscall %3d (%12s):(0x%llx, 0x%llx, 0x%llx, "
+                      "0x%llx, 0x%llx, 0x%llx) proc: %d core: %d vcore: %d\n",
+                      read_tsc(),
+                      sysc->num, syscall_table[sysc->num].name,
+                          sysc->arg0, sysc->arg1, sysc->arg2, sysc->arg3, sysc->arg4,
+                          sysc->arg5, p->pid, coreid, vcoreid);
+       }
+       trace = kmalloc(SYSTR_BUF_SZ, 0);
+       if (!trace)
+               return;
+       kthread->trace = trace;
+       trace->start_timestamp = read_tsc();
+       trace->syscallno = sysc->num;
+       trace->arg0 = sysc->arg0;
+       trace->arg1 = sysc->arg1;
+       trace->arg2 = sysc->arg2;
+       trace->arg3 = sysc->arg3;
+       trace->arg4 = sysc->arg4;
+       trace->arg5 = sysc->arg5;
+       trace->pid = p->pid;
+       trace->coreid = coreid;
+       trace->vcoreid = vcoreid;
+       trace->pretty_buf = (char*)trace + sizeof(struct systrace_record);
+       trace->datalen = 0;
+       trace->data[0] = 0;
+}
+
+static void systrace_finish_trace(struct kthread *kthread, long retval)
+{
+       struct systrace_record *trace = kthread->trace;
+       size_t pretty_len;
+       if (trace) {
+               trace->end_timestamp = read_tsc();
+               trace->retval = retval;
+               kthread->trace = 0;
+               pretty_len = systrace_fill_pretty_buf(trace);
+               kprof_write_sysrecord(trace->pretty_buf, pretty_len);
+               if (systrace_flags & SYSTRACE_LOUD)
+                       printk("EXIT %s", trace->pretty_buf);
+               kfree(trace);
+       }
+}
+
 #ifdef CONFIG_SYSCALL_STRING_SAVING
 
 static void alloc_sysc_str(struct kthread *kth)
 {
        kth->name = kmalloc(SYSCALL_STRLEN, KMALLOC_WAIT);
+       kth->name[0] = 0;
 }
 
 static void free_sysc_str(struct kthread *kth)
@@ -150,7 +257,7 @@ void unset_errno(void)
        pcpui->cur_kthread->sysc->errstr[0] = '\0';
 }
 
-void set_errstr(char *fmt, ...)
+void set_errstr(const char *fmt, ...)
 {
        va_list ap;
        int rc;
@@ -194,6 +301,22 @@ char *get_cur_genbuf(void)
        return pcpui->cur_kthread->generic_buf;
 }
 
+/* Helper, looks up proc* for pid and ensures p controls that proc. 0 o/w */
+static struct proc *get_controllable_proc(struct proc *p, pid_t pid)
+{
+       struct proc *target = pid2proc(pid);
+       if (!target) {
+               set_errno(ESRCH);
+               return 0;
+       }
+       if (!proc_controls(p, target)) {
+               set_errno(EPERM);
+               proc_decref(target);
+               return 0;
+       }
+       return target;
+}
+
 /************** Utility Syscalls **************/
 
 static int sys_null(void)
@@ -205,14 +328,9 @@ static int sys_null(void)
  * async I/O handling. */
 static int sys_block(struct proc *p, unsigned int usec)
 {
-       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
-       struct alarm_waiter a_waiter;
-       init_awaiter(&a_waiter, 0);
        /* Note printing takes a few ms, so your printds won't be perfect. */
        printd("[kernel] sys_block(), sleeping at %llu\n", read_tsc());
-       set_awaiter_rel(&a_waiter, usec);
-       set_alarm(tchain, &a_waiter);
-       sleep_on_awaiter(&a_waiter);
+       kthread_usleep(usec);
        printd("[kernel] sys_block(), waking up at %llu\n", read_tsc());
        return 0;
 }
@@ -377,7 +495,6 @@ static int sys_proc_create(struct proc *p, char *path, size_t path_l,
                set_errstr("Failed to alloc new proc");
                goto mid_error;
        }
-       proc_set_progname(new_p, file_name(program));
        /* close the CLOEXEC ones, even though this isn't really an exec */
        close_9ns_files(new_p, TRUE);
        close_all_files(&new_p->open_files, TRUE);
@@ -396,6 +513,8 @@ static int sys_proc_create(struct proc *p, char *path, size_t path_l,
                set_errstr("Failed to load elf");
                goto late_error;
        }
+       /* progname is argv0, which accounts for symlinks */
+       proc_set_progname(p, p->procinfo->argbuf);
        kref_put(&program->f_kref);
        __proc_ready(new_p);
        pid = new_p->pid;
@@ -416,29 +535,20 @@ mid_error:
 /* Makes process PID runnable.  Consider moving the functionality to process.c */
 static error_t sys_proc_run(struct proc *p, unsigned pid)
 {
-       struct proc *target = pid2proc(pid);
        error_t retval = 0;
-
-       if (!target) {
-               set_errno(ESRCH);
+       struct proc *target = get_controllable_proc(p, pid);
+       if (!target)
                return -1;
-       }
-       /* make sure we have access and it's in the right state to be activated */
-       if (!proc_controls(p, target)) {
-               set_errno(EPERM);
-               goto out_error;
-       } else if (target->state != PROC_CREATED) {
+       if (target->state != PROC_CREATED) {
                set_errno(EINVAL);
-               goto out_error;
+               proc_decref(target);
+               return -1;
        }
        /* Note a proc can spam this for someone it controls.  Seems safe - if it
         * isn't we can change it. */
        proc_wakeup(target);
        proc_decref(target);
        return 0;
-out_error:
-       proc_decref(target);
-       return -1;
 }
 
 /* Destroy proc pid.  If this is called by the dying process, it will never
@@ -448,17 +558,9 @@ out_error:
 static error_t sys_proc_destroy(struct proc *p, pid_t pid, int exitcode)
 {
        error_t r;
-       struct proc *p_to_die = pid2proc(pid);
-
-       if (!p_to_die) {
-               set_errno(ESRCH);
-               return -1;
-       }
-       if (!proc_controls(p, p_to_die)) {
-               proc_decref(p_to_die);
-               set_errno(EPERM);
+       struct proc *p_to_die = get_controllable_proc(p, pid);
+       if (!p_to_die)
                return -1;
-       }
        if (p_to_die == p) {
                p->exitcode = exitcode;
                printd("[PID %d] proc exiting gracefully (code %d)\n", p->pid,exitcode);
@@ -479,6 +581,7 @@ static int sys_proc_yield(struct proc *p, bool being_nice)
         * early.  If it doesn't return, it expects to eat our reference (for now).
         */
        free_sysc_str(pcpui->cur_kthread);
+       systrace_finish_trace(pcpui->cur_kthread, 0);
        finish_sysc(pcpui->cur_kthread->sysc, pcpui->cur_proc);
        pcpui->cur_kthread->sysc = 0;   /* don't touch sysc again */
        proc_incref(p, 1);
@@ -641,7 +744,8 @@ static int sys_exec(struct proc *p, char *path, size_t path_l,
                                   sizeof(pi->argbuf)))
                goto mid_error;
        /* This is the point of no return for the process. */
-       proc_set_progname(p, file_name(program));
+       /* progname is argv0, which accounts for symlinks */
+       proc_set_progname(p, p->procinfo->argbuf);
        #ifdef CONFIG_X86
        /* clear this, so the new program knows to get an LDT */
        p->procdata->ldt = 0;
@@ -663,6 +767,7 @@ static int sys_exec(struct proc *p, char *path, size_t path_l,
        }
        printd("[PID %d] exec %s\n", p->pid, file_name(program));
        kref_put(&program->f_kref);
+       systrace_finish_trace(pcpui->cur_kthread, 0);
        goto success;
        /* These error and out paths are so we can handle the async interface, both
         * for when we want to error/return to the proc, as well as when we succeed
@@ -672,9 +777,10 @@ mid_error:
         * error value (errno is already set). */
        kref_put(&program->f_kref);
 early_error:
-       free_sysc_str(pcpui->cur_kthread);
        finish_current_sysc(-1);
+       systrace_finish_trace(pcpui->cur_kthread, -1);
 success:
+       free_sysc_str(pcpui->cur_kthread);
        /* Here's how we restart the new (on success) or old (on failure) proc: */
        spin_lock(&p->proc_lock);
        __unmap_vcore(p, 0);    /* VC# keep in sync with proc_run_s */
@@ -925,16 +1031,9 @@ static int sys_notify(struct proc *p, int target_pid, unsigned int ev_type,
                       struct event_msg *u_msg)
 {
        struct event_msg local_msg = {0};
-       struct proc *target = pid2proc(target_pid);
-       if (!target) {
-               set_errno(ESRCH);
-               return -1;
-       }
-       if (!proc_controls(p, target)) {
-               proc_decref(target);
-               set_errno(EPERM);
+       struct proc *target = get_controllable_proc(p, target_pid);
+       if (!target)
                return -1;
-       }
        /* if the user provided an ev_msg, copy it in and use that */
        if (u_msg) {
                if (memcpy_from_user(p, &local_msg, u_msg, sizeof(struct event_msg))) {
@@ -988,31 +1087,52 @@ static int sys_vc_entry(struct proc *p)
        return 0;
 }
 
-/* This will set a local timer for usec, then shut down the core.  There's a
- * slight race between spinner and halt.  For now, the core will wake up for
- * other interrupts and service them, but will not process routine messages or
- * do anything other than halt until the alarm goes off.  We could just unset
- * the alarm and return early.  On hardware, there are a lot of interrupts that
- * come in.  If we ever use this, we can take a closer look.  */
+/* This will halt the core, waking on an IRQ.  These could be kernel IRQs for
+ * things like timers or devices, or they could be IPIs for RKMs (__notify for
+ * an evq with IPIs for a syscall completion, etc).
+ *
+ * We don't need to finish the syscall early (worried about the syscall struct,
+ * on the vcore's stack).  The syscall will finish before any __preempt RKM
+ * executes, so the vcore will not restart somewhere else before the syscall
+ * completes (unlike with yield, where the syscall itself adjusts the vcore
+ * structures).
+ *
+ * In the future, RKM code might avoid sending IPIs if the core is already in
+ * the kernel.  That code will need to check the CPU's state in some manner, and
+ * send if the core is halted/idle.
+ *
+ * The core must wake up for RKMs, including RKMs that arrive while the kernel
+ * is trying to halt.  The core need not abort the halt for notif_pending for
+ * the vcore, only for a __notify or other RKM.  Anyone setting notif_pending
+ * should then attempt to __notify (o/w it's probably a bug). */
 static int sys_halt_core(struct proc *p, unsigned int usec)
 {
-       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
-       struct alarm_waiter a_waiter;
-       bool spinner = TRUE;
-       void unblock(struct alarm_waiter *waiter)
-       {
-               spinner = FALSE;
-       }
-       init_awaiter(&a_waiter, unblock);
-       set_awaiter_rel(&a_waiter, MAX(usec, 100));
-       set_alarm(tchain, &a_waiter);
-       enable_irq();
-       /* Could wake up due to another interrupt, but we want to sleep still. */
-       while (spinner) {
-               cpu_halt();     /* slight race between spinner and halt */
-               cpu_relax();
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct preempt_data *vcpd;
+       /* The user can only halt CG cores!  (ones it owns) */
+       if (management_core())
+               return -1;
+       disable_irq();
+       /* both for accounting and possible RKM optimizations */
+       __set_cpu_state(pcpui, CPU_STATE_IDLE);
+       wrmb();
+       if (has_routine_kmsg()) {
+               __set_cpu_state(pcpui, CPU_STATE_KERNEL);
+               enable_irq();
+               return 0;
+       }
+       /* This situation possible, though the check is not necessary.  We can't
+        * assert notif_pending isn't set, since another core may be in the
+        * proc_notify.  Thus we can't tell if this check here caught a bug, or just
+        * aborted early. */
+       vcpd = &p->procdata->vcore_preempt_data[pcpui->owning_vcoreid];
+       if (vcpd->notif_pending) {
+               __set_cpu_state(pcpui, CPU_STATE_KERNEL);
+               enable_irq();
+               return 0;
        }
-       printd("Returning from halting\n");
+       /* CPU_STATE is reset to KERNEL by the IRQ handler that wakes us */
+       cpu_halt();
        return 0;
 }
 
@@ -1083,6 +1203,8 @@ static unsigned long sys_populate_va(struct proc *p, uintptr_t va,
 
 static intreg_t sys_read(struct proc *p, int fd, void *buf, int len)
 {
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct systrace_record *t = pcpui->cur_kthread->trace;
        ssize_t ret;
        struct file *file = get_file_from_fd(&p->open_files, fd);
        sysc_save_str("read on fd %d", fd);
@@ -1099,17 +1221,26 @@ static intreg_t sys_read(struct proc *p, int fd, void *buf, int len)
                 * it */
                ret = file->f_op->read(file, buf, len, &file->f_pos);
                kref_put(&file->f_kref);
-               return ret;
+       } else {
+               /* plan9, should also handle errors (EBADF) */
+               ret = sysread(fd, buf, len);
+       }
+
+       if ((ret > 0) && t) {
+               t->datalen = MIN(sizeof(t->data), ret);
+               memmove(t->data, buf, t->datalen);
        }
-       /* plan9, should also handle errors (EBADF) */
-    ret = sysread(fd, buf, len);
+
        return ret;
 }
 
 static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
 {
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct systrace_record *t = pcpui->cur_kthread->trace;
        ssize_t ret;
        struct file *file = get_file_from_fd(&p->open_files, fd);
+       sysc_save_str("write on fd %d", fd);
        /* VFS */
        if (file) {
                if (!file->f_op->write) {
@@ -1120,11 +1251,17 @@ static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
                /* TODO: (UMEM) */
                ret = file->f_op->write(file, buf, len, &file->f_pos);
                kref_put(&file->f_kref);
-               return ret;
+       } else {
+               /* plan9, should also handle errors */
+               ret = syswrite(fd, (void*)buf, len);
+       }
+
+       if (t) {
+               t->datalen = MIN(sizeof(t->data), ret);
+               memmove(t->data, buf, t->datalen);
        }
-       /* plan9, should also handle errors */
-       ret = syswrite(fd, (void*)buf, len);
        return ret;
+
 }
 
 /* Checks args/reads in the path, opens the file, and inserts it into the
@@ -1132,27 +1269,36 @@ static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
 static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
                          int oflag, int mode)
 {
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct systrace_record *t = pcpui->cur_kthread->trace;
        int fd = -1;
        struct file *file;
 
        printd("File %s Open attempt oflag %x mode %x\n", path, oflag, mode);
+       char *t_path = user_strdup_errno(p, path, path_l);
+       if (!t_path)
+               return -1;
+       if (t) {
+               t->datalen = MIN(sizeof(t->data), path_l);
+               memmove(t->data, t_path, path_l);
+       }
+
        /* Make sure only one of O_RDONLY, O_WRONLY, O_RDWR is specified in flag */
        if (((oflag & (O_RDONLY | O_WRONLY | O_RDWR)) != O_RDONLY) &&
            ((oflag & (O_RDONLY | O_WRONLY | O_RDWR)) != O_WRONLY) &&
            ((oflag & (O_RDONLY | O_WRONLY | O_RDWR)) != O_RDWR)) {
                set_errno(EINVAL);
+               user_memdup_free(p, t_path);
                return -1;
        }
-       char *t_path = user_strdup_errno(p, path, path_l);
-       if (!t_path)
-               return -1;
+
        sysc_save_str("open %s", t_path);
        mode &= ~p->fs_env.umask;
        file = do_file_open(t_path, oflag, mode);
        /* VFS */
        if (file) {
                /* stores the ref to file */
-               fd = insert_file(&p->open_files, file, 0, FALSE);
+               fd = insert_file(&p->open_files, file, 0, FALSE, oflag & O_CLOEXEC);
                kref_put(&file->f_kref);        /* drop our ref */
                if (fd < 0)
                        warn("File insertion failed");
@@ -1318,9 +1464,10 @@ intreg_t sys_fcntl(struct proc *p, int fd, int cmd, int arg)
                return -1;
        }
 
+       /* TODO: these are racy */
        switch (cmd) {
                case (F_DUPFD):
-                       retval = insert_file(&p->open_files, file, arg, FALSE);
+                       retval = insert_file(&p->open_files, file, arg, FALSE, FALSE);
                        if (retval < 0) {
                                set_errno(-retval);
                                retval = -1;
@@ -1330,8 +1477,13 @@ intreg_t sys_fcntl(struct proc *p, int fd, int cmd, int arg)
                        retval = p->open_files.fd[fd].fd_flags;
                        break;
                case (F_SETFD):
-                       if (arg == FD_CLOEXEC)
-                               file->f_flags |= O_CLOEXEC;
+                       /* I'm considering not supporting this at all.  They must do it at
+                        * open time or fix their buggy/racy code. */
+                       spin_lock(&p->open_files.lock);
+                       if (arg & FD_CLOEXEC)
+                               p->open_files.fd[fd].fd_flags |= FD_CLOEXEC;
+                       retval = p->open_files.fd[fd].fd_flags;
+                       spin_unlock(&p->open_files.lock);
                        break;
                case (F_GETFL):
                        retval = file->f_flags;
@@ -1497,34 +1649,42 @@ intreg_t sys_readlink(struct proc *p, char *path, size_t path_l,
        return ret;
 }
 
-intreg_t sys_chdir(struct proc *p, const char *path, size_t path_l)
+static intreg_t sys_chdir(struct proc *p, pid_t pid, const char *path, size_t path_l)
 {
        int retval;
-       char *t_path = user_strdup_errno(p, path, path_l);
-       if (!t_path)
+       char *t_path;
+       struct proc *target = get_controllable_proc(p, pid);
+       if (!target)
                return -1;
-       /* TODO: 9ns support */
-       retval = do_chdir(&p->fs_env, t_path);
-       user_memdup_free(p, t_path);
-       if (retval) {
-               set_errno(-retval);
+       t_path = user_strdup_errno(p, path, path_l);
+       if (!t_path) {
+               proc_decref(target);
                return -1;
        }
-       return 0;
+       /* TODO: 9ns support */
+       retval = do_chdir(&target->fs_env, t_path);
+       user_memdup_free(p, t_path);
+       proc_decref(target);
+       return retval;
 }
 
-intreg_t sys_fchdir(struct proc *p, int fd)
+static intreg_t sys_fchdir(struct proc *p, pid_t pid, int fd)
 {
        struct file *file;
        int retval;
+       struct proc *target = get_controllable_proc(p, pid);
+       if (!target)
+               return -1;
        file = get_file_from_fd(&p->open_files, fd);
        if (!file) {
                /* TODO: 9ns */
                set_errno(EBADF);
+               proc_decref(target);
                return -1;
        }
-       retval = do_fchdir(&p->fs_env, file);
+       retval = do_fchdir(&target->fs_env, file);
        kref_put(&file->f_kref);
+       proc_decref(target);
        return retval;
 }
 
@@ -1807,11 +1967,9 @@ static int vfs_wstat(struct file *file, uint8_t *stat_m, size_t stat_sz,
                        goto out;
        }
        if (flags & WSTAT_LENGTH) {
-               printk("Got truncate for file %s to length %d\n", file_name(file),
-                      dir->length);
-               /* Fail for now */
-               retval = -1;
-               goto out;
+               retval = do_truncate(file->f_dentry->d_inode, dir->length);
+               if (retval < 0)
+                       goto out;
        }
        if (flags & WSTAT_ATIME) {
                /* wstat only gives us seconds */
@@ -1876,23 +2034,35 @@ intreg_t sys_fwstat(struct proc *p, int fd, uint8_t *stat_m, size_t stat_sz,
 intreg_t sys_rename(struct proc *p, char *old_path, size_t old_path_l,
                     char *new_path, size_t new_path_l)
 {
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct systrace_record *t = pcpui->cur_kthread->trace;
        ERRSTACK(1);
        int mountpointlen = 0;
        char *from_path = user_strdup_errno(p, old_path, old_path_l);
        char *to_path = user_strdup_errno(p, new_path, new_path_l);
-       struct chan *oldchan, *newchan = NULL;
+       struct chan *oldchan = 0, *newchan = NULL;
        int retval = -1;
 
        if ((!from_path) || (!to_path))
                return -1;
        printd("sys_rename :%s: to :%s: : ", from_path, to_path);
+       if (t) {
+               t->datalen = snprintf((char *)t->data, sizeof(t->data), "Rename :%s: to :%s:", from_path, to_path);
+       }
 
        /* we need a fid for the wstat. */
-       oldchan = namec(from_path, Aaccess, 0, 0);
-       if (! oldchan) {
-               printd("Could not get a chan for %s\n", from_path);
-               set_errno(ENOENT);
-               goto done;
+       /* TODO: maybe wrap the 9ns stuff better.  sysrename maybe? */
+
+       /* discard namec error */
+       if (!waserror()) {
+               oldchan = namec(from_path, Aaccess, 0, 0);
+       }
+       poperror();
+       if (!oldchan) {
+               retval = do_rename(from_path, to_path);
+               user_memdup_free(p, from_path);
+               user_memdup_free(p, to_path);
+               return retval;
        }
 
        printd("Oldchan: %C\n", oldchan);
@@ -1994,16 +2164,19 @@ static intreg_t sys_dup_fds_to(struct proc *p, unsigned int pid,
        int slot;
        struct file *file;
 
-       if (!is_user_rwaddr(map, sizeof(struct childfdmap) * nentries))
-               return -EINVAL;
-       child = pid2proc(pid);
+       if (!is_user_rwaddr(map, sizeof(struct childfdmap) * nentries)) {
+               set_errno(EINVAL);
+               return -1;
+       }
+       child = get_controllable_proc(p, pid);
        if (!child)
-               return -ENOENT;
+               return -1;
        for (int i = 0; i < nentries; i++) {
                map[i].ok = -1;
                file = get_file_from_fd(&p->open_files, map[i].parentfd);
                if (file) {
-                       slot = insert_file(&child->open_files, file, map[i].childfd, TRUE);
+                       slot = insert_file(&child->open_files, file, map[i].childfd, TRUE,
+                                          FALSE);
                        if (slot == map[i].childfd) {
                                map[i].ok = 0;
                                ret++;
@@ -2111,42 +2284,10 @@ const int max_syscall = sizeof(syscall_table)/sizeof(syscall_table[0]);
 intreg_t syscall(struct proc *p, uintreg_t sc_num, uintreg_t a0, uintreg_t a1,
                  uintreg_t a2, uintreg_t a3, uintreg_t a4, uintreg_t a5)
 {
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        intreg_t ret = -1;
        ERRSTACK(1);
 
-
-       uint32_t coreid, vcoreid;
-       if (systrace_flags & SYSTRACE_ON) {
-               if ((systrace_flags & SYSTRACE_ALLPROC) || (proc_is_traced(p))) {
-                       coreid = core_id();
-                       vcoreid = proc_get_vcoreid(p);
-                       if (systrace_flags & SYSTRACE_LOUD) {
-                               printk("[%16llu] Syscall %3d (%12s):(%p, %p, %p, %p, "
-                                      "%p, %p) proc: %d core: %d vcore: %d\n", read_tsc(),
-                                      sc_num, syscall_table[sc_num].name, a0, a1, a2, a3,
-                                      a4, a5, p->pid, coreid, vcoreid);
-                       } else {
-                               struct systrace_record *trace;
-                               uintptr_t idx, new_idx;
-                               do {
-                                       idx = systrace_bufidx;
-                                       new_idx = (idx + 1) % systrace_bufsize;
-                               } while (!atomic_cas_u32(&systrace_bufidx, idx, new_idx));
-                               trace = &systrace_buffer[idx];
-                               trace->timestamp = read_tsc();
-                               trace->syscallno = sc_num;
-                               trace->arg0 = a0;
-                               trace->arg1 = a1;
-                               trace->arg2 = a2;
-                               trace->arg3 = a3;
-                               trace->arg4 = a4;
-                               trace->arg5 = a5;
-                               trace->pid = p->pid;
-                               trace->coreid = coreid;
-                               trace->vcoreid = vcoreid;
-                       }
-               }
-       }
        if (sc_num > max_syscall || syscall_table[sc_num].call == NULL) {
                printk("[kernel] Invalid syscall %d for proc %d\n", sc_num, p->pid);
                printk("\tArgs: %p, %p, %p, %p, %p, %p\n", a0, a1, a2, a3, a4, a5);
@@ -2168,12 +2309,11 @@ intreg_t syscall(struct proc *p, uintreg_t sc_num, uintreg_t a0, uintreg_t a1,
        ret = syscall_table[sc_num].call(p, a0, a1, a2, a3, a4, a5);
        //printd("after syscall errstack base %p\n", get_cur_errbuf());
        if (get_cur_errbuf() != &errstack[0]) {
-               coreid = core_id();
-               vcoreid = proc_get_vcoreid(p);
+               /* Can't trust coreid and vcoreid anymore, need to check the trace */
                printk("[%16llu] Syscall %3d (%12s):(%p, %p, %p, %p, "
-                      "%p, %p) proc: %d core: %d vcore: %d\n", read_tsc(),
+                      "%p, %p) proc: %d\n", read_tsc(),
                       sc_num, syscall_table[sc_num].name, a0, a1, a2, a3,
-                      a4, a5, p->pid, coreid, vcoreid);
+                      a4, a5, p->pid);
                if (sc_num != SYS_fork)
                        printk("YOU SHOULD PANIC: errstack mismatch");
        }
@@ -2194,6 +2334,7 @@ void run_local_syscall(struct syscall *sysc)
                return;
        }
        pcpui->cur_kthread->sysc = sysc;        /* let the core know which sysc it is */
+       systrace_start_trace(pcpui->cur_kthread, sysc);
        alloc_sysc_str(pcpui->cur_kthread);
        /* syscall() does not return for exec and yield, so put any cleanup in there
         * too. */
@@ -2202,6 +2343,7 @@ void run_local_syscall(struct syscall *sysc)
        /* Need to re-load pcpui, in case we migrated */
        pcpui = &per_cpu_info[core_id()];
        free_sysc_str(pcpui->cur_kthread);
+       systrace_finish_trace(pcpui->cur_kthread, sysc->retval);
        /* Some 9ns paths set errstr, but not errno.  glibc will ignore errstr.
         * this is somewhat hacky, since errno might get set unnecessarily */
        if ((current_errstr()[0] != 0) && (!sysc->err))
@@ -2298,6 +2440,14 @@ int systrace_reg(bool all, struct proc *p)
        return retval;
 }
 
+int systrace_trace_pid(struct proc *p)
+{
+       if (systrace_reg(false, p))
+               error("no more processes");
+       systrace_start(true);
+       return 0;
+}
+
 void systrace_stop(void)
 {
        spin_lock_irqsave(&systrace_lock);
@@ -2334,10 +2484,10 @@ void systrace_print(bool all, struct proc *p)
        /* if you want to be clever, you could make this start from the earliest
         * timestamp and loop around.  Careful of concurrent writes. */
        for (int i = 0; i < systrace_bufsize; i++)
-               if (systrace_buffer[i].timestamp)
+               if (systrace_buffer[i].start_timestamp)
                        printk("[%16llu] Syscall %3d (%12s):(%p, %p, %p, %p, %p,"
                               "%p) proc: %d core: %d vcore: %d\n",
-                              systrace_buffer[i].timestamp,
+                              systrace_buffer[i].start_timestamp,
                               systrace_buffer[i].syscallno,
                               syscall_table[systrace_buffer[i].syscallno].name,
                               systrace_buffer[i].arg0,