7236e609b3a1976f683749215b36a73eaafedc16
[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     distcap_state_t state;
71     err = dom_cnode_get_state(cap, &state);
72     GOTO_IF_ERR(err, report_error);
73
74     if (distcap_state_is_busy(state)) {
75         err = MON_ERR_REMOTE_CAP_RETRY;
76         goto report_error;
77     }
78
79     struct revoke_master_st *rst;
80     err = calloce(1, sizeof(*rst), &rst);
81     GOTO_IF_ERR(err, report_error);
82     rst->cap = cap;
83     err = monitor_domains_cap_identify(cap.croot, cap.cptr, cap.bits, &rst->rawcap);
84     GOTO_IF_ERR(err, free_st);
85     rst->result_handler = result_handler;
86     rst->st = st;
87
88     if (distcap_state_is_foreign(state)) {
89         // need to retrieve ownership
90         capops_retrieve(rst->cap, revoke_retrieve__rx, rst);
91     }
92     else {
93         if (num_monitors_online() == 1) {
94             DEBUG_CAPOPS("%s: only one monitor: do simpler revoke\n",
95                     __FUNCTION__);
96             // no remote monitors exist; do simplified revocation process
97             revoke_no_remote(rst);
98             // return here
99             return;
100         }
101         // have ownership, initiate revoke
102         revoke_local(rst);
103     }
104
105     return;
106
107 free_st:
108     free(rst);
109
110 report_error:
111     result_handler(err, st);
112 }
113
114 static void
115 revoke_result__rx(errval_t result,
116                   struct revoke_master_st *st,
117                   bool locked)
118 {
119     DEBUG_CAPOPS("%s\n", __FUNCTION__);
120     errval_t err;
121
122     if (locked) {
123         caplock_unlock(st->cap);
124     }
125
126     if (err_is_ok(result)) {
127         // clear the remote copies bit
128         err = monitor_domcap_remote_relations(st->cap.croot, st->cap.cptr,
129                                               st->cap.bits, 0, RRELS_COPY_BIT,
130                                               NULL);
131         if (err_is_fail(err) && err_no(err) != SYS_ERR_CAP_NOT_FOUND) {
132             DEBUG_ERR(err, "resetting remote copies bit after revoke");
133         }
134     }
135
136     st->result_handler(result, st->st);
137     free(st);
138 }
139
140 static void
141 revoke_retrieve__rx(errval_t result, void *st_)
142 {
143     struct revoke_master_st *st = (struct revoke_master_st*)st_;
144
145     if (err_is_fail(result)) {
146         revoke_result__rx(result, st, false);
147     }
148     else {
149 #ifndef NDEBUG
150         distcap_state_t state;
151         errval_t err = dom_cnode_get_state(st->cap, &state);
152         PANIC_IF_ERR(err, "dom_cnode_get_state");
153         assert(!distcap_state_is_foreign(state));
154 #endif
155         revoke_local(st);
156     }
157 }
158
159 static void
160 revoke_local(struct revoke_master_st *st)
161 {
162     DEBUG_CAPOPS("%s: called from %p\n", __FUNCTION__,
163             __builtin_return_address(0));
164     errval_t err;
165
166     delete_steps_pause();
167
168     err = monitor_revoke_mark_target(st->cap.croot,
169                                      st->cap.cptr,
170                                      st->cap.bits);
171     PANIC_IF_ERR(err, "marking revoke");
172
173     // XXX: could check whether remote copies exist here(?), -SG, 2014-11-05
174     err = capsend_relations(&st->rawcap, revoke_mark__send,
175             &st->revoke_mc_st, &st->dests);
176     PANIC_IF_ERR(err, "initiating revoke mark multicast");
177 }
178
179 static void
180 revoke_no_remote(struct revoke_master_st *st)
181 {
182     assert(num_monitors_online() == 1);
183
184     if (!delete_steps_get_waitset()) {
185         delete_steps_init(get_default_waitset());
186     }
187
188     errval_t err;
189     DEBUG_CAPOPS("%s\n", __FUNCTION__);
190
191     // pause deletion steps
192     DEBUG_CAPOPS("%s: delete_steps_pause()\n", __FUNCTION__);
193     delete_steps_pause();
194
195     // mark target of revoke
196     DEBUG_CAPOPS("%s: mon_revoke_mark_tgt()\n", __FUNCTION__);
197     err = monitor_revoke_mark_target(st->cap.croot,
198                                      st->cap.cptr,
199                                      st->cap.bits);
200     PANIC_IF_ERR(err, "marking revoke");
201
202
203     // resume delete steps
204     DEBUG_CAPOPS("%s: delete_steps_resume()\n", __FUNCTION__);
205     delete_steps_resume();
206
207     // wait on delete queue, marking that remote cores are done
208     st->remote_fin = true;
209     DEBUG_CAPOPS("%s: delete_queue_wait()\n", __FUNCTION__);
210     struct event_closure steps_fin_cont
211         = MKCLOSURE(revoke_master_steps__fin, st);
212     delete_queue_wait(&st->del_qn, steps_fin_cont);
213 }
214
215 static errval_t
216 revoke_mark__send(struct intermon_binding *b,
217                   intermon_caprep_t *caprep,
218                   struct capsend_mc_st *mc_st)
219 {
220     struct revoke_master_st *st;
221     ptrdiff_t off = offsetof(struct revoke_master_st, revoke_mc_st);
222     st = (struct revoke_master_st*)((uintptr_t)mc_st - off);
223     return intermon_capops_revoke_mark__tx(b, NOP_CONT, *caprep, (lvaddr_t)st);
224 }
225
226 void
227 revoke_mark__rx(struct intermon_binding *b,
228                 intermon_caprep_t caprep,
229                 genvaddr_t st)
230 {
231     DEBUG_CAPOPS("%s\n", __FUNCTION__);
232     errval_t err;
233     struct intermon_state *inter_st = (struct intermon_state*)b->st;
234
235     struct revoke_slave_st *rvk_st;
236     err = calloce(1, sizeof(*rvk_st), &rvk_st);
237     PANIC_IF_ERR(err, "allocating revoke slave state");
238
239     rvk_st->from = inter_st->core_id;
240     rvk_st->st = st;
241     caprep_to_capability(&caprep, &rvk_st->rawcap);
242
243     if (!slaves_head) {
244         assert(!slaves_tail);
245         slaves_head = slaves_tail = rvk_st;
246     }
247     else {
248         assert(slaves_tail);
249         assert(!slaves_tail->next);
250         slaves_tail->next = rvk_st;
251         slaves_tail = rvk_st;
252     }
253
254     // pause any ongoing "delete stepping" as mark phases on other nodes need
255     // to delete all foreign copies before we can delete locally owned caps
256     delete_steps_pause();
257
258     // XXX: this invocation could create a scheduling hole that could be
259     // problematic in RT systems and should probably be done in a loop.
260     err = monitor_revoke_mark_relations(&rvk_st->rawcap);
261     if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
262         // found no copies or descendants of capability on this core,
263         // do nothing. -SG
264         DEBUG_CAPOPS("no copies on core %d\n", disp_get_core_id());
265     } else if (err_is_fail(err)) {
266         USER_PANIC_ERR(err, "marking revoke");
267     }
268
269     rvk_st->im_qn.cont = revoke_ready__send;
270     err = capsend_target(rvk_st->from, (struct msg_queue_elem*)rvk_st);
271     PANIC_IF_ERR(err, "enqueing revoke_ready");
272 }
273
274 static void
275 revoke_ready__send(struct intermon_binding *b,
276                    struct intermon_msg_queue_elem *e)
277 {
278     errval_t err;
279     struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
280     err = intermon_capops_revoke_ready__tx(b, NOP_CONT, rvk_st->st);
281     PANIC_IF_ERR(err, "sending revoke_ready");
282 }
283
284 void
285 revoke_ready__rx(struct intermon_binding *b, genvaddr_t st)
286 {
287     DEBUG_CAPOPS("%s\n", __FUNCTION__);
288     errval_t err;
289
290     struct revoke_master_st *rvk_st = (struct revoke_master_st*)(lvaddr_t)st;
291     if (!capsend_handle_mc_reply(&rvk_st->revoke_mc_st)) {
292         DEBUG_CAPOPS("%s: waiting for remote cores\n", __FUNCTION__);
293         // multicast not complete
294         return;
295     }
296
297     DEBUG_CAPOPS("%s: sending commit\n", __FUNCTION__);
298     err = capsend_relations(&rvk_st->rawcap, revoke_commit__send,
299             &rvk_st->revoke_mc_st, &rvk_st->dests);
300     PANIC_IF_ERR(err, "enqueing revoke_commit multicast");
301
302     delete_steps_resume();
303
304     struct event_closure steps_fin_cont
305         = MKCLOSURE(revoke_master_steps__fin, rvk_st);
306     delete_queue_wait(&rvk_st->del_qn, steps_fin_cont);
307 }
308
309 static errval_t
310 revoke_commit__send(struct intermon_binding *b,
311                     intermon_caprep_t *caprep,
312                     struct capsend_mc_st *mc_st)
313 {
314     struct revoke_master_st *st;
315     ptrdiff_t off = offsetof(struct revoke_master_st, revoke_mc_st);
316     st = (struct revoke_master_st*)((char*)mc_st - off);
317     return intermon_capops_revoke_commit__tx(b, NOP_CONT, (lvaddr_t)st);
318 }
319
320 void
321 revoke_commit__rx(struct intermon_binding *b,
322                   genvaddr_t st)
323 {
324     assert(slaves_head);
325     assert(slaves_tail);
326     assert(!slaves_tail->next);
327
328     struct revoke_slave_st *rvk_st = slaves_head;
329     while (rvk_st && rvk_st->st != st) { rvk_st = rvk_st->next; }
330     assert(rvk_st);
331
332     delete_steps_resume();
333
334     struct event_closure steps_fin_cont
335         = MKCLOSURE(revoke_slave_steps__fin, rvk_st);
336     delete_queue_wait(&rvk_st->del_qn, steps_fin_cont);
337 }
338
339 static void
340 revoke_slave_steps__fin(void *st)
341 {
342     errval_t err;
343     struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)st;
344
345     rvk_st->im_qn.cont = revoke_done__send;
346     err = capsend_target(rvk_st->from, (struct msg_queue_elem*)rvk_st);
347     PANIC_IF_ERR(err, "enqueueing revoke_done");
348 }
349
350 inline static void
351 remove_slave_from_list(struct revoke_slave_st *rvk_st)
352 {
353     // remove from slave list
354     if (slaves_head == slaves_tail) {
355         // only one element in list
356         if (rvk_st == slaves_head) {
357             // we're only, clear list
358             slaves_head = slaves_tail = 0;
359         } else {
360             // we're not the element in list??
361             printf("rvk_st: %p; head&tail: %p\n", rvk_st, slaves_head);
362         }
363     } else {
364         // more than one element in list
365         if (rvk_st == slaves_head) {
366             // we're first, remove from head of list
367             slaves_head=slaves_head->next;
368         } else {
369             // we're non-first
370             // find prev
371             struct revoke_slave_st *p = slaves_head;
372             for (;p&&p->next!=rvk_st;p=p->next);
373             // make sure we found prev of us
374             assert(p&&p->next==rvk_st);
375             // remove us
376             p->next = rvk_st->next;
377             if (rvk_st == slaves_tail) {
378                 // we were last, set last to prev
379                 slaves_tail = p;
380             }
381         }
382     }
383 }
384
385 static void
386 revoke_done__send(struct intermon_binding *b,
387                   struct intermon_msg_queue_elem *e)
388 {
389     errval_t err;
390     struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
391     err = intermon_capops_revoke_done__tx(b, NOP_CONT, rvk_st->st);
392     PANIC_IF_ERR(err, "sending revoke_done");
393     remove_slave_from_list(rvk_st);
394     free(rvk_st);
395 }
396
397 void
398 revoke_done__rx(struct intermon_binding *b,
399                 genvaddr_t st)
400 {
401     struct revoke_master_st *rvk_st = (struct revoke_master_st*)(lvaddr_t)st;
402     if (!capsend_handle_mc_reply(&rvk_st->revoke_mc_st)) {
403         // multicast not complete
404         return;
405     }
406
407     rvk_st->remote_fin = true;
408     if (rvk_st->local_fin) {
409         revoke_result__rx(SYS_ERR_OK, rvk_st, true);
410     }
411 }
412
413 static void
414 revoke_master_steps__fin(void *st)
415 {
416     struct revoke_master_st *rvk_st = (struct revoke_master_st*)st;
417     rvk_st->local_fin = true;
418     if (rvk_st->remote_fin) {
419         revoke_result__rx(SYS_ERR_OK, rvk_st, true);
420     }
421 }