2 * Copyright (c) 2012 ETH Zurich.
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
10 #include <barrelfish/barrelfish.h>
16 #include "delete_int.h"
17 #include "dom_invocations.h"
18 #include "monitor_debug.h"
20 struct revoke_slave_st *slaves_head = 0, *slaves_tail = 0;
22 struct revoke_master_st {
23 struct delete_queue_node del_qn;
25 struct capability rawcap;
26 struct capsend_mc_st revoke_mc_st;
27 struct capsend_destset dests;
28 revoke_result_handler_t result_handler;
30 bool local_fin, remote_fin;
33 struct revoke_slave_st {
34 struct intermon_msg_queue_elem im_qn;
35 struct delete_queue_node del_qn;
36 struct capability rawcap;
41 struct revoke_slave_st *next;
44 static void revoke_result__rx(errval_t result,
45 struct revoke_master_st *st,
47 static void revoke_retrieve__rx(errval_t result, void *st_);
48 static void revoke_local(struct revoke_master_st *st);
49 static void revoke_no_remote(struct revoke_master_st *st);
50 static errval_t revoke_mark__send(struct intermon_binding *b,
51 intermon_caprep_t *caprep,
52 struct capsend_mc_st *mc_st);
53 static void revoke_ready__send(struct intermon_binding *b,
54 struct intermon_msg_queue_elem *e);
55 static errval_t revoke_commit__send(struct intermon_binding *b,
56 intermon_caprep_t *caprep,
57 struct capsend_mc_st *mc_st);
58 static void revoke_slave_steps__fin(void *st);
59 static void revoke_done__send(struct intermon_binding *b,
60 struct intermon_msg_queue_elem *e);
61 static void revoke_master_steps__fin(void *st);
64 capops_revoke(struct domcapref cap,
65 revoke_result_handler_t result_handler,
70 DEBUG_CAPOPS("%s ## start revocation protocol\n", __FUNCTION__);
72 distcap_state_t state;
73 err = dom_cnode_get_state(cap, &state);
74 GOTO_IF_ERR(err, report_error);
76 if (distcap_state_is_busy(state)) {
77 err = MON_ERR_REMOTE_CAP_RETRY;
81 struct revoke_master_st *rst;
82 err = calloce(1, sizeof(*rst), &rst);
83 GOTO_IF_ERR(err, report_error);
85 err = monitor_domains_cap_identify(cap.croot, cap.cptr, cap.bits, &rst->rawcap);
86 GOTO_IF_ERR(err, free_st);
87 rst->result_handler = result_handler;
90 if (distcap_state_is_foreign(state)) {
91 // need to retrieve ownership
92 DEBUG_CAPOPS("%s getting cap ownership\n", __FUNCTION__);
93 capops_retrieve(rst->cap, revoke_retrieve__rx, rst);
96 if (num_monitors_online() == 1) {
97 DEBUG_CAPOPS("%s: only one monitor: do simpler revoke\n",
99 // no remote monitors exist; do simplified revocation process
100 revoke_no_remote(rst);
104 // have ownership, initiate revoke
114 result_handler(err, st);
118 revoke_result__rx(errval_t result,
119 struct revoke_master_st *st,
122 DEBUG_CAPOPS("%s\n", __FUNCTION__);
126 caplock_unlock(st->cap);
129 if (err_is_ok(result)) {
130 // clear the remote copies bit
131 err = monitor_domcap_remote_relations(st->cap.croot, st->cap.cptr,
132 st->cap.bits, 0, RRELS_COPY_BIT,
134 if (err_is_fail(err) && err_no(err) != SYS_ERR_CAP_NOT_FOUND) {
135 DEBUG_ERR(err, "resetting remote copies bit after revoke");
139 DEBUG_CAPOPS("%s ## revocation completed, calling %p\n", __FUNCTION__,
142 st->result_handler(result, st->st);
146 revoke_retrieve__rx(errval_t result, void *st_)
148 struct revoke_master_st *st = (struct revoke_master_st*)st_;
150 if (err_is_fail(result)) {
151 revoke_result__rx(result, st, false);
156 distcap_state_t state;
157 errval_t err = dom_cnode_get_state(st->cap, &state);
158 PANIC_IF_ERR(err, "dom_cnode_get_state");
159 assert(!distcap_state_is_foreign(state));
166 revoke_local(struct revoke_master_st *st)
168 DEBUG_CAPOPS("%s: called from %p\n", __FUNCTION__,
169 __builtin_return_address(0));
172 delete_steps_pause();
174 err = monitor_revoke_mark_target(st->cap.croot,
177 PANIC_IF_ERR(err, "marking revoke");
180 DEBUG_CAPOPS("%s ## revocation: mark phase\n", __FUNCTION__);
181 // XXX: could check whether remote copies exist here(?), -SG, 2014-11-05
182 err = capsend_relations(&st->rawcap, revoke_mark__send,
183 &st->revoke_mc_st, &st->dests);
184 PANIC_IF_ERR(err, "initiating revoke mark multicast");
188 revoke_no_remote(struct revoke_master_st *st)
190 assert(num_monitors_online() == 1);
192 if (!delete_steps_get_waitset()) {
193 delete_steps_init(get_default_waitset());
197 DEBUG_CAPOPS("%s\n", __FUNCTION__);
199 // pause deletion steps
200 DEBUG_CAPOPS("%s: delete_steps_pause()\n", __FUNCTION__);
201 delete_steps_pause();
203 // mark target of revoke
204 DEBUG_CAPOPS("%s: mon_revoke_mark_tgt()\n", __FUNCTION__);
205 err = monitor_revoke_mark_target(st->cap.croot,
208 PANIC_IF_ERR(err, "marking revoke");
211 // resume delete steps
212 DEBUG_CAPOPS("%s: delete_steps_resume()\n", __FUNCTION__);
213 delete_steps_resume();
215 // wait on delete queue, marking that remote cores are done
216 st->remote_fin = true;
217 DEBUG_CAPOPS("%s: delete_queue_wait()\n", __FUNCTION__);
218 struct event_closure steps_fin_cont
219 = MKCLOSURE(revoke_master_steps__fin, st);
220 delete_queue_wait(&st->del_qn, steps_fin_cont);
224 revoke_mark__send(struct intermon_binding *b,
225 intermon_caprep_t *caprep,
226 struct capsend_mc_st *mc_st)
228 struct revoke_master_st *st;
229 ptrdiff_t off = offsetof(struct revoke_master_st, revoke_mc_st);
230 st = (struct revoke_master_st*)((uintptr_t)mc_st - off);
231 return intermon_capops_revoke_mark__tx(b, NOP_CONT, *caprep, (lvaddr_t)st);
235 revoke_mark__rx(struct intermon_binding *b,
236 intermon_caprep_t caprep,
239 DEBUG_CAPOPS("%s\n", __FUNCTION__);
241 struct intermon_state *inter_st = (struct intermon_state*)b->st;
243 struct revoke_slave_st *rvk_st;
244 err = calloce(1, sizeof(*rvk_st), &rvk_st);
245 PANIC_IF_ERR(err, "allocating revoke slave state");
247 rvk_st->from = inter_st->core_id;
249 caprep_to_capability(&caprep, &rvk_st->rawcap);
252 assert(!slaves_tail);
253 slaves_head = slaves_tail = rvk_st;
257 assert(!slaves_tail->next);
258 slaves_tail->next = rvk_st;
259 slaves_tail = rvk_st;
262 // pause any ongoing "delete stepping" as mark phases on other nodes need
263 // to delete all foreign copies before we can delete locally owned caps
264 delete_steps_pause();
266 // XXX: this invocation could create a scheduling hole that could be
267 // problematic in RT systems and should probably be done in a loop.
268 err = monitor_revoke_mark_relations(&rvk_st->rawcap);
269 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
270 // found no copies or descendants of capability on this core,
272 DEBUG_CAPOPS("no copies on core %d\n", disp_get_core_id());
273 } else if (err_is_fail(err)) {
274 USER_PANIC_ERR(err, "marking revoke");
277 rvk_st->im_qn.cont = revoke_ready__send;
278 err = capsend_target(rvk_st->from, (struct msg_queue_elem*)rvk_st);
279 PANIC_IF_ERR(err, "enqueing revoke_ready");
283 revoke_ready__send(struct intermon_binding *b,
284 struct intermon_msg_queue_elem *e)
287 struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
288 err = intermon_capops_revoke_ready__tx(b, NOP_CONT, rvk_st->st);
289 PANIC_IF_ERR(err, "sending revoke_ready");
293 revoke_ready__rx(struct intermon_binding *b, genvaddr_t st)
295 DEBUG_CAPOPS("%s\n", __FUNCTION__);
298 struct revoke_master_st *rvk_st = (struct revoke_master_st*)(lvaddr_t)st;
299 if (!capsend_handle_mc_reply(&rvk_st->revoke_mc_st)) {
300 DEBUG_CAPOPS("%s: waiting for remote cores\n", __FUNCTION__);
301 // multicast not complete
305 DEBUG_CAPOPS("%s ## revocation: commit phase\n", __FUNCTION__);
306 err = capsend_relations(&rvk_st->rawcap, revoke_commit__send,
307 &rvk_st->revoke_mc_st, &rvk_st->dests);
308 PANIC_IF_ERR(err, "enqueing revoke_commit multicast");
310 delete_steps_resume();
312 struct event_closure steps_fin_cont
313 = MKCLOSURE(revoke_master_steps__fin, rvk_st);
314 delete_queue_wait(&rvk_st->del_qn, steps_fin_cont);
318 revoke_commit__send(struct intermon_binding *b,
319 intermon_caprep_t *caprep,
320 struct capsend_mc_st *mc_st)
322 struct revoke_master_st *st;
323 ptrdiff_t off = offsetof(struct revoke_master_st, revoke_mc_st);
324 st = (struct revoke_master_st*)((char*)mc_st - off);
325 return intermon_capops_revoke_commit__tx(b, NOP_CONT, (lvaddr_t)st);
329 revoke_commit__rx(struct intermon_binding *b,
334 assert(!slaves_tail->next);
336 struct revoke_slave_st *rvk_st = slaves_head;
337 while (rvk_st && rvk_st->st != st) { rvk_st = rvk_st->next; }
340 delete_steps_resume();
342 struct event_closure steps_fin_cont
343 = MKCLOSURE(revoke_slave_steps__fin, rvk_st);
344 delete_queue_wait(&rvk_st->del_qn, steps_fin_cont);
348 revoke_slave_steps__fin(void *st)
351 struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)st;
353 rvk_st->im_qn.cont = revoke_done__send;
354 err = capsend_target(rvk_st->from, (struct msg_queue_elem*)rvk_st);
355 PANIC_IF_ERR(err, "enqueueing revoke_done");
359 remove_slave_from_list(struct revoke_slave_st *rvk_st)
361 // remove from slave list
362 if (slaves_head == slaves_tail) {
363 // only one element in list
364 if (rvk_st == slaves_head) {
365 // we're only, clear list
366 slaves_head = slaves_tail = 0;
368 // we're not the element in list??
369 printf("rvk_st: %p; head&tail: %p\n", rvk_st, slaves_head);
372 // more than one element in list
373 if (rvk_st == slaves_head) {
374 // we're first, remove from head of list
375 slaves_head=slaves_head->next;
379 struct revoke_slave_st *p = slaves_head;
380 for (;p&&p->next!=rvk_st;p=p->next);
381 // make sure we found prev of us
382 assert(p&&p->next==rvk_st);
384 p->next = rvk_st->next;
385 if (rvk_st == slaves_tail) {
386 // we were last, set last to prev
394 revoke_done__send(struct intermon_binding *b,
395 struct intermon_msg_queue_elem *e)
398 struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
399 err = intermon_capops_revoke_done__tx(b, NOP_CONT, rvk_st->st);
400 PANIC_IF_ERR(err, "sending revoke_done");
401 remove_slave_from_list(rvk_st);
406 revoke_done__rx(struct intermon_binding *b,
409 DEBUG_CAPOPS("%s\n", __FUNCTION__);
411 struct revoke_master_st *rvk_st = (struct revoke_master_st*)(lvaddr_t)st;
413 if (!capsend_handle_mc_reply(&rvk_st->revoke_mc_st)) {
414 // multicast not complete
418 DEBUG_CAPOPS("%s ## revocation: fin phase\n", __FUNCTION__);
419 rvk_st->remote_fin = true;
420 if (rvk_st->local_fin) {
421 revoke_result__rx(SYS_ERR_OK, rvk_st, true);
426 revoke_master_steps__fin(void *st)
428 struct revoke_master_st *rvk_st = (struct revoke_master_st*)st;
429 rvk_st->local_fin = true;
430 if (rvk_st->remote_fin) {
431 revoke_result__rx(SYS_ERR_OK, rvk_st, true);