monitor: bugfixes in the revocation protocol
[barrelfish] / usr / monitor / capops / revoke.c
1 /*
2  * Copyright (c) 2012 ETH Zurich.
3  * All rights reserved.
4  *
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.
8  */
9
10 #include <barrelfish/barrelfish.h>
11 #include "monitor.h"
12 #include "capops.h"
13 #include "capsend.h"
14 #include "caplock.h"
15 #include "internal.h"
16 #include "delete_int.h"
17 #include "dom_invocations.h"
18 #include "monitor_debug.h"
19
20 struct revoke_slave_st *slaves_head = 0, *slaves_tail = 0;
21
22 struct revoke_master_st {
23     struct delete_queue_node del_qn;
24     struct domcapref cap;
25     struct capability rawcap;
26     struct capsend_mc_st revoke_mc_st;
27     struct capsend_destset dests;
28     revoke_result_handler_t result_handler;
29     void *st;
30     bool local_fin, remote_fin;
31 };
32
33 struct revoke_slave_st {
34     struct intermon_msg_queue_elem im_qn;
35     struct delete_queue_node del_qn;
36     struct capability rawcap;
37     struct capref cap;
38     coreid_t from;
39     genvaddr_t st;
40     errval_t status;
41     struct revoke_slave_st *next;
42 };
43
44 static void revoke_result__rx(errval_t result,
45                               struct revoke_master_st *st,
46                               bool locked);
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);
62
63 void
64 capops_revoke(struct domcapref cap,
65               revoke_result_handler_t result_handler,
66               void *st)
67 {
68     errval_t err;
69
70     DEBUG_CAPOPS("%s ## start revocation protocol\n", __FUNCTION__);
71
72     distcap_state_t state;
73     err = dom_cnode_get_state(cap, &state);
74     GOTO_IF_ERR(err, report_error);
75
76     if (distcap_state_is_busy(state)) {
77         err = MON_ERR_REMOTE_CAP_RETRY;
78         goto report_error;
79     }
80
81     struct revoke_master_st *rst;
82     err = calloce(1, sizeof(*rst), &rst);
83     GOTO_IF_ERR(err, report_error);
84     rst->cap = cap;
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;
88     rst->st = st;
89
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);
94     }
95     else {
96         if (num_monitors_online() == 1) {
97             DEBUG_CAPOPS("%s: only one monitor: do simpler revoke\n",
98                     __FUNCTION__);
99             // no remote monitors exist; do simplified revocation process
100             revoke_no_remote(rst);
101             // return here
102             return;
103         }
104         // have ownership, initiate revoke
105         revoke_local(rst);
106     }
107
108     return;
109
110 free_st:
111     free(rst);
112
113 report_error:
114     result_handler(err, st);
115 }
116
117 static void
118 revoke_result__rx(errval_t result,
119                   struct revoke_master_st *st,
120                   bool locked)
121 {
122     DEBUG_CAPOPS("%s\n", __FUNCTION__);
123     errval_t err;
124
125     if (locked) {
126         caplock_unlock(st->cap);
127     }
128
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,
133                                               NULL);
134         if (err_is_fail(err) && err_no(err) != SYS_ERR_CAP_NOT_FOUND) {
135             DEBUG_ERR(err, "resetting remote copies bit after revoke");
136         }
137     }
138
139     DEBUG_CAPOPS("%s ## revocation completed, calling %p\n", __FUNCTION__,
140                  st->result_handler);
141
142     st->result_handler(result, st->st);
143 }
144
145 static void
146 revoke_retrieve__rx(errval_t result, void *st_)
147 {
148     struct revoke_master_st *st = (struct revoke_master_st*)st_;
149
150     if (err_is_fail(result)) {
151         revoke_result__rx(result, st, false);
152     }
153     else {
154
155 #ifndef NDEBUG
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));
160 #endif
161         revoke_local(st);
162     }
163 }
164
165 static void
166 revoke_local(struct revoke_master_st *st)
167 {
168     DEBUG_CAPOPS("%s: called from %p\n", __FUNCTION__,
169             __builtin_return_address(0));
170     errval_t err;
171
172     delete_steps_pause();
173
174     err = monitor_revoke_mark_target(st->cap.croot,
175                                      st->cap.cptr,
176                                      st->cap.bits);
177     PANIC_IF_ERR(err, "marking revoke");
178
179
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");
185 }
186
187 static void
188 revoke_no_remote(struct revoke_master_st *st)
189 {
190     assert(num_monitors_online() == 1);
191
192     if (!delete_steps_get_waitset()) {
193         delete_steps_init(get_default_waitset());
194     }
195
196     errval_t err;
197     DEBUG_CAPOPS("%s\n", __FUNCTION__);
198
199     // pause deletion steps
200     DEBUG_CAPOPS("%s: delete_steps_pause()\n", __FUNCTION__);
201     delete_steps_pause();
202
203     // mark target of revoke
204     DEBUG_CAPOPS("%s: mon_revoke_mark_tgt()\n", __FUNCTION__);
205     err = monitor_revoke_mark_target(st->cap.croot,
206                                      st->cap.cptr,
207                                      st->cap.bits);
208     PANIC_IF_ERR(err, "marking revoke");
209
210
211     // resume delete steps
212     DEBUG_CAPOPS("%s: delete_steps_resume()\n", __FUNCTION__);
213     delete_steps_resume();
214
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);
221 }
222
223 static errval_t
224 revoke_mark__send(struct intermon_binding *b,
225                   intermon_caprep_t *caprep,
226                   struct capsend_mc_st *mc_st)
227 {
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);
232 }
233
234 void
235 revoke_mark__rx(struct intermon_binding *b,
236                 intermon_caprep_t caprep,
237                 genvaddr_t st)
238 {
239     DEBUG_CAPOPS("%s\n", __FUNCTION__);
240     errval_t err;
241     struct intermon_state *inter_st = (struct intermon_state*)b->st;
242
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");
246
247     rvk_st->from = inter_st->core_id;
248     rvk_st->st = st;
249     caprep_to_capability(&caprep, &rvk_st->rawcap);
250
251     if (!slaves_head) {
252         assert(!slaves_tail);
253         slaves_head = slaves_tail = rvk_st;
254     }
255     else {
256         assert(slaves_tail);
257         assert(!slaves_tail->next);
258         slaves_tail->next = rvk_st;
259         slaves_tail = rvk_st;
260     }
261
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();
265
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,
271         // do nothing. -SG
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");
275     }
276
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");
280 }
281
282 static void
283 revoke_ready__send(struct intermon_binding *b,
284                    struct intermon_msg_queue_elem *e)
285 {
286     errval_t err;
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");
290 }
291
292 void
293 revoke_ready__rx(struct intermon_binding *b, genvaddr_t st)
294 {
295     DEBUG_CAPOPS("%s\n", __FUNCTION__);
296     errval_t err;
297
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
302         return;
303     }
304
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");
309
310     delete_steps_resume();
311
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);
315 }
316
317 static errval_t
318 revoke_commit__send(struct intermon_binding *b,
319                     intermon_caprep_t *caprep,
320                     struct capsend_mc_st *mc_st)
321 {
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);
326 }
327
328 void
329 revoke_commit__rx(struct intermon_binding *b,
330                   genvaddr_t st)
331 {
332     assert(slaves_head);
333     assert(slaves_tail);
334     assert(!slaves_tail->next);
335
336     struct revoke_slave_st *rvk_st = slaves_head;
337     while (rvk_st && rvk_st->st != st) { rvk_st = rvk_st->next; }
338     assert(rvk_st);
339
340     delete_steps_resume();
341
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);
345 }
346
347 static void
348 revoke_slave_steps__fin(void *st)
349 {
350     errval_t err;
351     struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)st;
352
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");
356 }
357
358 inline static void
359 remove_slave_from_list(struct revoke_slave_st *rvk_st)
360 {
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;
367         } else {
368             // we're not the element in list??
369             printf("rvk_st: %p; head&tail: %p\n", rvk_st, slaves_head);
370         }
371     } else {
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;
376         } else {
377             // we're non-first
378             // find prev
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);
383             // remove us
384             p->next = rvk_st->next;
385             if (rvk_st == slaves_tail) {
386                 // we were last, set last to prev
387                 slaves_tail = p;
388             }
389         }
390     }
391 }
392
393 static void
394 revoke_done__send(struct intermon_binding *b,
395                   struct intermon_msg_queue_elem *e)
396 {
397     errval_t err;
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);
402     free(rvk_st);
403 }
404
405 void
406 revoke_done__rx(struct intermon_binding *b,
407                 genvaddr_t st)
408 {
409     DEBUG_CAPOPS("%s\n", __FUNCTION__);
410
411     struct revoke_master_st *rvk_st = (struct revoke_master_st*)(lvaddr_t)st;
412
413     if (!capsend_handle_mc_reply(&rvk_st->revoke_mc_st)) {
414         // multicast not complete
415         return;
416     }
417
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);
422     }
423 }
424
425 static void
426 revoke_master_steps__fin(void *st)
427 {
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);
432     }
433 }