Allow a parent to set up a child's fd's via a new system call
authorRonald G. Minnich <rminnich@gmail.com>
Tue, 19 Aug 2014 17:15:29 +0000 (17:15 +0000)
committerRonald G. Minnich <rminnich@gmail.com>
Tue, 19 Aug 2014 17:15:29 +0000 (17:15 +0000)
Needed for Go. The parent sets up an array of
childfdmap
structs, with parent and childfds, then calls system call 65536,
which we might want to consider naming ;-)

Not working.

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
kern/include/ros/syscall.h
kern/include/vfs.h
kern/src/ns/sysfile.c
kern/src/process.c
kern/src/syscall.c
kern/src/vfs.c
tests/childfdmap.c [new file with mode: 0644]

index 0f6f52f..01f3521 100644 (file)
@@ -32,6 +32,12 @@ struct syscall {
        char                                            errstr[MAX_ERRSTR_LEN];
 };
 
+struct childfdmap {
+       int parentfd;
+       int childfd;
+       int ok;
+};
+
 #ifndef ROS_KERNEL
 
 /* Temp hack, til the rest of glibc/userspace uses sys/syscall.h */
index 26b150e..65df904 100644 (file)
@@ -479,7 +479,7 @@ void file_release(struct kref *kref);
 /* Process-related File management functions */
 struct file *get_file_from_fd(struct files_struct *open_files, int fd);
 struct file *put_file_from_fd(struct files_struct *open_files, int file_desc);
-int insert_file(struct files_struct *open_files, struct file *file, int low_fd);
+int insert_file(struct files_struct *open_files, struct file *file, int low_fd, int must);
 void close_all_files(struct files_struct *open_files, bool cloexec);
 void clone_files(struct files_struct *src, struct files_struct *dst);
 int do_chdir(struct fs_struct *fs_env, char *path);
index 6061347..8641aa9 100644 (file)
@@ -291,6 +291,7 @@ int syscreate(char *path, int mode, uint32_t perm)
        return fd;
 }
 
+// This is in need of rework but for now just copy and convert.
 int sysdup(int old, int new)
 {
        ERRSTACK(2);
@@ -345,6 +346,62 @@ int sysdup(int old, int new)
        return fd;
 }
 
+int sysdup2(struct proc *to, int old, int new)
+{
+       ERRSTACK(2);
+       int fd;
+       struct chan *c, *oc;
+       struct fgrp *fromf = current->fgrp;
+       struct fgrp *tof = to->fgrp;
+
+       if (waserror()) {
+               poperror();
+               return -1;
+       }
+
+       c = fdtochan(current->fgrp, old, -1, 0, 1);
+       if (c->qid.type & QTAUTH) {
+               cclose(c);
+               error(Eperm);
+       }
+       fd = new;
+       if (fd != -1) {
+               /* ideally we'll be done with the VFS before we fix this */
+               /* double check the ccloses when you fix this */
+               panic("Need to sync with the VFS");
+               spin_lock(&tof->lock);
+               if (tof->closed) {
+                       spin_unlock(&tof->lock);
+                       cclose(c);
+                       return -1;
+               }
+               if (fd < 0 || growfd(tof, fd) < 0) {
+                       spin_unlock(&tof->lock);
+                       cclose(c);
+                       error(Ebadfd);
+               }
+               if (fd > tof->maxfd)
+                       tof->maxfd = fd;
+               oc = tof->fd[fd];
+               tof->fd[fd] = c;
+               spin_unlock(&tof->lock);
+               if (oc)
+                       cclose(oc);
+       } else {
+               panic("unhandled; rewrite newfd");
+               if (waserror()) {
+                       cclose(c);
+                       nexterror();
+               }
+               fd = newfd(c);
+               if (fd < 0)
+                       error(Enofd);
+               poperror();
+       }
+       poperror();
+       return fd;
+}
+
 char *sysfd2path(int fd)
 {
        ERRSTACK(1);
index 19efc07..1857c04 100644 (file)
@@ -389,9 +389,9 @@ error_t proc_alloc(struct proc **pp, struct proc *parent, int flags)
                        clone_files(&parent->open_files, &p->open_files);
        } else {
                /* no parent, we're created from the kernel */
-               assert(insert_file(&p->open_files, dev_stdin,  0) == 0);
-               assert(insert_file(&p->open_files, dev_stdout, 0) == 1);
-               assert(insert_file(&p->open_files, dev_stderr, 0) == 2);
+               assert(insert_file(&p->open_files, dev_stdin,  0, 0) == 0);
+               assert(insert_file(&p->open_files, dev_stdout, 1, 0) == 1);
+               assert(insert_file(&p->open_files, dev_stderr, 2, 0) == 2);
        }
        /* Init the ucq hash lock */
        p->ucq_hashlock = (struct hashlock*)&p->ucq_hl_noref;
index 3d30132..6e4cddb 100644 (file)
@@ -1127,6 +1127,35 @@ static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
        return ret;
 }
 
+static intreg_t sys_mapchildfds(struct proc *p, int pid, struct childfdmap *map, int nentries)
+{
+       ssize_t ret = 0;
+       int i;
+       // TODO: validate pointer, etc.
+       struct proc *child = pid2proc(pid);
+       if (! child)
+               return -ENOENT;
+
+       for (i = 0; i < nentries; i++) {
+               int slot;
+               struct file *file = get_file_from_fd(&p->open_files, map[i].parentfd);
+               printk("Try to map parent fd %d(%p) to %d\n", map[i].parentfd, file, map[i].childfd);
+               map[i].ok = -1;
+               if (! file) {
+                       printk("sys_mapchildfds: %d is wrong\n", map[i].parentfd);
+                       continue;
+               }
+               slot = insert_file(&child->open_files, file, map[i].childfd, 1);
+               printk("%s: slot is %d\n", __func__, slot);
+               if (slot == map[i].childfd) {
+                       map[i].ok = 0;
+                       ret++;
+               }
+               kref_put(&file->f_kref);
+       }
+       return ret;
+}
+
 /* Checks args/reads in the path, opens the file, and inserts it into the
  * process's open file list. */
 static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
@@ -1151,7 +1180,7 @@ static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
        file = do_file_open(t_path, oflag, mode);
        /* VFS */
        if (file) {
-               fd = insert_file(&p->open_files, file, 0);      /* stores the ref to file */
+               fd = insert_file(&p->open_files, file, 0, 0);   /* stores the ref to file */
                kref_put(&file->f_kref);        /* drop our ref */
                if (fd < 0)
                        warn("File insertion failed");
@@ -1319,7 +1348,7 @@ intreg_t sys_fcntl(struct proc *p, int fd, int cmd, int arg)
 
        switch (cmd) {
                case (F_DUPFD):
-                       retval = insert_file(&p->open_files, file, arg);
+                       retval = insert_file(&p->open_files, file, arg, 0);
                        if (retval < 0) {
                                set_errno(-retval);
                                retval = -1;
@@ -2059,6 +2088,7 @@ const struct sys_table_entry syscall_table[] = {
        [SYS_wstat] ={(syscall_t)sys_wstat, "wstat"},
        [SYS_fwstat] ={(syscall_t)sys_fwstat, "fwstat"},
        [SYS_rename] ={(syscall_t)sys_rename, "rename"},
+       [65536] = {(syscall_t)sys_mapchildfds, "mapchildfds"},
 };
 const int max_syscall = sizeof(syscall_table)/sizeof(syscall_table[0]);
 /* Executes the given syscall.
index 38560c8..cc0a165 100644 (file)
@@ -2244,11 +2244,15 @@ int claim_fd(struct files_struct *open_files, int file_desc)
 
 /* Inserts the file in the files_struct, returning the corresponding new file
  * descriptor, or an error code.  We start looking for open fds from low_fd. */
-int insert_file(struct files_struct *open_files, struct file *file, int low_fd)
+int insert_file(struct files_struct *open_files, struct file *file, int low_fd, int must)
 {
        int slot;
        spin_lock(&open_files->lock);
-       slot = __get_fd(open_files, low_fd);
+       if (must)
+               slot = __claim_fd(open_files, low_fd);
+       else
+               slot = __get_fd(open_files, low_fd);
+
        if (slot < 0) {
                spin_unlock(&open_files->lock);
                return slot;
diff --git a/tests/childfdmap.c b/tests/childfdmap.c
new file mode 100644 (file)
index 0000000..e692c70
--- /dev/null
@@ -0,0 +1,69 @@
+#define _LARGEFILE64_SOURCE /* needed to use lseek64 */
+
+#include <stdio.h> 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <arch/arch.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ros/syscall.h>
+#include <parlib.h>
+
+/* Test the childfdmap system call.
+ * Create a pipe, start the spawn, dup the pipes over fd 0 and 1, write
+ * to it, see that you get the same back.
+ */
+char filename[512];
+int main(int argc, char *argv[]) 
+{ 
+       struct childfdmap childfdmap[3];
+       int ret;
+       int flag = 0;
+       int kid;
+       int in[2], out[2];
+       char hi[3];
+       if (pipe(in) < 0) {
+               perror("pipe");
+               exit(1);
+       }
+       if (pipe(out) < 0) {
+               perror("2nd pipe");
+               exit(1);
+       }
+       printf("pipe(in) [%d, %d]; pipe(out)[%d, %d]\n", in[0], in[1], out[0], out[1]);
+       childfdmap[0].parentfd = in[0];
+       childfdmap[0].childfd = in[1];
+       childfdmap[1].parentfd = out[0];
+       childfdmap[1].childfd = out[1];
+
+       sprintf(filename, "/bin/%s", argv[0]);
+       kid = sys_proc_create(filename, strlen(filename), NULL, NULL, 0);
+       if (kid < 0) {
+               perror("create failed");
+               exit(1);
+       }
+
+       ret = syscall(65536, kid, childfdmap, 2);
+       if (ret < 0) {
+               perror("childfdmap faled");
+               exit(2);
+       }
+
+
+       sys_proc_run(kid);
+       if (write(childfdmap[0].parentfd, "HI", 2) < 2) {
+               perror("write HI");
+               exit(3);
+       }
+
+       if (read(childfdmap[1].parentfd, hi, 2) < 2) {
+               perror("read HI");
+               exit(4);
+       }
+
+       return 0;
+}