Browse Source

Debug waitpid tests (partially): Fix exit status wrt signals, support nlink in the chroot fs. We don't currently support core dumps from graphene, so some waitpid tests will fail for this reason.

Don Porter 7 years ago
parent
commit
7d98e8ca28

+ 4 - 1
LibOS/shim/include/shim_fs.h

@@ -192,7 +192,10 @@ struct shim_d_ops {
     int (*rename) (struct shim_dentry * old, struct shim_dentry * new);
 
     /* readdir: given the path relative to the mount point, read the childs
-       into the the buffer */
+       into the the buffer.  This call always returns everything under
+       the directory in one big buffer; you do not need to try again
+       or keep a cursor in the directory.  You do need to free the 
+       returned buffer. */
     int (*readdir) (struct shim_dentry * dent, struct shim_dirent ** dirent);
 };
 

+ 1 - 0
LibOS/shim/include/shim_handle.h

@@ -78,6 +78,7 @@ struct shim_file_data {
     unsigned long       atime;
     unsigned long       mtime;
     unsigned long       ctime;
+    unsigned long       nlink;
 };
 
 struct shim_file_handle {

+ 4 - 3
LibOS/shim/include/shim_ipc.h

@@ -165,12 +165,13 @@ enum {
 struct shim_ipc_cld_exit {
     IDTYPE ppid, tid;
     unsigned int exitcode;
+    unsigned int term_signal;
 #ifdef PROFILE
     unsigned long time;
 #endif
 } __attribute__((packed));
 
-int ipc_cld_exit_send (IDTYPE ppid, IDTYPE tid, unsigned int exitcode);
+int ipc_cld_exit_send (IDTYPE ppid, IDTYPE tid, unsigned int exitcode, unsigned int term_signal);
 int ipc_cld_exit_callback (IPC_CALLBACK_ARGS);
 
 /* CLD_JOIN: child join the parent group */
@@ -595,9 +596,9 @@ int do_ipc_duplex (struct shim_ipc_msg_obj * msg,
                    void * private_data);
 
 void ipc_parent_exit  (struct shim_ipc_port * port, IDTYPE vmid,
-                       unsigned int exitcode);
+                       unsigned int exitcode, unsigned int term_signal);
 void ipc_child_exit   (struct shim_ipc_port * port, IDTYPE vmid,
-                       unsigned int exitcode);
+                       unsigned int exitcode, unsigned int term_signal);
 
 int create_ipc_helper (void);
 int exit_with_ipc_helper (bool handover);

+ 6 - 1
LibOS/shim/include/shim_thread.h

@@ -67,6 +67,8 @@ struct shim_thread {
 
     PAL_HANDLE exit_event;
     int exit_code;
+    int term_signal; // Store the terminating signal, if any; needed for
+                     // wait() and friends
     bool is_alive;
 
     PAL_HANDLE child_exit_event;
@@ -103,6 +105,7 @@ struct shim_simple_thread {
     /* exit event and status */
     PAL_HANDLE exit_event;
     int exit_code;
+    int term_signal;
     bool is_alive;
 
     /* nodes in global handles */
@@ -292,7 +295,9 @@ void set_handle_map (struct shim_thread * thread,
 
 /* shim exit callback */
 int thread_exit (struct shim_thread * self, bool send_ipc);
-int try_process_exit (int error_code);
+/* If the process was killed by a signal, pass it in the second
+ *  argument, else pass zero */
+int try_process_exit (int error_code, int term_signal);
 
 /* thread cloning helpers */
 struct clone_args {

+ 10 - 3
LibOS/shim/src/bookkeep/shim_signal.c

@@ -578,17 +578,24 @@ static void sighandler_kill (int sig, siginfo_t * info, void * ucontext)
                 break;
         }
 
-    try_process_exit(0);
+    try_process_exit(0, sig);
     DkThreadExit();
 }
 
+/* We don't currently implement core dumps, but put a wrapper
+ * in case we do in the future */
+static void sighandler_core (int sig, siginfo_t * info, void * ucontext)
+{
+    sighandler_kill(sig, info, ucontext);
+}
+
 static void (*default_sighandler[NUM_SIGS]) (int, siginfo_t *, void *) =
     {
         /* SIGHUP */    &sighandler_kill,
         /* SIGINT */    &sighandler_kill,
         /* SIGQUIT */   &sighandler_kill,
         /* SIGILL */    &sighandler_kill,
-        /* SIGTRAP */   NULL,
+        /* SIGTRAP */   &sighandler_core,
         /* SIGABRT */   &sighandler_kill,
         /* SIGBUS */    &sighandler_kill,
         /* SIGFPE */    &sighandler_kill,
@@ -597,7 +604,7 @@ static void (*default_sighandler[NUM_SIGS]) (int, siginfo_t *, void *) =
         /* SIGSEGV */   &sighandler_kill,
         /* SIGUSR2 */   NULL,
         /* SIGPIPE */   &sighandler_kill,
-        /* SIGALRM */   NULL,
+        /* SIGALRM */   &sighandler_kill,
         /* SIGTERM */   &sighandler_kill,
         /* SIGSTKFLT */ NULL,
         /* SIGCHLD */   NULL,

+ 89 - 21
LibOS/shim/src/fs/chroot/fs.c

@@ -212,9 +212,14 @@ static int create_data (struct shim_dentry * dent, const char * uri, int len)
     return 0;
 }
 
-static int __query_attr (struct shim_file_data * data, PAL_HANDLE pal_handle)
+static int chroot_readdir (struct shim_dentry * dent,
+                           struct shim_dirent ** dirent);
+
+static int __query_attr (struct shim_dentry * dent,
+                         struct shim_file_data * data, PAL_HANDLE pal_handle)
 {
     PAL_STREAM_ATTR pal_attr;
+    enum shim_file_type old_type = data->type;
 
     if (pal_handle ?
         !DkStreamAttributesQuerybyHandle(pal_handle, &pal_attr) :
@@ -234,6 +239,42 @@ static int __query_attr (struct shim_file_data * data, PAL_HANDLE pal_handle)
                  (pal_attr.runnable  ? S_IXUSR : 0);
 
     atomic_set(&data->size, pal_attr.pending_size);
+
+    if (data->type == FILE_DIR) {
+        int ret;
+        /* Move up the uri update; need to convert manifest-level file:
+         * directives to 'dir:' uris */
+        if (old_type != FILE_DIR) {
+            dent->state |= DENTRY_ISDIRECTORY;
+            if ((ret = make_uri(dent)) < 0) {
+                unlock(data->lock);
+                return ret;
+            }
+        }
+        
+        /* DEP 3/18/17: If we have a directory, we need to find out how many
+         * children it has by hand. */
+        /* XXX: Keep coherent with rmdir/mkdir/creat, etc */
+        struct shim_dirent *d, *dbuf = NULL;
+        int nlink = 0;
+        int rv = chroot_readdir(dent, &dbuf);
+        if (rv != 0)
+            return rv;
+        if (dbuf) {
+            for (d = dbuf; d; d = d->next)
+                nlink++;
+            free(dbuf);
+            debug("Querying a directory; I count %d links.\n", nlink);
+        } else
+            nlink = 2; // Educated guess...
+        data->nlink = nlink;
+    } else {
+        /* DEP 3/18/17: Right now, we don't support hard links,
+         * so just return 1;
+         */ 
+        data->nlink = 1;
+    }
+    
     data->queried = true;
 
     return 0;
@@ -287,21 +328,11 @@ static int query_dentry (struct shim_dentry * dent, PAL_HANDLE pal_handle,
 
     lock(data->lock);
 
-    enum shim_file_type old_type = data->type;
-
-    if (!data->queried && (ret = __query_attr(data, pal_handle)) < 0) {
+    if (!data->queried && (ret = __query_attr(dent, data, pal_handle)) < 0) {
         unlock(data->lock);
         return ret;
     }
 
-    if (data->type == FILE_DIR && old_type != FILE_DIR) {
-        dent->state |= DENTRY_ISDIRECTORY;
-        if ((ret = make_uri(dent)) < 0) {
-            unlock(data->lock);
-            return ret;
-        }
-    }
-
     if (mode)
         *mode = data->mode;
 
@@ -318,14 +349,23 @@ static int query_dentry (struct shim_dentry * dent, PAL_HANDLE pal_handle,
         stat->st_atime  = (time_t) data->atime;
         stat->st_mtime  = (time_t) data->mtime;
         stat->st_ctime  = (time_t) data->ctime;
+        stat->st_nlink  = data->nlink;
 
+        
         switch (data->type) {
-            case FILE_REGULAR:  stat->st_mode |= S_IFREG;   break;
-            case FILE_DIR:      stat->st_mode |= S_IFDIR;   break;
+            case FILE_REGULAR:
+                stat->st_mode |= S_IFREG;
+                break;
+            case FILE_DIR:
+                stat->st_mode |= S_IFDIR;
+                break;
             case FILE_DEV:
-            case FILE_TTY:      stat->st_mode |= S_IFCHR;   break;
+            case FILE_TTY:
+                stat->st_mode |= S_IFCHR;
+                break;
             default:            break;
         }
+        debug("Stat: Returning link cound %d\n", stat->st_nlink);
     }
 
     unlock(data->lock);
@@ -356,7 +396,8 @@ static int chroot_lookup (struct shim_dentry * dent, bool force)
     return query_dentry(dent, NULL, NULL, NULL);
 }
 
-static int __chroot_open (const char * uri, int len, int flags, mode_t mode,
+static int __chroot_open (struct shim_dentry * dent,
+                          const char * uri, int len, int flags, mode_t mode,
                           struct shim_handle * hdl,
                           struct shim_file_data * data)
 {
@@ -396,7 +437,7 @@ static int __chroot_open (const char * uri, int len, int flags, mode_t mode,
 
     if (!data->queried) {
         lock(data->lock);
-        ret = __query_attr(data, palhdl);
+        ret = __query_attr(dent, data, palhdl);
         unlock(data->lock);
     }
 
@@ -422,7 +463,7 @@ static int chroot_open (struct shim_handle * hdl, struct shim_dentry * dent,
     if ((ret = try_create_data(dent, NULL, 0, &data)) < 0)
         return ret;
 
-    if ((ret = __chroot_open(NULL, 0, flags, dent->mode, hdl, data)) < 0)
+    if ((ret = __chroot_open(dent, NULL, 0, flags, dent->mode, hdl, data)) < 0)
         return ret;
 
     struct shim_file_handle * file = &hdl->info.file;
@@ -448,7 +489,7 @@ static int chroot_creat (struct shim_handle * hdl, struct shim_dentry * dir,
     if ((ret = try_create_data(dent, NULL, 0, &data)) < 0)
         return ret;
 
-    if ((ret = __chroot_open(NULL, 0, flags|O_CREAT|O_EXCL, mode, hdl,
+    if ((ret = __chroot_open(dent, NULL, 0, flags|O_CREAT|O_EXCL, mode, hdl,
                              data)) < 0)
         return ret;
 
@@ -467,6 +508,14 @@ static int chroot_creat (struct shim_handle * hdl, struct shim_dentry * dir,
     hdl->acc_mode   = ACC_MODE(flags & O_ACCMODE);
     qstrcopy(&hdl->uri, &data->host_uri);
 
+    /* Increment the parent's link count */
+    struct shim_file_data *parent_data = FILE_DENTRY_DATA(dir);
+    if (parent_data) {
+        lock(parent_data->lock);
+        if (parent_data->queried)
+            parent_data->nlink++;
+        unlock(parent_data->lock);
+    }
     return 0;
 }
 
@@ -485,7 +534,17 @@ static int chroot_mkdir (struct shim_dentry * dir, struct shim_dentry * dent,
             return ret;
     }
 
-    return __chroot_open(NULL, 0, O_CREAT|O_EXCL, mode, NULL, data);
+    ret = __chroot_open(dent, NULL, 0, O_CREAT|O_EXCL, mode, NULL, data);
+
+    /* Increment the parent's link count */
+    struct shim_file_data *parent_data = FILE_DENTRY_DATA(dir);
+    if (parent_data) {
+        lock(parent_data->lock);
+        if (parent_data->queried)
+            parent_data->nlink++;
+        unlock(parent_data->lock);
+    }
+    return ret;
 }
 
 #define NEED_RECREATE(hdl)   (!FILE_HANDLE_DATA(hdl))
@@ -512,7 +571,7 @@ static int chroot_recreate (struct shim_handle * hdl)
         qstrsetstr(&data->host_uri, uri, len);
     }
 
-    return __chroot_open(uri, len, hdl->flags, 0, hdl, data);
+    return __chroot_open(hdl->dentry, uri, len, hdl->flags, 0, hdl, data);
 }
 
 static inline bool check_version (struct shim_handle * hdl)
@@ -1067,6 +1126,15 @@ static int chroot_unlink (struct shim_dentry * dir, struct shim_dentry * dent)
     atomic_inc(&data->version);
     atomic_set(&data->size, 0);
 
+    /* Drop the parent's link count */
+    struct shim_file_data *parent_data = FILE_DENTRY_DATA(dir);
+    if (parent_data) { 
+        lock(parent_data->lock);
+        if (parent_data->queried)
+            parent_data->nlink--;
+        unlock(parent_data->lock);
+    }
+    
     return 0;
 }
 

+ 15 - 8
LibOS/shim/src/ipc/shim_ipc_child.c

@@ -37,7 +37,7 @@
 #include <errno.h>
 
 static int ipc_thread_exit (IDTYPE vmid, IDTYPE ppid, IDTYPE tid,
-                            unsigned int exitcode, unsigned long exit_time)
+                            unsigned int exitcode, unsigned int term_signal, unsigned long exit_time)
 {
     assert(vmid != cur_process.vmid);
 
@@ -52,6 +52,7 @@ static int ipc_thread_exit (IDTYPE vmid, IDTYPE ppid, IDTYPE tid,
         int ret = 0;
         //assert(thread->vmid == vmid && !thread->in_vm);
         thread->exit_code = -exitcode;
+        thread->term_signal = term_signal;
 #ifdef PROFILE
         thread->exit_time = exit_time;
 #endif
@@ -71,6 +72,7 @@ static int ipc_thread_exit (IDTYPE vmid, IDTYPE ppid, IDTYPE tid,
 
     sthread->is_alive = 0;
     sthread->exit_code = -exitcode;
+    sthread->term_signal = term_signal;
 #ifdef PROFILE
     sthread->exit_time = exit_time;
 #endif
@@ -80,7 +82,7 @@ static int ipc_thread_exit (IDTYPE vmid, IDTYPE ppid, IDTYPE tid,
 }
 
 void ipc_parent_exit (struct shim_ipc_port * port, IDTYPE vmid,
-                      unsigned int exitcode)
+                      unsigned int exitcode, unsigned int term_signal)
 {
     debug("ipc port %p of process %u closed suggests parent exiting\n",
           port, vmid);
@@ -103,6 +105,7 @@ void ipc_parent_exit (struct shim_ipc_port * port, IDTYPE vmid,
 struct thread_info {
     IDTYPE vmid;
     unsigned int exitcode;
+    unsigned int term_signal;
 };
 
 static int child_sthread_exit (struct shim_simple_thread * thread, void * arg,
@@ -112,6 +115,7 @@ static int child_sthread_exit (struct shim_simple_thread * thread, void * arg,
     if (thread->vmid == info->vmid) {
         if (thread->is_alive) {
             thread->exit_code = -info->exitcode;
+            thread->term_signal = info->term_signal;
             thread->is_alive = false;
             DkEventSet(thread->exit_event);
         }
@@ -127,6 +131,7 @@ static int child_thread_exit (struct shim_thread * thread, void * arg,
     if (thread->vmid == info->vmid) {
         if (thread->is_alive) {
             thread->exit_code = -info->exitcode;
+            thread->term_signal = info->term_signal;
             thread_exit(thread, false);
         }
         return 1;
@@ -134,9 +139,9 @@ static int child_thread_exit (struct shim_thread * thread, void * arg,
     return 0;
 }
 
-int remove_child_thread (IDTYPE vmid, unsigned int exitcode)
+int remove_child_thread (IDTYPE vmid, unsigned int exitcode, unsigned int term_signal)
 {
-    struct thread_info info = { .vmid = vmid, .exitcode = exitcode };
+    struct thread_info info = { .vmid = vmid, .exitcode = exitcode, .term_signal = term_signal };
     int nkilled = 0, ret;
 
     assert(vmid != cur_process.vmid);
@@ -154,12 +159,12 @@ int remove_child_thread (IDTYPE vmid, unsigned int exitcode)
 }
 
 void ipc_child_exit (struct shim_ipc_port * port, IDTYPE vmid,
-                     unsigned int exitcode)
+                     unsigned int exitcode, unsigned int term_signal)
 {
     debug("ipc port %p of process %u closed suggests child exiting\n",
           port, vmid);
 
-    remove_child_thread(vmid, 0);
+    remove_child_thread(vmid, 0, term_signal);
 }
 
 static struct shim_ipc_port * get_parent_port (IDTYPE * dest)
@@ -178,7 +183,7 @@ DEFINE_PROFILE_INTERVAL(ipc_cld_exit_turnaround, ipc);
 DEFINE_PROFILE_INTERVAL(ipc_cld_exit_send, ipc);
 DEFINE_PROFILE_INTERVAL(ipc_cld_exit_callback, ipc);
 
-int ipc_cld_exit_send (IDTYPE ppid, IDTYPE tid, unsigned int exitcode)
+int ipc_cld_exit_send (IDTYPE ppid, IDTYPE tid, unsigned int exitcode, unsigned int term_signal)
 {
     unsigned long send_time = GET_PROFILE_INTERVAL();
     BEGIN_PROFILE_INTERVAL_SET(send_time);
@@ -192,6 +197,7 @@ int ipc_cld_exit_send (IDTYPE ppid, IDTYPE tid, unsigned int exitcode)
     msgin->ppid = ppid;
     msgin->tid = tid;
     msgin->exitcode = exitcode;
+    msgin->term_signal = term_signal;
 #ifdef PROFILE
     msgin->time = send_time;
 #endif
@@ -220,7 +226,8 @@ int ipc_cld_exit_callback (IPC_CALLBACK_ARGS)
           msg->src, msgin->ppid, msgin->tid, msgin->exitcode);
 
     int ret = ipc_thread_exit(msg->src, msgin->ppid, msgin->tid,
-                              msgin->exitcode, time);
+                              msgin->exitcode, msgin->term_signal,
+                              time);
     SAVE_PROFILE_INTERVAL(ipc_cld_exit_callback);
     return ret;
 }

+ 1 - 1
LibOS/shim/src/sys/shim_exec.c

@@ -414,6 +414,6 @@ err:
     if (cur_thread->dummy)
         switch_dummy_thread(cur_thread);
 
-    try_process_exit(0);
+    try_process_exit(0, 0);
     return 0;
 }

+ 8 - 5
LibOS/shim/src/sys/shim_exit.c

@@ -50,7 +50,7 @@ int thread_exit(struct shim_thread * self, bool send_ipc)
     /* Chia-Che: Broadcast exit message as early as possible,
        so other process can start early on responding. */
     if (self->in_vm && send_ipc)
-        ipc_cld_exit_send(self->ppid, self->tid, self->exit_code);
+        ipc_cld_exit_send(self->ppid, self->tid, self->exit_code, self->term_signal);
 
     lock(self->lock);
 
@@ -103,7 +103,7 @@ out:
         DkEventSet(parent->child_exit_event);
     } else {
         debug("parent not here, need to tell another process\n");
-        ipc_cld_exit_send(self->ppid, self->tid, self->exit_code);
+        ipc_cld_exit_send(self->ppid, self->tid, self->exit_code, self->term_signal);
     }
 
     struct robust_list_head * robust_list = (void *) self->robust_list;
@@ -127,11 +127,12 @@ out:
     return 0;
 }
 
-int try_process_exit (int error_code)
+int try_process_exit (int error_code, int term_signal)
 {
     struct shim_thread * cur_thread = get_cur_thread();
 
     cur_thread->exit_code = -error_code;
+    cur_thread->term_signal = term_signal;
 
     if (cur_thread->in_vm)
         thread_exit(cur_thread, true);
@@ -159,6 +160,7 @@ int shim_do_exit_group (int error_code)
         sysparser_printf("---- shim_exit_group (returning %d)\n", error_code);
 
     if (cur_thread->dummy) {
+        cur_thread->term_signal = 0;
         thread_exit(cur_thread, true);
         switch_dummy_thread(cur_thread);
     }
@@ -167,7 +169,7 @@ int shim_do_exit_group (int error_code)
     do_kill_proc(cur_thread->tgid, cur_thread->tgid, SIGKILL, false);
 
     debug("now exit the process\n");
-    try_process_exit(error_code);
+    try_process_exit(error_code, 0);
 
 #ifdef PROFILE
     if (ENTER_TIME)
@@ -188,11 +190,12 @@ int shim_do_exit (int error_code)
         sysparser_printf("---- shim_exit (returning %d)\n", error_code);
 
     if (cur_thread->dummy) {
+        cur_thread->term_signal = 0;
         thread_exit(cur_thread, true);
         switch_dummy_thread(cur_thread);
     }
 
-    try_process_exit(error_code);
+    try_process_exit(error_code, 0);
 
 #ifdef PROFILE
     if (ENTER_TIME)

+ 1 - 1
LibOS/shim/src/sys/shim_fs.c

@@ -58,7 +58,7 @@ int shim_do_unlink (const char * file)
     if (!dent->parent)
         return -EACCES;
 
-    if (dent->state & DENTRY_ISDIRECTORY)
+    if (dent->state & DENTRY_ISDIRECTORY) 
         return -EISDIR;
 
     if (dent->fs && dent->fs->d_ops &&

+ 1 - 1
LibOS/shim/src/sys/shim_sigaction.c

@@ -471,7 +471,7 @@ int shim_do_kill (pid_t pid, int sig)
        specified by pid. */
     else if (pid > 0) {
         ret = do_kill_proc(cur->tid, pid, sig, true);
-        send_to_self = (pid == cur->pgid);
+        send_to_self = (pid == cur->tgid);
     }
 
     /* If pid is less than -1, then sig is sent to every process in the

+ 6 - 2
LibOS/shim/src/sys/shim_wait.c

@@ -137,8 +137,12 @@ found_child:
     unlock(cur->lock);
 
 found:
-    if (status)
-        *status = (thread->exit_code & 0xff) << 8;
+    if (status) {
+        /* Bits 0--7 are for the signal, if any.  
+         * Bits 8--15 are for the exit code */
+        *status = thread->term_signal;
+        *status |= ((thread->exit_code & 0xff) << 8);
+    }
 
     ret = thread->tid;
     SAVE_PROFILE_INTERVAL_SINCE(child_exit_notification, thread->exit_time);

+ 23 - 7
LibOS/shim/test/apps/ltp/PASSED

@@ -163,6 +163,7 @@ getsockopt01,1
 getsockopt01,2
 gettid01,1
 getuid01,1
+kill01,1
 kill03,1
 kill09,1
 listen01,1
@@ -641,21 +642,36 @@ wait02,1
 wait401,1
 wait401,2
 waitpid01,1
+waitpid01,2
 waitpid02,1
+waitpid02,2
 waitpid02,3
+waitpid03,1
+waitpid03,2
 waitpid05,1
+waitpid05,2
+waitpid05,3
+waitpid05,4
+waitpid05,5
+waitpid05,7
+waitpid05,8
+waitpid05,10
 waitpid05,11
+waitpid05,13
 waitpid05,14
-waitpid05,18
+waitpid05,16
+waitpid05,17
+waitpid05,19
+waitpid05,20
+waitpid05,21
 waitpid05,22
+waitpid05,24
+waitpid05,25
 waitpid05,26
-waitpid05,3
+waitpid05,27
+waitpid05,28
+waitpid05,29
 waitpid05,30
-waitpid05,34
-waitpid05,37
-waitpid05,4
-waitpid05,40
-waitpid05,7
 write01,1
 write02,1
 write03,1