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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <barrelfish/barrelfish.h> 11#include <if/intermon_defs.h> 12#include "monitor.h" 13#include "capops.h" 14#include "capsend.h" 15#include "caplock.h" 16#include "internal.h" 17#include "dom_invocations.h" 18 19/* 20 * RPC State {{{1 21 */ 22 23struct cap_move_rpc_st { 24 // capref to a copy of the cap in question 25 struct domcapref capref; 26 // caller st 27 void *st; 28 // reuslt handler 29 move_result_handler_t result_handler; 30}; 31 32/* 33 * Move request 34 */ 35 36struct move_request_msg_st { 37 struct intermon_msg_queue_elem queue_elem; 38 intermon_caprep_t caprep; 39 uint8_t relations; 40 struct cap_move_rpc_st *st; 41}; 42 43static void 44move_request_send_cont(struct intermon_binding *b, struct intermon_msg_queue_elem *e) 45{ 46 errval_t err; 47 struct move_request_msg_st *msg_st = (struct move_request_msg_st*)e; 48 err = intermon_capops_move_request__tx(b, NOP_CONT, msg_st->caprep, 49 msg_st->relations, (lvaddr_t)msg_st->st); 50 51 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 52 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__); 53 struct intermon_state *inter_st = (struct intermon_state *)b->st; 54 // requeue send request at front and return 55 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset, 56 (struct msg_queue_elem *)e); 57 GOTO_IF_ERR(err, handle_err); 58 return; 59 } 60 61handle_err: 62 if (err_is_fail(err)) { 63 struct cap_move_rpc_st *rpc_st = (struct cap_move_rpc_st*)msg_st->st; 64 if (rpc_st->result_handler) { 65 rpc_st->result_handler(err, rpc_st->st); 66 } 67 free(rpc_st); 68 } 69 free(msg_st); 70} 71 72static errval_t 73move_request(struct domcapref capref, struct capability *cap, uint8_t relations, 74 coreid_t dest, move_result_handler_t result_handler, void *st) 75{ 76 errval_t err; 77 78 struct cap_move_rpc_st *rpc_st = malloc(sizeof(struct cap_move_rpc_st)); 79 if (!rpc_st) { 80 return LIB_ERR_MALLOC_FAIL; 81 } 82 rpc_st->capref = capref; 83 rpc_st->st = st; 84 rpc_st->result_handler = result_handler; 85 86 struct move_request_msg_st *msg_st = malloc(sizeof(struct move_request_msg_st)); 87 if (!msg_st) { 88 free(rpc_st); 89 return LIB_ERR_MALLOC_FAIL; 90 } 91 msg_st->queue_elem.cont = move_request_send_cont; 92 capability_to_caprep(cap, &msg_st->caprep); 93 msg_st->relations = relations; 94 msg_st->st = rpc_st; 95 96 err = capsend_target(dest, (struct msg_queue_elem*)msg_st); 97 if (err_is_fail(err)) { 98 free(msg_st); 99 free(rpc_st); 100 return err; 101 } 102 103 return SYS_ERR_OK; 104} 105 106/* 107 * Move result 108 */ 109 110struct move_result_msg_st { 111 struct intermon_msg_queue_elem queue_elem; 112 errval_t status; 113 genvaddr_t st; 114}; 115 116static void 117move_result_send_cont(struct intermon_binding *b, struct intermon_msg_queue_elem *e) 118{ 119 errval_t err; 120 struct move_result_msg_st *msg_st = (struct move_result_msg_st*)e; 121 err = intermon_capops_move_result__tx(b, NOP_CONT, msg_st->status, msg_st->st); 122 123 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 124 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__); 125 struct intermon_state *inter_st = (struct intermon_state *)b->st; 126 // requeue send request at front and return 127 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset, 128 (struct msg_queue_elem *)e); 129 GOTO_IF_ERR(err, handle_err); 130 return; 131 } 132 133handle_err: 134 if (err_is_fail(err)) { 135 USER_PANIC_ERR(err, "failed to send move_result"); 136 } 137 free(msg_st); 138} 139 140static errval_t 141move_result(coreid_t dest, errval_t status, genvaddr_t st) 142{ 143 errval_t err; 144 145 struct move_result_msg_st *msg_st = calloc(1, sizeof(struct move_result_msg_st)); 146 msg_st->queue_elem.cont = move_result_send_cont; 147 msg_st->status = status; 148 msg_st->st = st; 149 150 err = capsend_target(dest, (struct msg_queue_elem*)msg_st); 151 if (err_is_fail(err)) { 152 free(msg_st); 153 return err; 154 } 155 156 return SYS_ERR_OK; 157} 158 159/* 160 * Receive handlers {{{1 161 */ 162 163static void 164free_owner_recv_cap(void *arg) 165{ 166 struct capref *cap = (struct capref*)arg; 167 caplock_unlock(get_cap_domref(*cap)); 168 errval_t err = cap_destroy(*cap); 169 if (err_is_fail(err)) { 170 DEBUG_ERR(err, "destroying cap receiving ownersihp"); 171 } 172 free(cap); 173} 174 175void 176move_request__rx_handler(struct intermon_binding *b, intermon_caprep_t caprep, uint8_t relations, genvaddr_t st) 177{ 178 errval_t err, send_err; 179 struct intermon_state *inter_st = (struct intermon_state*)b->st; 180 coreid_t from = inter_st->core_id; 181 assert(from != my_core_id); 182 183 struct capability cap; 184 caprep_to_capability(&caprep, &cap); 185 186 struct capref *capref = calloc(1, sizeof(*capref)); 187 if (!capref) { 188 err = LIB_ERR_MALLOC_FAIL; 189 goto send_err; 190 } 191 192 err = slot_alloc(capref); 193 if (err_is_fail(err)) { 194 goto free_st; 195 } 196 197 struct domcapref domcapref = get_cap_domref(*capref); 198 199 err = monitor_copy_if_exists(&cap, *capref); 200 if (err_is_fail(err)) { 201 goto free_slot; 202 } 203 204 err = monitor_lock_cap(domcapref.croot, domcapref.cptr, domcapref.level); 205 if (err_is_fail(err)) { 206 goto destroy_cap; 207 } 208 209 err = monitor_set_domcap_owner(domcapref, my_core_id); 210 if (err_is_fail(err)) { 211 goto unlock_cap; 212 } 213 214 err = monitor_domcap_remote_relations(domcapref.croot, domcapref.cptr, 215 domcapref.level, relations, 216 ~(uint8_t)0, NULL); 217 if (err_is_fail(err)) { 218 goto reset_owner; 219 } 220 221 // If broadcast send doesn't fail, unlock cap only after all nodes have 222 // acknowledged ownership change, see free_owner_recv_cap(). 223 // XXX: should we wait to signal move completion until broadcast really 224 // completes? -SG,2017-11-09. 225 err = capsend_update_owner(domcapref, MKCONT(free_owner_recv_cap, capref)); 226 if (err_is_fail(err)) { 227 goto reset_owner; 228 } 229 230 err = SYS_ERR_OK; 231 goto send_err; 232 233reset_owner: 234 send_err = monitor_set_domcap_owner(domcapref, from); 235 if (err_is_fail(send_err)) { 236 USER_PANIC_ERR(send_err, "failed to reset owner while handling move failure"); 237 } 238 239unlock_cap: 240 send_err = monitor_unlock_cap(domcapref.croot, domcapref.cptr, 241 domcapref.level); 242 if (err_is_fail(send_err)) { 243 USER_PANIC_ERR(send_err, "failed to unlock cap while handling move failure"); 244 } 245 246destroy_cap: 247 cap_destroy(*capref); 248 249free_slot: 250 slot_free(*capref); 251 252free_st: 253 free(capref); 254 255send_err: 256 send_err = move_result(from, err, st); 257 if (err_is_fail(send_err)) { 258 USER_PANIC_ERR(send_err, "failed to send error to request_copy sender"); 259 } 260} 261 262void 263move_result__rx_handler(struct intermon_binding *b, errval_t status, genvaddr_t st) 264{ 265 struct intermon_state *inter_st = (struct intermon_state*)b->st; 266 coreid_t from = inter_st->core_id; 267 assert(from != my_core_id); 268 struct cap_move_rpc_st *rpc_st = (struct cap_move_rpc_st*)(lvaddr_t)st; 269 270 caplock_unlock(rpc_st->capref); 271 rpc_st->result_handler(status, rpc_st->st); 272 free(rpc_st); 273} 274 275/* 276 * Move operation {{{1 277 */ 278 279errval_t 280capops_move(struct domcapref capref, coreid_t dest, move_result_handler_t result_handler, 281 void *st) 282{ 283 errval_t err; 284 distcap_state_t state; 285 286 err = dom_cnode_get_state(capref, &state); 287 if (err_is_fail(err)) { 288 return err; 289 } 290 if (distcap_state_is_busy(state)) { 291 return MON_ERR_REMOTE_CAP_RETRY; 292 } 293 if (distcap_state_is_foreign(state)) { 294 return MON_ERR_CAP_FOREIGN; 295 } 296 297 if (dest == my_core_id) { 298 // tried to move to self and already owner, no-op 299 if (result_handler) { 300 result_handler(SYS_ERR_OK, st); 301 } 302 return SYS_ERR_OK; 303 } 304 305 struct capability cap; 306 err = monitor_domains_cap_identify(capref.croot, capref.cptr, capref.level, &cap); 307 if (err_is_fail(err)) { 308 return err; 309 } 310 311 if (!distcap_needs_locality(cap.type)) { 312 // XXX: move doesn't make sense here, but is "OK" result correct? 313 return SYS_ERR_OK; 314 } 315 if (!distcap_is_moveable(cap.type)) { 316 return MON_ERR_CAP_MOVE; 317 } 318 319 err = monitor_lock_cap(capref.croot, capref.cptr, capref.level); 320 if (err_is_fail(err)) { 321 return err; 322 } 323 324 uint8_t relations; 325 err = monitor_domcap_remote_relations(capref.croot, capref.cptr, capref.level, 326 0, 0, &relations); 327 if (err_is_fail(err)) { 328 caplock_unlock(capref); 329 return err; 330 } 331 332 err = move_request(capref, &cap, relations, dest, result_handler, st); 333 if (err_is_fail(err)) { 334 caplock_unlock(capref); 335 return err; 336 } 337 338 return SYS_ERR_OK; 339} 340