Преглед на файлове

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 години
родител
ревизия
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