49d006d6369e3aa9f78db2978243a38686fcd860
[barrelfish] / usr / monitor / capops / retrieve.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 <if/intermon_defs.h>
12 #include "monitor.h"
13 #include "capops.h"
14 #include "capsend.h"
15 #include "magic.h"
16 #include "caplock.h"
17 #include "internal.h"
18 #include "dom_invocations.h"
19 #include "monitor_invocations.h"
20
21 struct retrieve_rpc_st {
22     struct intermon_msg_queue_elem iqn;
23     struct domcapref cap;
24     struct capability rawcap;
25     move_result_handler_t result_handler;
26     void *st;
27     coreid_t prev_owner;
28 };
29
30 struct retrieve_response_st {
31     struct intermon_msg_queue_elem iqn;
32     errval_t status;
33     uint8_t relations;
34     genvaddr_t st;
35     coreid_t from;
36 };
37
38 static void retrieve_owner__enq(struct retrieve_rpc_st *st);
39 static void retrieve_owner__send(struct intermon_binding *b,
40                                  struct intermon_msg_queue_elem *e);
41 static void retrieve_result__enq(errval_t status,
42                                  struct retrieve_response_st *st);
43 static void retrieve_result__send(struct intermon_binding *b,
44                                   struct intermon_msg_queue_elem *e);
45 static void retrieve_ownership_update__fin(void *st);
46
47 void
48 capops_retrieve(struct domcapref cap,
49                 move_result_handler_t result_handler,
50                 void *st)
51 {
52     errval_t err;
53
54     DEBUG_CAPOPS("%s ## start transfer ownership \n", __FUNCTION__);
55
56     distcap_state_t state;
57     err = dom_cnode_get_state(cap, &state);
58     GOTO_IF_ERR(err, report_error);
59     if (distcap_state_is_busy(state)) {
60         err = MON_ERR_REMOTE_CAP_RETRY;
61     }
62     GOTO_IF_ERR(err, report_error);
63
64     err = monitor_lock_cap(cap.croot, cap.cptr, cap.bits);
65     GOTO_IF_ERR(err, report_error);
66
67     struct retrieve_rpc_st *rst = NULL;
68     err = calloce(1, sizeof(*rst), &rst);
69     GOTO_IF_ERR(err, unlock_cap);
70
71     rst->cap = cap;
72     rst->result_handler = result_handler;
73     rst->st = st;
74
75     err = monitor_domains_cap_identify(cap.croot, cap.cptr, cap.bits, &rst->rawcap);
76     GOTO_IF_ERR(err, free_st);
77
78     err = monitor_get_domcap_owner(cap, &rst->prev_owner);
79     GOTO_IF_ERR(err, free_st);
80
81     if (rst->prev_owner == my_core_id) {
82         err = SYS_ERR_OK;
83         goto free_st;
84     }
85
86     retrieve_owner__enq(rst);
87
88     return;
89
90 free_st:
91     free(rst);
92
93 unlock_cap:
94     caplock_unlock(cap);
95
96 report_error:
97     result_handler(err, st);
98 }
99
100 static void
101 retrieve_ownership__rx(errval_t status, struct retrieve_rpc_st *st)
102 {
103     DEBUG_CAPOPS("%s ## transfer ownership done. calling %p\n", __FUNCTION__,
104                  st->result_handler);
105
106     caplock_unlock(st->cap);
107     st->result_handler(status, st->st);
108     free(st);
109 }
110
111 static void
112 retrieve_owner__enq(struct retrieve_rpc_st *st)
113 {
114     errval_t err;
115
116     st->iqn.cont = retrieve_owner__send;
117     err = capsend_owner(st->cap, (struct msg_queue_elem*)st);
118     if (err_is_fail(err)) {
119         retrieve_ownership__rx(err, st);
120     }
121 }
122
123 static void
124 retrieve_owner__send(struct intermon_binding *b,
125                      struct intermon_msg_queue_elem *e)
126 {
127     errval_t err;
128     struct retrieve_rpc_st *st = (struct retrieve_rpc_st*)e;
129     intermon_caprep_t caprep;
130
131     err = monitor_set_domcap_owner(st->cap, my_core_id);
132     GOTO_IF_ERR(err, report_error);
133
134     capability_to_caprep(&st->rawcap, &caprep);
135     err = intermon_capops_retrieve_request__tx(b, NOP_CONT, caprep, (lvaddr_t)st);
136     GOTO_IF_ERR(err, report_error);
137
138     return;
139
140 report_error:
141     DEBUG_CAPOPS("%s failed \n", __FUNCTION__);
142     retrieve_ownership__rx(err, st);
143 }
144
145 void
146 retrieve_request__rx(struct intermon_binding *b,
147                      intermon_caprep_t caprep,
148                      genvaddr_t st)
149 {
150     errval_t err, err2;
151     struct intermon_state *inter_st = (struct intermon_state*)b->st;
152
153     DEBUG_CAPOPS("%s ## transfer ownership request\n", __FUNCTION__);
154
155     struct retrieve_response_st *rst;
156     err = calloce(1, sizeof(*rst), &rst);
157     PANIC_IF_ERR(err, "allocating retrieve respones state");
158     rst->st = st;
159     rst->from = inter_st->core_id;
160
161     struct capability rawcap;
162     caprep_to_capability(&caprep, &rawcap);
163
164     struct capref cap;
165     err = slot_alloc(&cap);
166     GOTO_IF_ERR(err, respond_err);
167
168     err = monitor_copy_if_exists(&rawcap, cap);
169     GOTO_IF_ERR(err, free_slot);
170
171     distcap_state_t state;
172     err = dom_cnode_get_state(get_cap_domref(cap), &state);
173     GOTO_IF_ERR(err, delete_cap);
174
175     if (distcap_state_is_busy(state)) {
176         err = MON_ERR_REMOTE_CAP_RETRY;
177         goto delete_cap;
178     }
179     if (distcap_state_is_foreign(state)) {
180         err = MON_ERR_CAP_FOREIGN;
181         goto delete_cap;
182     }
183
184     uint8_t relations, remote_relations;
185     err = monitor_cap_has_relations(cap, 0xFF, &relations);
186     GOTO_IF_ERR(err, delete_cap);
187
188     err = monitor_remote_relations(cap, 0, 0, &remote_relations);
189     GOTO_IF_ERR(err, delete_cap);
190
191     rst->relations = relations | remote_relations | RRELS_COPY_BIT;
192
193     err = monitor_set_cap_owner(cap_root, get_cap_addr(cap),
194                                 get_cap_valid_bits(cap),
195                                 rst->from);
196
197 delete_cap:
198     err2 = cap_delete(cap);
199     DEBUG_IF_ERR(err2, "while deleting temp cap for retrieve");
200
201 free_slot:
202     err2 = slot_free(cap);
203     DEBUG_IF_ERR(err2, "freeing temp cap slot for retrieve");
204
205 respond_err:
206     retrieve_result__enq(err, rst);
207 }
208
209 static void
210 retrieve_result__enq(errval_t status, struct retrieve_response_st *st)
211 {
212     errval_t err;
213     st->status = status;
214     st->iqn.cont = retrieve_result__send;
215
216     err = capsend_target(st->from, (struct msg_queue_elem*)st);
217     PANIC_IF_ERR(err, "enqueing retrieve result");
218 }
219
220 static void
221 retrieve_result__send(struct intermon_binding *b,
222                       struct intermon_msg_queue_elem *e)
223 {
224     errval_t err;
225     struct retrieve_response_st *st = (struct retrieve_response_st*)e;
226
227     err = intermon_capops_retrieve_result__tx(b, NOP_CONT, st->status,
228                                               st->relations, st->st);
229     PANIC_IF_ERR(err, "sending retrieve result");
230     free(st);
231 }
232
233 void
234 retrieve_result__rx(struct intermon_binding *b, errval_t status,
235                     uint8_t relations, genvaddr_t st)
236 {
237     errval_t err;
238     struct retrieve_rpc_st *rst = (struct retrieve_rpc_st*)(lvaddr_t)st;
239
240     DEBUG_CAPOPS("%s ## ownership transferred: %s \n", __FUNCTION__,
241                  err_getstring(status));
242
243     if (err_is_fail(status)) {
244         err = status;
245         goto report_error;
246     }
247
248     err = monitor_domcap_remote_relations(rst->cap.croot, rst->cap.cptr,
249                                           rst->cap.bits, relations, 0xFF,
250                                           NULL);
251     PANIC_IF_ERR(err, "setting rrels for retrieved cap");
252
253     DEBUG_CAPOPS("%s broadcast updates to other monitors.\n", __FUNCTION__);
254
255     struct event_closure updated_cont
256         = MKCONT(retrieve_ownership_update__fin, rst);
257     err = capsend_update_owner(rst->cap, updated_cont);
258     PANIC_IF_ERR(err, "updating retrieve ownership");
259
260     return;
261
262 report_error:
263     retrieve_ownership__rx(err, rst);
264 }
265
266 static void
267 retrieve_ownership_update__fin(void *st)
268 {
269     struct retrieve_rpc_st *rst = (struct retrieve_rpc_st*)st;
270
271     DEBUG_CAPOPS("%s updated in ownership broadcasted.\n", __FUNCTION__);
272
273     retrieve_ownership__rx(SYS_ERR_OK, rst);
274 }