Fix VFS clone_fdt bug
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 29 Apr 2016 20:31:14 +0000 (16:31 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 2 May 2016 21:11:15 +0000 (17:11 -0400)
If we attempted to clone an FDT that had grown beyond its initial limit
(32) and still had open files for the high FDs, then we'd trip an assert.
The fix is to grow the destination's FDT to correspond to the source's.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/src/vfs.c
user/utest/file-posix.c

index a4dae4a..319cba8 100644 (file)
@@ -2653,6 +2653,8 @@ void clone_fdt(struct fd_table *src, struct fd_table *dst)
 {
        struct file *file;
        struct chan *chan;
+       int ret;
+
        spin_lock(&src->lock);
        if (src->closed) {
                spin_unlock(&src->lock);
@@ -2665,6 +2667,15 @@ void clone_fdt(struct fd_table *src, struct fd_table *dst)
                spin_unlock(&src->lock);
                return;
        }
+       while (src->max_files > dst->max_files) {
+               ret = grow_fd_set(dst);
+               if (ret < 0) {
+                       set_error(-ret, "Failed to grow for a clone_fdt");
+                       spin_unlock(&dst->lock);
+                       spin_unlock(&src->lock);
+                       return;
+               }
+       }
        for (int i = 0; i < src->max_fdset; i++) {
                if (GET_BITMASK_BIT(src->open_fds->fds_bits, i)) {
                        /* while max_files and max_fdset might not line up, we should never
index 99a1b71..1d75c35 100644 (file)
@@ -10,6 +10,7 @@
 #include <dirent.h>
 #include <stdlib.h>
 #include <string.h>
+#include <parlib/parlib.h>
 
 #include <utest/utest.h>
 
@@ -30,10 +31,32 @@ bool test_openat(void)
        return TRUE;
 }
 
+/* This tests opening a lot of files, enough to grow our file/chan table, then
+ * forking/spawning with DUP_FGRP.  It caused a panic at one point. */
+bool test_open_lots_and_spawn(void)
+{
+       char *p_argv[] = {0, 0, 0};
+       char *p_envp[] = {"LD_LIBRARY_PATH=/lib", 0};
+       int fd, pid;
+       const char *filename = "/bin/hello";
+
+       /* the kernel-internal number is 32 at the moment. */
+       for (int i = 0; i < 128; i++) {
+               fd = open("hello.txt", O_RDONLY);
+               UT_ASSERT(fd >= 0);
+       }
+       pid = sys_proc_create(filename, strlen(filename), p_argv, p_envp,
+                             PROC_DUP_FGRP);
+       UT_ASSERT(pid > 0);
+       sys_proc_destroy(pid, 0);
+       return TRUE;
+}
+
 /* <--- End definition of test cases ---> */
 
 struct utest utests[] = {
        UTEST_REG(openat),
+       UTEST_REG(open_lots_and_spawn),
 };
 int num_utests = sizeof(utests) / sizeof(struct utest);