Rewrote distributed revoke and delete handling.
authorMark Nevill <nevillm@ethz.ch>
Tue, 3 Jul 2012 19:45:54 +0000 (21:45 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 18 Jul 2013 13:00:06 +0000 (15:00 +0200)
25 files changed:
if/intermon.if
include/barrelfish_kpi/capabilities.h
kernel/Hakefile
kernel/arch/x86_64/syscall.c
kernel/cap_delete.c
kernel/include/capabilities.h
kernel/include/syscall.h
kernel/monitor.c [new file with mode: 0644]
kernel/syscall.c
usr/monitor/Hakefile
usr/monitor/capops/caplock.c
usr/monitor/capops/capsend.c
usr/monitor/capops/delete.c
usr/monitor/capops/delete_int.h [new file with mode: 0644]
usr/monitor/capops/deletestep.c [new file with mode: 0644]
usr/monitor/capops/init.c
usr/monitor/capops/internal.h
usr/monitor/capops/revoke.c
usr/monitor/include/arch/x86_64/monitor_invocations_arch.h
usr/monitor/include/capops.h
usr/monitor/include/capsend.h
usr/monitor/include/monitor_invocations.h
usr/monitor/inter.c
usr/monitor/invocations.c
usr/monitor/monitor_rpc_server.c

index d0eb2fe..f9590c7 100644 (file)
@@ -159,8 +159,10 @@ interface intermon "The Interface between monitors" {
     message capops_delete_remote(caprep cap, capop_st st);
     message capops_delete_remote_result(errval status, capop_st st);
 
-    message capops_request_revoke(caprep cap, capop_st st);
-    message capops_revoke_result(errval status, capop_st st);
+    message capops_revoke_mark(caprep cap, capop_st st);
+    message capops_revoke_ready(capop_st st);
+    message capops_revoke_commit(capop_st st);
+    message capops_revoke_done(capop_st st);
 
     // XXX: uint32 for bits? -MN
     message capops_request_retype(caprep src, int desttype, uint32 destbits, capop_st st);
index 93b4834..d23cf01 100644 (file)
@@ -143,10 +143,12 @@ enum kernel_cmd {
     KernelCmd_Lock_cap,
     KernelCmd_Unlock_cap,
     KernelCmd_Delete_last,
-    KernelCmd_Revoke_step,
+    KernelCmd_Revoke_mark_target,
+    KernelCmd_Revoke_mark_relations,
+    KernelCmd_Delete_step,
     KernelCmd_Clear_step,
     KernelCmd_Retype,
-    KernelCmd_Has_Descendants,
+    KernelCmd_Has_descendants,
     KernelCmd_Sync_timer,
     KernelCmd_Spawn_SCC_Core,
     KernelCmd_IPI_Register,
index a540b42..7ed6320 100644 (file)
@@ -31,7 +31,7 @@ let
     indep_cfiles = [ "gdb_stub.c", "capabilities.c", "cap_delete.c",
                      "dispatch.c", scheduler, "memset.c", "memmove.c",
                      "printf.c", "startup.c", "stdlib.c", "string.c",
-                     "syscall.c", "wakeup.c" ]
+                     "syscall.c", "monitor.c", "wakeup.c" ]
                      ++ microbench ++ timer
     indep_libs = [ "getopt", "mdb_kernel" ]
     mkrules arch arch_cfiles arch_sfiles mackerelFiles arch_libs arch_absolute_cfiles arch_absolute_sfiles realarch_cfiles realarch_sfiles = (
index 8dee994..0806e90 100644 (file)
@@ -204,39 +204,58 @@ static struct sysret monitor_handle_has_descendants(struct capability *kernel_ca
     };
 }
 
-/// Different handler for cap operations performed by the monitor
-static struct sysret monitor_handle_revoke_step(struct capability *kernel_cap,
+static struct sysret monitor_handle_delete_last(struct capability *kernel_cap,
                                                 int cmd, uintptr_t *args)
 {
     capaddr_t root_caddr = args[0];
     uint8_t root_vbits = args[1];
-
     capaddr_t target_caddr = args[2];
     uint8_t target_vbits = args[3];
+    capaddr_t retcn_caddr = args[4];
+    uint8_t retcn_vbits = args[5];
+    cslot_t ret_slot = args[6];
 
-    capaddr_t delcn_addr = args[4];
-    uint8_t delcn_vbits = args[5];
-    cslot_t del_slot = args[6];
-
-    return sys_monitor_revoke_step(root_caddr, root_vbits,
-                                   target_caddr, target_vbits,
-                                   delcn_addr, delcn_vbits, del_slot);
+    return sys_monitor_delete_last(root_caddr, root_vbits, target_caddr,
+                                   target_vbits, retcn_caddr, retcn_vbits,
+                                   ret_slot);
 }
 
-static struct sysret monitor_handle_delete_last(struct capability *kernel_cap,
-                                                int cmd, uintptr_t *args)
+static struct sysret monitor_handle_revoke_mark_tgt(struct capability *kernel_cap,
+                                                    int cmd, uintptr_t *args)
 {
     capaddr_t root_caddr = args[0];
     uint8_t root_vbits = args[1];
     capaddr_t target_caddr = args[2];
     uint8_t target_vbits = args[3];
-    capaddr_t retcn_caddr = args[4];
-    uint8_t retcn_vbits = args[5];
-    cslot_t ret_slot = args[6];
 
-    return sys_monitor_delete_last(root_caddr, root_vbits, target_caddr,
-                                   target_vbits, retcn_caddr, retcn_vbits,
-                                   ret_slot);
+    return sys_monitor_revoke_mark_tgt(root_caddr, root_vbits,
+                                       target_caddr, target_vbits);
+}
+
+static struct sysret monitor_handle_revoke_mark_rels(struct capability *kernel_cap,
+                                                     int cmd, uintptr_t *args)
+{
+    struct capability *base = (struct capability*)args;
+
+    return sys_monitor_revoke_mark_rels(base);
+}
+
+static struct sysret monitor_handle_delete_step(struct capability *kernel_cap,
+                                                int cmd, uintptr_t *args)
+{
+    capaddr_t ret_cn_addr = args[0];
+    capaddr_t ret_cn_bits = args[1];
+    capaddr_t ret_slot = args[2];
+    return sys_monitor_delete_step(ret_cn_addr, ret_cn_bits, ret_slot);
+}
+
+static struct sysret monitor_handle_clear_step(struct capability *kernel_cap,
+                                               int cmd, uintptr_t *args)
+{
+    capaddr_t ret_cn_addr = args[0];
+    capaddr_t ret_cn_bits = args[1];
+    capaddr_t ret_slot = args[2];
+    return sys_monitor_clear_step(ret_cn_addr, ret_cn_bits, ret_slot);
 }
 
 static struct sysret monitor_handle_register(struct capability *kernel_cap,
@@ -790,9 +809,12 @@ static invocation_handler_t invocations[ObjType_Num][CAP_MAX_CMD] = {
         [KernelCmd_Lock_cap]     = monitor_lock_cap,
         [KernelCmd_Unlock_cap]   = monitor_unlock_cap,
         [KernelCmd_Retype]       = monitor_handle_retype,
-        [KernelCmd_Has_Descendants] = monitor_handle_has_descendants,
+        [KernelCmd_Has_descendants] = monitor_handle_has_descendants,
         [KernelCmd_Delete_last]  = monitor_handle_delete_last,
-        [KernelCmd_Revoke_step]  = monitor_handle_revoke_step,
+        [KernelCmd_Revoke_mark_target] = monitor_handle_revoke_mark_tgt,
+        [KernelCmd_Revoke_mark_relations] = monitor_handle_revoke_mark_rels,
+        [KernelCmd_Delete_step] = monitor_handle_delete_step,
+        [KernelCmd_Clear_step] = monitor_handle_clear_step,
         [KernelCmd_Sync_timer]   = monitor_handle_sync_timer,
         [KernelCmd_IPI_Register] = kernel_ipi_register,
         [KernelCmd_IPI_Delete]   = kernel_ipi_delete
index 4a7626b..95b7cb4 100644 (file)
 #include <wakeup.h>
 
 struct cte *clear_head, *clear_tail;
-struct cte *delete_head;
+struct cte *delete_head, *delete_tail;
 
+static errval_t caps_try_delete(struct cte *cte);
 static errval_t cleanup_copy(struct cte *cte);
 static errval_t cleanup_last(struct cte *cte, struct cte *ret_ram_cap);
-static errval_t cleanup_last_dcb(struct cte *cte);
+static void caps_mark_revoke_copy(struct cte *cte);
+static void caps_mark_revoke_generic(struct cte *cte);
+static void clear_list_append(struct cte *cte);
+static errval_t caps_copyout_last(struct cte *target, struct cte *ret_cte);
 
 /**
  * \brief Try a "simple" delete of a cap. If this fails, the monitor needs to
@@ -42,11 +46,10 @@ static errval_t cleanup_last_dcb(struct cte *cte);
  */
 static errval_t caps_try_delete(struct cte *cte)
 {
-    if (distcap_is_in_delete(cte)) {
-        // already in process of being deleted
+    if (distcap_is_in_delete(cte) || cte->mdbnode.locked) {
+        // locked or already in process of being deleted
         return SYS_ERR_CAP_LOCKED;
     }
-
     if (distcap_is_foreign(cte) || has_copies(cte)) {
         return cleanup_copy(cte);
     }
@@ -84,33 +87,51 @@ errval_t caps_delete_last(struct cte *cte, struct cte *ret_ram_cap)
         return err;
     }
 
-    if (cte->cap.type == ObjType_CNode ||
-        cte->cap.type == ObjType_Dispatcher)
-    {
-        // CNodes and dcbs contain further CTEs, so cannot simply be deleted
-        // instead, we place them in a clear list, which is progressivly worked
-        // through until each list element contains only ctes that point to
-        // other CNodes or dcbs, at which point they are scheduled for final
-        // deletion, which only happens when the clear lists are empty.
-
-        if (cte->cap.type == ObjType_Dispatcher) {
-            err = cleanup_last_dcb(cte);
-            if (err_is_fail(err)) {
-                return err;
-            }
+    // CNodes and dcbs contain further CTEs, so cannot simply be deleted
+    // instead, we place them in a clear list, which is progressivly worked
+    // through until each list element contains only ctes that point to
+    // other CNodes or dcbs, at which point they are scheduled for final
+    // deletion, which only happens when the clear lists are empty.
+
+    if (cte->cap.type == ObjType_CNode) {
+        // Mark all non-Null slots for deletion
+        for (cslot_t i = 0; i < (1<<cte->cap.u.cnode.bits); i++) {
+            struct cte *slot = caps_locate_slot(cte->cap.u.cnode.cnode, i);
+            caps_mark_revoke_generic(slot);
         }
 
-        // insert at tail of cleanup list
-        distcap_set_deleted(cte);
-        if (clear_tail) {
-            clear_tail->delete_node.next = cte;
+        clear_list_append(cte);
+
+        return SYS_ERR_OK;
+    }
+    else if (cte->cap.type == ObjType_Dispatcher)
+    {
+        struct capability *cap = &cte->cap;
+        struct dcb *dcb = cap->u.dispatcher.dcb;
+
+        // Remove from queue
+        scheduler_remove(dcb);
+        // Reset curent if it was deleted
+        if (dcb_current == dcb) {
+            dcb_current = NULL;
         }
-        else {
-            assert(!clear_head);
-            clear_head = cte;
+
+        // Remove from wakeup queue
+        wakeup_remove(dcb);
+
+        // Notify monitor
+        if (monitor_ep.u.endpoint.listener == dcb) {
+            printk(LOG_ERR, "monitor terminated; expect badness!\n");
+            monitor_ep.u.endpoint.listener = NULL;
+        } else if (monitor_ep.u.endpoint.listener != NULL) {
+            uintptr_t payload = dcb->domain_id;
+            err = lmp_deliver_payload(&monitor_ep, NULL, &payload, 1, false);
+            assert(err_is_ok(err));
         }
-        clear_tail = cte;
-        memset(&cte->delete_node, 0, sizeof(cte->delete_node));
+
+        caps_mark_revoke_generic(&dcb->cspace);
+        caps_mark_revoke_generic(&dcb->disp_cte);
+        clear_list_append(cte);
 
         return SYS_ERR_OK;
     }
@@ -253,281 +274,271 @@ cleanup_last(struct cte *cte, struct cte *ret_ram_cap)
     return SYS_ERR_OK;
 }
 
-/**
- * \brief Remove dispatcher from system
+/*
+ * Mark phase of revoke mark & sweep
  */
-static errval_t
-cleanup_last_dcb(struct cte *cte)
+
+static void caps_mark_revoke_copy(struct cte *cte)
 {
-    printk(LOG_WARN, "cleanup_dcb: NYI\n");
+    errval_t err;
+    err = caps_try_delete(cte);
+    if (err_is_fail(err)) {
+        // this should not happen as there is a copy of the cap
+        panic("error while marking/deleting cap copy for revoke:"
+              " 0x%"PRIxGENPADDR"\n", err);
+    }
+}
 
-    struct capability *cap = &cte->cap;
-    struct dcb *dcb = cap->u.dispatcher.dcb;
-    // NOTE: do not clear CTEs in dcb as they are processed later
-
-    // Remove from queue
-    scheduler_remove(dcb);
-    // Reset curent if it was deleted
-    if (dcb_current == dcb) {
-        dcb_current = NULL;
-    }
-
-    // Remove from wakeup queue
-    wakeup_remove(dcb);
-
-    // Notify monitor
-    if (monitor_ep.u.endpoint.listener == dcb) {
-        printk(LOG_ERR, "monitor terminated; expect badness!\n");
-        monitor_ep.u.endpoint.listener = NULL;
-    } else if (monitor_ep.u.endpoint.listener != NULL) {
-        errval_t err;
-        uintptr_t payload = dcb->domain_id;
-        err = lmp_deliver_payload(&monitor_ep, NULL, &payload, 1, false);
-        assert(err_is_ok(err));
+static void caps_mark_revoke_generic(struct cte *cte)
+{
+    errval_t err;
+
+    if (cte->cap.type == ObjType_Null) {
+        return;
+    }
+    if (distcap_is_in_delete(cte)) {
+        return;
     }
 
-    return SYS_ERR_OK;
-}
+    err = caps_try_delete(cte);
+    if (err_no(err) == SYS_ERR_DELETE_LAST_OWNED)
+    {
+        cte->mdbnode.in_delete = true;
+        //cte->delete_node.next_slot = 0;
+
+        // insert into delete list
+        if (!delete_tail) {
+            assert(!delete_head);
+            delete_head = delete_tail = cte;
+            cte->delete_node.next = NULL;
+        }
+        else {
+            assert(delete_head);
+            assert(!delete_tail->delete_node.next);
+            delete_tail->delete_node.next = cte;
+            delete_tail = cte;
+        }
 
-static errval_t caps_copyout_last(struct cte *target, struct cte *ret_cte);
-static errval_t caps_clear_next_cnode(struct cte *cnode, struct cte *ret_next);
-static errval_t caps_clear_next_dispatcher(struct cte *dispatcher, struct cte *ret_next);
+        // because the monitors will perform a 2PC that deletes all foreign
+        // copies before starting the delete steps, and because the in_delete
+        // bit marks this cap as "busy" (see distcap_get_state), we can clear
+        // the remote copies bit.
+        cte->mdbnode.remote_copies = 0;
+    }
+    else if (err_is_fail(err)) {
+        // some serious mojo went down in the cleanup voodoo
+        panic("error while marking/deleting descendant cap for revoke:"
+              " 0x%"PRIxGENPADDR"\n", err);
+    }
+}
 
-/*
- * \brief Delete next element in cleared cnode/dcb graph
+/**
+ * \brief Mark capabilities for a revoke operation.
+ * \param base The data for the capability being revoked
+ * \param revoked The revoke target if it is on this core. This specific
+ *        capability copy will not be marked. If supplied, is_copy(base,
+ *        &revoked->cap) must hold.
+ * \returns
+ *        - CAP_NOT_FOUND if no copies or desendants are present on this core.
+ *        - SYS_ERR_OK otherwise.
  */
-
-errval_t caps_continue_clear(struct cte *ret_next)
+errval_t caps_mark_revoke(struct capability *base, struct cte *revoked)
 {
-    errval_t err = SYS_ERR_OK;
-    assert(ret_next->cap.type == ObjType_Null);
-
-    while (clear_head) {
-        // get next element from clear list head
-        struct cte *current = clear_head;
+    assert(base);
+    assert(!revoked || revoked->mdbnode.owner == my_core_id);
+
+    // to avoid multiple mdb_find_greater, we store the predecessor of the
+    // current position
+    struct cte *prev = mdb_find_greater(base, true), *next = NULL;
+    if (!prev || !(is_copy(base, &prev->cap)
+                   || is_ancestor(&prev->cap, base)))
+    {
+        return SYS_ERR_CAP_NOT_FOUND;
+    }
 
-        // clear cap as far as possible
-        switch (current->cap.type) {
-        case ObjType_CNode:
-            err = caps_clear_next_cnode(current, ret_next);
-            break;
-        case ObjType_Dispatcher:
-            err = caps_clear_next_dispatcher(current, ret_next);
-            break;
-        default:
-            printk(LOG_ERR, "Unexpected cap type in delete_next");
-            break;
+    for (next = mdb_successor(prev);
+         next && is_copy(base, &next->cap);
+         next = mdb_successor(prev))
+    {
+        // note: if next is a copy of base, prev will also be a copy
+        if (next == revoked) {
+            // do not delete the revoked capability, use it as the new prev
+            // instead, and delete the old prev.
+            next = prev;
+            prev = revoked;
         }
+        assert(revoked || next->mdbnode.owner != my_core_id);
+        caps_mark_revoke_copy(next);
+    }
 
-        if (err_is_fail(err)) {
-            return err;
+    for (next = mdb_successor(prev);
+         next && is_ancestor(&next->cap, base);
+         next = mdb_successor(prev))
+    {
+        caps_mark_revoke_generic(next);
+        if (next->cap.type) {
+            // the cap has not been deleted, so we must use it as the new prev
+            prev = next;
         }
+    }
 
-        // cap was cleared successfully, now contains only other cnodes and
-        // dcbs marked as deleted
-
-        // remove element from clear list head
-        if (clear_tail == current) {
-            assert(clear_head == current);
-            clear_head = clear_tail = NULL;
+    if (prev != revoked && !prev->mdbnode.in_delete) {
+        if (is_copy(base, &prev->cap)) {
+            caps_mark_revoke_copy(prev);
         }
         else {
-            clear_head = current->delete_node.next;
+            // due to early termination the condition, prev must be a
+            // descendant
+            assert(is_ancestor(&prev->cap, base));
+            caps_mark_revoke_generic(prev);
         }
-        memset(&current->delete_node, 0, sizeof(current->delete_node));
-
-        // put element on "final delete" queue
-        current->delete_node.next = delete_head;
-        delete_head = current;
-    };
-
-    assert(!clear_head);
-    assert(!clear_tail);
-
-    if (delete_head) {
-        struct cte *cleared = delete_head;
-        delete_head = cleared->delete_node.next;
-        return cleanup_last(delete_head, ret_next);
     }
 
     return SYS_ERR_OK;
 }
 
-static errval_t caps_copyout_last(struct cte *target, struct cte *ret_cte)
-{
-    errval_t err;
+/*
+ * Sweep phase
+ */
 
-    // create a copy in slot specified by the caller, then delete
-    // `next` slot so the new copy is still the last copy.
-    err = caps_copy_to_cte(ret_cte, target, false, 0, 0);
-    if (err_is_fail(err)) {
-        return err;
+static void clear_list_append(struct cte *cte)
+{
+    if (!clear_tail) {
+        assert(!clear_head);
+        clear_head = clear_tail = cte;
     }
-
-    err = cleanup_copy(target);
-    if (err_is_fail(err)) {
-        return err;
+    else {
+        assert(clear_head);
+        clear_tail = clear_tail->delete_node.next = cte;
     }
-
-    return SYS_ERR_OK;
+    cte->delete_node.next = NULL;
 }
 
-static errval_t
-caps_clear_next_cnode(struct cte *cte, struct cte *ret_next)
+errval_t caps_delete_step(struct cte *ret_next)
 {
     errval_t err = SYS_ERR_OK;
 
-    assert(cte->cap.type == ObjType_CNode);
-    struct CNode *cnode = &cte->cap.u.cnode;
-    size_t size = 1 << cnode->bits;
-    cslot_t index = cte->delete_node.next_slot;
+    assert(ret_next);
+    assert(ret_next->cap.type == ObjType_Null);
 
-    if (index > size) {
-        printk(LOG_ERR, "Unexpected delete index into cnode slots");
-        return SYS_ERR_OK;
+    if (!delete_head) {
+        return SYS_ERR_CAP_NOT_FOUND;
     }
+    assert(delete_head->mdbnode.in_delete);
 
-    // iterate through remaining slots until all are cleared or an issue is
-    // encountered
-    for (; err_is_ok(err) && index < size; index++) {
-        // determine slot for current index
-        struct cte *current = caps_locate_slot(cnode->cnode, index);
-
-        if (current->cap.type == ObjType_Null) {
-            // skip empty slots
-            continue;
-        }
-
-        // try simple delete
-        err = caps_try_delete(current);
-
-        if (err_no(err) == SYS_ERR_DELETE_LAST_OWNED) {
-            // create a copy in slot specified by the caller, then delete
-            // `next` slot so the new copy is still the last copy.
-            err = caps_copyout_last(current, ret_next);
-            assert(err_is_ok(err));
-
-            return SYS_ERR_DELETE_LAST_OWNED;
+    struct cte *cte = delete_head, *next = cte->delete_node.next;
+    if (cte->mdbnode.locked) {
+        err = SYS_ERR_CAP_LOCKED;
+    }
+    else if (distcap_is_foreign(cte) || has_copies(cte)) {
+        err = cleanup_copy(cte);
+    }
+    else if (cte->mdbnode.remote_copies) {
+        err = caps_copyout_last(cte, ret_next);
+        if (err_is_ok(err)) {
+            delete_head = next;
+            err = SYS_ERR_DELETE_LAST_OWNED;
         }
     }
+    else {
+        err = caps_delete_last(cte, ret_next);
+    }
 
+    if (err_is_ok(err)) {
+        delete_head = next;
+    }
     return err;
 }
 
-static errval_t
-caps_clear_next_dispatcher(struct cte *cte, struct cte *ret_next)
+errval_t caps_clear_step(struct cte *ret_ram_cap)
 {
-    errval_t err = SYS_ERR_OK;
-    assert(cte->cap.type == ObjType_Dispatcher);
-    cslot_t index = cte->delete_node.next_slot;
-    struct dcb *dcb = cte->cap.u.dispatcher.dcb;
-    size_t size = 2; // dcb has 2 slots
+    errval_t err;
+    assert(!delete_head);
+    assert(!delete_tail);
 
-    if (index > size) {
-        printk(LOG_ERR, "Unexpected delete index into dcb slots");
-        return SYS_ERR_OK;
+    if (!clear_head) {
+        assert(!clear_tail);
+        return SYS_ERR_CAP_NOT_FOUND;
     }
-
-    for (; err_is_ok(err) && index < size; index++) {
-        // determine slot for current index
-        struct cte *current;
-        switch (index) {
-        case 0:
-            current = &dcb->cspace;
-            break;
-        case 1:
-            current = &dcb->disp_cte;
-            break;
-        default:
-            assert(false);
-        }
-
-        if (current->cap.type == ObjType_Null) {
-            // skip empty slots
-            continue;
+    assert((clear_head == clear_tail) == (!clear_head->delete_node.next));
+
+    struct cte *cte = clear_head;
+
+#ifndef NDEBUG
+    // some sanity checks
+#define CHECK_SLOT(slot) do { \
+    assert((slot)->cap.type == ObjType_Null \
+           || (slot)->cap.type == ObjType_CNode \
+           || (slot)->cap.type == ObjType_Dispatcher); \
+    if ((slot)->cap.type != ObjType_Null) { \
+        assert((slot)->mdbnode.in_delete); \
+    } \
+} while (0)
+
+    if (cte->cap.type == ObjType_CNode) {
+        for (cslot_t i = 0; i < (1<<cte->cap.u.cnode.bits); i++) {
+            struct cte *slot = caps_locate_slot(cte->cap.u.cnode.cnode, i);
+            CHECK_SLOT(slot);
         }
+    }
+    else if (cte->cap.type == ObjType_Dispatcher) {
+        struct dcb *dcb = cte->cap.u.dispatcher.dcb;
+        CHECK_SLOT(&dcb->cspace);
+        CHECK_SLOT(&dcb->disp_cte);
+    }
+    else {
+        panic("Non-CNode/Dispatcher cap type in clear list!");
+    }
 
-        // try simple delete
-        err = caps_try_delete(current);
+#undef CHECK_SLOT
+#endif
 
-        if (err_no(err) == SYS_ERR_DELETE_LAST_OWNED) {
-            // create a copy in slot specified by the caller, then delete
-            // `next` slot so the new copy is still the last copy.
-            err = caps_copyout_last(current, ret_next);
-            assert(err_is_ok(err));
+    struct cte *after = cte->delete_node.next;
+    err = cleanup_last(cte, ret_ram_cap);
+    if (err_is_ok(err)) {
+        if (after) {
+            clear_head = after;
+        }
+        else {
+            clear_head = clear_tail = NULL;
         }
     }
-
     return err;
 }
 
-errval_t caps_continue_revoke(struct cte *target, struct cte *ret_next)
+static errval_t caps_copyout_last(struct cte *target, struct cte *ret_cte)
 {
     errval_t err;
 
-    assert(ret_next);
-    assert(ret_next->cap.type == ObjType_Null);
-
-    // delete copies backwards
-    struct cte *next = mdb_predecessor(target);
-    while (next && is_copy(&next->cap, &target->cap)) {
-        err = cleanup_copy(next);
-        if (err_is_fail(err)) {
-            printk(LOG_WARN, "Error during revoke: %"PRIuPTR"\n", err);
-            return err;
-        }
-        next = mdb_predecessor(target);
-    }
-
-    // delete copies forwards
-    next = mdb_successor(target);
-    while (next && is_copy(&next->cap, &target->cap)) {
-        err = cleanup_copy(next);
-        if (err_is_fail(err)) {
-            printk(LOG_WARN, "Error during revoke: %"PRIuPTR"\n", err);
-            return err;
-        }
-        next = mdb_successor(target);
+    // create a copy in slot specified by the caller, then delete
+    // `next` slot so the new copy is still the last copy.
+    err = caps_copy_to_cte(ret_cte, target, false, 0, 0);
+    if (err_is_fail(err)) {
+        return err;
     }
 
-    // delete descendants
-    while (next && is_ancestor(&next->cap, &target->cap)) {
-        // recursing here ensures leaves are fully deleted before their parents
-        err = caps_continue_revoke(next, ret_next);
-        if (err_is_fail(err)) {
-            if (err_no(err) == SYS_ERR_DELETE_LAST_OWNED) {
-                assert(ret_next->cap.type != ObjType_Null);
-            }
-            return err;
-        }
-
-        // try simple delete
-        err = caps_try_delete(next);
-
-        if (err_no(err) == SYS_ERR_DELETE_LAST_OWNED) {
-            // create a copy in slot specified by the caller, then delete
-            // `next` slot so the new copy is still the last copy.
-            err = caps_copyout_last(next, ret_next);
-            assert(err_is_ok(err));
-
-            return SYS_ERR_DELETE_LAST_OWNED;
-        }
-        if (err_is_fail(err)) {
-            return err;
-        }
-
-        next = mdb_successor(target);
+    err = cleanup_copy(target);
+    if (err_is_fail(err)) {
+        return err;
     }
 
     return SYS_ERR_OK;
 }
 
+/*
+ * CNode invocations
+ */
+
 errval_t caps_delete(struct cte *cte)
 {
     errval_t err;
 
     TRACE_CAP_MSG("deleting", cte);
 
+    if (cte->mdbnode.locked) {
+        return SYS_ERR_CAP_LOCKED;
+    }
+
     err = caps_try_delete(cte);
     if (err_no(err) == SYS_ERR_DELETE_LAST_OWNED) {
         err = err_push(err, SYS_ERR_RETRY_THROUGH_MONITOR);
index fc447ec..44a80b3 100644 (file)
@@ -30,7 +30,7 @@ struct cte;
 
 struct delete_list {
     struct cte *next;
-    cslot_t next_slot;
+    //cslot_t next_slot;
 };
 
 STATIC_ASSERT((sizeof(struct capability) + sizeof(struct mdbnode)
@@ -87,19 +87,26 @@ errval_t is_retypeable(struct cte *src_cte,
                        enum objtype dest_type,
                        bool from_monitor);
 
-errval_t caps_delete_last(struct cte *cte, struct cte *ret_ram_cap);
-errval_t caps_continue_clear(struct cte *ret_next);
-errval_t caps_continue_revoke(struct cte *target, struct cte *ret_next);
-errval_t caps_delete(struct cte *cte);
-errval_t caps_revoke(struct cte *cte);
-
 errval_t caps_lookup_cap(struct capability *cnode_cap, capaddr_t cptr,
                          uint8_t vbits, struct capability **ret,
                          CapRights rights);
 errval_t caps_lookup_slot(struct capability *cnode_cap, capaddr_t cptr,
                           uint8_t vbits, struct cte **ret, CapRights rights);
-void mdb_remove_recursively(struct cte *cte);
-void mdb_insert_recursively(struct cte *cte);
+
+/*
+ * Delete and revoke
+ */
+
+errval_t caps_delete_last(struct cte *cte, struct cte *ret_ram_cap);
+errval_t caps_mark_revoke(struct capability *base, struct cte *revoked);
+errval_t caps_delete_step(struct cte *ret_next);
+errval_t caps_clear_step(struct cte *ret_ram_cap);
+errval_t caps_delete(struct cte *cte);
+errval_t caps_revoke(struct cte *cte);
+
+/*
+ * Cap tracing
+ */
 
 #ifdef TRACE_PMEM_CAPS
 static inline bool caps_should_trace(struct capability *cap)
index 944c2ca..65f6ee2 100644 (file)
@@ -44,8 +44,18 @@ sys_copy_or_mint(struct capability *root, capaddr_t destcn_cptr, cslot_t dest_sl
 struct sysret sys_delete(struct capability *root, capaddr_t cptr, uint8_t bits);
 struct sysret sys_revoke(struct capability *root, capaddr_t cptr, uint8_t bits);
 struct sysret sys_get_state(struct capability *root, capaddr_t cptr, uint8_t bits);
+struct sysret
+sys_dispatcher_setup_guest (struct capability *to,
+                            capaddr_t epp, capaddr_t vnodep,
+                            capaddr_t vmcbp, capaddr_t ctrlp);
+struct sysret sys_trace_setup(struct capability *cap, capaddr_t cptr);
+
+/*
+ * Monitor syscalls
+ */
+
 struct sysret sys_monitor_register(capaddr_t ep_caddr);
-struct sysret sys_cap_has_relations(capaddr_t caddr, uint8_t vbits, uint8_t mask);
+struct sysret sys_monitor_domain_id(capaddr_t cptr, domainid_t domain_id);
 struct sysret sys_monitor_remote_relations(capaddr_t root_addr, uint8_t root_bits,
                                            capaddr_t cptr, uint8_t bits,
                                            uint8_t relations, uint8_t mask);
@@ -53,28 +63,39 @@ struct sysret sys_monitor_identify_cap(struct capability *root,
                                        capaddr_t cptr, uint8_t bits,
                                        struct capability *retbuf);
 struct sysret sys_monitor_nullify_cap(capaddr_t cptr, uint8_t bits);
-struct sysret
-sys_dispatcher_setup_guest (struct capability *to,
-                            capaddr_t epp, capaddr_t vnodep,
-                            capaddr_t vmcbp, capaddr_t ctrlp);
-struct sysret sys_monitor_domain_id(capaddr_t cptr, domainid_t domain_id);
-struct sysret sys_get_cap_owner(capaddr_t root_addr, uint8_t root_bits, capaddr_t cptr, uint8_t bits);
-struct sysret sys_set_cap_owner(capaddr_t root_addr, uint8_t root_bits, capaddr_t cptr, uint8_t bits, coreid_t owner);
-struct sysret sys_lock_cap(capaddr_t root_addr, uint8_t root_bits, capaddr_t cptr, uint8_t bits);
-struct sysret sys_unlock_cap(capaddr_t root_addr, uint8_t root_bits, capaddr_t cptr, uint8_t bits);
+struct sysret sys_get_cap_owner(capaddr_t root_addr, uint8_t root_bits,
+                                capaddr_t cptr, uint8_t bits);
+struct sysret sys_set_cap_owner(capaddr_t root_addr, uint8_t root_bits,
+                                capaddr_t cptr, uint8_t bits, coreid_t owner);
+struct sysret sys_cap_has_relations(capaddr_t caddr, uint8_t vbits, uint8_t mask);
+struct sysret sys_lock_cap(capaddr_t root_addr, uint8_t root_bits,
+                           capaddr_t cptr, uint8_t bits);
+struct sysret sys_unlock_cap(capaddr_t root_addr, uint8_t root_bits,
+                             capaddr_t cptr, uint8_t bits);
 struct sysret sys_monitor_copy_existing(struct capability *src,
                                         capaddr_t cnode_cptr,
                                         uint8_t cnode_vbits,
                                         cslot_t slot);
+
+/*
+ * Monitor syscalls for delete & revoke
+ */
+
 struct sysret sys_monitor_delete_last(capaddr_t root_addr, uint8_t root_bits,
                                       capaddr_t target_addr, uint8_t target_bits,
                                       capaddr_t ret_cn_addr, uint8_t ret_cn_bits,
                                       cslot_t ret_slot);
-struct sysret sys_monitor_revoke_step(capaddr_t root_addr, uint8_t root_bits,
-                                      capaddr_t target_addr, uint8_t target_bits,
-                                      capaddr_t del_cn_addr, uint8_t del_cn_bits,
-                                      cslot_t del_slot);
-struct sysret sys_monitor_clear_step(capaddr_t ret_cn_addr, uint8_t ret_cn_bits, cslot_t ret_slot);
+struct sysret sys_monitor_revoke_mark_tgt(capaddr_t root_addr,
+                                          uint8_t root_bits,
+                                          capaddr_t target_addr,
+                                          uint8_t target_bits);
+struct sysret sys_monitor_revoke_mark_rels(struct capability *base);
+struct sysret sys_monitor_delete_step(capaddr_t ret_cn_addr,
+                                      uint8_t ret_cn_bits,
+                                      cslot_t ret_slot);
+struct sysret sys_monitor_clear_step(capaddr_t ret_cn_addr,
+                                     uint8_t ret_cn_bits,
+                                     cslot_t ret_slot);
 struct sysret sys_trace_setup(struct capability *cap, capaddr_t cptr);
 struct sysret sys_idcap_identify(struct capability *cap, idcap_id_t *id);
 
diff --git a/kernel/monitor.c b/kernel/monitor.c
new file mode 100644 (file)
index 0000000..8301fba
--- /dev/null
@@ -0,0 +1,442 @@
+/**
+ * \file
+ * \brief Arch-generic system calls implementation.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <stdio.h>
+#include <string.h>
+#include <syscall.h>
+#include <barrelfish_kpi/syscalls.h>
+//#include <capabilities.h>
+//#include <mdb/mdb.h>
+#include <mdb/mdb_tree.h>
+//#include <cap_predicates.h>
+#include <dispatch.h>
+#include <distcaps.h>
+//#include <wakeup.h>
+//#include <paging_kernel_helper.h>
+//#include <exec.h>
+//#include <irq.h>
+//#include <trace/trace.h>
+
+static errval_t sys_double_lookup(capaddr_t rptr, uint8_t rbits,
+                                  capaddr_t tptr, uint8_t tbits,
+                                  struct cte **cte);
+static errval_t sys_retslot_lookup(capaddr_t cnptr, uint8_t cnbits,
+                                   cslot_t slot, struct cte **cte);
+
+struct sysret sys_monitor_register(capaddr_t ep_caddr)
+{
+    errval_t err;
+    struct capability *ep;
+    err = caps_lookup_cap(&dcb_current->cspace.cap, ep_caddr, CPTR_BITS, &ep,
+                          CAPRIGHTS_READ);
+
+    if(err_is_fail(err)) {
+        printf("Failure looking up endpoint!\n");
+        return SYSRET(err);
+    }
+
+    monitor_ep = *ep;
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+struct sysret sys_cap_has_relations(capaddr_t caddr, uint8_t vbits,
+                                    uint8_t mask)
+{
+    errval_t err;
+
+    caddr >>= (CPTR_BITS-vbits);
+
+    struct cte *cap;
+    err = caps_lookup_slot(&dcb_current->cspace.cap, caddr, vbits, &cap,
+                           CAPRIGHTS_READ);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    uint8_t res = 0;
+    if (mask & RRELS_COPY_BIT && has_copies(cap)) {
+        res |= RRELS_COPY_BIT;
+    }
+    if (mask & RRELS_ANCS_BIT && has_ancestors(cap)) {
+        res |= RRELS_ANCS_BIT;
+    }
+    if (mask & RRELS_DESC_BIT && has_descendants(cap)) {
+        res |= RRELS_DESC_BIT;
+    }
+
+    return (struct sysret) { .error = SYS_ERR_OK, .value = res };
+}
+
+struct sysret sys_monitor_remote_relations(capaddr_t root_addr, uint8_t root_bits,
+                                           capaddr_t cptr, uint8_t bits,
+                                           uint8_t relations, uint8_t mask)
+{
+    errval_t err;
+
+    // XXX: aldskfjaldsfa -MN
+    cptr >>= (CPTR_BITS-bits);
+
+    struct cte *cte;
+    err = sys_double_lookup(root_addr, root_bits, cptr, bits, &cte);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+#ifdef TRACE_PMEM_CAPS
+    if (caps_should_trace(&cte->cap)) {
+        char buf[512];
+        static const char chars[] = "~~01";
+#define MK01(b) ((int)((b)!=0))
+#define BITC(BIT) (chars[(2*MK01(mask & BIT)+MK01(relations & BIT))])
+        snprintf(buf, 512, "set remote: c %c, a %c, d %c",
+                 BITC(RRELS_COPY_BIT), BITC(RRELS_ANCS_BIT),
+                 BITC(RRELS_DESC_BIT));
+#undef BITC
+#undef MK01
+        TRACE_CAP_MSG(buf, cte);
+    }
+#endif
+
+    if (mask) {
+        mdb_set_relations(cte, relations, mask);
+    }
+
+    relations = 0;
+    if (cte->mdbnode.remote_copies) {
+        relations |= RRELS_COPY_BIT;
+    }
+    if (cte->mdbnode.remote_ancs) {
+        relations |= RRELS_ANCS_BIT;
+    }
+    if (cte->mdbnode.remote_descs) {
+        relations |= RRELS_DESC_BIT;
+    }
+
+    return (struct sysret){ .error = SYS_ERR_OK, .value = relations };
+}
+
+struct sysret sys_monitor_identify_cap(struct capability *root,
+                                       capaddr_t cptr, uint8_t bits,
+                                       struct capability *retbuf)
+{
+    struct capability *cap;
+    errval_t err = caps_lookup_cap(root, cptr, bits, &cap, CAPRIGHTS_READ);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_IDENTIFY_LOOKUP));
+    }
+
+    // XXX: Write cap data directly back to user-space
+    // FIXME: this should involve a pointer/range check for reliability,
+    // but because the monitor is inherently trusted it's not a security hole
+    *retbuf = *cap;
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+struct sysret sys_monitor_nullify_cap(capaddr_t cptr, uint8_t bits)
+{
+    struct capability *root = &dcb_current->cspace.cap;
+    struct cte *cte;
+    errval_t err = caps_lookup_slot(root, cptr, bits, &cte,
+                                    CAPRIGHTS_READ_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    // remove from MDB
+    remove_mapping(cte);
+
+    // zero-out cap entry
+    memset(cte, 0, sizeof(cte));
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+struct sysret sys_monitor_domain_id(capaddr_t cptr, domainid_t domain_id)
+{
+    struct capability *root = &dcb_current->cspace.cap;
+    struct capability *disp;
+
+    errval_t err = caps_lookup_cap(root, cptr, CPTR_BITS, &disp,
+                                   CAPRIGHTS_READ_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    disp->u.dispatcher.dcb->domain_id = domain_id;
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+static errval_t sys_double_lookup(capaddr_t rptr, uint8_t rbits,
+                                  capaddr_t tptr, uint8_t tbits,
+                                  struct cte **cte)
+{
+    errval_t err;
+
+    // XXX: wwwwwhyyyyy
+    rptr >>= (CPTR_BITS-rbits);
+
+    struct capability *root;
+    err = caps_lookup_cap(&dcb_current->cspace.cap, rptr, rbits,
+                          &root, CAPRIGHTS_READ);
+    if (err_is_fail(err)) {
+        return err_push(err, SYS_ERR_ROOT_CAP_LOOKUP);
+    }
+
+    err = caps_lookup_slot(root, tptr, tbits, cte, CAPRIGHTS_READ);
+    if (err_is_fail(err)) {
+        return err_push(err, SYS_ERR_IDENTIFY_LOOKUP);
+    }
+
+    return SYS_ERR_OK;
+}
+
+struct sysret sys_get_cap_owner(capaddr_t root_addr, uint8_t root_bits, capaddr_t cptr, uint8_t bits)
+{
+    errval_t err;
+
+    cptr >>= (CPTR_BITS-bits);
+
+    struct cte *cte;
+    err = sys_double_lookup(root_addr, root_bits, cptr, bits, &cte);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    return (struct sysret) { .error = SYS_ERR_OK, .value = cte->mdbnode.owner };
+}
+
+struct sysret sys_set_cap_owner(capaddr_t root_addr, uint8_t root_bits, capaddr_t cptr, uint8_t bits, coreid_t owner)
+{
+    errval_t err;
+
+    cptr >>= (CPTR_BITS-bits);
+
+    struct cte *cte;
+    err = sys_double_lookup(root_addr, root_bits, cptr, bits, &cte);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    cte->mdbnode.owner = owner;
+
+    TRACE_CAP(cte);
+
+    struct cte *pred = cte;
+    do {
+        pred->mdbnode.owner = owner;
+        pred = mdb_predecessor(pred);
+    } while (is_copy(&pred->cap, &cte->cap));
+
+    struct cte *succ = cte;
+    do {
+        succ->mdbnode.owner = owner;
+        succ = mdb_successor(succ);
+    } while (is_copy(&succ->cap, &cte->cap));
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+static void sys_lock_cap_common(struct cte *cte, bool lock)
+{
+    struct cte *pred = cte;
+    do {
+        pred->mdbnode.locked = lock;
+        pred = mdb_predecessor(pred);
+    } while (is_copy(&pred->cap, &cte->cap));
+
+    struct cte *succ = cte;
+    do {
+        succ->mdbnode.locked = lock;
+        succ = mdb_successor(succ);
+    } while (is_copy(&succ->cap, &cte->cap));
+}
+
+struct sysret sys_lock_cap(capaddr_t root_addr, uint8_t root_bits, capaddr_t target_addr, uint8_t target_bits)
+{
+    errval_t err;
+
+    struct cte *target;
+    err = sys_double_lookup(root_addr, root_bits, target_addr, target_bits, &target);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    if (target->mdbnode.locked) {
+        return SYSRET(SYS_ERR_CAP_LOCKED);
+    }
+
+    TRACE_CAP(target);
+
+    sys_lock_cap_common(target, true);
+    return SYSRET(SYS_ERR_OK);
+}
+
+struct sysret sys_unlock_cap(capaddr_t root_addr, uint8_t root_bits, capaddr_t target_addr, uint8_t target_bits)
+{
+    errval_t err;
+
+    struct cte *target;
+    err = sys_double_lookup(root_addr, root_bits, target_addr, target_bits, &target);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    TRACE_CAP(target);
+
+    // XXX: check if already unlocked? -MN
+    sys_lock_cap_common(target, false);
+    return SYSRET(SYS_ERR_OK);
+}
+
+struct sysret sys_monitor_copy_existing(struct capability *src,
+                                        capaddr_t cnode_cptr,
+                                        uint8_t cnode_vbits,
+                                        cslot_t slot)
+{
+    struct cte *copy = mdb_find_equal(src);
+    if (!copy || copy->mdbnode.in_delete) {
+        return SYSRET(SYS_ERR_CAP_NOT_FOUND);
+    }
+
+    struct cte *cnode;
+    errval_t err = caps_lookup_slot(&dcb_current->cspace.cap, cnode_cptr,
+                                    cnode_vbits, &cnode, CAPRIGHTS_READ_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_SLOT_LOOKUP_FAIL));
+    }
+    if (cnode->cap.type != ObjType_CNode) {
+        return SYSRET(SYS_ERR_CNODE_TYPE);
+    }
+
+    return SYSRET(caps_copy_to_cnode(cnode, slot, copy, false, 0, 0));
+}
+
+struct sysret sys_monitor_delete_last(capaddr_t root_addr, uint8_t root_bits,
+                                      capaddr_t target_addr, uint8_t target_bits,
+                                      capaddr_t ret_cn_addr, uint8_t ret_cn_bits,
+                                      cslot_t ret_slot)
+{
+    errval_t err;
+
+    struct cte *target;
+    err = sys_double_lookup(root_addr, root_bits, target_addr, target_bits, &target);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    // XXX: wwwwwhyyyyy
+    ret_cn_addr >>= (CPTR_BITS-ret_cn_bits);
+
+    struct capability *retcn;
+    err = caps_lookup_cap(&dcb_current->cspace.cap, ret_cn_addr, ret_cn_bits, &retcn, CAPRIGHTS_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_DEST_CNODE_LOOKUP));
+    }
+
+    if (retcn->type != ObjType_CNode) {
+        return SYSRET(SYS_ERR_DEST_CNODE_INVALID);
+    }
+    if (ret_slot > (1<<retcn->u.cnode.bits)) {
+        return SYSRET(SYS_ERR_SLOTS_INVALID);
+    }
+
+    struct cte *retslot = caps_locate_slot(retcn->u.cnode.cnode, ret_slot);
+
+    return SYSRET(caps_delete_last(target, retslot));
+}
+
+struct sysret sys_monitor_revoke_mark_tgt(capaddr_t root_addr, uint8_t root_bits,
+                                          capaddr_t target_addr, uint8_t target_bits)
+{
+    errval_t err;
+
+    // XXX: wwwwwhyyyyy
+    target_addr >>= (CPTR_BITS-target_bits);
+
+    struct cte *target;
+    err = sys_double_lookup(root_addr, root_bits, target_addr, target_bits, &target);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    return SYSRET(caps_mark_revoke(&target->cap, target));
+}
+
+struct sysret sys_monitor_revoke_mark_rels(struct capability *base)
+{
+    return SYSRET(caps_mark_revoke(base, NULL));
+}
+
+static errval_t sys_retslot_lookup(capaddr_t cnptr, uint8_t cnbits,
+                                   cslot_t slot, struct cte **cte)
+{
+    errval_t err;
+
+    struct capability *retcn;
+    err = caps_lookup_cap(&dcb_current->cspace.cap, cnptr, cnbits, &retcn, CAPRIGHTS_WRITE);
+    if (err_is_fail(err)) {
+        return err_push(err, SYS_ERR_DEST_CNODE_LOOKUP);
+    }
+
+    if (retcn->type != ObjType_CNode) {
+        return SYS_ERR_DEST_CNODE_INVALID;
+    }
+    if (slot > (1<<retcn->u.cnode.bits)) {
+        return SYS_ERR_SLOTS_INVALID;
+    }
+
+    struct cte *retslot;
+    retslot = caps_locate_slot(retcn->u.cnode.cnode, slot);
+
+    if (retslot->cap.type != ObjType_Null) {
+        return SYS_ERR_SLOT_IN_USE;
+    }
+
+    *cte = retslot;
+    return SYS_ERR_OK;
+}
+
+struct sysret sys_monitor_delete_step(capaddr_t ret_cn_addr,
+                                     uint8_t ret_cn_bits,
+                                     cslot_t ret_slot)
+{
+    errval_t err;
+
+    struct cte *retslot;
+    err = sys_retslot_lookup(ret_cn_addr, ret_cn_bits, ret_slot, &retslot);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    return SYSRET(caps_delete_step(retslot));
+}
+
+struct sysret sys_monitor_clear_step(capaddr_t ret_cn_addr,
+                                     uint8_t ret_cn_bits,
+                                     cslot_t ret_slot)
+{
+    errval_t err;
+
+    struct cte *retslot;
+    err = sys_retslot_lookup(ret_cn_addr, ret_cn_bits, ret_slot, &retslot);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    return SYSRET(caps_clear_step(retslot));
+}
index 377785c..0791a71 100644 (file)
 #include <syscall.h>
 #include <barrelfish_kpi/syscalls.h>
 #include <capabilities.h>
-#include <mdb/mdb.h>
-#include <mdb/mdb_tree.h>
-#include <cap_predicates.h>
+//#include <mdb/mdb.h>
+//#include <mdb/mdb_tree.h>
+//#include <cap_predicates.h>
 #include <dispatch.h>
 #include <distcaps.h>
 #include <wakeup.h>
-#include <paging_kernel_helper.h>
-#include <exec.h>
-#include <irq.h>
+//#include <paging_kernel_helper.h>
+//#include <exec.h>
+//#include <irq.h>
 #include <trace/trace.h>
 
 /// Keep track of all DCBs for tracing rundown
 /// XXX this is never garbage-collected at the moment
 struct dcb *dcbs_list = NULL;
 
-static errval_t sys_double_lookup(capaddr_t rptr, uint8_t rbits,
-                                  capaddr_t tptr, uint8_t tbits,
-                                  struct cte **cte);
-
 errval_t sys_print(const char *str, size_t length)
 {
     /* FIXME: check that string is mapped and accessible to caller! */
index c7b31d2..dbdef81 100644 (file)
@@ -34,7 +34,7 @@
                      "capops/capqueue.c", "capops/caplock.c", "capops/copy.c",
                      "capops/move.c", "capops/retrieve.c", "capops/delete.c",
                      "capops/revoke.c", "capops/retype.c", "capops/init.c",
-                     "capops/magic.c" ]
+                     "capops/magic.c", "capops/deletestep.c" ]
 
      arch_srcs "x86_32"  = [ "arch/x86/boot.c", "arch/x86/inter.c", "arch/x86/monitor_server.c", "arch/x86/notify_ipi.c" ]
      arch_srcs "x86_64"  = [ "arch/x86/boot.c", "arch/x86/inter.c", "arch/x86/monitor_server.c", "arch/x86/notify_ipi.c" ]
index 40e7d3e..3dd37d7 100644 (file)
@@ -31,7 +31,10 @@ caplock_unlock(struct domcapref cap)
     errval_t err = monitor_unlock_cap(cap.croot,
                                       cap.cptr >> (CPTR_BITS-cap.bits),
                                       cap.bits);
-    if (err_is_fail(err)) {
+    if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
+        DEBUG_ERR(err, "unlocking cap");
+    }
+    else if (err_is_fail(err)) {
         USER_PANIC_ERR(err, "unlocking cap");
     }
     capqueue_notify(&global_queue);
index 349a5e5..471b658 100644 (file)
@@ -145,11 +145,9 @@ capsend_mc_init(struct capsend_mc_st *mc_st, struct capability *cap,
     return SYS_ERR_OK;
 }
 
-bool capsend_handle_mc_reply(genvaddr_t st)
+bool capsend_handle_mc_reply(struct capsend_mc_st *st)
 {
-    struct capsend_mc_st *mc_st = (struct capsend_mc_st*)st;
-
-    if (!--mc_st->num_pending) {
+    if (!--st->num_pending) {
         return true;
     }
     else {
@@ -337,7 +335,7 @@ find_cap_result__rx_handler(struct intermon_binding *b, errval_t result, genvadd
     }
 
     // check to see if broadcast is complete
-    if (capsend_handle_mc_reply(st)) {
+    if (capsend_handle_mc_reply(&fc_bc_st->bc)) {
         if (!fc_bc_st->found) {
             // broadcast did not find a core, report notfound to caller
             fc_bc_st->result_handler(SYS_ERR_CAP_NOT_FOUND, 0, fc_bc_st->st);
@@ -383,7 +381,7 @@ capsend_find_descendants(struct domcapref src, capsend_result_fn result_fn, void
     mc_st->result_fn = result_fn;
     mc_st->st = st;
     mc_st->have_result = false;
-    return capsend_descendants(&cap, find_descendants_send_cont, (struct capsend_mc_st*)mc_st);
+    return capsend_relations(&cap, find_descendants_send_cont, (struct capsend_mc_st*)mc_st);
 }
 
 
@@ -457,7 +455,7 @@ find_descendants_result__rx_handler(struct intermon_binding *b, errval_t status,
         DEBUG_ERR(status, "ignoring bad find_descendants result");
     }
 
-    if (capsend_handle_mc_reply(st)) {
+    if (capsend_handle_mc_reply(&mc_st->mc_st)) {
         if (!mc_st->have_result) {
             mc_st->result_fn(SYS_ERR_CAP_NOT_FOUND, mc_st->st);
         }
@@ -553,11 +551,11 @@ owner_updated(coreid_t owner, genvaddr_t st)
 void
 owner_updated__rx_handler(struct intermon_binding *b, genvaddr_t st)
 {
-    if (!capsend_handle_mc_reply(st)) {
+    struct update_owner_broadcast_st *uo_bc_st = (struct update_owner_broadcast_st*)st;
+    if (!capsend_handle_mc_reply(&uo_bc_st->bc)) {
         // broadcast is not complete
         return;
     }
-    struct update_owner_broadcast_st *uo_bc_st = (struct update_owner_broadcast_st*)st;
     struct event_closure *cl = &uo_bc_st->completion_continuation;
     cl->handler(cl->arg);
     free(uo_bc_st);
@@ -613,9 +611,9 @@ capsend_copies(struct capability *cap,
 }
 
 errval_t
-capsend_descendants(struct capability *cap,
-            capsend_send_fn send_fn,
-            struct capsend_mc_st *mc_st)
+capsend_relations(struct capability *cap,
+                  capsend_send_fn send_fn,
+                  struct capsend_mc_st *mc_st)
 {
     // this is currently just a broadcast
     return capsend_broadcast(mc_st, cap, send_fn);
index f7d96b6..f21f7c1 100644 (file)
 #include "capqueue.h"
 #include "dom_invocations.h"
 #include "internal.h"
+#include "delete_int.h"
 #include <if/mem_rpcclient_defs.h>
 
-struct delete_st {
-    struct event_queue_node qn;
-    struct domcapref capref;
-    struct capability cap;
-    struct capref newcap;
-    delete_result_handler_t result_handler;
-    void *st;
-};
-
 struct delete_remote_mc_st {
     struct capsend_mc_st mc_st;
     struct delete_st *del_st;
@@ -59,8 +51,7 @@ delete_result__rx(errval_t status, struct delete_st *del_st, bool locked)
     handler(status, st);
 }
 
-__attribute__((unused))
-static void
+void
 send_new_ram_cap(struct capref cap)
 {
     errval_t err, result;
@@ -83,10 +74,45 @@ send_new_ram_cap(struct capref cap)
 
     thread_mutex_unlock(&ram_alloc_state->ram_alloc_lock);
 
-    err = cap_destroy(cap);
+    err = cap_delete(cap);
     assert(err_is_ok(err));
 }
 
+static void delete_wait__fin(void *st_)
+{
+    struct delete_st *st = (struct delete_st*)st_;
+    delete_result__rx(SYS_ERR_OK, st, false);
+}
+
+static void delete_last(struct delete_st* del_st)
+{
+    errval_t err;
+    bool locked = true;
+
+    err = monitor_delete_last(del_st->capref.croot, del_st->capref.cptr,
+                              del_st->capref.bits, del_st->newcap);
+    GOTO_IF_ERR(err, report_error);
+    if (err_no(err) == SYS_ERR_RAM_CAP_CREATED) {
+        send_new_ram_cap(del_st->newcap);
+        err = SYS_ERR_OK;
+    }
+
+    // at this point the cap has become "unlocked" because it is either deleted
+    // or in a clear/delete queue
+    locked = false;
+
+    if (!del_st->wait) {
+        goto report_error;
+    }
+
+    delete_queue_wait(&del_st->qn, MKCLOSURE(delete_wait__fin, del_st));
+
+    return;
+
+report_error:
+    delete_result__rx(err, del_st, locked);
+}
+
 /*
  * Non-moveable cap types: deleting all foreign copies when last owned copy of
  * cap is deleted
@@ -199,7 +225,7 @@ delete_remote_result__rx(struct intermon_binding *b, errval_t status,
     }
     status = mc_st->status;
 
-    if (!capsend_handle_mc_reply(st)) {
+    if (!capsend_handle_mc_reply(&mc_st->mc_st)) {
         // multicast not complete
         return;
     }
@@ -248,7 +274,7 @@ find_core_cont(errval_t status, coreid_t core, void *st)
 {
     // called with the result of "find core with cap" when trying to move the
     // last cap
-    errval_t err;
+    errval_t err = status;
     struct delete_st *del_st = (struct delete_st*)st;
 
     // unlock cap so it can be manipulated
@@ -260,30 +286,29 @@ find_core_cont(errval_t status, coreid_t core, void *st)
                                               del_st->capref.cptr,
                                               del_st->capref.bits,
                                               0, RRELS_COPY_BIT, NULL);
-
-        // now a "regular" delete should work again
-        err = dom_cnode_delete(del_st->capref);
-        if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) {
-            USER_PANIC_ERR(err, "this really should not happen");
-        }
-        else if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
-            // this shouldn't really happen either, but isn't a problem
-            err = SYS_ERR_OK;
+        if (err_is_fail(err)) {
+            if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
+                err = SYS_ERR_OK;
+            }
+            goto report_error;
         }
 
-        delete_result__rx(err, del_st, false);
+        delete_last(del_st);
     }
     else if (err_is_fail(status)) {
         // an error occured
-        delete_result__rx(status, del_st, false);
+        goto report_error;
     }
     else {
         // core found, attempt move
         err = capops_move(del_st->capref, core, move_result_cont, st);
-        if (err_is_fail(err)) {
-            delete_result__rx(err, del_st, false);
-        }
+        GOTO_IF_ERR(err, report_error);
     }
+
+    return;
+
+report_error:
+    delete_result__rx(err, del_st, false);
 }
 
 static void
@@ -311,68 +336,6 @@ move_result_cont(errval_t status, void *st)
 }
 
 /*
- * Deleting CNode special case {{{1
- */
-
-#if 0
-struct delete_cnode_st {
-    struct capref delcap;
-    void *st;
-};
-
-static void
-delete_cnode_slot_result(errval_t status, void *st)
-{
-    errval_t err;
-
-    struct delete_cnode_st *dst = (struct delete_cnode_st*)st;
-    if (err_is_ok(status) || err_no(status) == SYS_ERR_CAP_NOT_FOUND) {
-        if (dst->delcap.slot < (1 << dst->delcap.cnode.size_bits)) {
-            dst->delcap.slot++;
-            capops_delete(get_cap_domref(dst->delcap), delete_cnode_slot_result, dst);
-        }
-        else {
-            err = SYS_ERR_OK;
-        }
-    }
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(status, "deleting cnode slot failed");
-    }
-}
-
-__attribute__((unused))
-static errval_t
-delete_cnode(struct capref cap, void *st)
-{
-    errval_t err;
-
-    err = monitor_set_cap_deleted(cap);
-    if (err_is_fail(err)) {
-        return err;
-    }
-
-    struct capability cnode_cap;
-    err = monitor_cap_identify(cap, &cnode_cap);
-    if (err_is_fail(err)) {
-        return err;
-    }
-    assert(cnode_cap.type == ObjType_CNode);
-
-    struct cnoderef cnode = build_cnoderef(cap, cnode_cap.u.cnode.bits);
-    struct delete_cnode_st *dcst = malloc(sizeof(struct delete_cnode_st));
-    dcst->delcap.cnode = cnode;
-    dcst->delcap.slot = 0;
-    dcst->st = st;
-
-    err = capops_delete(get_cap_domref(dcst->delcap), delete_cnode_slot_result, dcst);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "deleting cnode slot failed");
-    }
-    return err;
-}
-#endif
-
-/*
  * Delete operation
  */
 
@@ -397,7 +360,7 @@ delete_trylock_cont(void *st)
     err = monitor_lock_cap(del_st->capref.croot, del_st->capref.cptr,
                            del_st->capref.bits);
     if (err_no(err) == SYS_ERR_CAP_LOCKED) {
-        caplock_wait(del_st->capref, &del_st->qn,
+        caplock_wait(del_st->capref, &del_st->lock_qn,
                      MKCLOSURE(delete_trylock_cont, del_st));
         return;
     }
@@ -415,7 +378,19 @@ delete_trylock_cont(void *st)
         locked = true;
     }
 
-    if (distcap_is_moveable(del_st->cap.type)) {
+    // check if there could be any remote relations
+    uint8_t relations;
+    err = monitor_domcap_remote_relations(del_st->capref.croot,
+                                          del_st->capref.cptr,
+                                          del_st->capref.bits,
+                                          0, 0, &relations);
+    GOTO_IF_ERR(err, report_error);
+
+    if (!(relations && RRELS_COPY_BIT)) {
+        // no remote relations, procede with final delete
+        delete_last(del_st);
+    }
+    else if (distcap_is_moveable(del_st->cap.type)) {
         // if cap is moveable, move ownership so cap can then be deleted
         err = capsend_find_cap(&del_st->cap, find_core_cont, del_st);
         GOTO_IF_ERR(err, report_error);
@@ -432,7 +407,14 @@ report_error:
 }
 
 void
-capops_delete(struct domcapref cap, delete_result_handler_t result_handler,
+capops_delete_int(struct delete_st *del_st)
+{
+    delete_trylock_cont(del_st);
+}
+
+void
+capops_delete(struct domcapref cap,
+              delete_result_handler_t result_handler,
               void *st)
 {
     errval_t err;
@@ -443,8 +425,9 @@ capops_delete(struct domcapref cap, delete_result_handler_t result_handler,
         goto err_cont;
     }
 
-    // simple delete was not able to delete cap as it was last copy and may
-    // have remote copies, need to move or revoke cap
+    // simple delete was not able to delete cap as it was last copy and:
+    //  - may have remote copies, need to move or revoke cap
+    //  - contains further slots which need to be cleared
 
     struct delete_st *del_st;
     err = calloce(1, sizeof(*del_st), &del_st);
@@ -458,10 +441,11 @@ capops_delete(struct domcapref cap, delete_result_handler_t result_handler,
     GOTO_IF_ERR(err, free_st);
 
     del_st->capref = cap;
+    del_st->wait = true;
     del_st->result_handler = result_handler;
     del_st->st = st;
 
-    // after this steup is complete, nothing less than a catastrophic failure
+    // after this setup is complete, nothing less than a catastrophic failure
     // should stop the delete
     delete_trylock_cont(del_st);
     return;
diff --git a/usr/monitor/capops/delete_int.h b/usr/monitor/capops/delete_int.h
new file mode 100644 (file)
index 0000000..a15c62e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef CAPOPS_DELETE_INT_H
+#define CAPOPS_DELETE_INT_H
+
+#include <capops.h>
+#include <barrelfish/waitset.h>
+#include <barrelfish/event_queue.h>
+
+void delete_steps_init(struct waitset *ws);
+void delete_steps_trigger(void);
+void delete_steps_pause(void);
+void delete_steps_resume(void);
+
+struct delete_queue_node {
+    struct event_queue_node qn;
+    struct delete_queue_node *next;
+    struct event_closure cont;
+};
+
+void delete_queue_wait(struct delete_queue_node *qn,
+                       struct event_closure cont);
+void delete_queue_init(struct waitset *ws);
+
+struct delete_st {
+    struct delete_queue_node qn;
+    struct event_queue_node lock_qn;
+    struct domcapref capref;
+    struct capability cap;
+    struct capref newcap;
+    bool wait;
+    delete_result_handler_t result_handler;
+    void *st;
+};
+
+void capops_delete_int(struct delete_st *del_st);
+
+void send_new_ram_cap(struct capref cap);
+
+#endif
diff --git a/usr/monitor/capops/deletestep.c b/usr/monitor/capops/deletestep.c
new file mode 100644 (file)
index 0000000..3f3b16c
--- /dev/null
@@ -0,0 +1,171 @@
+#include "internal.h"
+#include "delete_int.h"
+#include <monitor_invocations.h>
+#include <caplock.h>
+#include <barrelfish/event_queue.h>
+
+static struct event_queue trigger_queue;
+static bool triggered;
+static int suspended;
+static struct event_queue_node trigger_qn;
+static struct event_closure step_closure;
+static struct event_queue_node caplock_qn;
+static struct delete_st delete_step_st;
+static struct capref delcap;
+static struct event_queue delete_queue;
+static struct delete_queue_node *pending_head, *pending_tail;
+
+static void delete_steps_cont(void *st);
+static void delete_steps_clear(void *st);
+static void delete_queue_notify(void);
+
+void
+delete_steps_init(struct waitset *ws)
+{
+    errval_t err;
+
+    event_queue_init(&trigger_queue, ws, EVENT_QUEUE_CONTINUOUS);
+    triggered = false;
+    suspended = 0;
+    step_closure = MKCLOSURE(delete_steps_cont, NULL);
+
+    event_queue_init(&delete_queue, ws, EVENT_QUEUE_CONTINUOUS);
+    pending_head = pending_tail = NULL;
+
+    delete_step_st.wait = false;
+    delete_step_st.result_handler = NULL;
+    err = slot_alloc(&delcap);
+    PANIC_IF_ERR(err, "allocating delete_steps slot");
+    delete_step_st.capref = get_cap_domref(delcap);
+    err = slot_alloc(&delete_step_st.newcap);
+    PANIC_IF_ERR(err, "allocating delete_steps new cap slot");
+}
+
+void
+delete_steps_trigger(void)
+{
+    if (!triggered) {
+        triggered = true;
+        if (!suspended) {
+            event_queue_add(&trigger_queue, &trigger_qn, step_closure);
+        }
+    }
+}
+
+void
+delete_steps_pause(void)
+{
+    suspended++;
+}
+
+void
+delete_steps_resume(void)
+{
+    assert(suspended > 0);
+    suspended--;
+    if (!suspended) {
+        event_queue_add(&trigger_queue, &trigger_qn, step_closure);
+    }
+}
+
+static void
+delete_steps_delete_result(errval_t status, void *st)
+{
+    assert(err_is_ok(status));
+    delete_steps_resume();
+}
+
+static void
+delete_steps_cont(void *st)
+{
+    errval_t err;
+    assert(triggered);
+    if (suspended) {
+        return;
+    }
+
+    err = monitor_delete_step(delcap);
+    if (err_no(err) == SYS_ERR_CAP_LOCKED) {
+        // XXX
+        caplock_wait(get_cap_domref(NULL_CAP), &caplock_qn, step_closure);
+    }
+    if (err_no(err) == SYS_ERR_DELETE_LAST_OWNED) {
+        assert(!delete_step_st.result_handler);
+        delete_step_st.result_handler = delete_steps_delete_result;
+        delete_step_st.st = NULL;
+        capops_delete_int(&delete_step_st);
+    }
+    else if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
+        delete_steps_clear(st);
+    }
+    else if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "while performing delete steps");
+    }
+    else {
+        if (err_no(err) == SYS_ERR_RAM_CAP_CREATED) {
+            send_new_ram_cap(delcap);
+        }
+        event_queue_add(&trigger_queue, &trigger_qn, step_closure);
+    }
+}
+
+static void
+delete_steps_clear(void *st)
+{
+    errval_t err;
+    while (true) {
+        err = monitor_clear_step(delcap);
+        if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
+            break;
+        }
+        else if (err_is_fail(err)) {
+            USER_PANIC_ERR(err, "while performing clear steps");
+        }
+        else if (err_no(err) == SYS_ERR_RAM_CAP_CREATED) {
+            send_new_ram_cap(delcap);
+        }
+    }
+    triggered = false;
+    delete_queue_notify();
+}
+
+void
+delete_queue_wait(struct delete_queue_node *qn, struct event_closure cont)
+{
+    // enqueue the node in the list of pending events
+    if (!pending_head) {
+        assert(!pending_tail);
+        pending_head = pending_tail = qn;
+        qn->next = NULL;
+    }
+    else {
+        assert(pending_tail);
+        assert(!pending_tail->next);
+        pending_tail->next = qn;
+        pending_tail = qn;
+        qn->next = NULL;
+    }
+
+    // trigger "stepping" mode of the delete/revoke state machine
+    delete_steps_trigger();
+}
+
+static void
+delete_queue_notify(void)
+{
+    // this should only be triggered when the "stepping" mode of the
+    // delete/revoke state machine completes, so a notify without any
+    // operations pending would be very strange and is probably a bug
+    assert(pending_head);
+    assert(pending_tail);
+
+    // extract the contents of the queue of currently pending delete operations
+    struct delete_queue_node *curr = pending_head;
+    pending_head = pending_tail = NULL;
+
+    // put them all in the event queue so they are executed
+    for ( ; curr; curr = curr->next) {
+        event_queue_add(&delete_queue, &curr->qn, curr->cont);
+    }
+}
+
index c16362e..3fe56f4 100644 (file)
@@ -1,8 +1,9 @@
 #include <if/intermon_defs.h>
 #include <capops.h>
 #include "internal.h"
+#include "delete_int.h"
 
-errval_t capops_intermon_init(struct intermon_binding *b)
+errval_t capops_init(struct waitset *ws, struct intermon_binding *b)
 {
     b->rx_vtbl.capops_request_copy            = request_copy__rx;
     b->rx_vtbl.capops_recv_copy               = recv_copy__rx;
@@ -13,8 +14,10 @@ errval_t capops_intermon_init(struct intermon_binding *b)
     b->rx_vtbl.capops_retrieve_result         = retrieve_result__rx;
     b->rx_vtbl.capops_delete_remote           = delete_remote__rx;
     b->rx_vtbl.capops_delete_remote_result    = delete_remote_result__rx;
-    b->rx_vtbl.capops_request_revoke          = request_revoke__rx_handler;
-    b->rx_vtbl.capops_revoke_result           = revoke_result__rx_handler;
+    b->rx_vtbl.capops_revoke_mark             = revoke_mark__rx;
+    b->rx_vtbl.capops_revoke_ready            = revoke_ready__rx;
+    b->rx_vtbl.capops_revoke_commit           = revoke_commit__rx;
+    b->rx_vtbl.capops_revoke_done             = revoke_done__rx;
     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;
@@ -24,5 +27,7 @@ errval_t capops_intermon_init(struct intermon_binding *b)
     b->rx_vtbl.capops_find_descendants        = find_descendants__rx_handler;
     b->rx_vtbl.capops_find_descendants_result = find_descendants_result__rx_handler;
 
+    delete_steps_init(ws);
+
     return SYS_ERR_OK;
 }
index 9eeb7c2..cc01eb1 100644 (file)
 #ifndef CAPOPS_INTERNAL_H
 #define CAPOPS_INTERNAL_H
 
+#include <stdlib.h>
 #include <errors/errno.h>
 #include <barrelfish/waitset.h>
+#include <barrelfish/debug.h>
 #include <capops.h>
+#include <if/intermon_defs.h>
 
 typedef void (*gen_result_cont_fn)(errval_t, void*);
 struct result_closure {
@@ -23,12 +26,14 @@ struct result_closure {
 #define CALLRESCONT(c,e) ((c).handler((e), (c).arg))
 
 #define malloce(size, ret) \
-    (*(ret) = malloc(size), \
-     *(ret) ? SYS_ERR_OK : LIB_ERR_MALLOC_FAIL)
+    ((*(ret) = malloc(size)) \
+     ? SYS_ERR_OK \
+     : LIB_ERR_MALLOC_FAIL)
 
 #define calloce(n, size, ret) \
-    (*(ret) = calloc(n, size), \
-     *(ret) ? SYS_ERR_OK : LIB_ERR_MALLOC_FAIL)
+    ((*(ret) = calloc(n, size)) \
+     ? SYS_ERR_OK \
+     : LIB_ERR_MALLOC_FAIL)
 
 #define GOTO_IF_ERR(err, label) do { \
     if (err_is_fail(err)) { \
@@ -95,9 +100,11 @@ 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);
-void revoke_result__rx_handler(struct intermon_binding *b, errval_t status,
-                               genvaddr_t st);
+void revoke_mark__rx(struct intermon_binding *b,
+                     intermon_caprep_t caprep,
+                     genvaddr_t st);
+void revoke_ready__rx(struct intermon_binding *b, genvaddr_t st);
+void revoke_commit__rx(struct intermon_binding *b, genvaddr_t st);
+void revoke_done__rx(struct intermon_binding *b, genvaddr_t st);
 
 #endif
index 84dacde..920167e 100644 (file)
 #include "magic.h"
 #include "caplock.h"
 #include "internal.h"
+#include "delete_int.h"
 #include "dom_invocations.h"
 
-struct revoke_st {
-    struct domcapref revokecap;
-    struct capref delcap;
-    struct event_queue_node lock_queue_node;
+struct revoke_slave_st *slaves_head = 0, *slaves_tail = 0;
+
+struct revoke_master_st {
+    struct delete_queue_node del_qn;
+    struct domcapref cap;
+    struct capability rawcap;
+    struct capsend_mc_st revoke_mc_st;
     revoke_result_handler_t result_handler;
     void *st;
+    bool local_fin, remote_fin;
 };
 
-static errval_t revoke_local(struct revoke_st *rst);
-
-/*
- * Request revoke from owner {{{1
- */
+struct revoke_slave_st {
+    struct intermon_msg_queue_elem im_qn;
+    struct delete_queue_node del_qn;
+    struct capability rawcap;
+    struct capref cap;
+    coreid_t from;
+    genvaddr_t st;
+    errval_t status;
+    struct revoke_slave_st *next;
+};
 
-/*
- * Handle completed revoke request {{{2
- */
+static void revoke_result__rx(errval_t result,
+                              struct revoke_master_st *st,
+                              bool locked);
+static void revoke_retrieve__rx(errval_t result, void *st_);
+static void revoke_local(struct revoke_master_st *st);
+static errval_t revoke_mark__send(struct intermon_binding *b,
+                                  intermon_caprep_t *caprep,
+                                  struct capsend_mc_st *mc_st);
+static void revoke_ready__send(struct intermon_binding *b,
+                               struct intermon_msg_queue_elem *e);
+static errval_t revoke_commit__send(struct intermon_binding *b,
+                                    intermon_caprep_t *caprep,
+                                    struct capsend_mc_st *mc_st);
+static void revoke_slave_steps__fin(void *st);
+static void revoke_done__send(struct intermon_binding *b,
+                              struct intermon_msg_queue_elem *e);
+static void revoke_master_steps__fin(void *st);
 
-static void
-request_revoke_move_result(errval_t status, void *st)
+void
+capops_revoke(struct domcapref cap,
+              revoke_result_handler_t result_handler,
+              void *st)
 {
     errval_t err;
-    struct revoke_st *rst = (struct revoke_st*)st;
 
-    if (err_is_ok(status)) {
-        // move succeeded, start local revoke
-        err = revoke_local(rst);
-    }
-    else {
-        err = status;
-    }
+    distcap_state_t state;
+    err = dom_cnode_get_state(cap, &state);
+    GOTO_IF_ERR(err, report_error);
 
-    if (err_is_fail(err)) {
-        rst->result_handler(err, rst->st);
-        free(rst);
+    if (distcap_state_is_busy(state)) {
+        err = MON_ERR_REMOTE_CAP_RETRY;
+        goto report_error;
     }
-}
 
-void
-revoke_result__rx_handler(struct intermon_binding *b, errval_t status, genvaddr_t st)
-{
-    request_revoke_move_result(status, (void*)st);
-}
+    struct revoke_master_st *rst;
+    err = calloce(1, sizeof(*rst), &rst);
+    GOTO_IF_ERR(err, report_error);
+    rst->cap = cap;
+    err = monitor_domains_cap_identify(cap.croot, cap.cptr, cap.bits, &rst->rawcap);
+    GOTO_IF_ERR(err, free_st);
+    rst->result_handler = result_handler;
+    rst->st = st;
 
-/*
- * Handle and reply to revoke request {{{1
- */
+    if (distcap_state_is_foreign(state)) {
+        // need to retrieve ownership
+        capops_retrieve(rst->cap, revoke_retrieve__rx, st);
+    }
+    else {
+        // have ownership, initiate revoke
+        revoke_local(rst);
+    }
 
-struct revoke_request_st {
-    struct capref capref;
-    coreid_t from;
-    genvaddr_t st;
-};
+    return;
 
-/*
- * Revoke request result
- */
+free_st:
+    free(rst);
 
-struct revoke_result_msg_st {
-    struct intermon_msg_queue_elem queue_elem;
-    errval_t status;
-    genvaddr_t st;
-};
+report_error:
+    result_handler(err, st);
+}
 
 static void
-revoke_result_send_cont(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
+revoke_result__rx(errval_t result,
+                  struct revoke_master_st *st,
+                  bool locked)
 {
     errval_t err;
-    struct revoke_result_msg_st *msg_st = (struct revoke_result_msg_st*)e;
-    err = intermon_capops_revoke_result__tx(b, NOP_CONT, msg_st->status, msg_st->st);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "failed to send revoke_result message");
+
+    if (locked) {
+        caplock_unlock(st->cap);
     }
-    free(msg_st);
+
+    if (err_is_ok(result)) {
+        // clear the remote copies bit
+        err = monitor_domcap_remote_relations(st->cap.croot, st->cap.cptr,
+                                              st->cap.bits, 0, RRELS_COPY_BIT,
+                                              NULL);
+        if (err_is_fail(err) && err_no(err) != SYS_ERR_CAP_NOT_FOUND) {
+            DEBUG_ERR(err, "resetting remote copies bit after revoke");
+        }
+    }
+
+    st->result_handler(result, st->st);
 }
 
-static errval_t
-revoke_result(coreid_t dest, errval_t status, genvaddr_t st)
+static void
+revoke_retrieve__rx(errval_t result, void *st_)
 {
-    errval_t err;
-    struct revoke_result_msg_st *msg_st;
-    msg_st = malloc(sizeof(*msg_st));
-    if (!msg_st) {
-        return LIB_ERR_MALLOC_FAIL;
-    }
-    msg_st->queue_elem.cont = revoke_result_send_cont;
-    msg_st->status = status;
-    msg_st->st = st;
+    struct revoke_master_st *st = (struct revoke_master_st*)st_;
 
-    err = capsend_target(dest, (struct msg_queue_elem*)msg_st);
-    if (err_is_fail(err)) {
-        free(msg_st);
+    if (err_is_fail(result)) {
+        revoke_result__rx(result, st, false);
+    }
+    else {
+        revoke_local(st);
     }
-    return err;
 }
 
-/*
- * Move result handler {{{2
- */
-
 static void
-request_revoke_move_cont(errval_t status, void *st)
+revoke_local(struct revoke_master_st *st)
 {
     errval_t err;
-    struct revoke_request_st *rst = (struct revoke_request_st*)st;
-    err = revoke_result(rst->from, status, rst->st);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "could not send revoke request result");
-    }
-    free(st);
+
+    delete_steps_pause();
+
+    err = monitor_revoke_mark_target(st->cap.croot,
+                                     st->cap.cptr,
+                                     st->cap.bits);
+    PANIC_IF_ERR(err, "marking revoke");
+
+    err = capsend_relations(&st->rawcap, revoke_mark__send, &st->revoke_mc_st);
+    PANIC_IF_ERR(err, "initiating revoke mark multicast");
+
 }
 
-/*
- * Revoke request receive handler {{{2
- */
+static errval_t
+revoke_mark__send(struct intermon_binding *b,
+                  intermon_caprep_t *caprep,
+                  struct capsend_mc_st *mc_st)
+{
+    struct revoke_master_st *st;
+    ptrdiff_t off = offsetof(struct revoke_master_st, revoke_mc_st);
+    st = (struct revoke_master_st*)((char*)mc_st - off);
+    return intermon_capops_revoke_mark__tx(b, NOP_CONT, *caprep,
+                                           (genvaddr_t)st);
+}
 
 void
-request_revoke__rx_handler(struct intermon_binding *b, intermon_caprep_t caprep, genvaddr_t st)
+revoke_mark__rx(struct intermon_binding *b,
+                intermon_caprep_t caprep,
+                genvaddr_t st)
 {
-    errval_t err, send_err;
+    errval_t err;
     struct intermon_state *inter_st = (struct intermon_state*)b->st;
-    coreid_t from = inter_st->core_id;
-    struct capability cap;
-    caprep_to_capability(&caprep, &cap);
-
-    struct capref capref;
-    err = slot_alloc(&capref);
-    if (err_is_fail(err)) {
-        goto send_err;
-    }
 
-    err = monitor_copy_if_exists(&cap, capref);
-    if (err_is_fail(err)) {
-        goto free_slot;
-    }
+    struct revoke_slave_st *rvk_st;
+    err = calloce(1, sizeof(*rvk_st), &rvk_st);
+    PANIC_IF_ERR(err, "allocating revoke slave state");
 
-    distcap_state_t state;
-    err = cap_get_state(capref, &state);
-    if (err_is_fail(err)) {
-        goto destroy_cap;
-    }
+    rvk_st->from = inter_st->core_id;
+    caprep_to_capability(&caprep, &rvk_st->rawcap);
 
-    if (distcap_state_is_foreign(state)) {
-        err = MON_ERR_CAP_FOREIGN;
-        goto destroy_cap;
+    if (!slaves_head) {
+        assert(!slaves_tail);
+        slaves_head = slaves_tail = rvk_st;
     }
-
-    if (distcap_state_is_busy(state)) {
-        err = MON_ERR_REMOTE_CAP_RETRY;
-        goto destroy_cap;
-    }
-
-    struct revoke_request_st *rst;
-    rst = malloc(sizeof(*rst));
-    if (!rst) {
-        err = LIB_ERR_MALLOC_FAIL;
-        goto destroy_cap;
-    }
-    rst->capref = capref;
-    rst->from = from;
-    rst->st = st;
-
-    err = capops_move(get_cap_domref(capref), from, request_revoke_move_cont, rst);
-    if (err_is_fail(err)) {
-        goto free_st;
+    else {
+        assert(slaves_tail);
+        assert(!slaves_tail->next);
+        slaves_tail->next = rvk_st;
+        slaves_tail = rvk_st;
     }
 
-    return;
-
-free_st:
-    free(rst);
+    // pause any ongoing "delete stepping" as mark phases on other nodes need
+    // to delete all foreign copies before we can delete locally owned caps
+    delete_steps_pause();
 
-destroy_cap:
-    cap_destroy(capref);
+    // XXX: this invocation could create a scheduling hole that could be
+    // problematic in RT systems and should probably be done in a loop.
+    err = monitor_revoke_mark_relations(&rvk_st->rawcap);
+    PANIC_IF_ERR(err, "marking revoke");
 
-free_slot:
-    slot_free(capref);
-
-send_err:
-    send_err = revoke_result(from, err, st);
-    if (err_is_fail(send_err)) {
-        USER_PANIC_ERR(send_err, "could not send revoke error");
-    }
+    rvk_st->im_qn.cont = revoke_ready__send;
+    err = capsend_target(rvk_st->from, (struct msg_queue_elem*)rvk_st);
+    PANIC_IF_ERR(err, "enqueing revoke_ready");
 }
 
-/*
- * Revoke request {{{2
- */
-
-struct request_revoke_msg_st {
-    struct intermon_msg_queue_elem queue_elem;
-    intermon_caprep_t caprep;
-    struct revoke_st *st;
-};
-
 static void
-request_revoke_send_cont(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
+revoke_ready__send(struct intermon_binding *b,
+                   struct intermon_msg_queue_elem *e)
 {
-    struct request_revoke_msg_st *msg_st = (struct request_revoke_msg_st*)e;
     errval_t err;
-    err = intermon_capops_request_revoke__tx(b, NOP_CONT, msg_st->caprep, (genvaddr_t)msg_st->st);
-    if (err_is_fail(err)) {
-        struct revoke_st *rst = msg_st->st;
-        rst->result_handler(err, rst->st);
-        free(rst);
-    }
-    free(msg_st);
+    struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
+    err = intermon_capops_revoke_ready__tx(b, NOP_CONT, rvk_st->st);
+    PANIC_IF_ERR(err, "sending revoke_ready");
 }
 
-static errval_t
-request_revoke(struct revoke_st *st)
+void
+revoke_ready__rx(struct intermon_binding *b, genvaddr_t st)
 {
     errval_t err;
-    struct capability cap;
-    err = monitor_domains_cap_identify(st->revokecap.croot, st->revokecap.cptr,
-                                       st->revokecap.bits, &cap);
-    if (err_is_fail(err)) {
-        return err;
-    }
 
-    struct request_revoke_msg_st *msg_st = malloc(sizeof(struct request_revoke_msg_st));
-    if (!msg_st) {
-        return LIB_ERR_MALLOC_FAIL;
-    }
-    msg_st->queue_elem.cont = request_revoke_send_cont;
-    capability_to_caprep(&cap, &msg_st->caprep);
-    msg_st->st = st;
-
-    err = capsend_owner(st->revokecap, (struct msg_queue_elem*)msg_st);
-    if (err_is_fail(err)) {
-        free(msg_st);
-        return err;
+    struct revoke_master_st *rvk_st = (struct revoke_master_st*)st;
+    if (!capsend_handle_mc_reply(&rvk_st->revoke_mc_st)) {
+        // multicast not complete
+        return;
     }
 
-    return SYS_ERR_OK;
-}
+    err = capsend_relations(&rvk_st->rawcap, revoke_commit__send, &rvk_st->revoke_mc_st);
+    PANIC_IF_ERR(err, "enqueing revoke_commit multicast");
 
+    delete_steps_resume();
 
-/*
- * Local revocation handling {{{1
- */
+    struct event_closure steps_fin_cont
+        = MKCLOSURE(revoke_master_steps__fin, rvk_st);
+    delete_queue_wait(&rvk_st->del_qn, steps_fin_cont);
+}
 
-static void
-revoke_delete_result(errval_t status, void *st)
+static errval_t
+revoke_commit__send(struct intermon_binding *b,
+                    intermon_caprep_t *caprep,
+                    struct capsend_mc_st *mc_st)
 {
-    errval_t err;
-    struct revoke_st *rst = (struct revoke_st*)st;
+    struct revoke_master_st *st;
+    ptrdiff_t off = offsetof(struct revoke_master_st, revoke_mc_st);
+    st = (struct revoke_master_st*)((char*)mc_st - off);
+    return intermon_capops_revoke_commit__tx(b, NOP_CONT, (genvaddr_t)st);
+}
 
-    if (err_is_fail(status)) {
-        caplock_unlock(rst->revokecap);
-        rst->result_handler(status, rst->st);
-        free(rst);
-        return;
-    }
+void
+revoke_commit__rx(struct intermon_binding *b,
+                  genvaddr_t st)
+{
+    assert(slaves_head);
+    assert(slaves_tail);
+    assert(!slaves_tail->next);
 
-    err = revoke_local(rst);
-    if (err_is_fail(err)) {
-        rst->result_handler(err, rst->st);
-    }
+    struct revoke_slave_st *rvk_st = slaves_head;
+    while (rvk_st && rvk_st->st != st) { rvk_st = rvk_st->next; }
+    assert(rvk_st);
+
+    delete_steps_resume();
+
+    struct event_closure steps_fin_cont
+        = MKCLOSURE(revoke_slave_steps__fin, rvk_st);
+    delete_queue_wait(&rvk_st->del_qn, steps_fin_cont);
 }
 
 static void
-revoke_unlock_cont(void *arg)
+revoke_slave_steps__fin(void *st)
 {
     errval_t err;
-    struct revoke_st *rst = (struct revoke_st*)arg;
-    err = monitor_lock_cap(rst->revokecap.croot, rst->revokecap.cptr,
-                           rst->revokecap.bits);
-    err = revoke_local(rst);
-    rst->result_handler(err, rst->st);
+    struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)st;
+
+    rvk_st->im_qn.cont = revoke_done__send;
+    err = capsend_target(rvk_st->from, (struct msg_queue_elem*)rvk_st);
+    PANIC_IF_ERR(err, "enqueueing revoke_done");
 }
 
-static errval_t
-revoke_local(struct revoke_st *rst)
+static void
+revoke_done__send(struct intermon_binding *b,
+                  struct intermon_msg_queue_elem *e)
 {
     errval_t err;
-    err = monitor_continue_revoke(rst->revokecap.croot, rst->revokecap.cptr,
-                                  rst->revokecap.bits, rst->delcap);
-    if (err_no(err) == SYS_ERR_DELETE_LAST_OWNED) {
-        // kernel encountered a local cap with no copies, explicitly perform a
-        // delete in the monitor to deal with possible remote copies
-        assert(!capref_is_null(rst->delcap));
-        capops_delete(get_cap_domref(rst->delcap), revoke_delete_result, rst);
-        return SYS_ERR_OK;
-    }
-    else if (err_no(err) == MON_ERR_REMOTE_CAP_RETRY) {
-        // cap is locked, wait in queue for unlock
-        assert(!capref_is_null(rst->delcap));
-        caplock_wait(get_cap_domref(rst->delcap), &rst->lock_queue_node, MKCLOSURE(revoke_unlock_cont, rst));
-        return SYS_ERR_OK;
-    }
-    else {
-        // revoke failed or succeeded locally without any distributed cap
-        // interaction
-        caplock_unlock(rst->revokecap);
-        rst->result_handler(err, rst->st);
-    }
-
-    slot_free(rst->delcap);
-    free(rst);
-
-    return err;
+    struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
+    err = intermon_capops_revoke_done__tx(b, NOP_CONT, rvk_st->st);
+    PANIC_IF_ERR(err, "sending revoke_done");
+    free(rvk_st);
 }
 
-/*
- * Revoke operation {{{1
- */
-
-errval_t
-capops_revoke(struct domcapref cap, revoke_result_handler_t result_handler, void *st)
+void
+revoke_done__rx(struct intermon_binding *b,
+                genvaddr_t st)
 {
-    errval_t err;
-
-    distcap_state_t state;
-    err = dom_cnode_get_state(cap, &state);
-    if (err_is_fail(err)) {
-        return err;
-    }
-
-    if (distcap_state_is_busy(state)) {
-        return MON_ERR_REMOTE_CAP_RETRY;
-    }
-
-    err = monitor_lock_cap(cap.croot, cap.cptr, cap.bits);
-    if (err_is_fail(err)) {
-        return err_push(err, MON_ERR_RCAP_DB_LOCK);
-    }
-
-    struct revoke_st *rst = calloc(1, sizeof(struct revoke_st));
-    if (!rst) {
-        err = LIB_ERR_MALLOC_FAIL;
-        goto unlock_cap;
+    struct revoke_master_st *rvk_st = (struct revoke_master_st*)st;
+    if (!capsend_handle_mc_reply(&rvk_st->revoke_mc_st)) {
+        // multicast not complete
+        return;
     }
-    rst->revokecap = cap;
-    rst->result_handler = result_handler;
-    rst->st = st;
 
-    if (distcap_state_is_foreign(state)) {
-        err = request_revoke(rst);
-    }
-    else {
-        err = slot_alloc(&rst->delcap);
-        if (err_is_fail(err)) {
-            goto free_st;
-        }
-
-        err = revoke_local(rst);
+    rvk_st->remote_fin = true;
+    if (rvk_st->local_fin) {
+        revoke_result__rx(SYS_ERR_OK, rvk_st, true);
     }
+}
 
-    if (err_is_ok(err)) {
-        return err;
+static void
+revoke_master_steps__fin(void *st)
+{
+    struct revoke_master_st *rvk_st = (struct revoke_master_st*)st;
+    rvk_st->local_fin = true;
+    if (rvk_st->remote_fin) {
+        revoke_result__rx(SYS_ERR_OK, rvk_st, true);
     }
-
-free_st:
-    free(rst);
-
-unlock_cap:
-    caplock_unlock(cap);
-
-    return err;
 }
index f046074..6b8e450 100644 (file)
@@ -216,11 +216,35 @@ invoke_monitor_delete_last(capaddr_t root, int rbits, capaddr_t cap, int cbits,
 }
 
 static inline errval_t
-invoke_monitor_continue_revoke(capaddr_t root, int rbits, capaddr_t cap, int cbits,
-                           capaddr_t retcn, int retcnbits, cslot_t retslot)
+invoke_monitor_revoke_mark_target(capaddr_t root, int rbits,
+                                  capaddr_t cap, int cbits)
 {
-    return cap_invoke8(cap_kernel, KernelCmd_Revoke_step, root, rbits, cap,
-                       cbits, retcn, retcnbits, retslot).error;
+    return cap_invoke5(cap_kernel, KernelCmd_Revoke_mark_target,
+                       root, rbits, cap, cbits).error;
+}
+
+static inline errval_t
+invoke_monitor_revoke_mark_relations(uint64_t *raw_base)
+{
+    assert(sizeof(struct capability) % sizeof(uint64_t) == 0);
+    assert(sizeof(struct capability) / sizeof(uint64_t) == 4);
+    return cap_invoke5(cap_kernel, KernelCmd_Revoke_mark_relations,
+                       raw_base[0], raw_base[1],
+                       raw_base[2], raw_base[3]).error;
+}
+
+static inline errval_t
+invoke_monitor_delete_step(capaddr_t retcn, int retcnbits, cslot_t retslot)
+{
+    return cap_invoke4(cap_kernel, KernelCmd_Delete_step,
+                       retcn, retcnbits, retslot).error;
+}
+
+static inline errval_t
+invoke_monitor_clear_step(capaddr_t retcn, int retcnbits, cslot_t retslot)
+{
+    return cap_invoke4(cap_kernel, KernelCmd_Clear_step,
+                       retcn, retcnbits, retslot).error;
 }
 
 static inline errval_t
@@ -229,7 +253,7 @@ invoke_monitor_has_descendants(uint64_t *raw, bool *res)
     assert(sizeof(struct capability) % sizeof(uint64_t) == 0);
     assert(sizeof(struct capability) / sizeof(uint64_t) == 4);
     struct sysret sysret;
-    sysret = cap_invoke5(cap_kernel, KernelCmd_Has_Descendants,
+    sysret = cap_invoke5(cap_kernel, KernelCmd_Has_descendants,
                          raw[0], raw[1], raw[2], raw[3]);
     if (err_is_ok(sysret.error)) {
         *res = sysret.value;
index 8e7c566..651fbf5 100644 (file)
@@ -31,8 +31,9 @@ void capops_delete(struct domcapref cap,
                    delete_result_handler_t result_handler, void *st);
 
 typedef void (*revoke_result_handler_t)(errval_t, void*);
-errval_t capops_revoke(struct domcapref cap,
-                       revoke_result_handler_t result_handler, void *st);
+void capops_revoke(struct domcapref cap,
+                   revoke_result_handler_t result_handler,
+                   void *st);
 
 typedef void (*retype_result_handler_t)(errval_t, void*);
 void capops_retype(enum objtype type, size_t objbits, struct capref croot,
@@ -41,6 +42,6 @@ void capops_retype(enum objtype type, size_t objbits, struct capref croot,
                    retype_result_handler_t result_handler, void *st);
 
 struct intermon_binding;
-errval_t capops_intermon_init(struct intermon_binding *b);
+errval_t capops_init(struct waitset *ws, struct intermon_binding *b);
 
 #endif
index 73041c4..9c29db8 100644 (file)
 struct capsend_mc_msg_st;
 struct capsend_mc_st;
 
-typedef errval_t (*capsend_send_fn)(struct intermon_binding*, intermon_caprep_t*, struct capsend_mc_st*); /* binding, caprep, user_st */
+typedef errval_t (*capsend_send_fn)(struct intermon_binding* /*binding*/,
+                                    intermon_caprep_t* /*caprep*/,
+                                    struct capsend_mc_st* /*user_st*/);
 
-bool capsend_handle_mc_reply(genvaddr_t mc_st); /* returns true if was last reply */
+bool capsend_handle_mc_reply(struct capsend_mc_st *mc_st); /* returns true if was last reply */
 
 struct capsend_mc_st {
     struct capsend_mc_msg_st *msg_st_arr;
@@ -32,22 +34,33 @@ struct capsend_mc_st {
     capsend_send_fn send_fn;
 };
 
-errval_t capsend_target(coreid_t dest, struct msg_queue_elem *queue_elem);
+errval_t capsend_target(coreid_t dest,
+                        struct msg_queue_elem *queue_elem);
 
-errval_t capsend_owner(struct domcapref capref, struct msg_queue_elem *queue_elem);
+errval_t capsend_owner(struct domcapref capref,
+                       struct msg_queue_elem *queue_elem);
 
-errval_t capsend_update_owner(struct domcapref capref, struct event_closure continuation);
+errval_t capsend_update_owner(struct domcapref capref,
+                              struct event_closure continuation);
 
-errval_t capsend_copies(struct capability *cap, capsend_send_fn send_fn, struct capsend_mc_st *mc_st);
+errval_t capsend_copies(struct capability *cap,
+                        capsend_send_fn send_fn,
+                        struct capsend_mc_st *mc_st);
 
-errval_t capsend_descendants(struct capability *cap, capsend_send_fn send_fn, struct capsend_mc_st *mc_st);
+errval_t capsend_relations(struct capability *cap,
+                           capsend_send_fn send_fn,
+                           struct capsend_mc_st *mc_st);
 
 typedef void (*capsend_find_cap_result_fn)(errval_t, coreid_t, void*);
 
-errval_t capsend_find_cap(struct capability *cap, capsend_find_cap_result_fn result_fn, void *st);
+errval_t capsend_find_cap(struct capability *cap,
+                          capsend_find_cap_result_fn result_fn,
+                          void *st);
 
 typedef void (*capsend_result_fn)(errval_t, void*);
 
-errval_t capsend_find_descendants(struct domcapref src, capsend_result_fn result_fn, void *st);
+errval_t capsend_find_descendants(struct domcapref src,
+                                  capsend_result_fn result_fn,
+                                  void *st);
 
 #endif
index 628708f..1236a8c 100644 (file)
@@ -49,8 +49,19 @@ errval_t monitor_get_cap_owner(struct capref croot, capaddr_t cptr, int bits, co
 errval_t monitor_set_cap_owner(struct capref croot, capaddr_t cptr, int bits, coreid_t owner);
 errval_t monitor_lock_cap(struct capref croot, capaddr_t cptr, int bits);
 errval_t monitor_unlock_cap(struct capref croot, capaddr_t cptr, int bits);
-errval_t monitor_delete_last(struct capref croot, capaddr_t cptr, int bits, struct capref ret_cap);
-errval_t monitor_continue_revoke(struct capref croot, capaddr_t cptr, int bits, struct capref ret_cap);
 errval_t monitor_has_descendants(struct capability *cap, bool *res);
 
+/*
+ * Delete- and revoke-related operations
+ */
+
+errval_t monitor_delete_last(struct capref croot, capaddr_t cptr, int bits,
+                             struct capref ret_cap);
+errval_t monitor_revoke_mark_target(struct capref croot,
+                                    capaddr_t cptr,
+                                    int bits);
+errval_t monitor_revoke_mark_relations(struct capability *cap);
+errval_t monitor_delete_step(struct capref ret_cap);
+errval_t monitor_clear_step(struct capref ret_cap);
+
 #endif
index ebb55e8..15120e6 100644 (file)
@@ -670,7 +670,7 @@ errval_t intermon_init(struct intermon_binding *b, coreid_t coreid)
         return err;
     }
 
-    err = capops_intermon_init(b);
+    err = capops_init(b->waitset, b);
     if (err_is_fail(err)) {
         USER_PANIC_ERR(err, "capops_intermon_init failed");
         return err;
index 843e9e6..da68e86 100644 (file)
@@ -232,6 +232,11 @@ errval_t monitor_unlock_cap(struct capref croot, capaddr_t cptr, int bits)
     return invoke_monitor_unlock_cap(root_addr, root_bits, cptr, bits);
 }
 
+errval_t monitor_has_descendants(struct capability *cap, bool *res)
+{
+    return invoke_monitor_has_descendants((uint64_t*)cap, res);
+}
+
 errval_t monitor_delete_last(struct capref croot, capaddr_t cptr, int bits, struct capref ret_cap)
 {
     capaddr_t root_addr = get_cap_addr(croot);
@@ -243,18 +248,29 @@ errval_t monitor_delete_last(struct capref croot, capaddr_t cptr, int bits, stru
                                       ret_cn, ret_cn_bits, ret_slot);
 }
 
-errval_t monitor_continue_revoke(struct capref croot, capaddr_t cptr, int bits, struct capref ret_cap)
+errval_t monitor_revoke_mark_target(struct capref croot, capaddr_t cptr,
+                                    int bits)
 {
     capaddr_t root_addr = get_cap_addr(croot);
     uint8_t root_bits = get_cap_valid_bits(croot);
-    capaddr_t ret_cn = ret_cap.cnode.address;
-    uint8_t ret_cn_bits = ret_cap.cnode.address_bits;
-    cslot_t ret_slot = ret_cap.slot;
-    return invoke_monitor_continue_revoke(root_addr, root_bits, cptr, bits,
-                                          ret_cn, ret_cn_bits, ret_slot);
+    return invoke_monitor_revoke_mark_target(root_addr, root_bits, cptr, bits);
 }
 
-errval_t monitor_has_descendants(struct capability *cap, bool *res)
+errval_t monitor_revoke_mark_relations(struct capability *cap)
 {
-    return invoke_monitor_has_descendants((uint64_t*)cap, res);
+    return invoke_monitor_revoke_mark_relations((uint64_t*)cap);
+}
+
+errval_t monitor_delete_step(struct capref ret_cap)
+{
+    return invoke_monitor_delete_step(get_cnode_addr(ret_cap),
+                                      get_cnode_valid_bits(ret_cap),
+                                      ret_cap.slot);
+}
+
+errval_t monitor_clear_step(struct capref ret_cap)
+{
+    return invoke_monitor_clear_step(get_cnode_addr(ret_cap),
+                                     get_cnode_valid_bits(ret_cap),
+                                     ret_cap.slot);
 }
index 8c848ce..48f1454 100644 (file)
@@ -58,10 +58,7 @@ static void remote_cap_revoke(struct monitor_blocking_binding *b,
                               struct capref croot, capaddr_t src, uint8_t vbits)
 {
     struct domcapref cap = { .croot = croot, .cptr = src, .bits = vbits };
-    errval_t err = capops_revoke(cap, revoke_reply_status, (void*)b);
-    if (err_is_fail(err)) {
-        revoke_reply_status(err, (void*)b);
-    }
+    capops_revoke(cap, revoke_reply_status, (void*)b);
 }
 
 static void rsrc_manifest(struct monitor_blocking_binding *b,
@@ -234,12 +231,7 @@ static void cap_set_remote(struct monitor_blocking_binding *b,
 
     *tmpcap = cap;
 
-#if 0
-    bool has_descendants;
-    //reterr = monitor_cap_remote(cap, remote, &has_descendants);
-#else
     reterr = ERR_NOTIMP;
-#endif
     err = b->tx_vtbl.cap_set_remote_response(b, MKCONT(cap_set_remote_done, tmpcap),
                                              reterr);
     if(err_is_fail(err)) {