Implement kill_request_handler in spawnd, using domain caps.
authorRazvan Damachi <razvan.damachi@gmail.com>
Wed, 21 Jun 2017 12:30:56 +0000 (14:30 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 31 Aug 2017 14:35:07 +0000 (16:35 +0200)
Domain cap hashing is now used by spawnd in a manner similar to the process
manager's, for looking up domains to kill as per incoming kill(domain_cap)
requests.

Note that with the new API and implementation, spawnd no longer tracks domain
exit code or waiters (although some backwards-compatibility is attempted), this
task being now attributed to the process manager (to be implemented).

Signed-off-by: Razvan Damachi <razvan.damachi@gmail.com>

errors/errno.fugu
include/barrelfish/domain.h
lib/barrelfish/domain.c
usr/proc_mgmt/domain.c
usr/proc_mgmt/domain.h
usr/proc_mgmt/pending_clients.c
usr/proc_mgmt/pending_clients.h
usr/proc_mgmt/service.c
usr/spawnd/ps.c
usr/spawnd/ps.h
usr/spawnd/service.c

index 2f59462..84d3e87 100755 (executable)
@@ -663,6 +663,10 @@ errors spawn SPAWN_ERR_ {
     failure DOMAIN_ALLOCATE    "No more domain descriptors",
     failure DOMAIN_NOTFOUND    "Domain not found",
     failure DOMAIN_RUNNING    "Domain is running",
+    
+    failure CREATE_DOMAIN_TABLE  "Failed to create domain hash table",
+    failure DOMAIN_CAP_HASH      "Failed to compute hash code for domain cap",
+    failure DOMAIN_TABLE_FIND    "Failed to find requested domain in domain table",
 
     failure FIND_SPAWNDS       "Unable to find spawn daemons",
     failure MALFORMED_SPAWND_RECORD "Spawn record without ID found?",
index 0ef645a..b169ceb 100644 (file)
@@ -103,6 +103,7 @@ errval_t domain_wakeup_on_disabled(dispatcher_handle_t disp,
                                    struct thread *thread,
                                    dispatcher_handle_t mydisp);
 errval_t domain_thread_move_to(struct thread *thread, coreid_t core_id);
+errval_t domain_cap_hash(struct capref domain_cap, uint64_t *ret_hash);
 
 __END_DECLS
 
index f528ae5..4e90933 100644 (file)
@@ -1423,3 +1423,23 @@ struct slot_alloc_state *get_slot_alloc_state(void)
     struct dispatcher_generic* disp = get_dispatcher_generic(handle);
     return &disp->core_state.c.slot_alloc_state;
 }
+
+/**
+ * \brief Returns a 64-bit hash code for a given domain cap.
+ */
+errval_t domain_cap_hash(struct capref domain_cap, uint64_t *ret_hash)
+{
+    assert(ret_hash != NULL);
+
+    struct capability ret_cap;
+    errval_t err = debug_cap_identify(domain_cap, &ret_cap);
+    if (err_is_fail(err)) {
+        return err_push(err, PROC_MGMT_ERR_DOMAIN_CAP_HASH);
+    }
+    assert(ret_cap.type == ObjType_Domain);
+
+    static uint64_t base = 1 + (uint64_t) MAX_COREID;
+    *ret_hash = base * ret_cap.u.domain.coreid + ret_cap.u.domain.core_local_id;
+
+    return SYS_ERR_OK;
+}
\ No newline at end of file
index 1c09dad..8516128 100644 (file)
 #define HASH_INDEX_BUCKETS 6151
 static collections_hash_table* domain_table = NULL;
 
-errval_t domain_cap_hash(struct capref domain_cap, uint64_t *ret_hash)
-{
-    assert(ret_hash != NULL);
-
-    struct capability ret_cap;
-    errval_t err = debug_cap_identify(domain_cap, &ret_cap);
-    if (err_is_fail(err)) {
-        return err_push(err, PROC_MGMT_ERR_DOMAIN_CAP_HASH);
-    }
-    assert(ret_cap.type == ObjType_Domain);
-
-    static uint64_t base = 1 + (uint64_t) MAX_COREID;
-    *ret_hash = base * ret_cap.u.domain.coreid + ret_cap.u.domain.core_local_id;
-
-    return SYS_ERR_OK;
-}
-
 errval_t domain_new(struct capref domain_cap, struct domain_entry **ret_entry)
 {
     assert(ret_entry != NULL);
index cf37c72..a338eda 100644 (file)
@@ -42,7 +42,6 @@ struct domain_entry {
     struct domain_waiter *waiters;         // Clients waiting after this domain.
 };
 
-errval_t domain_cap_hash(struct capref domain_cap, uint64_t *ret_hash);
 errval_t domain_new(struct capref domain_cap, struct domain_entry **ret_entry);
 errval_t domain_get_by_cap(struct capref domain_cap,
                            struct domain_entry **ret_entry);
index d4ff3ae..999bdcf 100644 (file)
@@ -45,7 +45,7 @@ errval_t pending_clients_add(struct capref domain_cap,
 }
 
 errval_t pending_clients_release(struct capref domain_cap,
-                                        struct pending_client *ret_cl)
+                                        struct pending_client **ret_cl)
 {
     uint64_t key;
     errval_t err = domain_cap_hash(domain_cap, &key);
@@ -58,7 +58,7 @@ errval_t pending_clients_release(struct capref domain_cap,
         return PROC_MGMT_ERR_CLIENTS_TABLE_FIND;
     }
     if (ret_cl != NULL) {
-        *ret_cl = *((struct pending_client*) table_entry);
+        *ret_cl = (struct pending_client*) table_entry;
     }
 
     collections_hash_delete(pending_clients_table, key);
index f5c2a4f..32261e4 100644 (file)
@@ -36,6 +36,6 @@ errval_t pending_clients_add(struct capref domain_cap,
                              struct proc_mgmt_binding *b, enum ClientType type,
                              coreid_t core_id);
 errval_t pending_clients_release(struct capref domain_cap,
-                                 struct pending_client *ret_cl);
+                                 struct pending_client **ret_cl);
 
 #endif  // PENDING_CLIENTS_H
\ No newline at end of file
index 1eedcd0..91027c1 100644 (file)
@@ -60,7 +60,7 @@ static void add_spawnd_handler_non_monitor(struct proc_mgmt_binding *b,
 static void spawn_reply_handler(struct spawn_binding *b,
                                 struct capref domain_cap, errval_t spawn_err)
 {
-    struct pending_client cl;
+    struct pending_client *cl;
     errval_t err = pending_clients_release(domain_cap, &cl);
     if (err_is_fail(err)) {
         // This might be a kill request issued after a successful spawn/span
@@ -73,36 +73,36 @@ static void spawn_reply_handler(struct spawn_binding *b,
     }
 
     errval_t resp_err;
-    switch (cl.type) {
+    switch (cl->type) {
         case ClientType_Spawn:
             err = spawn_err;
             if (err_is_ok(spawn_err)) {
-                err = domain_spawn(domain_cap, cl.core_id);
+                err = domain_spawn(domain_cap, cl->core_id);
             }
-            resp_err = cl.b->tx_vtbl.spawn_response(cl.b, NOP_CONT, err,
+            resp_err = cl->b->tx_vtbl.spawn_response(cl->b, NOP_CONT, err,
                                                      domain_cap);
             break;
 
         case ClientType_SpawnWithCaps:
             err = spawn_err;
             if (err_is_ok(spawn_err)) {
-                err = domain_spawn(domain_cap, cl.core_id);
+                err = domain_spawn(domain_cap, cl->core_id);
             }
-            resp_err = cl.b->tx_vtbl.spawn_with_caps_response(cl.b, NOP_CONT,
+            resp_err = cl->b->tx_vtbl.spawn_with_caps_response(cl->b, NOP_CONT,
                                                                err, domain_cap);
             break;
 
         case ClientType_Span:
             err = spawn_err;
             if (err_is_ok(spawn_err)) {
-                err = domain_span(domain_cap, cl.core_id);
+                err = domain_span(domain_cap, cl->core_id);
             }
-            resp_err = cl.b->tx_vtbl.span_response(cl.b, NOP_CONT, err);
+            resp_err = cl->b->tx_vtbl.span_response(cl->b, NOP_CONT, err);
             break;
 
         default:
             // TODO(razvan): Handle the other cases, e.g. kill.
-            debug_printf("Unknown client type %u\n", cl.type);
+            debug_printf("Unknown client type %u\n", cl->type);
             return;
     }
 
@@ -111,10 +111,10 @@ static void spawn_reply_handler(struct spawn_binding *b,
         // there's been an error in the process manager's book-keeping
         // of domains. Therefore, if the request was a spawn or span one, spawnd
         // needs to be asked to stop the dispatcher which it has just enqueued.
-        if (cl.type == ClientType_Spawn ||
-            cl.type == ClientType_SpawnWithCaps ||
-            cl.type == ClientType_Span) {
-            struct spawnd_state *state = spawnd_state_get(cl.core_id);
+        if (cl->type == ClientType_Spawn ||
+            cl->type == ClientType_SpawnWithCaps ||
+            cl->type == ClientType_Span) {
+            struct spawnd_state *state = spawnd_state_get(cl->core_id);
             assert(state != NULL);
             struct spawn_binding *spb = state->b;
             assert(spb != NULL);
@@ -129,6 +129,8 @@ static void spawn_reply_handler(struct spawn_binding *b,
         }
     }
 
+    free(cl);
+
     if (err_is_fail(resp_err)) {
         DEBUG_ERR(resp_err, "failed to send response to client");
     }
index f1e0d1a..50542f7 100644 (file)
 #include <string.h>
 #include <assert.h>
 #include <barrelfish/barrelfish.h>
+#include <collections/hash_table.h>
 #include <vfs/vfs.h>
 
 #include "ps.h"
 
+#define HASH_INDEX_BUCKETS 6151
+static collections_hash_table* domain_table = NULL;
+
 static struct ps_entry *entries[MAX_DOMAINS];
 
 errval_t ps_allocate(struct ps_entry *entry, domainid_t *domainid)
@@ -24,6 +28,7 @@ errval_t ps_allocate(struct ps_entry *entry, domainid_t *domainid)
         if(entries[i] == NULL) {
             entries[i] = entry;
             *domainid = i;
+            entry->domain_id = i;
             return SYS_ERR_OK;
         }
     }
@@ -51,3 +56,48 @@ struct ps_entry *ps_get(domainid_t domain_id)
 
     return entries[domain_id];
 }
+
+errval_t ps_hash_domain(struct ps_entry *entry, struct capref domain_cap)
+{
+    entry->domain_cap = domain_cap;
+
+    if (domain_table == NULL) {
+        collections_hash_create_with_buckets(&domain_table, HASH_INDEX_BUCKETS,
+                                             NULL);
+        if (domain_table == NULL) {
+            return SPAWN_ERR_CREATE_DOMAIN_TABLE;
+        }
+    }
+
+    uint64_t key;
+    errval_t err = domain_cap_hash(entry->domain_cap, &key);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    collections_hash_insert(domain_table, key, entry);
+
+    return SYS_ERR_OK;
+}
+
+errval_t ps_release_domain(struct capref domain_cap,
+                           struct ps_entry **ret_entry)
+{
+    assert(ret_entry != NULL);
+
+    uint64_t key;
+    errval_t err = domain_cap_hash(domain_cap, &key);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    void *table_entry = collections_hash_find(domain_table, key);
+    if (table_entry == NULL) {
+        return SPAWN_ERR_DOMAIN_TABLE_FIND;
+    }
+    *ret_entry = (struct ps_entry*) table_entry;
+
+    collections_hash_delete(domain_table, key);
+
+    return SYS_ERR_OK;
+}
index f9473c5..5c22100 100644 (file)
@@ -31,7 +31,12 @@ struct ps_entry {
     char *argv[MAX_CMDLINE_ARGS];
     char *argbuf;
     size_t argbytes;
+
+    domainid_t domain_id;
+
     struct capref domain_cap;
+    uint64_t domain_cap_hash;
+    
     struct capref rootcn_cap;
     struct capref dcb;
     struct cnoderef rootcn;
@@ -45,4 +50,8 @@ void ps_remove(domainid_t domain_id);
 bool ps_exists(domainid_t domain_id);
 struct ps_entry *ps_get(domainid_t domain_id);
 
+errval_t ps_hash_domain(struct ps_entry *entry, struct capref domain_cap);
+errval_t ps_release_domain(struct capref domain_cap,
+                           struct ps_entry **ret_entry);
+
 #endif
index 66102ca..742ee91 100644 (file)
@@ -188,7 +188,16 @@ static errval_t spawn(struct capref domain_cap, const char *path,
     err = cap_copy(pe->dcb, si.dcb);
     assert(err_is_ok(err));
     pe->status = PS_STATUS_RUNNING;
-    pe->domain_cap = domain_cap;
+    
+    if (!capref_is_null(domain_cap)) {
+        err = ps_hash_domain(pe, domain_cap);
+        if (err_is_fail(err)) {
+            free(pe);
+            spawn_free(&si);
+            return err_push(err, SPAWN_ERR_DOMAIN_CAP_HASH);
+        }
+    }
+
     err = ps_allocate(pe, domainid);
     if(err_is_fail(err)) {
         free(pe);
@@ -487,7 +496,15 @@ static void span_request_handler(struct spawn_binding *b,
     err = cap_copy(pe->dcb, si.dcb);
     assert(err_is_ok(err));
     pe->status = PS_STATUS_RUNNING;
-    pe->domain_cap = domain_cap;
+
+    err = ps_hash_domain(pe, domain_cap);
+    if (err_is_fail(err)) {
+        free(pe);
+        spawn_free(&si);
+        err = err_push(err, SPAWN_ERR_DOMAIN_CAP_HASH);
+        goto reply;
+    }
+
     domainid_t domainid;
     err = ps_allocate(pe, &domainid);
     if(err_is_fail(err)) {
@@ -507,10 +524,46 @@ reply:
     }
 }
 
+static void cleanup_cap(struct capref cap)
+{
+    errval_t err;
+
+    err = cap_revoke(cap);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "cap_revoke");
+    }
+    err = cap_destroy(cap);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "cap_destroy");
+    }
+}
+
 static void kill_request_handler(struct spawn_binding *b,
                                  struct capref domain_cap)
 {
-    debug_printf("kill_request_handler: NYI\n");
+    errval_t err, reply_err;
+    struct ps_entry *pe;
+    err = ps_release_domain(domain_cap, &pe);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_DOMAIN_NOTFOUND);
+        goto reply;
+    }
+
+    // Garbage collect victim's capabilities
+    cleanup_cap(pe->dcb);       // Deschedule dispatcher (do this first!)
+    cleanup_cap(pe->rootcn_cap);
+
+    // Cleanup struct ps_entry. Note that waiters will be handled by the process
+    // manager, as opposed to the old protocol of handling them here.
+    free(pe->argbuf);
+    ps_remove(pe->domain_id);
+    free(pe);
+
+reply:
+    reply_err = b->tx_vtbl.spawn_reply(b, NOP_CONT, domain_cap, err);
+    if (err_is_fail(reply_err)) {
+        DEBUG_ERR(err, "failed to send spawn_reply");
+    }
 }
 
 /**
@@ -542,20 +595,6 @@ static void cleanup_domain(domainid_t domainid)
     ps_remove(domainid);
 }
 
-static void cleanup_cap(struct capref cap)
-{
-    errval_t err;
-
-    err = cap_revoke(cap);
-    if (err_is_fail(err)) {
-        DEBUG_ERR(err, "cap_revoke");
-    }
-    err = cap_destroy(cap);
-    if (err_is_fail(err)) {
-        DEBUG_ERR(err, "cap_destroy");
-    }
-}
-
 static errval_t kill_domain(domainid_t domainid, uint8_t exitcode)
 {
     struct ps_entry *ps = ps_get(domainid);