Refactored retype in monitor.
authorMark Nevill <nevillm@ethz.ch>
Sat, 9 Jun 2012 01:23:21 +0000 (03:23 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 18 Jul 2013 12:58:34 +0000 (14:58 +0200)
usr/monitor/capops/init.c
usr/monitor/capops/internal.h
usr/monitor/capops/retype.c
usr/monitor/include/capops.h
usr/monitor/monitor_rpc_server.c

index 4f75bb9..333777d 100644 (file)
@@ -13,8 +13,8 @@ errval_t capops_intermon_init(struct intermon_binding *b)
     b->rx_vtbl.capops_delete_remote_result    = delete_remote_result__rx_handler;
     b->rx_vtbl.capops_request_revoke          = request_revoke__rx_handler;
     b->rx_vtbl.capops_revoke_result           = revoke_result__rx_handler;
-    b->rx_vtbl.capops_request_retype          = request_retype__rx_handler;
-    b->rx_vtbl.capops_retype_response         = retype_response__rx_handler;
+    b->rx_vtbl.capops_request_retype          = retype_request__rx;
+    b->rx_vtbl.capops_retype_response         = retype_response__rx;
     b->rx_vtbl.capops_update_owner            = update_owner__rx_handler;
     b->rx_vtbl.capops_owner_updated           = owner_updated__rx_handler;
     b->rx_vtbl.capops_find_cap                = find_cap__rx_handler;
index 42ecd19..d138330 100644 (file)
 #ifndef CAPOPS_INTERNAL_H
 #define CAPOPS_INTERNAL_H
 
+typedef void (*gen_result_cont_fn)(errval_t, void*);
+struct result_closure {
+    gen_result_cont_fn handler;
+    void *arg;
+};
+#define MKRESCONT(h,a) ((struct result_closure){ .handler = (h), .arg = (a) })
+#define CALLRESCONT(c,e) ((c).handler((e), (c).arg))
+
 #define malloce(size, ret) \
     (*(ret) = malloc(size), \
      *(ret) ? SYS_ERR_OK : LIB_ERR_MALLOC_FAIL)
@@ -73,10 +81,9 @@ void move_request__rx_handler(struct intermon_binding *b,
                               genvaddr_t st);
 void move_result__rx_handler(struct intermon_binding *b, errval_t status,
                              genvaddr_t st);
-void request_retype__rx_handler(struct intermon_binding *b,
-                                intermon_caprep_t srcrep, int desttype,
-                                uint32_t destbits, genvaddr_t st);
-void retype_response__rx_handler(struct intermon_binding *b, errval_t status,
+void retype_request__rx(struct intermon_binding *b, intermon_caprep_t srcrep,
+                        int desttype, uint32_t destbits, genvaddr_t st);
+void retype_response__rx(struct intermon_binding *b, errval_t status,
                                  genvaddr_t st);
 void request_revoke__rx_handler(struct intermon_binding *b,
                                 intermon_caprep_t caprep, genvaddr_t st);
index 8987ff3..03d32eb 100644 (file)
@@ -9,8 +9,10 @@
 
 #include <barrelfish/barrelfish.h>
 #include <barrelfish/caddr.h>
+#include <if/intermon_defs.h>
 #include <monitor.h>
 #include <monitor_invocations.h>
+#include <dom_invocations.h>
 #include "capops.h"
 #include "capsend.h"
 #include "caplock.h"
 #include "internal.h"
 
 /*
- *
+ * Retype states
  */
 
-struct retype_st {
+struct retype_check_st {
     enum objtype type;
     size_t objbits;
     struct domcapref src;
+    struct result_closure cont;
+};
+
+struct retype_output_st {
     struct domcapref destcn;
     cslot_t start_slot;
-    retype_result_handler_t result_handler;
-    void *st;
+    struct result_closure cont;
 };
 
-static void
-create_copies_cont(errval_t status, void *st)
-{
-    errval_t err = status;
-    struct retype_st *rtst = (struct retype_st*)st;
-    if (err_is_ok(err)) {
-        err = SYS_ERR_REVOKE_FIRST;
-    }
-    if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
-        // no descendants found
-        assert(capcmp(rtst->src.croot, rtst->destcn.croot));
-        err = monitor_create_caps(rtst->src.croot, rtst->type, rtst->objbits,
-                                  rtst->src.cptr, rtst->src.bits,
-                                  rtst->destcn.cptr, rtst->destcn.bits,
-                                  rtst->start_slot);
-    }
-    rtst->result_handler(err, rtst->st);
-    free(rtst);
-}
+struct requested_retype_st {
+    struct intermon_msg_queue_elem queue_elem;
+    struct retype_check_st check;
+    struct capref src;
+    coreid_t from;
+    errval_t status;
+    genvaddr_t request_st;
+};
+
+struct local_retype_st {
+    struct retype_check_st check;
+    struct retype_output_st output;
+};
 
-struct request_retype_msg_st {
+struct retype_request_st {
     struct intermon_msg_queue_elem queue_elem;
-    struct retype_st *st;
     intermon_caprep_t caprep;
+    struct retype_check_st check;
+    struct retype_output_st output;
 };
 
+/*
+ * Prototypes for static functions so ordering does not matter
+ */
+
+static void check_retype__enq(struct retype_check_st *check_st);
+static void retype_check__rx(errval_t status, struct retype_check_st* check,
+                             struct retype_output_st *output, void *to_free);
+
+/**
+ * \brief Intermon is ready to send retype result
+ */
 static void
-request_retype_send_cont(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
+retype_result__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
 {
-    struct request_retype_msg_st *msg_st = (struct request_retype_msg_st*)e;
-    struct retype_st *rtst = msg_st->st;
-    assert(rtst);
-    errval_t err = intermon_capops_request_retype__tx(b, NOP_CONT, msg_st->caprep, rtst->type, rtst->objbits, (genvaddr_t)rtst);
-    if (err_is_fail(err)) {
-        rtst->result_handler(err, rtst->st);
-        free(rtst);
-    }
+    errval_t err;
+    struct requested_retype_st *req_st = (struct requested_retype_st*)e;
+    err = intermon_capops_retype_response__tx(b, NOP_CONT, req_st->status,
+                                              req_st->request_st);
+    PANIC_IF_ERR(err, "sending retype result message");
+    free(req_st);
 }
 
-static errval_t
-request_retype(retype_result_handler_t result_handler, struct retype_st *st)
+/**
+ * \brief Enqueue retype result
+ */
+static void
+retype_result__enq(struct requested_retype_st *req_st)
 {
-    errval_t err;
-    struct capability cap;
-    err = monitor_domains_cap_identify(st->src.croot, st->src.cptr, st->src.bits, &cap);
-    if (err_is_fail(err)) {
-        return err;
-    }
-
-    struct request_retype_msg_st *msg_st;
-    msg_st = malloc(sizeof(*msg_st));
-    if (!msg_st) {
-        return LIB_ERR_MALLOC_FAIL;
-    }
-    msg_st->queue_elem.cont = request_retype_send_cont;
-    msg_st->st = st;
-    capability_to_caprep(&cap, &msg_st->caprep);
-
-    err = capsend_owner(st->src, (struct msg_queue_elem*)msg_st);
+    req_st->queue_elem.cont = retype_result__send;
+    errval_t err = capsend_target(req_st->from, (struct msg_queue_elem*)req_st);
     if (err_is_fail(err)) {
-        free(msg_st);
+        DEBUG_ERR(err, "failed to enqueue retype result");
+        free(req_st);
     }
-    return err;
 }
 
-struct retype_result_st {
-    struct intermon_msg_queue_elem queue_elem;
-    struct capref src;
-    coreid_t from;
-    errval_t status;
-    genvaddr_t st;
-};
-
+/**
+ * \brief Retype temporary cap has been deleted
+ */
 static void
-retype_result_send_cont(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
+retype_tmpcap_delete__cont(errval_t status, void *st)
 {
     errval_t err;
-    struct retype_result_st *rtst = (struct retype_result_st*)e;
-    err = intermon_capops_retype_response__tx(b, NOP_CONT, rtst->status, rtst->st);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "failed to send retype_result message");
+    struct requested_retype_st *req_st = (struct requested_retype_st*)st;
+
+    if (err_is_fail(status) && err_no(status) != SYS_ERR_CAP_NOT_FOUND) {
+        DEBUG_ERR(status, "deleting tmp retype cap, cap will leak");
     }
-    free(rtst);
+
+    err = slot_free(req_st->src);
+    DEBUG_IF_ERR(err, "freeing tmp retype slot, slot will leak");
+    req_st->src = NULL_CAP;
+    memset(&req_st->check.src, 0, sizeof(struct domcapref));
+
+    retype_result__enq(req_st);
 }
 
+/**
+ * \brief The check for a retype request has completed
+ */
 static void
-retype_result_cont(errval_t status, void *st)
+retype_request_check__rx(errval_t status, void *st)
 {
     errval_t err;
-    struct retype_result_st *rtst = (struct retype_result_st*)st;
+    struct requested_retype_st *req_st = (struct requested_retype_st*)st;
+
     if (err_is_ok(status)) {
-        status = monitor_remote_relations(rtst->src, RRELS_DESC_BIT,
+        status = monitor_remote_relations(req_st->src, RRELS_DESC_BIT,
                                           RRELS_DESC_BIT, NULL);
     }
-    rtst->status = status;
-    rtst->queue_elem.cont = retype_result_send_cont;
-    err = capsend_target(rtst->from, (struct msg_queue_elem*)rtst);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "failed to enqueue retype_result");
+
+    req_st->status = status;
+
+    if (!capref_is_null(req_st->src)) {
+        err = capops_delete(req_st->check.src, retype_tmpcap_delete__cont, req_st);
+        if (err_is_fail(err)) {
+            retype_tmpcap_delete__cont(err, req_st);
+        }
+    }
+    else {
+        retype_result__enq(req_st);
     }
 }
 
 void
-request_retype__rx_handler(struct intermon_binding *b, intermon_caprep_t srcrep, int desttype, uint32_t destbits, genvaddr_t st)
+retype_request__rx(struct intermon_binding *b, intermon_caprep_t srcrep,
+                   int desttype, uint32_t destbits, genvaddr_t st)
 {
     errval_t err;
 
-    struct intermon_state *inter_st = (struct intermon_state*)b->st;
-    coreid_t from = inter_st->core_id;
+    // allocate and setup state
+    struct requested_retype_st *req_st;
+    err = calloce(1, sizeof(*req_st), &req_st);
+    PANIC_IF_ERR(err, "allocating retype request state");
+
+    req_st->queue_elem.cont = retype_result__send;
+    req_st->check.type = desttype;
+    req_st->check.objbits = destbits;
+    req_st->check.cont = MKRESCONT(retype_request_check__rx, req_st);
+    req_st->from = ((struct intermon_state*)b->st)->core_id;
+    req_st->request_st = st;
+
+    // get slot and cap
+    err = slot_alloc(&req_st->src);
+    GOTO_IF_ERR(err, cont_err);
+    req_st->check.src = get_cap_domref(req_st->src);
 
     struct capability cap;
     caprep_to_capability(&srcrep, &cap);
+    err = monitor_copy_if_exists(&cap, req_st->src);
+    GOTO_IF_ERR(err, cont_err);
 
-    struct retype_result_st *rtst;
-    rtst = calloc(1, sizeof(*rtst));
-    if (!rtst) {
-        USER_PANIC_ERR(LIB_ERR_MALLOC_FAIL, "could not allocate retype request reply state");
-    }
-    rtst->from = from;
-    rtst->st = st;
+    // validate cap state
+    distcap_state_t state;
+    err = dom_cnode_get_state(req_st->check.src, &state);
+    GOTO_IF_ERR(err, cont_err);
 
-    err = slot_alloc(&rtst->src);
-    if (err_is_fail(err)) {
-        goto reply_err;
+    if (distcap_state_is_foreign(state)) {
+        err = MON_ERR_CAP_FOREIGN;
+        goto cont_err;
     }
-
-    err = monitor_copy_if_exists(&cap, rtst->src);
-    if (err_is_fail(err)) {
-        goto free_slot;
+    if (distcap_state_is_busy(state)) {
+        err = MON_ERR_REMOTE_CAP_RETRY;
+        goto cont_err;
     }
 
-    distcap_state_t state;
-    err = cap_get_state(rtst->src, &state);
+    // initiate check
+    check_retype__enq(&req_st->check);
+
+    return;
+
+cont_err:
+    retype_request_check__rx(err, req_st);
+}
+
+static void
+retype_result__rx(errval_t status, struct retype_request_st *req_st)
+{
+    retype_check__rx(status, &req_st->check, &req_st->output, req_st);
+}
+
+/**
+ * \brief Handle the response to a retype request
+ */
+void
+retype_response__rx(struct intermon_binding *b, errval_t status, genvaddr_t st)
+{
+    struct retype_request_st *req_st = (struct retype_request_st*)st;
+    retype_result__rx(status, req_st);
+}
+
+/**
+ * \brief Intermon is ready to send request_retype
+ */
+static void
+retype_request__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
+{
+    struct retype_request_st *req_st = (struct retype_request_st*)e;
+    errval_t err;
+
+    err = intermon_capops_request_retype__tx(b, NOP_CONT, req_st->caprep,
+                                             req_st->check.type,
+                                             req_st->check.objbits,
+                                             (genvaddr_t)req_st);
+
     if (err_is_fail(err)) {
-        goto destroy_cap;
+        retype_result__rx(err, req_st);
     }
+}
 
-    if (distcap_state_is_foreign(state)) {
-        err = MON_ERR_CAP_FOREIGN;
-        goto destroy_cap;
-    }
+/**
+ * \brief Enqueue a retype request
+ */
+static void
+retype_request__enq(struct retype_request_st *req_st)
+{
+    errval_t err;
+    struct capability cap;
+    err = monitor_domains_cap_identify(req_st->check.src.croot,
+                                       req_st->check.src.cptr,
+                                       req_st->check.src.bits, &cap);
+    GOTO_IF_ERR(err, err_cont);
 
-    if (distcap_state_is_busy(state)) {
-        err = MON_ERR_REMOTE_CAP_RETRY;
-        goto destroy_cap;
+    req_st->queue_elem.cont = retype_request__send;
+    capability_to_caprep(&cap, &req_st->caprep);
+
+    err = capsend_owner(req_st->check.src, (struct msg_queue_elem*)req_st);
+    GOTO_IF_ERR(err, err_cont);
+
+    return;
+
+err_cont:
+    retype_result__rx(err, req_st);
+}
+
+/**
+ * \brief The descendants search has completed
+ */
+static void
+find_descendants__rx(errval_t status, void *st)
+{
+    struct retype_check_st *check_st = (struct retype_check_st*)st;
+
+    // need to translate error codes:
+    // - descendants found -> revoke first
+    // - not found -> ok
+    // - otherwise -> unchanged
+    if (err_is_ok(status)) {
+        status = SYS_ERR_REVOKE_FIRST;
+    }
+    else if (err_no(status) == SYS_ERR_CAP_NOT_FOUND) {
+        status = err_push(status, SYS_ERR_OK);
     }
 
-    if (desttype == ObjType_EndPoint) {
+    // unlock cap and procede with check result continuation
+    caplock_unlock(check_st->src);
+    CALLRESCONT(check_st->cont, status);
+}
+
+/**
+ * \brief Enqueue a retype check
+ */
+static void
+check_retype__enq(struct retype_check_st *check_st)
+{
+    errval_t err;
+
+    if (check_st->type == ObjType_EndPoint) {
         // XXX: because of the current "multi-retype" hack for endpoints, a
         // dispatcher->endpoint retype can happen irrespective of the existence
         // of descendents on any core.
-        err = monitor_remote_relations(rtst->src, RRELS_DESC_BIT,
-                                       RRELS_DESC_BIT, NULL);
-        goto destroy_cap;
+        err = monitor_domcap_remote_relations(check_st->src.croot,
+                                              check_st->src.cptr,
+                                              check_st->src.bits,
+                                              RRELS_DESC_BIT,
+                                              RRELS_DESC_BIT, NULL);
+        goto cont_err;
     }
 
-    struct domcapref domsrc = get_cap_domref(rtst->src);
-    err = monitor_lock_cap(domsrc.croot, domsrc.cptr, domsrc.bits);
-    if (err_is_fail(err)) {
-        goto destroy_cap;
-    }
+    err = monitor_lock_cap(check_st->src.croot, check_st->src.cptr,
+                           check_st->src.bits);
+    GOTO_IF_ERR(err, cont_err);
 
-    err = capsend_find_descendants(domsrc, retype_result_cont, rtst);
-    if (err_is_fail(err)) {
-        goto unlock_cap;
-    }
+    err = capsend_find_descendants(check_st->src, find_descendants__rx,
+                                   check_st);
+    GOTO_IF_ERR(err, unlock_cap);
 
     return;
 
 unlock_cap:
-    caplock_unlock(domsrc);
+    caplock_unlock(check_st->src);
 
-destroy_cap:
-    cap_delete(rtst->src);
-
-free_slot:
-    slot_free(rtst->src);
+cont_err:
+    CALLRESCONT(check_st->cont, err);
+}
 
-reply_err:
-    retype_result_cont(err, rtst);
+/**
+ * \brief Handle a completed retype check
+ */
+static void
+retype_check__rx(errval_t status, struct retype_check_st* check,
+                 struct retype_output_st *output, void *to_free)
+{
+    errval_t err = status;
+    if (err_is_ok(err)) {
+        // the retype may procede
+        struct domcapref *src = &check->src;
+        struct domcapref *destcn = &output->destcn;
+        assert(capcmp(src->croot, destcn->croot));
+        err = monitor_create_caps(src->croot, check->type, check->objbits,
+                                  src->cptr, src->bits, destcn->cptr,
+                                  destcn->bits, output->start_slot);
+    }
+    struct result_closure cont = output->cont;
+    assert(cont.handler);
+    free(to_free);
+    CALLRESCONT(cont, err);
 }
 
-void
-retype_response__rx_handler(struct intermon_binding *b, errval_t status, genvaddr_t st)
+/**
+ * \brief Handle result of a owner-initiated retype check.
+ */
+static void
+local_retype_check__rx(errval_t status, void *st)
 {
-    create_copies_cont(status, (void*)st);
+    struct local_retype_st *rtp_st = (struct local_retype_st*)st;
+    retype_check__rx(status, &rtp_st->check, &rtp_st->output, rtp_st);
 }
 
 /*
  * Entry
  */
 
-errval_t
+void
 capops_retype(enum objtype type, size_t objbits, struct capref croot,
               capaddr_t dest_cn, uint8_t dest_bits, cslot_t dest_slot,
               capaddr_t src, uint8_t src_bits,
               retype_result_handler_t result_handler, void *st)
 {
     errval_t err;
-
     distcap_state_t src_state;
+    struct retype_request_st *rtp_req_st;
+    struct local_retype_st *rtp_loc_st;
+
     err = invoke_cnode_get_state(croot, src, src_bits, &src_state);
-    if (err_is_fail(err)) {
-        return err;
-    }
+    GOTO_IF_ERR(err, err_cont);
 
     if (distcap_state_is_busy(src_state)) {
-        return MON_ERR_REMOTE_CAP_RETRY;
+        err = MON_ERR_REMOTE_CAP_RETRY;
+        goto err_cont;
     }
 
     err = invoke_cnode_retype(croot, src, type, objbits, dest_cn, dest_slot,
                               dest_bits);
     if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR) {
-        return err;
+        goto err_cont;
     }
 
     // if retype invocation failed with "retry through mon", we assume that
     // distcap_needs_locality(cap) would return true.
 
-    struct retype_st *rst = malloc(sizeof(struct retype_st));
-    rst->type = type;
-    rst->objbits = objbits;
-    rst->src = (struct domcapref){ .croot = croot, .cptr = src, .bits = src_bits };
-    rst->destcn = (struct domcapref){ .croot = croot, .cptr = dest_cn, .bits = dest_bits };
-    rst->start_slot = dest_slot;
-    rst->result_handler = result_handler;
-    rst->st = st;
-
     if (distcap_state_is_foreign(src_state)) {
-        err = request_retype(create_copies_cont, rst);
+        // setup retype request
+        err = calloce(1, sizeof(*rtp_req_st), &rtp_req_st);
+        GOTO_IF_ERR(err, err_cont);
+
+        // fill in parameters
+        rtp_req_st->check.type = type;
+        rtp_req_st->check.objbits = objbits;
+        rtp_req_st->check.src = (struct domcapref){
+            .croot = croot,
+            .cptr = src,
+            .bits = src_bits,
+        };
+        rtp_req_st->output.destcn = (struct domcapref){
+            .croot = croot,
+            .cptr = dest_cn,
+            .bits = dest_bits,
+        };
+        rtp_req_st->output.start_slot = dest_slot;
+        rtp_req_st->output.cont = MKRESCONT(result_handler, st);
+
+        // enqueue retype request
+        retype_request__enq(rtp_req_st);
     }
     else {
-        err = capsend_find_descendants(rst->src, create_copies_cont, rst);
+        // on owner, setup retype check
+        err = calloce(1, sizeof(*rtp_loc_st), &rtp_loc_st);
+        GOTO_IF_ERR(err, err_cont);
+
+        // fill in parameters
+        rtp_loc_st->check.type = type;
+        rtp_loc_st->check.objbits = objbits;
+        rtp_loc_st->check.src = (struct domcapref){
+            .croot = croot,
+            .cptr = src,
+            .bits = src_bits,
+        };
+        rtp_loc_st->output.destcn = (struct domcapref){
+            .croot = croot,
+            .cptr = dest_cn,
+            .bits = dest_bits,
+        };
+        rtp_loc_st->output.start_slot = dest_slot;
+        rtp_loc_st->output.cont = MKRESCONT(result_handler, st);
+
+        // setup handler for retype check result
+        rtp_loc_st->check.cont = MKRESCONT(local_retype_check__rx, rtp_loc_st);
+
+        // initiate check
+        check_retype__enq(&rtp_loc_st->check);
     }
 
-    if (err_is_fail(err)) {
-        free(rst);
-    }
+    return;
 
-    return err;
+err_cont:
+    result_handler(err, st);
 }
 
index b1947fd..dec20b2 100644 (file)
@@ -32,10 +32,10 @@ errval_t capops_revoke(struct domcapref cap,
                        revoke_result_handler_t result_handler, void *st);
 
 typedef void (*retype_result_handler_t)(errval_t, void*);
-errval_t capops_retype(enum objtype type, size_t objbits, struct capref croot,
-                       capaddr_t dest_cn, uint8_t dest_bits, cslot_t dest_slot,
-                       capaddr_t src, uint8_t src_bits, retype_result_handler_t
-                       result_handler, void *st);
+void capops_retype(enum objtype type, size_t objbits, struct capref croot,
+                   capaddr_t dest_cn, uint8_t dest_bits, cslot_t dest_slot,
+                   capaddr_t src, uint8_t src_bits,
+                   retype_result_handler_t result_handler, void *st);
 
 struct intermon_binding;
 errval_t capops_intermon_init(struct intermon_binding *b);
index bfc93b8..e75718b 100644 (file)
@@ -29,12 +29,8 @@ static void remote_cap_retype(struct monitor_blocking_binding *b,
                               uint64_t new_type, uint8_t size_bits,
                               capaddr_t to, capaddr_t slot, int32_t dcn_vbits)
 {
-    errval_t err;
-    err = capops_retype(new_type, size_bits, croot, to, dcn_vbits, slot, src,
-                        CPTR_BITS, retype_reply_status, (void*)b);
-    if (err_is_fail(err)) {
-        retype_reply_status(err, (void*)b);
-    }
+    capops_retype(new_type, size_bits, croot, to, dcn_vbits, slot, src,
+                  CPTR_BITS, retype_reply_status, (void*)b);
 }
 
 static void delete_reply_status(errval_t status, void *st)