1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc * Changes:
3433d6423SLionel Sambuc * Jan 22, 2010: Created (Cristiano Giuffrida)
4433d6423SLionel Sambuc */
5433d6423SLionel Sambuc
6433d6423SLionel Sambuc #include "inc.h"
7433d6423SLionel Sambuc
8433d6423SLionel Sambuc #include "kernel/proc.h"
9433d6423SLionel Sambuc
10433d6423SLionel Sambuc static int check_request(struct rs_start *rs_start);
11433d6423SLionel Sambuc
12433d6423SLionel Sambuc /*===========================================================================*
13433d6423SLionel Sambuc * do_up *
14433d6423SLionel Sambuc *===========================================================================*/
do_up(m_ptr)15433d6423SLionel Sambuc int do_up(m_ptr)
16433d6423SLionel Sambuc message *m_ptr; /* request message pointer */
17433d6423SLionel Sambuc {
18433d6423SLionel Sambuc /* A request was made to start a new system service. */
19433d6423SLionel Sambuc struct rproc *rp;
20433d6423SLionel Sambuc struct rprocpub *rpub;
21*181fb1b2SDavid van Moolenbroek int i, r;
22433d6423SLionel Sambuc struct rs_start rs_start;
23433d6423SLionel Sambuc int noblock;
24fb6bd596SCristiano Giuffrida int init_flags = 0;
25433d6423SLionel Sambuc
26433d6423SLionel Sambuc /* Check if the call can be allowed. */
27433d6423SLionel Sambuc if((r = check_call_permission(m_ptr->m_source, RS_UP, NULL)) != OK)
28433d6423SLionel Sambuc return r;
29433d6423SLionel Sambuc
30433d6423SLionel Sambuc /* Allocate a new system service slot. */
31433d6423SLionel Sambuc r = alloc_slot(&rp);
32433d6423SLionel Sambuc if(r != OK) {
33433d6423SLionel Sambuc printf("RS: do_up: unable to allocate a new slot: %d\n", r);
34433d6423SLionel Sambuc return r;
35433d6423SLionel Sambuc }
36433d6423SLionel Sambuc rpub = rp->r_pub;
37433d6423SLionel Sambuc
38433d6423SLionel Sambuc /* Copy the request structure. */
39433d6423SLionel Sambuc r = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
40433d6423SLionel Sambuc if (r != OK) {
41433d6423SLionel Sambuc return r;
42433d6423SLionel Sambuc }
43433d6423SLionel Sambuc r = check_request(&rs_start);
44433d6423SLionel Sambuc if (r != OK) {
45433d6423SLionel Sambuc return r;
46433d6423SLionel Sambuc }
47fb6bd596SCristiano Giuffrida
48fb6bd596SCristiano Giuffrida /* Check flags. */
49433d6423SLionel Sambuc noblock = (rs_start.rss_flags & RSS_NOBLOCK);
50fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_FORCE_INIT_CRASH) {
51fb6bd596SCristiano Giuffrida init_flags |= SEF_INIT_CRASH;
52fb6bd596SCristiano Giuffrida }
53fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_FORCE_INIT_FAIL) {
54fb6bd596SCristiano Giuffrida init_flags |= SEF_INIT_FAIL;
55fb6bd596SCristiano Giuffrida }
56fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_FORCE_INIT_TIMEOUT) {
57fb6bd596SCristiano Giuffrida init_flags |= SEF_INIT_TIMEOUT;
58fb6bd596SCristiano Giuffrida }
59fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_FORCE_INIT_DEFCB) {
60fb6bd596SCristiano Giuffrida init_flags |= SEF_INIT_DEFCB;
61fb6bd596SCristiano Giuffrida }
62433d6423SLionel Sambuc
63433d6423SLionel Sambuc /* Initialize the slot as requested. */
64433d6423SLionel Sambuc r = init_slot(rp, &rs_start, m_ptr->m_source);
65433d6423SLionel Sambuc if(r != OK) {
66433d6423SLionel Sambuc printf("RS: do_up: unable to init the new slot: %d\n", r);
67433d6423SLionel Sambuc return r;
68433d6423SLionel Sambuc }
69433d6423SLionel Sambuc
70433d6423SLionel Sambuc /* Check for duplicates */
71433d6423SLionel Sambuc if(lookup_slot_by_label(rpub->label)) {
72433d6423SLionel Sambuc printf("RS: service with the same label '%s' already exists\n",
73433d6423SLionel Sambuc rpub->label);
74433d6423SLionel Sambuc return EBUSY;
75433d6423SLionel Sambuc }
76433d6423SLionel Sambuc if(rpub->dev_nr>0 && lookup_slot_by_dev_nr(rpub->dev_nr)) {
77433d6423SLionel Sambuc printf("RS: service with the same device number %d already exists\n",
78433d6423SLionel Sambuc rpub->dev_nr);
79433d6423SLionel Sambuc return EBUSY;
80433d6423SLionel Sambuc }
81*181fb1b2SDavid van Moolenbroek for (i = 0; i < rpub->nr_domain; i++) {
82*181fb1b2SDavid van Moolenbroek if (lookup_slot_by_domain(rpub->domain[i]) != NULL) {
83*181fb1b2SDavid van Moolenbroek printf("RS: service with the same domain %d already exists\n",
84*181fb1b2SDavid van Moolenbroek rpub->domain[i]);
85*181fb1b2SDavid van Moolenbroek return EBUSY;
86*181fb1b2SDavid van Moolenbroek }
87*181fb1b2SDavid van Moolenbroek }
88433d6423SLionel Sambuc
89433d6423SLionel Sambuc /* All information was gathered. Now try to start the system service. */
90fb6bd596SCristiano Giuffrida r = start_service(rp, init_flags);
91433d6423SLionel Sambuc if(r != OK) {
92433d6423SLionel Sambuc return r;
93433d6423SLionel Sambuc }
94433d6423SLionel Sambuc
95433d6423SLionel Sambuc /* Unblock the caller immediately if requested. */
96433d6423SLionel Sambuc if(noblock) {
97433d6423SLionel Sambuc return OK;
98433d6423SLionel Sambuc }
99433d6423SLionel Sambuc
100433d6423SLionel Sambuc /* Late reply - send a reply when service completes initialization. */
101433d6423SLionel Sambuc rp->r_flags |= RS_LATEREPLY;
102433d6423SLionel Sambuc rp->r_caller = m_ptr->m_source;
103433d6423SLionel Sambuc rp->r_caller_request = RS_UP;
104433d6423SLionel Sambuc
105433d6423SLionel Sambuc return EDONTREPLY;
106433d6423SLionel Sambuc }
107433d6423SLionel Sambuc
108433d6423SLionel Sambuc /*===========================================================================*
109433d6423SLionel Sambuc * do_down *
110433d6423SLionel Sambuc *===========================================================================*/
do_down(message * m_ptr)111433d6423SLionel Sambuc int do_down(message *m_ptr)
112433d6423SLionel Sambuc {
113433d6423SLionel Sambuc register struct rproc *rp;
114433d6423SLionel Sambuc int s;
115433d6423SLionel Sambuc char label[RS_MAX_LABEL_LEN];
116433d6423SLionel Sambuc
117433d6423SLionel Sambuc /* Copy label. */
118433d6423SLionel Sambuc s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
119433d6423SLionel Sambuc m_ptr->m_rs_req.len, label, sizeof(label));
120433d6423SLionel Sambuc if(s != OK) {
121433d6423SLionel Sambuc return s;
122433d6423SLionel Sambuc }
123433d6423SLionel Sambuc
124433d6423SLionel Sambuc /* Lookup slot by label. */
125433d6423SLionel Sambuc rp = lookup_slot_by_label(label);
126433d6423SLionel Sambuc if(!rp) {
127433d6423SLionel Sambuc if(rs_verbose)
128433d6423SLionel Sambuc printf("RS: do_down: service '%s' not found\n", label);
129433d6423SLionel Sambuc return(ESRCH);
130433d6423SLionel Sambuc }
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc /* Check if the call can be allowed. */
133433d6423SLionel Sambuc if((s = check_call_permission(m_ptr->m_source, RS_DOWN, rp)) != OK)
134433d6423SLionel Sambuc return s;
135433d6423SLionel Sambuc
136433d6423SLionel Sambuc /* Stop service. */
137433d6423SLionel Sambuc if (rp->r_flags & RS_TERMINATED) {
138433d6423SLionel Sambuc /* A recovery script is requesting us to bring down the service.
139433d6423SLionel Sambuc * The service is already gone, simply perform cleanup.
140433d6423SLionel Sambuc */
141433d6423SLionel Sambuc if(rs_verbose)
142433d6423SLionel Sambuc printf("RS: recovery script performs service down...\n");
143433d6423SLionel Sambuc unpublish_service(rp);
144433d6423SLionel Sambuc cleanup_service(rp);
145433d6423SLionel Sambuc return(OK);
146433d6423SLionel Sambuc }
147433d6423SLionel Sambuc stop_service(rp,RS_EXITING);
148433d6423SLionel Sambuc
149433d6423SLionel Sambuc /* Late reply - send a reply when service dies. */
150433d6423SLionel Sambuc rp->r_flags |= RS_LATEREPLY;
151433d6423SLionel Sambuc rp->r_caller = m_ptr->m_source;
152433d6423SLionel Sambuc rp->r_caller_request = RS_DOWN;
153433d6423SLionel Sambuc
154433d6423SLionel Sambuc return EDONTREPLY;
155433d6423SLionel Sambuc }
156433d6423SLionel Sambuc
157433d6423SLionel Sambuc /*===========================================================================*
158433d6423SLionel Sambuc * do_restart *
159433d6423SLionel Sambuc *===========================================================================*/
do_restart(message * m_ptr)160433d6423SLionel Sambuc int do_restart(message *m_ptr)
161433d6423SLionel Sambuc {
162433d6423SLionel Sambuc struct rproc *rp;
163433d6423SLionel Sambuc int s, r;
164433d6423SLionel Sambuc char label[RS_MAX_LABEL_LEN];
165433d6423SLionel Sambuc char script[MAX_SCRIPT_LEN];
166433d6423SLionel Sambuc
167433d6423SLionel Sambuc /* Copy label. */
168433d6423SLionel Sambuc s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
169433d6423SLionel Sambuc m_ptr->m_rs_req.len, label, sizeof(label));
170433d6423SLionel Sambuc if(s != OK) {
171433d6423SLionel Sambuc return s;
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc
174433d6423SLionel Sambuc /* Lookup slot by label. */
175433d6423SLionel Sambuc rp = lookup_slot_by_label(label);
176433d6423SLionel Sambuc if(!rp) {
177433d6423SLionel Sambuc if(rs_verbose)
178433d6423SLionel Sambuc printf("RS: do_restart: service '%s' not found\n", label);
179433d6423SLionel Sambuc return(ESRCH);
180433d6423SLionel Sambuc }
181433d6423SLionel Sambuc
182433d6423SLionel Sambuc /* Check if the call can be allowed. */
183433d6423SLionel Sambuc if((r = check_call_permission(m_ptr->m_source, RS_RESTART, rp)) != OK)
184433d6423SLionel Sambuc return r;
185433d6423SLionel Sambuc
186433d6423SLionel Sambuc /* We can only be asked to restart a service from a recovery script. */
187433d6423SLionel Sambuc if (! (rp->r_flags & RS_TERMINATED) ) {
188433d6423SLionel Sambuc if(rs_verbose)
189433d6423SLionel Sambuc printf("RS: %s is still running\n", srv_to_string(rp));
190433d6423SLionel Sambuc return EBUSY;
191433d6423SLionel Sambuc }
192433d6423SLionel Sambuc
193433d6423SLionel Sambuc if(rs_verbose)
194433d6423SLionel Sambuc printf("RS: recovery script performs service restart...\n");
195433d6423SLionel Sambuc
196433d6423SLionel Sambuc /* Restart the service, but make sure we don't call the script again. */
197433d6423SLionel Sambuc strcpy(script, rp->r_script);
198433d6423SLionel Sambuc rp->r_script[0] = '\0';
199433d6423SLionel Sambuc restart_service(rp);
200433d6423SLionel Sambuc strcpy(rp->r_script, script);
201433d6423SLionel Sambuc
202433d6423SLionel Sambuc return OK;
203433d6423SLionel Sambuc }
204433d6423SLionel Sambuc
205433d6423SLionel Sambuc /*===========================================================================*
206433d6423SLionel Sambuc * do_clone *
207433d6423SLionel Sambuc *===========================================================================*/
do_clone(message * m_ptr)208433d6423SLionel Sambuc int do_clone(message *m_ptr)
209433d6423SLionel Sambuc {
210433d6423SLionel Sambuc struct rproc *rp;
211433d6423SLionel Sambuc struct rprocpub *rpub;
212433d6423SLionel Sambuc int s, r;
213433d6423SLionel Sambuc char label[RS_MAX_LABEL_LEN];
214433d6423SLionel Sambuc
215433d6423SLionel Sambuc /* Copy label. */
216433d6423SLionel Sambuc s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
217433d6423SLionel Sambuc m_ptr->m_rs_req.len, label, sizeof(label));
218433d6423SLionel Sambuc if(s != OK) {
219433d6423SLionel Sambuc return s;
220433d6423SLionel Sambuc }
221433d6423SLionel Sambuc
222433d6423SLionel Sambuc /* Lookup slot by label. */
223433d6423SLionel Sambuc rp = lookup_slot_by_label(label);
224433d6423SLionel Sambuc if(!rp) {
225433d6423SLionel Sambuc if(rs_verbose)
226433d6423SLionel Sambuc printf("RS: do_clone: service '%s' not found\n", label);
227433d6423SLionel Sambuc return(ESRCH);
228433d6423SLionel Sambuc }
229433d6423SLionel Sambuc rpub = rp->r_pub;
230433d6423SLionel Sambuc
231433d6423SLionel Sambuc /* Check if the call can be allowed. */
232433d6423SLionel Sambuc if((r = check_call_permission(m_ptr->m_source, RS_CLONE, rp)) != OK)
233433d6423SLionel Sambuc return r;
234433d6423SLionel Sambuc
235433d6423SLionel Sambuc /* Don't clone if a replica is already available. */
236433d6423SLionel Sambuc if(rp->r_next_rp) {
237433d6423SLionel Sambuc return EEXIST;
238433d6423SLionel Sambuc }
239433d6423SLionel Sambuc
240433d6423SLionel Sambuc /* Clone the service as requested. */
241433d6423SLionel Sambuc rpub->sys_flags |= SF_USE_REPL;
242fb6bd596SCristiano Giuffrida if ((r = clone_service(rp, RST_SYS_PROC, 0)) != OK) {
243433d6423SLionel Sambuc rpub->sys_flags &= ~SF_USE_REPL;
244433d6423SLionel Sambuc return r;
245433d6423SLionel Sambuc }
246433d6423SLionel Sambuc
247433d6423SLionel Sambuc return OK;
248433d6423SLionel Sambuc }
249433d6423SLionel Sambuc
250433d6423SLionel Sambuc /*===========================================================================*
251fb6bd596SCristiano Giuffrida * do_unclone *
252fb6bd596SCristiano Giuffrida *===========================================================================*/
do_unclone(message * m_ptr)253fb6bd596SCristiano Giuffrida int do_unclone(message *m_ptr)
254fb6bd596SCristiano Giuffrida {
255fb6bd596SCristiano Giuffrida struct rproc *rp;
256fb6bd596SCristiano Giuffrida struct rprocpub *rpub;
257fb6bd596SCristiano Giuffrida int s, r;
258fb6bd596SCristiano Giuffrida char label[RS_MAX_LABEL_LEN];
259fb6bd596SCristiano Giuffrida
260fb6bd596SCristiano Giuffrida /* Copy label. */
261fb6bd596SCristiano Giuffrida s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
262fb6bd596SCristiano Giuffrida m_ptr->m_rs_req.len, label, sizeof(label));
263fb6bd596SCristiano Giuffrida if(s != OK) {
264fb6bd596SCristiano Giuffrida return s;
265fb6bd596SCristiano Giuffrida }
266fb6bd596SCristiano Giuffrida
267fb6bd596SCristiano Giuffrida /* Lookup slot by label. */
268fb6bd596SCristiano Giuffrida rp = lookup_slot_by_label(label);
269fb6bd596SCristiano Giuffrida if(!rp) {
270fb6bd596SCristiano Giuffrida if(rs_verbose)
271fb6bd596SCristiano Giuffrida printf("RS: do_unclone: service '%s' not found\n", label);
272fb6bd596SCristiano Giuffrida return(ESRCH);
273fb6bd596SCristiano Giuffrida }
274fb6bd596SCristiano Giuffrida rpub = rp->r_pub;
275fb6bd596SCristiano Giuffrida
276fb6bd596SCristiano Giuffrida /* Check if the call can be allowed. */
277fb6bd596SCristiano Giuffrida if((r = check_call_permission(m_ptr->m_source, RS_UNCLONE, rp)) != OK)
278fb6bd596SCristiano Giuffrida return r;
279fb6bd596SCristiano Giuffrida
280fb6bd596SCristiano Giuffrida /* Don't unclone if no replica is available. */
281fb6bd596SCristiano Giuffrida if(!(rpub->sys_flags & SF_USE_REPL)) {
282fb6bd596SCristiano Giuffrida return ENOENT;
283fb6bd596SCristiano Giuffrida }
284fb6bd596SCristiano Giuffrida
285fb6bd596SCristiano Giuffrida /* Unclone the service as requested. */
286fb6bd596SCristiano Giuffrida rpub->sys_flags &= ~SF_USE_REPL;
287fb6bd596SCristiano Giuffrida if(rp->r_next_rp) {
288fb6bd596SCristiano Giuffrida cleanup_service_now(rp->r_next_rp);
289fb6bd596SCristiano Giuffrida rp->r_next_rp = NULL;
290fb6bd596SCristiano Giuffrida }
291fb6bd596SCristiano Giuffrida
292fb6bd596SCristiano Giuffrida return OK;
293fb6bd596SCristiano Giuffrida }
294fb6bd596SCristiano Giuffrida
295fb6bd596SCristiano Giuffrida /*===========================================================================*
296433d6423SLionel Sambuc * do_edit *
297433d6423SLionel Sambuc *===========================================================================*/
do_edit(message * m_ptr)298433d6423SLionel Sambuc int do_edit(message *m_ptr)
299433d6423SLionel Sambuc {
300433d6423SLionel Sambuc struct rproc *rp;
301433d6423SLionel Sambuc struct rprocpub *rpub;
302433d6423SLionel Sambuc struct rs_start rs_start;
303433d6423SLionel Sambuc int r;
304433d6423SLionel Sambuc char label[RS_MAX_LABEL_LEN];
305433d6423SLionel Sambuc
306433d6423SLionel Sambuc /* Copy the request structure. */
307433d6423SLionel Sambuc r = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
308433d6423SLionel Sambuc if (r != OK) {
309433d6423SLionel Sambuc return r;
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc
312433d6423SLionel Sambuc /* Copy label. */
313433d6423SLionel Sambuc r = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
314433d6423SLionel Sambuc rs_start.rss_label.l_len, label, sizeof(label));
315433d6423SLionel Sambuc if(r != OK) {
316433d6423SLionel Sambuc return r;
317433d6423SLionel Sambuc }
318433d6423SLionel Sambuc
319433d6423SLionel Sambuc /* Lookup slot by label. */
320433d6423SLionel Sambuc rp = lookup_slot_by_label(label);
321433d6423SLionel Sambuc if(!rp) {
322433d6423SLionel Sambuc if(rs_verbose)
323433d6423SLionel Sambuc printf("RS: do_edit: service '%s' not found\n", label);
324433d6423SLionel Sambuc return ESRCH;
325433d6423SLionel Sambuc }
326433d6423SLionel Sambuc rpub = rp->r_pub;
327433d6423SLionel Sambuc
328433d6423SLionel Sambuc /* Check if the call can be allowed. */
329433d6423SLionel Sambuc if((r = check_call_permission(m_ptr->m_source, RS_EDIT, rp)) != OK)
330433d6423SLionel Sambuc return r;
331433d6423SLionel Sambuc
332433d6423SLionel Sambuc if(rs_verbose)
333433d6423SLionel Sambuc printf("RS: %s edits settings\n", srv_to_string(rp));
334433d6423SLionel Sambuc
335433d6423SLionel Sambuc /* Synch the privilege structure with the kernel. */
336433d6423SLionel Sambuc if ((r = sys_getpriv(&rp->r_priv, rpub->endpoint)) != OK) {
337433d6423SLionel Sambuc printf("RS: do_edit: unable to synch privilege structure: %d\n", r);
338433d6423SLionel Sambuc return r;
339433d6423SLionel Sambuc }
340433d6423SLionel Sambuc
341433d6423SLionel Sambuc /* Tell scheduler this process is finished */
342433d6423SLionel Sambuc if ((r = sched_stop(rp->r_scheduler, rpub->endpoint)) != OK) {
343433d6423SLionel Sambuc printf("RS: do_edit: scheduler won't give up process: %d\n", r);
344433d6423SLionel Sambuc return r;
345433d6423SLionel Sambuc }
346433d6423SLionel Sambuc
347433d6423SLionel Sambuc /* Edit the slot as requested. */
348433d6423SLionel Sambuc if((r = edit_slot(rp, &rs_start, m_ptr->m_source)) != OK) {
349433d6423SLionel Sambuc printf("RS: do_edit: unable to edit the existing slot: %d\n", r);
350433d6423SLionel Sambuc return r;
351433d6423SLionel Sambuc }
352433d6423SLionel Sambuc
353433d6423SLionel Sambuc /* Update privilege structure. */
354433d6423SLionel Sambuc r = sys_privctl(rpub->endpoint, SYS_PRIV_UPDATE_SYS, &rp->r_priv);
355433d6423SLionel Sambuc if(r != OK) {
356433d6423SLionel Sambuc printf("RS: do_edit: unable to update privilege structure: %d\n", r);
357433d6423SLionel Sambuc return r;
358433d6423SLionel Sambuc }
359433d6423SLionel Sambuc
360433d6423SLionel Sambuc /* Update VM calls. */
361433d6423SLionel Sambuc if ((r = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0],
362433d6423SLionel Sambuc !!(rp->r_priv.s_flags & SYS_PROC))) != OK) {
363433d6423SLionel Sambuc printf("RS: do_edit: failed: %d\n", r);
364433d6423SLionel Sambuc return r;
365433d6423SLionel Sambuc }
366433d6423SLionel Sambuc
367433d6423SLionel Sambuc /* Reinitialize scheduling. */
368433d6423SLionel Sambuc if ((r = sched_init_proc(rp)) != OK) {
369433d6423SLionel Sambuc printf("RS: do_edit: unable to reinitialize scheduling: %d\n", r);
370433d6423SLionel Sambuc return r;
371433d6423SLionel Sambuc }
372433d6423SLionel Sambuc
373433d6423SLionel Sambuc /* Cleanup old replicas and create a new one, if necessary. */
374433d6423SLionel Sambuc if(rpub->sys_flags & SF_USE_REPL) {
375433d6423SLionel Sambuc if(rp->r_next_rp) {
376433d6423SLionel Sambuc cleanup_service(rp->r_next_rp);
377433d6423SLionel Sambuc rp->r_next_rp = NULL;
378433d6423SLionel Sambuc }
379fb6bd596SCristiano Giuffrida if ((r = clone_service(rp, RST_SYS_PROC, 0)) != OK) {
380433d6423SLionel Sambuc printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
381433d6423SLionel Sambuc }
382433d6423SLionel Sambuc }
383433d6423SLionel Sambuc
384433d6423SLionel Sambuc return OK;
385433d6423SLionel Sambuc }
386433d6423SLionel Sambuc
387433d6423SLionel Sambuc /*===========================================================================*
388433d6423SLionel Sambuc * do_refresh *
389433d6423SLionel Sambuc *===========================================================================*/
do_refresh(message * m_ptr)390433d6423SLionel Sambuc int do_refresh(message *m_ptr)
391433d6423SLionel Sambuc {
392433d6423SLionel Sambuc register struct rproc *rp;
393433d6423SLionel Sambuc int s;
394433d6423SLionel Sambuc char label[RS_MAX_LABEL_LEN];
395433d6423SLionel Sambuc
396433d6423SLionel Sambuc /* Copy label. */
397433d6423SLionel Sambuc s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
398433d6423SLionel Sambuc m_ptr->m_rs_req.len, label, sizeof(label));
399433d6423SLionel Sambuc if(s != OK) {
400433d6423SLionel Sambuc return s;
401433d6423SLionel Sambuc }
402433d6423SLionel Sambuc
403433d6423SLionel Sambuc /* Lookup slot by label. */
404433d6423SLionel Sambuc rp = lookup_slot_by_label(label);
405433d6423SLionel Sambuc if(!rp) {
406433d6423SLionel Sambuc if(rs_verbose)
407433d6423SLionel Sambuc printf("RS: do_refresh: service '%s' not found\n", label);
408433d6423SLionel Sambuc return(ESRCH);
409433d6423SLionel Sambuc }
410433d6423SLionel Sambuc
411433d6423SLionel Sambuc /* Check if the call can be allowed. */
412433d6423SLionel Sambuc if((s = check_call_permission(m_ptr->m_source, RS_REFRESH, rp)) != OK)
413433d6423SLionel Sambuc return s;
414433d6423SLionel Sambuc
415433d6423SLionel Sambuc /* Refresh service. */
416433d6423SLionel Sambuc if(rs_verbose)
417433d6423SLionel Sambuc printf("RS: %s refreshing\n", srv_to_string(rp));
418433d6423SLionel Sambuc stop_service(rp,RS_REFRESHING);
419433d6423SLionel Sambuc
420fb6bd596SCristiano Giuffrida /* Late reply - send a reply when refresh completes. */
421fb6bd596SCristiano Giuffrida rp->r_flags |= RS_LATEREPLY;
422fb6bd596SCristiano Giuffrida rp->r_caller = m_ptr->m_source;
423fb6bd596SCristiano Giuffrida rp->r_caller_request = RS_REFRESH;
424fb6bd596SCristiano Giuffrida
425fb6bd596SCristiano Giuffrida return EDONTREPLY;
426433d6423SLionel Sambuc }
427433d6423SLionel Sambuc
428433d6423SLionel Sambuc /*===========================================================================*
429433d6423SLionel Sambuc * do_shutdown *
430433d6423SLionel Sambuc *===========================================================================*/
do_shutdown(message * m_ptr)431433d6423SLionel Sambuc int do_shutdown(message *m_ptr)
432433d6423SLionel Sambuc {
433433d6423SLionel Sambuc int slot_nr;
434433d6423SLionel Sambuc struct rproc *rp;
435433d6423SLionel Sambuc int r;
436433d6423SLionel Sambuc
437433d6423SLionel Sambuc /* Check if the call can be allowed. */
438433d6423SLionel Sambuc if (m_ptr != NULL) {
439433d6423SLionel Sambuc if((r = check_call_permission(m_ptr->m_source, RS_SHUTDOWN, NULL)) != OK)
440433d6423SLionel Sambuc return r;
441433d6423SLionel Sambuc }
442433d6423SLionel Sambuc
443433d6423SLionel Sambuc if(rs_verbose)
444433d6423SLionel Sambuc printf("RS: shutting down...\n");
445433d6423SLionel Sambuc
446433d6423SLionel Sambuc /* Set flag to tell RS we are shutting down. */
447433d6423SLionel Sambuc shutting_down = TRUE;
448433d6423SLionel Sambuc
449433d6423SLionel Sambuc /* Don't restart dead services. */
450433d6423SLionel Sambuc for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
451433d6423SLionel Sambuc rp = &rproc[slot_nr];
452433d6423SLionel Sambuc if (rp->r_flags & RS_IN_USE) {
453433d6423SLionel Sambuc rp->r_flags |= RS_EXITING;
454433d6423SLionel Sambuc }
455433d6423SLionel Sambuc }
456433d6423SLionel Sambuc return(OK);
457433d6423SLionel Sambuc }
458433d6423SLionel Sambuc
459433d6423SLionel Sambuc /*===========================================================================*
460433d6423SLionel Sambuc * do_init_ready *
461433d6423SLionel Sambuc *===========================================================================*/
do_init_ready(message * m_ptr)462433d6423SLionel Sambuc int do_init_ready(message *m_ptr)
463433d6423SLionel Sambuc {
464433d6423SLionel Sambuc int who_p;
465433d6423SLionel Sambuc message m;
466fb6bd596SCristiano Giuffrida struct rproc *rp, *new_rp;
467433d6423SLionel Sambuc struct rprocpub *rpub;
468fb6bd596SCristiano Giuffrida int result;
469433d6423SLionel Sambuc int r;
470433d6423SLionel Sambuc
471433d6423SLionel Sambuc who_p = _ENDPOINT_P(m_ptr->m_source);
472433d6423SLionel Sambuc result = m_ptr->m_rs_init.result;
473433d6423SLionel Sambuc
474433d6423SLionel Sambuc rp = rproc_ptr[who_p];
475433d6423SLionel Sambuc rpub = rp->r_pub;
476433d6423SLionel Sambuc
477433d6423SLionel Sambuc /* Make sure the originating service was requested to initialize. */
478433d6423SLionel Sambuc if(! (rp->r_flags & RS_INITIALIZING) ) {
479433d6423SLionel Sambuc if(rs_verbose)
480433d6423SLionel Sambuc printf("RS: do_init_ready: got unexpected init ready msg from %d\n",
481433d6423SLionel Sambuc m_ptr->m_source);
482433d6423SLionel Sambuc return EINVAL;
483433d6423SLionel Sambuc }
484433d6423SLionel Sambuc
485433d6423SLionel Sambuc /* Check if something went wrong and the service failed to init.
486433d6423SLionel Sambuc * In that case, kill the service.
487433d6423SLionel Sambuc */
488433d6423SLionel Sambuc if(result != OK) {
489433d6423SLionel Sambuc if(rs_verbose)
490433d6423SLionel Sambuc printf("RS: %s initialization error: %s\n", srv_to_string(rp),
491433d6423SLionel Sambuc init_strerror(result));
492fb6bd596SCristiano Giuffrida if (result == ERESTART && !SRV_IS_UPDATING(rp))
493433d6423SLionel Sambuc rp->r_flags |= RS_REINCARNATE;
494433d6423SLionel Sambuc crash_service(rp); /* simulate crash */
495fb6bd596SCristiano Giuffrida rp->r_init_err = result;
496433d6423SLionel Sambuc return EDONTREPLY;
497433d6423SLionel Sambuc }
498433d6423SLionel Sambuc
499fb6bd596SCristiano Giuffrida if(rs_verbose)
500fb6bd596SCristiano Giuffrida printf("RS: %s initialized\n", srv_to_string(rp));
501fb6bd596SCristiano Giuffrida
502fb6bd596SCristiano Giuffrida /* If updating, check if there is no service to update left. In that case,
503fb6bd596SCristiano Giuffrida * end the update process. If VM has completed initialization as part of
504fb6bd596SCristiano Giuffrida * multi-component live update, let the other services under update run now.
505fb6bd596SCristiano Giuffrida */
506fb6bd596SCristiano Giuffrida if(SRV_IS_UPDATING(rp)) {
507fb6bd596SCristiano Giuffrida rupdate.num_init_ready_pending--;
508fb6bd596SCristiano Giuffrida rp->r_flags |= RS_INIT_DONE;
509fb6bd596SCristiano Giuffrida if(rupdate.num_init_ready_pending == 0) {
510fb6bd596SCristiano Giuffrida printf("RS: update succeeded\n");
511fb6bd596SCristiano Giuffrida end_update(OK, RS_REPLY);
512fb6bd596SCristiano Giuffrida }
513fb6bd596SCristiano Giuffrida }
514fb6bd596SCristiano Giuffrida else {
515433d6423SLionel Sambuc /* Mark the slot as no longer initializing. */
516433d6423SLionel Sambuc rp->r_flags &= ~RS_INITIALIZING;
517433d6423SLionel Sambuc rp->r_check_tm = 0;
518d91f738bSDavid van Moolenbroek rp->r_alive_tm = getticks();
519433d6423SLionel Sambuc
520433d6423SLionel Sambuc /* Reply and unblock the service before doing anything else. */
521433d6423SLionel Sambuc m.m_type = OK;
522433d6423SLionel Sambuc reply(rpub->endpoint, rp, &m);
523433d6423SLionel Sambuc
524fb6bd596SCristiano Giuffrida /* Finalize initialization. */
525fb6bd596SCristiano Giuffrida end_srv_init(rp);
526433d6423SLionel Sambuc }
527433d6423SLionel Sambuc
528fb6bd596SCristiano Giuffrida return EDONTREPLY;
529433d6423SLionel Sambuc }
530433d6423SLionel Sambuc
531433d6423SLionel Sambuc /*===========================================================================*
532433d6423SLionel Sambuc * do_update *
533433d6423SLionel Sambuc *===========================================================================*/
do_update(message * m_ptr)534433d6423SLionel Sambuc int do_update(message *m_ptr)
535433d6423SLionel Sambuc {
536433d6423SLionel Sambuc struct rproc *rp;
537fb6bd596SCristiano Giuffrida struct rproc *trg_rp;
538433d6423SLionel Sambuc struct rproc *new_rp;
539433d6423SLionel Sambuc struct rprocpub *rpub;
540fb6bd596SCristiano Giuffrida struct rprocupd *rpupd;
541433d6423SLionel Sambuc struct rs_start rs_start;
542fb6bd596SCristiano Giuffrida int noblock, do_self_update, force_self_update, batch_mode, prepare_only;
543433d6423SLionel Sambuc int s;
544433d6423SLionel Sambuc char label[RS_MAX_LABEL_LEN];
545fb6bd596SCristiano Giuffrida int prepare_state, prepare_maxtime;
546fb6bd596SCristiano Giuffrida endpoint_t state_endpoint;
547fb6bd596SCristiano Giuffrida int lu_flags = 0;
548fb6bd596SCristiano Giuffrida int init_flags = 0;
549fb6bd596SCristiano Giuffrida int allow_retries = 0;
550433d6423SLionel Sambuc
551433d6423SLionel Sambuc /* Copy the request structure. */
552433d6423SLionel Sambuc s = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
553433d6423SLionel Sambuc if (s != OK) {
554433d6423SLionel Sambuc return s;
555433d6423SLionel Sambuc }
556433d6423SLionel Sambuc
557433d6423SLionel Sambuc /* Copy label. */
558433d6423SLionel Sambuc s = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
559433d6423SLionel Sambuc rs_start.rss_label.l_len, label, sizeof(label));
560433d6423SLionel Sambuc if(s != OK) {
561433d6423SLionel Sambuc return s;
562433d6423SLionel Sambuc }
563433d6423SLionel Sambuc
564433d6423SLionel Sambuc /* Lookup slot by label. */
565433d6423SLionel Sambuc rp = lookup_slot_by_label(label);
566433d6423SLionel Sambuc if(!rp) {
567433d6423SLionel Sambuc if(rs_verbose)
568433d6423SLionel Sambuc printf("RS: do_update: service '%s' not found\n", label);
569433d6423SLionel Sambuc return ESRCH;
570433d6423SLionel Sambuc }
571433d6423SLionel Sambuc rpub = rp->r_pub;
572433d6423SLionel Sambuc
573fb6bd596SCristiano Giuffrida /* Check flags. */
574fb6bd596SCristiano Giuffrida noblock = (rs_start.rss_flags & RSS_NOBLOCK);
575fb6bd596SCristiano Giuffrida do_self_update = (rs_start.rss_flags & RSS_SELF_LU);
576fb6bd596SCristiano Giuffrida force_self_update = (rs_start.rss_flags & RSS_FORCE_SELF_LU);
577fb6bd596SCristiano Giuffrida batch_mode = (rs_start.rss_flags & RSS_BATCH);
578fb6bd596SCristiano Giuffrida prepare_only = (rs_start.rss_flags & RSS_PREPARE_ONLY_LU);
579fb6bd596SCristiano Giuffrida if(do_self_update || force_self_update) {
580fb6bd596SCristiano Giuffrida lu_flags |= SEF_LU_SELF;
581fb6bd596SCristiano Giuffrida }
582fb6bd596SCristiano Giuffrida if(prepare_only) {
583fb6bd596SCristiano Giuffrida lu_flags |= SEF_LU_PREPARE_ONLY;
584fb6bd596SCristiano Giuffrida }
585fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_ASR_LU) {
586fb6bd596SCristiano Giuffrida lu_flags |= SEF_LU_ASR;
587fb6bd596SCristiano Giuffrida }
588fb6bd596SCristiano Giuffrida if(!prepare_only && (rs_start.rss_flags & RSS_DETACH)) {
589fb6bd596SCristiano Giuffrida lu_flags |= SEF_LU_DETACHED;
590fb6bd596SCristiano Giuffrida }
591fb6bd596SCristiano Giuffrida if(rs_start.rss_map_prealloc_bytes <= 0
592fb6bd596SCristiano Giuffrida && rpub->endpoint == VM_PROC_NR
593fb6bd596SCristiano Giuffrida && (((lu_flags & (SEF_LU_SELF|SEF_LU_ASR)) != SEF_LU_SELF) || rs_start.rss_flags & RSS_FORCE_INIT_ST)
594fb6bd596SCristiano Giuffrida && RS_VM_DEFAULT_MAP_PREALLOC_LEN > 0) {
595fb6bd596SCristiano Giuffrida /* Give VM some mmapped regions by default on non-identical updates.*/
596fb6bd596SCristiano Giuffrida rs_start.rss_map_prealloc_bytes = RS_VM_DEFAULT_MAP_PREALLOC_LEN;
597fb6bd596SCristiano Giuffrida if(rs_verbose)
598fb6bd596SCristiano Giuffrida printf("RS: %s gets %ld default mmap bytes\n", srv_to_string(rp),
599fb6bd596SCristiano Giuffrida rs_start.rss_map_prealloc_bytes);
600fb6bd596SCristiano Giuffrida }
601fb6bd596SCristiano Giuffrida if((rs_start.rss_flags & RSS_NOMMAP_LU) || rs_start.rss_map_prealloc_bytes) {
602fb6bd596SCristiano Giuffrida /* Don't inherit mmapped regions at update time if requested or if
603fb6bd596SCristiano Giuffrida * mmap preallocation is used.
604fb6bd596SCristiano Giuffrida */
605fb6bd596SCristiano Giuffrida lu_flags |= SEF_LU_NOMMAP;
606fb6bd596SCristiano Giuffrida }
607fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_FORCE_INIT_CRASH) {
608fb6bd596SCristiano Giuffrida init_flags |= SEF_INIT_CRASH;
609fb6bd596SCristiano Giuffrida }
610fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_FORCE_INIT_FAIL) {
611fb6bd596SCristiano Giuffrida init_flags |= SEF_INIT_FAIL;
612fb6bd596SCristiano Giuffrida }
613fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_FORCE_INIT_TIMEOUT) {
614fb6bd596SCristiano Giuffrida init_flags |= SEF_INIT_TIMEOUT;
615fb6bd596SCristiano Giuffrida }
616fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_FORCE_INIT_DEFCB) {
617fb6bd596SCristiano Giuffrida init_flags |= SEF_INIT_DEFCB;
618fb6bd596SCristiano Giuffrida }
619fb6bd596SCristiano Giuffrida if(rs_start.rss_flags & RSS_FORCE_INIT_ST) {
620fb6bd596SCristiano Giuffrida init_flags |= SEF_INIT_ST;
621fb6bd596SCristiano Giuffrida }
622fb6bd596SCristiano Giuffrida init_flags |= lu_flags;
623fb6bd596SCristiano Giuffrida
624fb6bd596SCristiano Giuffrida /* Lookup target label (if any). */
625fb6bd596SCristiano Giuffrida trg_rp = NULL;
626fb6bd596SCristiano Giuffrida state_endpoint = NONE;
627fb6bd596SCristiano Giuffrida if(rs_start.rss_trg_label.l_len > 0) {
628fb6bd596SCristiano Giuffrida s = copy_label(m_ptr->m_source, rs_start.rss_trg_label.l_addr,
629fb6bd596SCristiano Giuffrida rs_start.rss_trg_label.l_len, label, sizeof(label));
630fb6bd596SCristiano Giuffrida if(s != OK) {
631fb6bd596SCristiano Giuffrida return s;
632fb6bd596SCristiano Giuffrida }
633fb6bd596SCristiano Giuffrida trg_rp = lookup_slot_by_label(label);
634fb6bd596SCristiano Giuffrida if(!trg_rp) {
635fb6bd596SCristiano Giuffrida if(rs_verbose)
636fb6bd596SCristiano Giuffrida printf("RS: do_update: target service '%s' not found\n", label);
637fb6bd596SCristiano Giuffrida return ESRCH;
638fb6bd596SCristiano Giuffrida }
639fb6bd596SCristiano Giuffrida state_endpoint = trg_rp->r_pub->endpoint;
640fb6bd596SCristiano Giuffrida }
641fb6bd596SCristiano Giuffrida
642433d6423SLionel Sambuc /* Check if the call can be allowed. */
643433d6423SLionel Sambuc if((s = check_call_permission(m_ptr->m_source, RS_UPDATE, rp)) != OK)
644433d6423SLionel Sambuc return s;
645433d6423SLionel Sambuc
646433d6423SLionel Sambuc /* Retrieve live update state. */
647fb6bd596SCristiano Giuffrida prepare_state = m_ptr->m_rs_update.state;
648fb6bd596SCristiano Giuffrida if(prepare_state == SEF_LU_STATE_NULL) {
649433d6423SLionel Sambuc return(EINVAL);
650433d6423SLionel Sambuc }
651433d6423SLionel Sambuc
652433d6423SLionel Sambuc /* Retrieve prepare max time. */
653433d6423SLionel Sambuc prepare_maxtime = m_ptr->m_rs_update.prepare_maxtime;
654fb6bd596SCristiano Giuffrida if(prepare_maxtime == 0) {
655433d6423SLionel Sambuc prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME;
656433d6423SLionel Sambuc }
657433d6423SLionel Sambuc
658433d6423SLionel Sambuc /* Make sure we are not already updating. */
659fb6bd596SCristiano Giuffrida if(RUPDATE_IS_UPDATING()) {
660fb6bd596SCristiano Giuffrida printf("RS: an update is already in progress\n");
661433d6423SLionel Sambuc return EBUSY;
662433d6423SLionel Sambuc }
663433d6423SLionel Sambuc
664fb6bd596SCristiano Giuffrida /* If an update is already scheduled, check constraints. */
665fb6bd596SCristiano Giuffrida if(RUPDATE_IS_UPD_SCHEDULED()) {
666fb6bd596SCristiano Giuffrida if(!batch_mode) {
667fb6bd596SCristiano Giuffrida printf("RS: an update is already scheduled, cannot start a new one\n");
668fb6bd596SCristiano Giuffrida return EBUSY;
669fb6bd596SCristiano Giuffrida }
670fb6bd596SCristiano Giuffrida if(SRV_IS_UPD_SCHEDULED(rp)) {
671fb6bd596SCristiano Giuffrida printf("RS: the specified process is already part of the currently scheduled update\n");
672fb6bd596SCristiano Giuffrida return EINVAL;
673fb6bd596SCristiano Giuffrida }
674fb6bd596SCristiano Giuffrida }
675fb6bd596SCristiano Giuffrida
676fb6bd596SCristiano Giuffrida /* Prepare-only update for VM, PM, and VFS is only supported with an unreachable state. */
677fb6bd596SCristiano Giuffrida if(prepare_only
678fb6bd596SCristiano Giuffrida && (rp->r_pub->endpoint == VM_PROC_NR || rp->r_pub->endpoint == PM_PROC_NR || rp->r_pub->endpoint == VFS_PROC_NR)) {
679fb6bd596SCristiano Giuffrida if(prepare_state != SEF_LU_STATE_UNREACHABLE) {
680fb6bd596SCristiano Giuffrida printf("RS: prepare-only update for VM, PM and VFS is only supported with state %d\n", SEF_LU_STATE_UNREACHABLE);
681fb6bd596SCristiano Giuffrida return EINVAL;
682fb6bd596SCristiano Giuffrida }
683fb6bd596SCristiano Giuffrida }
684fb6bd596SCristiano Giuffrida
685fb6bd596SCristiano Giuffrida /* Prepare-only update for RS is not supported. */
686fb6bd596SCristiano Giuffrida if(prepare_only && rp->r_pub->endpoint == RS_PROC_NR) {
687fb6bd596SCristiano Giuffrida printf("RS: prepare-only update for RS is not supported\n");
688fb6bd596SCristiano Giuffrida return EINVAL;
689fb6bd596SCristiano Giuffrida }
690fb6bd596SCristiano Giuffrida
691fb6bd596SCristiano Giuffrida /* Initialize update descriptor. */
692fb6bd596SCristiano Giuffrida rpupd = &rp->r_upd;
693fb6bd596SCristiano Giuffrida rupdate_upd_init(rpupd, rp);
694fb6bd596SCristiano Giuffrida rpupd->lu_flags |= lu_flags;
695fb6bd596SCristiano Giuffrida rpupd->init_flags |= init_flags;
696fb6bd596SCristiano Giuffrida rupdate_set_new_upd_flags(rpupd);
697fb6bd596SCristiano Giuffrida
698433d6423SLionel Sambuc /* A self update live updates a service instance into a replica, a regular
699433d6423SLionel Sambuc * update live updates a service instance into a new version, as specified
700433d6423SLionel Sambuc * by the given binary.
701433d6423SLionel Sambuc */
702fb6bd596SCristiano Giuffrida if(!prepare_only) {
703433d6423SLionel Sambuc if(do_self_update) {
704433d6423SLionel Sambuc if(rs_verbose)
705fb6bd596SCristiano Giuffrida printf("RS: %s requested to perform self update\n", srv_to_string(rp));
706433d6423SLionel Sambuc
707433d6423SLionel Sambuc /* Clone the system service and use the replica as the new version. */
708fb6bd596SCristiano Giuffrida s = clone_service(rp, LU_SYS_PROC, rpupd->init_flags);
709433d6423SLionel Sambuc if(s != OK) {
710433d6423SLionel Sambuc printf("RS: do_update: unable to clone service: %d\n", s);
711433d6423SLionel Sambuc return s;
712433d6423SLionel Sambuc }
713fb6bd596SCristiano Giuffrida new_rp = rp->r_new_rp;
714433d6423SLionel Sambuc }
715433d6423SLionel Sambuc else {
716433d6423SLionel Sambuc if(rs_verbose)
717fb6bd596SCristiano Giuffrida printf("RS: %s requested to perform %s update\n", srv_to_string(rp),
718fb6bd596SCristiano Giuffrida force_self_update ? "(forced) self" : "regular");
719433d6423SLionel Sambuc
720433d6423SLionel Sambuc /* Allocate a system service slot for the new version. */
721433d6423SLionel Sambuc s = alloc_slot(&new_rp);
722433d6423SLionel Sambuc if(s != OK) {
723433d6423SLionel Sambuc printf("RS: do_update: unable to allocate a new slot: %d\n", s);
724433d6423SLionel Sambuc return s;
725433d6423SLionel Sambuc }
726433d6423SLionel Sambuc
727433d6423SLionel Sambuc /* Initialize the slot as requested. */
728433d6423SLionel Sambuc s = init_slot(new_rp, &rs_start, m_ptr->m_source);
729433d6423SLionel Sambuc if(s != OK) {
730433d6423SLionel Sambuc printf("RS: do_update: unable to init the new slot: %d\n", s);
731433d6423SLionel Sambuc return s;
732433d6423SLionel Sambuc }
733433d6423SLionel Sambuc
734433d6423SLionel Sambuc /* Let the new version inherit defaults from the old one. */
735433d6423SLionel Sambuc inherit_service_defaults(rp, new_rp);
736433d6423SLionel Sambuc
737433d6423SLionel Sambuc /* Link the two versions. */
738433d6423SLionel Sambuc rp->r_new_rp = new_rp;
739433d6423SLionel Sambuc new_rp->r_old_rp = rp;
740433d6423SLionel Sambuc
741433d6423SLionel Sambuc /* Create new version of the service but don't let it run. */
742433d6423SLionel Sambuc new_rp->r_priv.s_flags |= LU_SYS_PROC;
743fb6bd596SCristiano Giuffrida new_rp->r_priv.s_init_flags |= rpupd->init_flags;
744433d6423SLionel Sambuc s = create_service(new_rp);
745433d6423SLionel Sambuc if(s != OK) {
746433d6423SLionel Sambuc printf("RS: do_update: unable to create a new service: %d\n", s);
747433d6423SLionel Sambuc return s;
748433d6423SLionel Sambuc }
749433d6423SLionel Sambuc }
750433d6423SLionel Sambuc
751fb6bd596SCristiano Giuffrida /* Set default state endpoint. */
752fb6bd596SCristiano Giuffrida if(state_endpoint == NONE) {
753fb6bd596SCristiano Giuffrida state_endpoint = new_rp->r_pub->endpoint;
754fb6bd596SCristiano Giuffrida }
755433d6423SLionel Sambuc
756433d6423SLionel Sambuc /* If RS is updating, set up signal managers for the new instance.
757433d6423SLionel Sambuc * The current RS instance must be made the backup signal manager to
758433d6423SLionel Sambuc * support rollback in case of a crash during initialization.
759433d6423SLionel Sambuc */
760433d6423SLionel Sambuc if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
761433d6423SLionel Sambuc s = update_sig_mgrs(new_rp, SELF, new_rp->r_pub->endpoint);
762433d6423SLionel Sambuc if(s != OK) {
763433d6423SLionel Sambuc cleanup_service(new_rp);
764433d6423SLionel Sambuc return s;
765433d6423SLionel Sambuc }
766433d6423SLionel Sambuc }
767433d6423SLionel Sambuc
768fb6bd596SCristiano Giuffrida /* Preallocate heap regions if requested. */
769fb6bd596SCristiano Giuffrida if(rs_start.rss_heap_prealloc_bytes < 0) {
770fb6bd596SCristiano Giuffrida rs_start.rss_heap_prealloc_bytes = 0;
771433d6423SLionel Sambuc }
772fb6bd596SCristiano Giuffrida if(rs_start.rss_heap_prealloc_bytes) {
773fb6bd596SCristiano Giuffrida size_t len;
774fb6bd596SCristiano Giuffrida if(rs_verbose)
775fb6bd596SCristiano Giuffrida printf("RS: %s preallocating %ld heap bytes\n", srv_to_string(new_rp),
776fb6bd596SCristiano Giuffrida rs_start.rss_heap_prealloc_bytes);
777fb6bd596SCristiano Giuffrida
778fb6bd596SCristiano Giuffrida len = rs_start.rss_heap_prealloc_bytes;
779fb6bd596SCristiano Giuffrida s = vm_memctl(new_rp->r_pub->endpoint, VM_RS_MEM_HEAP_PREALLOC,
780fb6bd596SCristiano Giuffrida NULL, &len);
781fb6bd596SCristiano Giuffrida if(s != OK) {
782fb6bd596SCristiano Giuffrida printf("vm_memctl(VM_RS_MEM_HEAP_PREALLOC) failed: %d\n", s);
783fb6bd596SCristiano Giuffrida cleanup_service(new_rp);
784fb6bd596SCristiano Giuffrida return s;
785fb6bd596SCristiano Giuffrida }
786fb6bd596SCristiano Giuffrida if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
787fb6bd596SCristiano Giuffrida vm_memctl(new_rp->r_pub->endpoint, VM_RS_MEM_PIN, 0, 0);
788fb6bd596SCristiano Giuffrida }
789433d6423SLionel Sambuc }
790433d6423SLionel Sambuc
791fb6bd596SCristiano Giuffrida /* Preallocate mmapped regions if requested. */
792fb6bd596SCristiano Giuffrida if(rs_start.rss_map_prealloc_bytes < 0) {
793fb6bd596SCristiano Giuffrida rs_start.rss_map_prealloc_bytes = 0;
794433d6423SLionel Sambuc }
795fb6bd596SCristiano Giuffrida if(rs_start.rss_map_prealloc_bytes) {
796fb6bd596SCristiano Giuffrida void *addr = NULL;
797fb6bd596SCristiano Giuffrida if(rs_verbose)
798fb6bd596SCristiano Giuffrida printf("RS: %s preallocating %ld mmap bytes\n", srv_to_string(new_rp),
799fb6bd596SCristiano Giuffrida rs_start.rss_map_prealloc_bytes);
800fb6bd596SCristiano Giuffrida
801fb6bd596SCristiano Giuffrida new_rp->r_map_prealloc_len = rs_start.rss_map_prealloc_bytes;
802fb6bd596SCristiano Giuffrida s = vm_memctl(new_rp->r_pub->endpoint, VM_RS_MEM_MAP_PREALLOC,
803fb6bd596SCristiano Giuffrida &addr, &new_rp->r_map_prealloc_len);
804fb6bd596SCristiano Giuffrida if(s != OK) {
805fb6bd596SCristiano Giuffrida printf("vm_memctl(VM_RS_MEM_MAP_PREALLOC) failed: %d\n", s);
806fb6bd596SCristiano Giuffrida cleanup_service(new_rp);
807fb6bd596SCristiano Giuffrida return s;
808433d6423SLionel Sambuc }
809fb6bd596SCristiano Giuffrida new_rp->r_map_prealloc_addr = (vir_bytes) addr;
810fb6bd596SCristiano Giuffrida }
811fb6bd596SCristiano Giuffrida }
812fb6bd596SCristiano Giuffrida
813fb6bd596SCristiano Giuffrida /* Process state data. */
814fb6bd596SCristiano Giuffrida s = init_state_data(m_ptr->m_source, prepare_state, &rs_start.rss_state_data, &rpupd->prepare_state_data);
815fb6bd596SCristiano Giuffrida if(s != OK) {
816fb6bd596SCristiano Giuffrida rupdate_upd_clear(rpupd);
817fb6bd596SCristiano Giuffrida return s;
818fb6bd596SCristiano Giuffrida }
819fb6bd596SCristiano Giuffrida
820fb6bd596SCristiano Giuffrida /* Create update grants. */
821fb6bd596SCristiano Giuffrida if(rpupd->prepare_state_data.size > 0) {
822fb6bd596SCristiano Giuffrida struct rs_state_data *state_data = &rpupd->prepare_state_data;
823fb6bd596SCristiano Giuffrida rpupd->prepare_state_data_gid = cpf_grant_direct(rpub->endpoint, (vir_bytes) state_data,
824fb6bd596SCristiano Giuffrida state_data->size, CPF_READ);
825fb6bd596SCristiano Giuffrida if(rpupd->prepare_state_data_gid == GRANT_INVALID) {
826fb6bd596SCristiano Giuffrida rupdate_upd_clear(rpupd);
827fb6bd596SCristiano Giuffrida return ENOMEM;
828fb6bd596SCristiano Giuffrida }
829fb6bd596SCristiano Giuffrida state_data->ipcf_els_gid = GRANT_INVALID;
830fb6bd596SCristiano Giuffrida if(state_data->ipcf_els) {
831fb6bd596SCristiano Giuffrida state_data->ipcf_els_gid = (int) cpf_grant_direct(rpub->endpoint, (vir_bytes) state_data->ipcf_els,
832fb6bd596SCristiano Giuffrida state_data->ipcf_els_size, CPF_READ);
833fb6bd596SCristiano Giuffrida if(state_data->ipcf_els_gid == GRANT_INVALID) {
834fb6bd596SCristiano Giuffrida rupdate_upd_clear(rpupd);
835fb6bd596SCristiano Giuffrida return ENOMEM;
836fb6bd596SCristiano Giuffrida }
837fb6bd596SCristiano Giuffrida }
838fb6bd596SCristiano Giuffrida state_data->eval_gid = GRANT_INVALID;
839fb6bd596SCristiano Giuffrida if(state_data->eval_addr) {
840fb6bd596SCristiano Giuffrida state_data->eval_gid = (int) cpf_grant_direct(rpub->endpoint, (vir_bytes) state_data->eval_addr,
841fb6bd596SCristiano Giuffrida state_data->eval_len, CPF_READ);
842fb6bd596SCristiano Giuffrida if(state_data->eval_gid == GRANT_INVALID) {
843fb6bd596SCristiano Giuffrida rupdate_upd_clear(rpupd);
844fb6bd596SCristiano Giuffrida return ENOMEM;
845fb6bd596SCristiano Giuffrida }
846fb6bd596SCristiano Giuffrida }
847fb6bd596SCristiano Giuffrida }
848fb6bd596SCristiano Giuffrida
849fb6bd596SCristiano Giuffrida /* Fill the new update descriptor and add it to the update chain. */
850fb6bd596SCristiano Giuffrida rpupd->prepare_state = prepare_state;
851fb6bd596SCristiano Giuffrida rpupd->state_endpoint = state_endpoint;
852d91f738bSDavid van Moolenbroek rpupd->prepare_tm = getticks();
853fb6bd596SCristiano Giuffrida rpupd->prepare_maxtime = prepare_maxtime;
854fb6bd596SCristiano Giuffrida rupdate_add_upd(rpupd);
855fb6bd596SCristiano Giuffrida
856fb6bd596SCristiano Giuffrida if(rs_verbose)
857fb6bd596SCristiano Giuffrida printf("RS: %s scheduled for %s\n", srv_to_string(rp), srv_upd_to_string(rpupd));
858fb6bd596SCristiano Giuffrida
859fb6bd596SCristiano Giuffrida /* If batch mode, reply immediately. More services to update will follow. */
860fb6bd596SCristiano Giuffrida if(batch_mode) {
861fb6bd596SCristiano Giuffrida return OK;
862fb6bd596SCristiano Giuffrida }
863fb6bd596SCristiano Giuffrida
864fb6bd596SCristiano Giuffrida /* Start preparing for the update process. */
865fb6bd596SCristiano Giuffrida s = start_update_prepare(allow_retries);
866fb6bd596SCristiano Giuffrida if(s == ESRCH) {
867fb6bd596SCristiano Giuffrida /* No process left in the update chain. We are done already. */
868fb6bd596SCristiano Giuffrida return OK;
869fb6bd596SCristiano Giuffrida }
870fb6bd596SCristiano Giuffrida if(s != OK) {
871fb6bd596SCristiano Giuffrida return s;
872fb6bd596SCristiano Giuffrida }
873fb6bd596SCristiano Giuffrida
874fb6bd596SCristiano Giuffrida /* Unblock the caller immediately if requested. */
875fb6bd596SCristiano Giuffrida if(noblock) {
876fb6bd596SCristiano Giuffrida return OK;
877fb6bd596SCristiano Giuffrida }
878fb6bd596SCristiano Giuffrida
879fb6bd596SCristiano Giuffrida /* Otherwise, send a reply when the new version completes initialization. */
880fb6bd596SCristiano Giuffrida rupdate.last_rpupd->rp->r_flags |= RS_LATEREPLY;
881fb6bd596SCristiano Giuffrida rupdate.last_rpupd->rp->r_caller = m_ptr->m_source;
882fb6bd596SCristiano Giuffrida rupdate.last_rpupd->rp->r_caller_request = RS_UPDATE;
883433d6423SLionel Sambuc
884433d6423SLionel Sambuc return EDONTREPLY;
885433d6423SLionel Sambuc }
886433d6423SLionel Sambuc
887433d6423SLionel Sambuc /*===========================================================================*
888433d6423SLionel Sambuc * do_upd_ready *
889433d6423SLionel Sambuc *===========================================================================*/
do_upd_ready(message * m_ptr)890433d6423SLionel Sambuc int do_upd_ready(message *m_ptr)
891433d6423SLionel Sambuc {
892fb6bd596SCristiano Giuffrida struct rproc *rp;
893fb6bd596SCristiano Giuffrida struct rprocupd *prev_rpupd, *rpupd;
894433d6423SLionel Sambuc int who_p;
895433d6423SLionel Sambuc int result;
896433d6423SLionel Sambuc int is_rs;
897fb6bd596SCristiano Giuffrida int i;
898433d6423SLionel Sambuc
899433d6423SLionel Sambuc who_p = _ENDPOINT_P(m_ptr->m_source);
900433d6423SLionel Sambuc rp = rproc_ptr[who_p];
901433d6423SLionel Sambuc result = m_ptr->m_rs_update.result;
902433d6423SLionel Sambuc
903433d6423SLionel Sambuc /* Make sure the originating service was requested to prepare for update. */
904fb6bd596SCristiano Giuffrida rpupd = rupdate.curr_rpupd;
905fb6bd596SCristiano Giuffrida if(!rpupd || rp != rpupd->rp || RUPDATE_IS_INITIALIZING()) {
906433d6423SLionel Sambuc if(rs_verbose)
907fb6bd596SCristiano Giuffrida printf("RS: %s sent late/unexpected update ready msg\n",
908fb6bd596SCristiano Giuffrida srv_to_string(rp));
909433d6423SLionel Sambuc return EINVAL;
910433d6423SLionel Sambuc }
911fb6bd596SCristiano Giuffrida rp->r_flags |= RS_PREPARE_DONE;
912433d6423SLionel Sambuc
913433d6423SLionel Sambuc /* Check if something went wrong and the service failed to prepare
914433d6423SLionel Sambuc * for the update. In that case, end the update process. The old version will
915433d6423SLionel Sambuc * be replied to and continue executing.
916433d6423SLionel Sambuc */
917433d6423SLionel Sambuc if(result != OK) {
918fb6bd596SCristiano Giuffrida printf("RS: update failed: %s\n", lu_strerror(result));
919433d6423SLionel Sambuc end_update(result, RS_REPLY);
920433d6423SLionel Sambuc
921433d6423SLionel Sambuc return EDONTREPLY;
922433d6423SLionel Sambuc }
923433d6423SLionel Sambuc
924fb6bd596SCristiano Giuffrida if(rs_verbose)
925fb6bd596SCristiano Giuffrida printf("RS: %s ready to update\n", srv_to_string(rp));
926fb6bd596SCristiano Giuffrida
927fb6bd596SCristiano Giuffrida /* If this is a multi-component update and this is not the last service
928fb6bd596SCristiano Giuffrida * in the update, request the next process to update.
929fb6bd596SCristiano Giuffrida */
930fb6bd596SCristiano Giuffrida if(start_update_prepare_next() != NULL) {
931433d6423SLionel Sambuc return EDONTREPLY;
932433d6423SLionel Sambuc }
933433d6423SLionel Sambuc
934fb6bd596SCristiano Giuffrida /* Now perform the update and request each new instance to initialize. */
935fb6bd596SCristiano Giuffrida start_update();
936fb6bd596SCristiano Giuffrida
937433d6423SLionel Sambuc return EDONTREPLY;
938433d6423SLionel Sambuc }
939433d6423SLionel Sambuc
940433d6423SLionel Sambuc /*===========================================================================*
941433d6423SLionel Sambuc * do_period *
942433d6423SLionel Sambuc *===========================================================================*/
do_period(m_ptr)943433d6423SLionel Sambuc void do_period(m_ptr)
944433d6423SLionel Sambuc message *m_ptr;
945433d6423SLionel Sambuc {
946433d6423SLionel Sambuc register struct rproc *rp;
947433d6423SLionel Sambuc register struct rprocpub *rpub;
948433d6423SLionel Sambuc clock_t now = m_ptr->m_notify.timestamp;
949433d6423SLionel Sambuc int s;
950433d6423SLionel Sambuc long period;
951433d6423SLionel Sambuc
952433d6423SLionel Sambuc /* If an update is in progress, check its status. */
953fb6bd596SCristiano Giuffrida if(RUPDATE_IS_UPDATING() && !RUPDATE_IS_INITIALIZING()) {
954433d6423SLionel Sambuc update_period(m_ptr);
955433d6423SLionel Sambuc }
956433d6423SLionel Sambuc
957433d6423SLionel Sambuc /* Search system services table. Only check slots that are in use and not
958433d6423SLionel Sambuc * updating.
959433d6423SLionel Sambuc */
960433d6423SLionel Sambuc for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
961433d6423SLionel Sambuc rpub = rp->r_pub;
962fb6bd596SCristiano Giuffrida
963fb6bd596SCristiano Giuffrida if ((rp->r_flags & RS_ACTIVE) && (!SRV_IS_UPDATING(rp) || ((rp->r_flags & (RS_INITIALIZING|RS_INIT_DONE|RS_INIT_PENDING)) == RS_INITIALIZING))) {
964433d6423SLionel Sambuc
965433d6423SLionel Sambuc /* Compute period. */
966433d6423SLionel Sambuc period = rp->r_period;
967433d6423SLionel Sambuc if(rp->r_flags & RS_INITIALIZING) {
968fb6bd596SCristiano Giuffrida period = SRV_IS_UPDATING(rp) ? UPD_INIT_MAXTIME(&rp->r_upd) : RS_INIT_T;
969433d6423SLionel Sambuc }
970433d6423SLionel Sambuc
971433d6423SLionel Sambuc /* If the service is to be revived (because it repeatedly exited,
972433d6423SLionel Sambuc * and was not directly restarted), the binary backoff field is
973433d6423SLionel Sambuc * greater than zero.
974433d6423SLionel Sambuc */
975433d6423SLionel Sambuc if (rp->r_backoff > 0) {
976433d6423SLionel Sambuc rp->r_backoff -= 1;
977433d6423SLionel Sambuc if (rp->r_backoff == 0) {
978433d6423SLionel Sambuc restart_service(rp);
979433d6423SLionel Sambuc }
980433d6423SLionel Sambuc }
981433d6423SLionel Sambuc
982433d6423SLionel Sambuc /* If the service was signaled with a SIGTERM and fails to respond,
983433d6423SLionel Sambuc * kill the system service with a SIGKILL signal.
984433d6423SLionel Sambuc */
985433d6423SLionel Sambuc else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
986433d6423SLionel Sambuc && rp->r_pid > 0) {
987433d6423SLionel Sambuc rp->r_stop_tm = 0;
988433d6423SLionel Sambuc crash_service(rp); /* simulate crash */
989433d6423SLionel Sambuc }
990433d6423SLionel Sambuc
991433d6423SLionel Sambuc /* There seems to be no special conditions. If the service has a
992433d6423SLionel Sambuc * period assigned check its status.
993433d6423SLionel Sambuc */
994433d6423SLionel Sambuc else if (period > 0) {
995433d6423SLionel Sambuc
996433d6423SLionel Sambuc /* Check if an answer to a status request is still pending. If
997433d6423SLionel Sambuc * the service didn't respond within time, kill it to simulate
998433d6423SLionel Sambuc * a crash. The failure will be detected and the service will
999433d6423SLionel Sambuc * be restarted automatically. Give the service a free pass if
1000433d6423SLionel Sambuc * somebody is initializing. There may be some weird dependencies
1001433d6423SLionel Sambuc * if another service is, for example, restarting at the same
1002433d6423SLionel Sambuc * time.
1003433d6423SLionel Sambuc */
1004433d6423SLionel Sambuc if (rp->r_alive_tm < rp->r_check_tm) {
1005433d6423SLionel Sambuc if (now - rp->r_alive_tm > 2*period &&
1006433d6423SLionel Sambuc rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) {
1007fb6bd596SCristiano Giuffrida struct rproc *rp2;
1008fb6bd596SCristiano Giuffrida int init_flag;
1009433d6423SLionel Sambuc if(rs_verbose)
1010433d6423SLionel Sambuc printf("RS: %s reported late\n", srv_to_string(rp));
1011fb6bd596SCristiano Giuffrida init_flag = rp->r_flags & RS_INITIALIZING;
1012fb6bd596SCristiano Giuffrida rp->r_flags &= ~RS_INITIALIZING;
1013fb6bd596SCristiano Giuffrida rp2 = lookup_slot_by_flags(RS_INITIALIZING);
1014fb6bd596SCristiano Giuffrida rp->r_flags |= init_flag;
1015fb6bd596SCristiano Giuffrida if(rp2 != NULL && !SRV_IS_UPDATING(rp)) {
1016433d6423SLionel Sambuc /* Skip for now. */
1017433d6423SLionel Sambuc if(rs_verbose)
1018433d6423SLionel Sambuc printf("RS: %s gets a free pass\n",
1019433d6423SLionel Sambuc srv_to_string(rp));
1020433d6423SLionel Sambuc rp->r_alive_tm = now;
1021433d6423SLionel Sambuc rp->r_check_tm = now+1;
1022433d6423SLionel Sambuc continue;
1023433d6423SLionel Sambuc }
1024433d6423SLionel Sambuc rp->r_flags |= RS_NOPINGREPLY;
1025433d6423SLionel Sambuc crash_service(rp); /* simulate crash */
1026fb6bd596SCristiano Giuffrida if(rp->r_flags & RS_INITIALIZING) {
1027fb6bd596SCristiano Giuffrida rp->r_init_err = EINTR;
1028fb6bd596SCristiano Giuffrida }
1029433d6423SLionel Sambuc }
1030433d6423SLionel Sambuc }
1031433d6423SLionel Sambuc
1032433d6423SLionel Sambuc /* No answer pending. Check if a period expired since the last
1033433d6423SLionel Sambuc * check and, if so request the system service's status.
1034433d6423SLionel Sambuc */
1035433d6423SLionel Sambuc else if (now - rp->r_check_tm > rp->r_period) {
1036433d6423SLionel Sambuc ipc_notify(rpub->endpoint); /* request status */
1037433d6423SLionel Sambuc rp->r_check_tm = now; /* mark time */
1038433d6423SLionel Sambuc }
1039433d6423SLionel Sambuc }
1040433d6423SLionel Sambuc }
1041433d6423SLionel Sambuc }
1042433d6423SLionel Sambuc
1043433d6423SLionel Sambuc /* Reschedule a synchronous alarm for the next period. */
1044433d6423SLionel Sambuc if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
1045433d6423SLionel Sambuc panic("couldn't set alarm: %d", s);
1046433d6423SLionel Sambuc }
1047433d6423SLionel Sambuc
1048433d6423SLionel Sambuc /*===========================================================================*
1049433d6423SLionel Sambuc * do_sigchld *
1050433d6423SLionel Sambuc *===========================================================================*/
do_sigchld()1051433d6423SLionel Sambuc void do_sigchld()
1052433d6423SLionel Sambuc {
1053433d6423SLionel Sambuc /* PM informed us that there are dead children to cleanup. Go get them. */
1054433d6423SLionel Sambuc pid_t pid;
1055433d6423SLionel Sambuc int status;
1056433d6423SLionel Sambuc struct rproc *rp;
1057433d6423SLionel Sambuc struct rproc **rps;
1058fb6bd596SCristiano Giuffrida int i, nr_rps, found;
1059433d6423SLionel Sambuc
1060433d6423SLionel Sambuc if(rs_verbose)
1061433d6423SLionel Sambuc printf("RS: got SIGCHLD signal, cleaning up dead children\n");
1062433d6423SLionel Sambuc
1063433d6423SLionel Sambuc while ( (pid = waitpid(-1, &status, WNOHANG)) != 0 ) {
1064433d6423SLionel Sambuc rp = lookup_slot_by_pid(pid);
1065433d6423SLionel Sambuc if(rp != NULL) {
1066433d6423SLionel Sambuc
1067433d6423SLionel Sambuc if(rs_verbose)
1068433d6423SLionel Sambuc printf("RS: %s exited via another signal manager\n",
1069433d6423SLionel Sambuc srv_to_string(rp));
1070433d6423SLionel Sambuc
1071433d6423SLionel Sambuc /* The slot is still there. This means RS is not the signal
1072433d6423SLionel Sambuc * manager assigned to the process. Ignore the event but
1073433d6423SLionel Sambuc * free slots for all the service instances and send a late
1074433d6423SLionel Sambuc * reply if necessary.
1075433d6423SLionel Sambuc */
1076fb6bd596SCristiano Giuffrida found = 0;
1077433d6423SLionel Sambuc get_service_instances(rp, &rps, &nr_rps);
1078433d6423SLionel Sambuc for(i=0;i<nr_rps;i++) {
1079fb6bd596SCristiano Giuffrida if(SRV_IS_UPDATING(rps[i])) {
1080fb6bd596SCristiano Giuffrida rps[i]->r_flags &= ~(RS_UPDATING|RS_PREPARE_DONE|RS_INIT_DONE|RS_INIT_PENDING);
1081fb6bd596SCristiano Giuffrida found = 1;
1082433d6423SLionel Sambuc }
1083433d6423SLionel Sambuc free_slot(rps[i]);
1084433d6423SLionel Sambuc }
1085fb6bd596SCristiano Giuffrida if(found) {
1086fb6bd596SCristiano Giuffrida rupdate_clear_upds();
1087fb6bd596SCristiano Giuffrida }
1088433d6423SLionel Sambuc }
1089433d6423SLionel Sambuc }
1090433d6423SLionel Sambuc }
1091433d6423SLionel Sambuc
1092433d6423SLionel Sambuc /*===========================================================================*
1093433d6423SLionel Sambuc * do_getsysinfo *
1094433d6423SLionel Sambuc *===========================================================================*/
do_getsysinfo(m_ptr)1095433d6423SLionel Sambuc int do_getsysinfo(m_ptr)
1096433d6423SLionel Sambuc message *m_ptr;
1097433d6423SLionel Sambuc {
1098433d6423SLionel Sambuc vir_bytes src_addr, dst_addr;
1099433d6423SLionel Sambuc int dst_proc;
11000eabb93cSDavid van Moolenbroek size_t size, len;
1101433d6423SLionel Sambuc int s;
1102433d6423SLionel Sambuc
1103433d6423SLionel Sambuc /* Check if the call can be allowed. */
1104433d6423SLionel Sambuc if((s = check_call_permission(m_ptr->m_source, 0, NULL)) != OK)
1105433d6423SLionel Sambuc return s;
1106433d6423SLionel Sambuc
11070eabb93cSDavid van Moolenbroek dst_proc = m_ptr->m_source;
11080eabb93cSDavid van Moolenbroek dst_addr = m_ptr->m_lsys_getsysinfo.where;
11090eabb93cSDavid van Moolenbroek size = m_ptr->m_lsys_getsysinfo.size;
11100eabb93cSDavid van Moolenbroek
1111433d6423SLionel Sambuc switch(m_ptr->m_lsys_getsysinfo.what) {
1112433d6423SLionel Sambuc case SI_PROC_TAB:
1113433d6423SLionel Sambuc src_addr = (vir_bytes) rproc;
1114433d6423SLionel Sambuc len = sizeof(struct rproc) * NR_SYS_PROCS;
1115433d6423SLionel Sambuc break;
11160eabb93cSDavid van Moolenbroek case SI_PROCALL_TAB:
11170eabb93cSDavid van Moolenbroek /* Copy out both tables, one after the other. */
11180eabb93cSDavid van Moolenbroek src_addr = (vir_bytes) rproc;
11190eabb93cSDavid van Moolenbroek len = sizeof(struct rproc) * NR_SYS_PROCS;
11200eabb93cSDavid van Moolenbroek if (len > size)
11210eabb93cSDavid van Moolenbroek return EINVAL;
11220eabb93cSDavid van Moolenbroek if ((s = sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len)) != OK)
11230eabb93cSDavid van Moolenbroek return s;
11240eabb93cSDavid van Moolenbroek dst_addr += len;
11250eabb93cSDavid van Moolenbroek size -= len;
11260eabb93cSDavid van Moolenbroek /* FALLTHROUGH */
1127433d6423SLionel Sambuc case SI_PROCPUB_TAB:
1128433d6423SLionel Sambuc src_addr = (vir_bytes) rprocpub;
1129433d6423SLionel Sambuc len = sizeof(struct rprocpub) * NR_SYS_PROCS;
1130433d6423SLionel Sambuc break;
1131433d6423SLionel Sambuc default:
1132433d6423SLionel Sambuc return(EINVAL);
1133433d6423SLionel Sambuc }
1134433d6423SLionel Sambuc
11350eabb93cSDavid van Moolenbroek if (len != size)
1136433d6423SLionel Sambuc return(EINVAL);
1137433d6423SLionel Sambuc
1138433d6423SLionel Sambuc return sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len);
1139433d6423SLionel Sambuc }
1140433d6423SLionel Sambuc
1141433d6423SLionel Sambuc /*===========================================================================*
1142433d6423SLionel Sambuc * do_lookup *
1143433d6423SLionel Sambuc *===========================================================================*/
do_lookup(m_ptr)1144433d6423SLionel Sambuc int do_lookup(m_ptr)
1145433d6423SLionel Sambuc message *m_ptr;
1146433d6423SLionel Sambuc {
1147433d6423SLionel Sambuc static char namebuf[100];
1148433d6423SLionel Sambuc int len, r;
1149433d6423SLionel Sambuc struct rproc *rrp;
1150433d6423SLionel Sambuc struct rprocpub *rrpub;
1151433d6423SLionel Sambuc
1152433d6423SLionel Sambuc len = m_ptr->m_rs_req.name_len;
1153433d6423SLionel Sambuc
1154433d6423SLionel Sambuc if(len < 2 || len >= sizeof(namebuf)) {
1155433d6423SLionel Sambuc printf("RS: len too weird (%d)\n", len);
1156433d6423SLionel Sambuc return EINVAL;
1157433d6423SLionel Sambuc }
1158433d6423SLionel Sambuc
1159433d6423SLionel Sambuc if((r=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->m_rs_req.name,
1160433d6423SLionel Sambuc SELF, (vir_bytes) namebuf, len)) != OK) {
1161433d6423SLionel Sambuc printf("RS: name copy failed\n");
1162433d6423SLionel Sambuc return r;
1163433d6423SLionel Sambuc
1164433d6423SLionel Sambuc }
1165433d6423SLionel Sambuc
1166433d6423SLionel Sambuc namebuf[len] = '\0';
1167433d6423SLionel Sambuc
1168433d6423SLionel Sambuc rrp = lookup_slot_by_label(namebuf);
1169433d6423SLionel Sambuc if(!rrp) {
1170433d6423SLionel Sambuc return ESRCH;
1171433d6423SLionel Sambuc }
1172433d6423SLionel Sambuc rrpub = rrp->r_pub;
1173433d6423SLionel Sambuc m_ptr->m_rs_req.endpoint = rrpub->endpoint;
1174433d6423SLionel Sambuc
1175433d6423SLionel Sambuc return OK;
1176433d6423SLionel Sambuc }
1177433d6423SLionel Sambuc
1178433d6423SLionel Sambuc /*===========================================================================*
1179fb6bd596SCristiano Giuffrida * do_sysctl *
1180fb6bd596SCristiano Giuffrida *===========================================================================*/
do_sysctl(message * m_ptr)1181fb6bd596SCristiano Giuffrida int do_sysctl(message *m_ptr)
1182fb6bd596SCristiano Giuffrida {
1183fb6bd596SCristiano Giuffrida int request_type = m_ptr->m_rs_req.subtype;
1184fb6bd596SCristiano Giuffrida int r, allow_retries = 1;
1185fb6bd596SCristiano Giuffrida switch(request_type) {
1186fb6bd596SCristiano Giuffrida case RS_SYSCTL_SRV_STATUS:
1187fb6bd596SCristiano Giuffrida print_services_status();
1188fb6bd596SCristiano Giuffrida break;
1189fb6bd596SCristiano Giuffrida case RS_SYSCTL_UPD_START:
1190fb6bd596SCristiano Giuffrida case RS_SYSCTL_UPD_RUN:
1191fb6bd596SCristiano Giuffrida r = start_update_prepare(allow_retries);
1192fb6bd596SCristiano Giuffrida print_update_status();
1193fb6bd596SCristiano Giuffrida if(r != OK) {
1194fb6bd596SCristiano Giuffrida if(r == ESRCH) {
1195fb6bd596SCristiano Giuffrida /* We are done already. */
1196fb6bd596SCristiano Giuffrida r = OK;
1197fb6bd596SCristiano Giuffrida }
1198fb6bd596SCristiano Giuffrida return r;
1199fb6bd596SCristiano Giuffrida }
1200fb6bd596SCristiano Giuffrida if(request_type == RS_SYSCTL_UPD_START) {
1201fb6bd596SCristiano Giuffrida return OK;
1202fb6bd596SCristiano Giuffrida }
1203fb6bd596SCristiano Giuffrida /* Send a reply when done. */
1204fb6bd596SCristiano Giuffrida rupdate.last_rpupd->rp->r_flags |= RS_LATEREPLY;
1205fb6bd596SCristiano Giuffrida rupdate.last_rpupd->rp->r_caller = m_ptr->m_source;
1206fb6bd596SCristiano Giuffrida rupdate.last_rpupd->rp->r_caller_request = RS_UPDATE;
1207fb6bd596SCristiano Giuffrida return EDONTREPLY;
1208fb6bd596SCristiano Giuffrida break;
1209fb6bd596SCristiano Giuffrida case RS_SYSCTL_UPD_STOP:
1210fb6bd596SCristiano Giuffrida r = abort_update_proc(EINTR);
1211fb6bd596SCristiano Giuffrida print_update_status();
1212fb6bd596SCristiano Giuffrida return r;
1213fb6bd596SCristiano Giuffrida break;
1214fb6bd596SCristiano Giuffrida case RS_SYSCTL_UPD_STATUS:
1215fb6bd596SCristiano Giuffrida print_update_status();
1216fb6bd596SCristiano Giuffrida break;
1217fb6bd596SCristiano Giuffrida default:
1218fb6bd596SCristiano Giuffrida printf("RS: bad sysctl type\n");
1219fb6bd596SCristiano Giuffrida return EINVAL;
1220fb6bd596SCristiano Giuffrida break;
1221fb6bd596SCristiano Giuffrida }
1222fb6bd596SCristiano Giuffrida
1223fb6bd596SCristiano Giuffrida return OK;
1224fb6bd596SCristiano Giuffrida }
1225fb6bd596SCristiano Giuffrida
1226fb6bd596SCristiano Giuffrida /*===========================================================================*
12273837bb5cSCristiano Giuffrida * do_fi *
12283837bb5cSCristiano Giuffrida *===========================================================================*/
do_fi(message * m_ptr)12293837bb5cSCristiano Giuffrida int do_fi(message *m_ptr)
12303837bb5cSCristiano Giuffrida {
12313837bb5cSCristiano Giuffrida struct rproc *rp;
12323837bb5cSCristiano Giuffrida struct rprocpub *rpub;
12333837bb5cSCristiano Giuffrida int s, r;
12343837bb5cSCristiano Giuffrida char label[RS_MAX_LABEL_LEN];
12353837bb5cSCristiano Giuffrida
12363837bb5cSCristiano Giuffrida /* Copy label. */
12373837bb5cSCristiano Giuffrida s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
12383837bb5cSCristiano Giuffrida m_ptr->m_rs_req.len, label, sizeof(label));
12393837bb5cSCristiano Giuffrida if(s != OK) {
12403837bb5cSCristiano Giuffrida return s;
12413837bb5cSCristiano Giuffrida }
12423837bb5cSCristiano Giuffrida
12433837bb5cSCristiano Giuffrida /* Lookup slot by label. */
12443837bb5cSCristiano Giuffrida rp = lookup_slot_by_label(label);
12453837bb5cSCristiano Giuffrida if(!rp) {
12463837bb5cSCristiano Giuffrida if(rs_verbose)
12473837bb5cSCristiano Giuffrida printf("RS: do_fi: service '%s' not found\n", label);
12483837bb5cSCristiano Giuffrida return(ESRCH);
12493837bb5cSCristiano Giuffrida }
12503837bb5cSCristiano Giuffrida rpub = rp->r_pub;
12513837bb5cSCristiano Giuffrida
12523837bb5cSCristiano Giuffrida /* Check if the call can be allowed. */
12533837bb5cSCristiano Giuffrida if((r = check_call_permission(m_ptr->m_source, RS_FI, rp)) != OK)
12543837bb5cSCristiano Giuffrida return r;
12553837bb5cSCristiano Giuffrida
12563837bb5cSCristiano Giuffrida /* Inject fault into the service as requested. */
12573837bb5cSCristiano Giuffrida s = fi_service(rp);
12583837bb5cSCristiano Giuffrida
12593837bb5cSCristiano Giuffrida return s;
12603837bb5cSCristiano Giuffrida }
12613837bb5cSCristiano Giuffrida
12623837bb5cSCristiano Giuffrida /*===========================================================================*
1263433d6423SLionel Sambuc * check_request *
1264433d6423SLionel Sambuc *===========================================================================*/
check_request(struct rs_start * rs_start)1265433d6423SLionel Sambuc static int check_request(struct rs_start *rs_start)
1266433d6423SLionel Sambuc {
1267433d6423SLionel Sambuc /* Verify scheduling parameters */
1268433d6423SLionel Sambuc if (rs_start->rss_scheduler != KERNEL &&
1269433d6423SLionel Sambuc (rs_start->rss_scheduler < 0 ||
1270433d6423SLionel Sambuc rs_start->rss_scheduler > LAST_SPECIAL_PROC_NR)) {
1271433d6423SLionel Sambuc printf("RS: check_request: invalid scheduler %d\n",
1272433d6423SLionel Sambuc rs_start->rss_scheduler);
1273433d6423SLionel Sambuc return EINVAL;
1274433d6423SLionel Sambuc }
1275433d6423SLionel Sambuc if (rs_start->rss_priority >= NR_SCHED_QUEUES) {
1276433d6423SLionel Sambuc printf("RS: check_request: priority %u out of range\n",
1277433d6423SLionel Sambuc rs_start->rss_priority);
1278433d6423SLionel Sambuc return EINVAL;
1279433d6423SLionel Sambuc }
1280433d6423SLionel Sambuc if (rs_start->rss_quantum <= 0) {
1281433d6423SLionel Sambuc printf("RS: check_request: quantum %u out of range\n",
1282433d6423SLionel Sambuc rs_start->rss_quantum);
1283433d6423SLionel Sambuc return EINVAL;
1284433d6423SLionel Sambuc }
1285433d6423SLionel Sambuc
1286433d6423SLionel Sambuc if (rs_start->rss_cpu == RS_CPU_BSP)
1287433d6423SLionel Sambuc rs_start->rss_cpu = machine.bsp_id;
1288433d6423SLionel Sambuc else if (rs_start->rss_cpu == RS_CPU_DEFAULT) {
1289433d6423SLionel Sambuc /* keep the default value */
1290433d6423SLionel Sambuc } else if (rs_start->rss_cpu < 0)
1291433d6423SLionel Sambuc return EINVAL;
1292433d6423SLionel Sambuc else if (rs_start->rss_cpu > machine.processors_count) {
1293433d6423SLionel Sambuc printf("RS: cpu number %d out of range 0-%d, using BSP\n",
1294433d6423SLionel Sambuc rs_start->rss_cpu, machine.processors_count);
1295433d6423SLionel Sambuc rs_start->rss_cpu = machine.bsp_id;
1296433d6423SLionel Sambuc }
1297433d6423SLionel Sambuc
1298433d6423SLionel Sambuc /* Verify signal manager. */
1299433d6423SLionel Sambuc if (rs_start->rss_sigmgr != SELF &&
1300433d6423SLionel Sambuc (rs_start->rss_sigmgr < 0 ||
1301433d6423SLionel Sambuc rs_start->rss_sigmgr > LAST_SPECIAL_PROC_NR)) {
1302433d6423SLionel Sambuc printf("RS: check_request: invalid signal manager %d\n",
1303433d6423SLionel Sambuc rs_start->rss_sigmgr);
1304433d6423SLionel Sambuc return EINVAL;
1305433d6423SLionel Sambuc }
1306433d6423SLionel Sambuc
1307433d6423SLionel Sambuc return OK;
1308433d6423SLionel Sambuc }
1309433d6423SLionel Sambuc
1310