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 <barrelfish/core_state.h> 12#include "monitor.h" 13#include "capops.h" 14#include "capsend.h" 15#include "caplock.h" 16#include "capqueue.h" 17#include "dom_invocations.h" 18#include "delete_int.h" 19#include "internal.h" 20#include "ram_alloc.h" 21#include <if/mem_defs.h> 22 23struct delete_remote_mc_st { 24 struct capsend_mc_st mc_st; 25 struct delete_st *del_st; 26 errval_t status; 27}; 28 29struct delete_remote_result_msg_st { 30 struct intermon_msg_queue_elem queue_elem; 31 errval_t status; 32 genvaddr_t st; 33}; 34 35static void delete_trylock_cont(void *st); 36 37static void 38delete_result__rx(errval_t status, struct delete_st *del_st, bool locked) 39{ 40 DEBUG_CAPOPS("%s: status=%s, locked=%d\n", __FUNCTION__, err_getcode(status), locked); 41 errval_t err; 42 43 if (locked) { 44 caplock_unlock(del_st->capref); 45 } 46 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"); 50 } 51 52 // Delete our copy of domain's rootcn 53 err = cap_destroy(del_st->capref.croot); 54 PANIC_IF_ERR(err, "cleaning up domain's rootcn"); 55 56 delete_result_handler_t handler = del_st->result_handler; 57 void *st = del_st->st; 58 free(del_st); 59 handler(status, st); 60} 61 62void 63send_new_ram_cap(struct capref cap) 64{ 65 DEBUG_CAPOPS("%s\n", __FUNCTION__); 66 errval_t err, result; 67 68 struct capability cap_data; 69 err = monitor_cap_identify(cap, &cap_data); 70 assert(err_is_ok(err)); 71 assert(cap_data.type == ObjType_RAM); 72 struct RAM ram = cap_data.u.ram; 73 74 struct ram_alloc_state *ram_alloc_state = get_ram_alloc_state(); 75 thread_mutex_lock(&ram_alloc_state->ram_alloc_lock); 76 77 struct mem_binding *b = get_mem_client(); 78 if (!b) { 79 DEBUG_CAPOPS("%s: forwarding to monitor.0\n", __FUNCTION__); 80 // we're not on core 0, so forward free_monitor msg to monitor.0 81 err = mon_ram_free(&cap_data, ram.base, log2ceil(ram.bytes)); 82 assert(err_is_ok(err)); 83 } else { 84 DEBUG_CAPOPS("%s: we are monitor.0\n", __FUNCTION__); 85 // XXX: This should not be an RPC! It could stall the monitor, but 86 // we trust mem_serv for the moment. 87 err = b->rpc_tx_vtbl.free_monitor(b, cap, ram.base, log2ceil(ram.bytes), &result); 88 assert(err_is_ok(err)); 89 assert(err_is_ok(result)); 90 } 91 92 thread_mutex_unlock(&ram_alloc_state->ram_alloc_lock); 93 94 // XXX: this seems to happen during the lmp transfer anyway -SG 95 if (!b) { 96 DEBUG_CAPOPS("%s: not monitor.0, deleting local copy\n", __FUNCTION__); 97 // should we do this if not on core 0? -SG 98 err = cap_delete(cap); 99 assert(err_is_ok(err)); 100 } 101 DEBUG_CAPOPS("%s: finished\n", __FUNCTION__); 102} 103 104static void delete_wait__fin(void *st_) 105{ 106 DEBUG_CAPOPS("%s\n", __FUNCTION__); 107 struct delete_st *st = (struct delete_st*)st_; 108 delete_result__rx(SYS_ERR_OK, st, false); 109} 110 111static void delete_last(struct delete_st* del_st) 112{ 113 DEBUG_CAPOPS("%s\n", __FUNCTION__); 114 errval_t err; 115 bool locked = true; 116 117 err = monitor_delete_last(del_st->capref.croot, del_st->capref.cptr, 118 del_st->capref.level, del_st->newcap); 119 GOTO_IF_ERR(err, report_error); 120 if (err_no(err) == SYS_ERR_RAM_CAP_CREATED) { 121 DEBUG_CAPOPS("%s: sending reclaimed RAM to memserv.\n", __FUNCTION__); 122 send_new_ram_cap(del_st->newcap); 123 err = SYS_ERR_OK; 124 } 125 126 DEBUG_CAPOPS("%s: deleted last copy\n", __FUNCTION__); 127 // at this point the cap has become "unlocked" because it is either deleted 128 // or in a clear/delete queue 129 locked = false; 130 131 if (!del_st->wait) { 132 goto report_error; 133 } 134 135 DEBUG_CAPOPS("%s: waiting on delete queue\n", __FUNCTION__); 136 delete_queue_wait(&del_st->qn, MKCLOSURE(delete_wait__fin, del_st)); 137 138 return; 139 140report_error: 141 DEBUG_CAPOPS("%s: reporting error: %s\n", __FUNCTION__, 142 err_getstring(err)); 143 delete_result__rx(err, del_st, locked); 144} 145 146/* 147 * Non-moveable cap types: deleting all foreign copies when last owned copy of 148 * cap is deleted 149 */ 150 151static errval_t 152delete_remote__send(struct intermon_binding *b, intermon_caprep_t *caprep, 153 struct capsend_mc_st *st) 154{ 155 return intermon_capops_delete_remote__tx(b, NOP_CONT, *caprep, 156 (lvaddr_t)st); 157} 158 159static void 160delete_remote__enq(struct capability *cap, struct delete_st *st) 161{ 162 DEBUG_CAPOPS("%s\n", __FUNCTION__); 163 errval_t err; 164 struct delete_remote_mc_st *mc_st; 165 166 err = malloce(sizeof(*mc_st), &mc_st); 167 GOTO_IF_ERR(err, report_error); 168 mc_st->del_st = st; 169 mc_st->status = SYS_ERR_OK; 170 171 err = capsend_copies(cap, delete_remote__send, 172 (struct capsend_mc_st*)mc_st); 173 GOTO_IF_ERR(err, report_error); 174 175 return; 176 177report_error: 178 delete_result__rx(err, st, true); 179} 180 181static void 182delete_remote_result__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e) 183{ 184 errval_t err; 185 struct delete_remote_result_msg_st *msg_st = (struct delete_remote_result_msg_st*)e; 186 err = intermon_capops_delete_remote_result__tx(b, NOP_CONT, msg_st->status, msg_st->st); 187 188 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 189 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__); 190 struct intermon_state *inter_st = (struct intermon_state *)b->st; 191 // requeue send request at front and return 192 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset, 193 (struct msg_queue_elem *)e); 194 GOTO_IF_ERR(err, handle_err); 195 return; 196 } 197 198handle_err: 199 PANIC_IF_ERR(err, "failed to send delete_remote_result msg"); 200 free(msg_st); 201} 202 203static void 204delete_remote_result__enq(coreid_t dest, errval_t status, genvaddr_t st) 205{ 206 DEBUG_CAPOPS("%s: dest=%d, status=%s\n", __FUNCTION__, dest, err_getcode(status)); 207 errval_t err; 208 209 struct delete_remote_result_msg_st *msg_st; 210 err = calloce(1, sizeof(*msg_st), &msg_st); 211 PANIC_IF_ERR(err, "allocating delete_remote_result st"); 212 213 msg_st->queue_elem.cont = delete_remote_result__send; 214 msg_st->status = status; 215 msg_st->st = st; 216 217 err = capsend_target(dest, (struct msg_queue_elem*)msg_st); 218 PANIC_IF_ERR(err, "failed to send delete_remote result"); 219} 220 221void 222delete_remote__rx(struct intermon_binding *b, intermon_caprep_t caprep, 223 genvaddr_t st) 224{ 225 DEBUG_CAPOPS("%s\n", __FUNCTION__); 226 errval_t err, err2; 227 struct capability cap; 228 struct intermon_state *inter_st = (struct intermon_state*)b->st; 229 coreid_t from = inter_st->core_id; 230 caprep_to_capability(&caprep, &cap); 231 struct capref capref; 232 233 err = slot_alloc(&capref); 234 GOTO_IF_ERR(err, send_err); 235 236 err = monitor_copy_if_exists(&cap, capref); 237 if (err_is_fail(err)) { 238 DEBUG_CAPOPS("%s: monitor_copy_if_exists: %s\n", __FUNCTION__, err_getcode(err)); 239 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) { 240 // not found implies there were no copies, so everything is OK 241 err = SYS_ERR_OK; 242 } 243 goto free_slot; 244 } 245 246 err = monitor_delete_foreigns(capref); 247 DEBUG_CAPOPS("%s: monitor_delete_foreigns: %s\n", __FUNCTION__, err_getcode(err)); 248 //err = monitor_delete_copies(capref); 249 //err2 = cap_delete(capref); 250 //DEBUG_IF_ERR(err2, "deleting temp delete_remote cap"); 251 //if (err_is_ok(err) && err_is_fail(err2)) { 252 // err = err2; 253 //} 254 255free_slot: 256 err2 = slot_free(capref); 257 DEBUG_IF_ERR(err2, "freeing temp delete_remote cap, will leak"); 258 259send_err: 260 delete_remote_result__enq(from, err, st); 261} 262 263void 264delete_remote_result__rx(struct intermon_binding *b, errval_t status, 265 genvaddr_t st) 266{ 267 DEBUG_CAPOPS("%s\n", __FUNCTION__); 268 errval_t err; 269 struct delete_remote_mc_st *mc_st = (struct delete_remote_mc_st*)(lvaddr_t)st; 270 struct delete_st *del_st = mc_st->del_st; 271 272 // XXX: do something with received errors? 273 if (err_is_fail(status)) { 274 mc_st->status = status; 275 } 276 status = mc_st->status; 277 278 if (!capsend_handle_mc_reply(&mc_st->mc_st)) { 279 // multicast not complete 280 return; 281 } 282 283 // multicast is complete, free state 284 free(mc_st); 285 286 // unlock cap so it can be deleted 287 caplock_unlock(del_st->capref); 288 289 if (err_is_ok(status)) { 290 // remote copies have been deleted, reset corresponding relations bit 291 err = monitor_domcap_remote_relations(del_st->capref.croot, 292 del_st->capref.cptr, 293 del_st->capref.level, 294 0, RRELS_COPY_BIT, NULL); 295 if (err_is_fail(err)) { 296 USER_PANIC_ERR(err, "clearing remote descs bit after remote delete"); 297 } 298 299 // All remote copies deleted, delete local copy; can be last 300 err = dom_cnode_delete(del_st->capref); 301 errval_t last_owned = err_push(SYS_ERR_DELETE_LAST_OWNED, 302 SYS_ERR_RETRY_THROUGH_MONITOR); 303 // We got DELETE_LAST_OWNED from cpu driver, do delete_last() 304 if (err == last_owned) { 305 delete_last(del_st); 306 // We just assume that delete_last() succeeds 307 err = SYS_ERR_OK; 308 } 309 else if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) { 310 // this shouldn't really happen either, but isn't a problem 311 err = SYS_ERR_OK; 312 } 313 else if (err_is_fail(err)) { 314 // other than DELETE_LAST_OWNED, the simple delete should not fail 315 // here. 316 USER_PANIC_ERR(err, "this really should not happen"); 317 } 318 } 319 else { 320 err = status; 321 } 322 323 delete_result__rx(err, del_st, false); 324} 325 326/* 327 * Moveable cap type: try to migrate ownership elsewhere 328 */ 329 330static void move_result_cont(errval_t status, void *st); 331 332static void 333find_core_cont(errval_t status, coreid_t core, void *st) 334{ 335 DEBUG_CAPOPS("%s\n", __FUNCTION__); 336 // called with the result of "find core with cap" when trying to move the 337 // last cap 338 errval_t err = status; 339 struct delete_st *del_st = (struct delete_st*)st; 340 341 // unlock cap so it can be manipulated 342 caplock_unlock(del_st->capref); 343 344 if (err_no(status) == SYS_ERR_CAP_NOT_FOUND) { 345 // no core with cap exists, delete local cap with cleanup 346 err = monitor_domcap_remote_relations(del_st->capref.croot, 347 del_st->capref.cptr, 348 del_st->capref.level, 349 0, RRELS_COPY_BIT, NULL); 350 if (err_is_fail(err)) { 351 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) { 352 err = SYS_ERR_OK; 353 } 354 goto report_error; 355 } 356 357 delete_last(del_st); 358 } 359 else if (err_is_fail(status)) { 360 // an error occured 361 goto report_error; 362 } 363 else { 364 // core found, attempt move 365 err = capops_move(del_st->capref, core, move_result_cont, st); 366 GOTO_IF_ERR(err, report_error); 367 } 368 369 return; 370 371report_error: 372 delete_result__rx(err, del_st, false); 373} 374 375static void 376move_result_cont(errval_t status, void *st) 377{ 378 DEBUG_CAPOPS("%s\n", __FUNCTION__); 379 errval_t err = status; 380 struct delete_st *del_st = (struct delete_st*)st; 381 assert(distcap_is_moveable(del_st->cap.type)); 382 383 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) { 384 // the found remote copy has disappeared, restart move process 385 delete_trylock_cont(del_st); 386 } 387 else if (err_is_fail(err)) { 388 delete_result__rx(err, del_st, false); 389 } 390 else { 391 // move succeeded, cap is now foreign 392 err = dom_cnode_delete(del_st->capref); 393 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) { 394 err = SYS_ERR_OK; 395 } 396 delete_result__rx(err, del_st, false); 397 } 398} 399 400/* 401 * Delete operation 402 */ 403 404static void 405delete_trylock_cont(void *st) 406{ 407 DEBUG_CAPOPS("%s\n", __FUNCTION__); 408 errval_t err; 409 bool locked = false; 410 struct delete_st *del_st = (struct delete_st*)st; 411 412 // try a simple delete 413 // NOTE: on the first pass, this is done twice (once in the capops_delete 414 // entry), but only this function is executed on every unlock event 415 err = dom_cnode_delete(del_st->capref); 416 if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR) { 417 // If cap is already locked, just enqueue for retry 418 if (err_no(err) == SYS_ERR_CAP_LOCKED) { 419 DEBUG_CAPOPS("%s: from cnode_delete(): cap already locked, queuing retry\n", __FUNCTION__); 420 caplock_wait(del_st->capref, &del_st->lock_qn, 421 MKCLOSURE(delete_trylock_cont, del_st)); 422 return; 423 } 424 // If cap not found, it has been deleted elsewhere, return OK 425 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) { 426 DEBUG_CAPOPS("%s: from cnode_delete(): cap not found, got deleted from elsewhere\n", __FUNCTION__); 427 err = err_push(SYS_ERR_OK, err); 428 } 429 goto report_error; 430 } 431 432 err = monitor_lock_cap(del_st->capref.croot, del_st->capref.cptr, 433 del_st->capref.level); 434 if (err_no(err) == SYS_ERR_CAP_LOCKED) { 435 DEBUG_CAPOPS("%s: from lock(): cap already locked, queuing retry\n", __FUNCTION__); 436 caplock_wait(del_st->capref, &del_st->lock_qn, 437 MKCLOSURE(delete_trylock_cont, del_st)); 438 return; 439 } 440 else if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) { 441 DEBUG_CAPOPS("%s: from lock(): cap not found, got deleted from elsewhere\n", __FUNCTION__); 442 // Some other operation (another delete or a revoke) has deleted the 443 // target cap. This is OK. 444 err = err_push(SYS_ERR_OK, err); 445 goto report_error; 446 } 447 else if (err_is_fail(err)) { 448 DEBUG_ERR(err, "locking cap for delete"); 449 goto report_error; 450 } 451 else { 452 locked = true; 453 } 454 455 // check if there could be any remote relations 456 uint8_t relations; 457 err = monitor_domcap_remote_relations(del_st->capref.croot, 458 del_st->capref.cptr, 459 del_st->capref.level, 460 0, 0, &relations); 461 GOTO_IF_ERR(err, report_error); 462 463 if (!(relations & RRELS_COPY_BIT)) { 464 // no remote relations, proceed with final delete 465 DEBUG_CAPOPS("%s: deleting last copy\n", __FUNCTION__); 466 delete_last(del_st); 467 } 468 else if (distcap_is_moveable(del_st->cap.type)) { 469 // if cap is moveable, move ownership so cap can then be deleted 470 DEBUG_CAPOPS("%s: move ownership\n", __FUNCTION__); 471 err = capsend_find_cap(&del_st->cap, find_core_cont, del_st); 472 GOTO_IF_ERR(err, report_error); 473 } 474 else { 475 DEBUG_CAPOPS("%s: cap type %d not moveable, delete all copies\n", 476 __FUNCTION__, del_st->cap.type); 477 // otherwise delete all remote copies and then delete last copy 478 delete_remote__enq(&del_st->cap, del_st); 479 } 480 481 return; 482 483report_error: 484 DEBUG_CAPOPS("%s: reporting error: %s\n", __FUNCTION__, err_getcode(err)); 485 delete_result__rx(err, del_st, locked); 486} 487 488void 489capops_delete_int(struct delete_st *del_st) 490{ 491 DEBUG_CAPOPS("%s\n", __FUNCTION__); 492 delete_trylock_cont(del_st); 493} 494 495void 496capops_delete(struct domcapref cap, 497 delete_result_handler_t result_handler, 498 void *st) 499{ 500 errval_t err; 501 DEBUG_CAPOPS("%s\n", __FUNCTION__); 502 503 // try a simple delete 504 DEBUG_CAPOPS("%s: trying simple delete\n", __FUNCTION__); 505 err = dom_cnode_delete(cap); 506 // We can also continue here if we get SYS_ERR_CAP_LOCKED, as we're going 507 // to handle already locked caps correctly in delete_trylock_cont(). 508 // -SG, 2017-05-02 509 if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR && 510 err_no(err) != SYS_ERR_CAP_LOCKED) 511 { 512 DEBUG_CAPOPS("%s: err != RETRY && err != LOCKED\n", __FUNCTION__); 513 goto err_cont; 514 } 515 516 // simple delete was not able to delete cap as: 517 // * it was last copy and: 518 // - may have remote copies, need to move or revoke cap 519 // - contains further slots which need to be cleared 520 // * currently locked 521 522 struct delete_st *del_st; 523 err = calloce(1, sizeof(*del_st), &del_st); 524 GOTO_IF_ERR(err, err_cont); 525 526 err = monitor_domains_cap_identify(cap.croot, cap.cptr, cap.level, 527 &del_st->cap); 528 GOTO_IF_ERR(err, free_st); 529 530 err = slot_alloc(&del_st->newcap); 531 GOTO_IF_ERR(err, free_st); 532 533 del_st->capref = cap; 534 del_st->wait = true; 535 del_st->result_handler = result_handler; 536 del_st->st = st; 537 538 // after this setup is complete, nothing less than a catastrophic failure 539 // should stop the delete 540 delete_trylock_cont(del_st); 541 return; 542 543free_st: 544 free(del_st); 545 546err_cont: 547 DEBUG_CAPOPS("%s: calling result handler with err=%"PRIuERRV"\n", __FUNCTION__, err); 548 result_handler(err, st); 549} 550