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>
11 #include <barrelfish/core_state.h>
17 #include "dom_invocations.h"
18 #include "delete_int.h"
20 #include "ram_alloc.h"
21 #include <if/mem_defs.h>
23 struct delete_remote_mc_st {
24 struct capsend_mc_st mc_st;
25 struct delete_st *del_st;
29 struct delete_remote_result_msg_st {
30 struct intermon_msg_queue_elem queue_elem;
35 static void delete_trylock_cont(void *st);
38 delete_result__rx(errval_t status, struct delete_st *del_st, bool locked)
40 DEBUG_CAPOPS("%s: status=%s, locked=%d\n", __FUNCTION__, err_getcode(status), locked);
44 caplock_unlock(del_st->capref);
47 err = slot_free(del_st->newcap);
48 if (err_is_fail(err) && err_no(err) != LIB_ERR_SLOT_UNALLOCATED) {
49 DEBUG_ERR(err, "freeing reclamation slot, will leak");
52 delete_result_handler_t handler = del_st->result_handler;
53 void *st = del_st->st;
59 send_new_ram_cap(struct capref cap)
61 DEBUG_CAPOPS("%s\n", __FUNCTION__);
64 struct capability cap_data;
65 err = monitor_cap_identify(cap, &cap_data);
66 assert(err_is_ok(err));
67 assert(cap_data.type == ObjType_RAM);
68 struct RAM ram = cap_data.u.ram;
70 struct ram_alloc_state *ram_alloc_state = get_ram_alloc_state();
71 thread_mutex_lock(&ram_alloc_state->ram_alloc_lock);
73 struct mem_binding *b = get_mem_client();
75 DEBUG_CAPOPS("%s: forwarding to monitor.0\n", __FUNCTION__);
76 // we're not on core 0, so forward free_monitor msg to monitor.0
77 err = mon_ram_free(&cap_data, ram.base, log2ceil(ram.bytes));
78 assert(err_is_ok(err));
80 DEBUG_CAPOPS("%s: we are monitor.0\n", __FUNCTION__);
81 // XXX: This should not be an RPC! It could stall the monitor, but
82 // we trust mem_serv for the moment.
83 err = b->rpc_tx_vtbl.free_monitor(b, cap, ram.base, log2ceil(ram.bytes), &result);
84 assert(err_is_ok(err));
85 assert(err_is_ok(result));
88 thread_mutex_unlock(&ram_alloc_state->ram_alloc_lock);
90 // XXX: this seems to happen during the lmp transfer anyway -SG
92 DEBUG_CAPOPS("%s: not monitor.0, deleting local copy\n", __FUNCTION__);
93 // should we do this if not on core 0? -SG
94 err = cap_delete(cap);
95 assert(err_is_ok(err));
97 DEBUG_CAPOPS("%s: finished\n", __FUNCTION__);
100 static void delete_wait__fin(void *st_)
102 DEBUG_CAPOPS("%s\n", __FUNCTION__);
103 struct delete_st *st = (struct delete_st*)st_;
104 delete_result__rx(SYS_ERR_OK, st, false);
107 static void delete_last(struct delete_st* del_st)
109 DEBUG_CAPOPS("%s\n", __FUNCTION__);
113 err = monitor_delete_last(del_st->capref.croot, del_st->capref.cptr,
114 del_st->capref.level, del_st->newcap);
115 GOTO_IF_ERR(err, report_error);
116 if (err_no(err) == SYS_ERR_RAM_CAP_CREATED) {
117 DEBUG_CAPOPS("%s: sending reclaimed RAM to memserv.\n", __FUNCTION__);
118 send_new_ram_cap(del_st->newcap);
122 DEBUG_CAPOPS("%s: deleted last copy\n", __FUNCTION__);
123 // at this point the cap has become "unlocked" because it is either deleted
124 // or in a clear/delete queue
131 DEBUG_CAPOPS("%s: waiting on delete queue\n", __FUNCTION__);
132 delete_queue_wait(&del_st->qn, MKCLOSURE(delete_wait__fin, del_st));
137 DEBUG_CAPOPS("%s: reporting error: %s\n", __FUNCTION__,
139 delete_result__rx(err, del_st, locked);
143 * Non-moveable cap types: deleting all foreign copies when last owned copy of
148 delete_remote__send(struct intermon_binding *b, intermon_caprep_t *caprep,
149 struct capsend_mc_st *st)
151 return intermon_capops_delete_remote__tx(b, NOP_CONT, *caprep,
156 delete_remote__enq(struct capability *cap, struct delete_st *st)
158 DEBUG_CAPOPS("%s\n", __FUNCTION__);
160 struct delete_remote_mc_st *mc_st;
162 err = malloce(sizeof(*mc_st), &mc_st);
163 GOTO_IF_ERR(err, report_error);
165 mc_st->status = SYS_ERR_OK;
167 err = capsend_copies(cap, delete_remote__send,
168 (struct capsend_mc_st*)mc_st);
169 GOTO_IF_ERR(err, report_error);
174 delete_result__rx(err, st, true);
178 delete_remote_result__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
181 struct delete_remote_result_msg_st *msg_st = (struct delete_remote_result_msg_st*)e;
182 err = intermon_capops_delete_remote_result__tx(b, NOP_CONT, msg_st->status, msg_st->st);
184 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
185 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
186 struct intermon_state *inter_st = (struct intermon_state *)b->st;
187 // requeue send request at front and return
188 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
189 (struct msg_queue_elem *)e);
190 GOTO_IF_ERR(err, handle_err);
195 PANIC_IF_ERR(err, "failed to send delete_remote_result msg");
200 delete_remote_result__enq(coreid_t dest, errval_t status, genvaddr_t st)
202 DEBUG_CAPOPS("%s: dest=%d, status=%s\n", __FUNCTION__, dest, err_getcode(status));
205 struct delete_remote_result_msg_st *msg_st;
206 err = calloce(1, sizeof(*msg_st), &msg_st);
207 PANIC_IF_ERR(err, "allocating delete_remote_result st");
209 msg_st->queue_elem.cont = delete_remote_result__send;
210 msg_st->status = status;
213 err = capsend_target(dest, (struct msg_queue_elem*)msg_st);
214 PANIC_IF_ERR(err, "failed to send delete_remote result");
218 delete_remote__rx(struct intermon_binding *b, intermon_caprep_t caprep,
221 DEBUG_CAPOPS("%s\n", __FUNCTION__);
223 struct capability cap;
224 struct intermon_state *inter_st = (struct intermon_state*)b->st;
225 coreid_t from = inter_st->core_id;
226 caprep_to_capability(&caprep, &cap);
227 struct capref capref;
229 err = slot_alloc(&capref);
230 GOTO_IF_ERR(err, send_err);
232 err = monitor_copy_if_exists(&cap, capref);
233 if (err_is_fail(err)) {
234 DEBUG_CAPOPS("%s: monitor_copy_if_exists: %s\n", __FUNCTION__, err_getcode(err));
235 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
236 // not found implies there were no copies, so everything is OK
242 err = monitor_delete_foreigns(capref);
243 DEBUG_CAPOPS("%s: monitor_delete_foreigns: %s\n", __FUNCTION__, err_getcode(err));
244 //err = monitor_delete_copies(capref);
245 //err2 = cap_delete(capref);
246 //DEBUG_IF_ERR(err2, "deleting temp delete_remote cap");
247 //if (err_is_ok(err) && err_is_fail(err2)) {
252 err2 = slot_free(capref);
253 DEBUG_IF_ERR(err2, "freeing temp delete_remote cap, will leak");
256 delete_remote_result__enq(from, err, st);
260 delete_remote_result__rx(struct intermon_binding *b, errval_t status,
263 DEBUG_CAPOPS("%s\n", __FUNCTION__);
265 struct delete_remote_mc_st *mc_st = (struct delete_remote_mc_st*)(lvaddr_t)st;
266 struct delete_st *del_st = mc_st->del_st;
268 // XXX: do something with received errors?
269 if (err_is_fail(status)) {
270 mc_st->status = status;
272 status = mc_st->status;
274 if (!capsend_handle_mc_reply(&mc_st->mc_st)) {
275 // multicast not complete
279 // multicast is complete, free state
282 // unlock cap so it can be deleted
283 caplock_unlock(del_st->capref);
285 if (err_is_ok(status)) {
286 // remote copies have been deleted, reset corresponding relations bit
287 err = monitor_domcap_remote_relations(del_st->capref.croot,
289 del_st->capref.level,
290 0, RRELS_COPY_BIT, NULL);
291 if (err_is_fail(err)) {
292 USER_PANIC_ERR(err, "clearing remote descs bit after remote delete");
295 // All remote copies deleted, delete local copy; can be last
296 err = dom_cnode_delete(del_st->capref);
297 errval_t last_owned = err_push(SYS_ERR_DELETE_LAST_OWNED,
298 SYS_ERR_RETRY_THROUGH_MONITOR);
299 // We got DELETE_LAST_OWNED from cpu driver, do delete_last()
300 if (err == last_owned) {
302 // We just assume that delete_last() succeeds
305 else if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
306 // this shouldn't really happen either, but isn't a problem
309 else if (err_is_fail(err)) {
310 // other than DELETE_LAST_OWNED, the simple delete should not fail
312 USER_PANIC_ERR(err, "this really should not happen");
319 delete_result__rx(err, del_st, false);
323 * Moveable cap type: try to migrate ownership elsewhere
326 static void move_result_cont(errval_t status, void *st);
329 find_core_cont(errval_t status, coreid_t core, void *st)
331 DEBUG_CAPOPS("%s\n", __FUNCTION__);
332 // called with the result of "find core with cap" when trying to move the
334 errval_t err = status;
335 struct delete_st *del_st = (struct delete_st*)st;
337 // unlock cap so it can be manipulated
338 caplock_unlock(del_st->capref);
340 if (err_no(status) == SYS_ERR_CAP_NOT_FOUND) {
341 // no core with cap exists, delete local cap with cleanup
342 err = monitor_domcap_remote_relations(del_st->capref.croot,
344 del_st->capref.level,
345 0, RRELS_COPY_BIT, NULL);
346 if (err_is_fail(err)) {
347 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
355 else if (err_is_fail(status)) {
360 // core found, attempt move
361 err = capops_move(del_st->capref, core, move_result_cont, st);
362 GOTO_IF_ERR(err, report_error);
368 delete_result__rx(err, del_st, false);
372 move_result_cont(errval_t status, void *st)
374 DEBUG_CAPOPS("%s\n", __FUNCTION__);
375 errval_t err = status;
376 struct delete_st *del_st = (struct delete_st*)st;
377 assert(distcap_is_moveable(del_st->cap.type));
379 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
380 // the found remote copy has disappeared, restart move process
381 delete_trylock_cont(del_st);
383 else if (err_is_fail(err)) {
384 delete_result__rx(err, del_st, false);
387 // move succeeded, cap is now foreign
388 err = dom_cnode_delete(del_st->capref);
389 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
392 delete_result__rx(err, del_st, false);
401 delete_trylock_cont(void *st)
403 DEBUG_CAPOPS("%s\n", __FUNCTION__);
406 struct delete_st *del_st = (struct delete_st*)st;
408 // try a simple delete
409 // NOTE: on the first pass, this is done twice (once in the capops_delete
410 // entry), but only this function is executed on every unlock event
411 err = dom_cnode_delete(del_st->capref);
412 if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR) {
413 // If cap is already locked, just enqueue for retry
414 if (err_no(err) == SYS_ERR_CAP_LOCKED) {
415 DEBUG_CAPOPS("%s: from cnode_delete(): cap already locked, queuing retry\n", __FUNCTION__);
416 caplock_wait(del_st->capref, &del_st->lock_qn,
417 MKCLOSURE(delete_trylock_cont, del_st));
420 // If cap not found, it has been deleted elsewhere, return OK
421 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
422 DEBUG_CAPOPS("%s: from cnode_delete(): cap not found, got deleted from elsewhere\n", __FUNCTION__);
423 err = err_push(SYS_ERR_OK, err);
428 err = monitor_lock_cap(del_st->capref.croot, del_st->capref.cptr,
429 del_st->capref.level);
430 if (err_no(err) == SYS_ERR_CAP_LOCKED) {
431 caplock_wait(del_st->capref, &del_st->lock_qn,
432 MKCLOSURE(delete_trylock_cont, del_st));
435 else if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
436 // Some other operation (another delete or a revoke) has deleted the
437 // target cap. This is OK.
438 err = err_push(SYS_ERR_OK, err);
441 else if (err_is_fail(err)) {
442 DEBUG_ERR(err, "locking cap for delete");
449 // check if there could be any remote relations
451 err = monitor_domcap_remote_relations(del_st->capref.croot,
453 del_st->capref.level,
455 GOTO_IF_ERR(err, report_error);
457 if (!(relations & RRELS_COPY_BIT)) {
458 // no remote relations, proceed with final delete
459 DEBUG_CAPOPS("%s: deleting last copy\n", __FUNCTION__);
462 else if (distcap_is_moveable(del_st->cap.type)) {
463 // if cap is moveable, move ownership so cap can then be deleted
464 DEBUG_CAPOPS("%s: move ownership\n", __FUNCTION__);
465 err = capsend_find_cap(&del_st->cap, find_core_cont, del_st);
466 GOTO_IF_ERR(err, report_error);
469 DEBUG_CAPOPS("%s: cap type %d not moveable, delete all copies\n",
470 __FUNCTION__, del_st->cap.type);
471 // otherwise delete all remote copies and then delete last copy
472 delete_remote__enq(&del_st->cap, del_st);
478 delete_result__rx(err, del_st, locked);
482 capops_delete_int(struct delete_st *del_st)
484 DEBUG_CAPOPS("%s\n", __FUNCTION__);
485 delete_trylock_cont(del_st);
489 capops_delete(struct domcapref cap,
490 delete_result_handler_t result_handler,
494 DEBUG_CAPOPS("%s\n", __FUNCTION__);
496 // try a simple delete
497 DEBUG_CAPOPS("%s: trying simple delete\n", __FUNCTION__);
498 err = dom_cnode_delete(cap);
499 // We can also continue here if we get SYS_ERR_CAP_LOCKED, as we're going
500 // to handle already locked caps correctly in delete_trylock_cont().
502 if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR &&
503 err_no(err) != SYS_ERR_CAP_LOCKED)
505 DEBUG_CAPOPS("%s: err != RETRY && err != LOCKED\n", __FUNCTION__);
509 // simple delete was not able to delete cap as:
510 // * it was last copy and:
511 // - may have remote copies, need to move or revoke cap
512 // - contains further slots which need to be cleared
513 // * currently locked
515 struct delete_st *del_st;
516 err = calloce(1, sizeof(*del_st), &del_st);
517 GOTO_IF_ERR(err, err_cont);
519 err = monitor_domains_cap_identify(cap.croot, cap.cptr, cap.level,
521 GOTO_IF_ERR(err, free_st);
523 err = slot_alloc(&del_st->newcap);
524 GOTO_IF_ERR(err, free_st);
526 del_st->capref = cap;
528 del_st->result_handler = result_handler;
531 // after this setup is complete, nothing less than a catastrophic failure
532 // should stop the delete
533 delete_trylock_cont(del_st);
540 DEBUG_CAPOPS("%s: calling result handler with err=%"PRIuERRV"\n", __FUNCTION__, err);
541 result_handler(err, st);