xref: /minix3/minix/servers/vfs/main.c (revision e3b8d4bb58a799dc7fd563ac39bf3015762af03b)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * a loop that gets messages requesting work, carries out the work, and sends
3433d6423SLionel Sambuc  * replies.
4433d6423SLionel Sambuc  *
5433d6423SLionel Sambuc  * The entry points into this file are:
6433d6423SLionel Sambuc  *   main:	main program of the Virtual File System
7433d6423SLionel Sambuc  *   reply:	send a reply to a process after the requested work is done
8433d6423SLionel Sambuc  *
9433d6423SLionel Sambuc  */
10433d6423SLionel Sambuc 
11433d6423SLionel Sambuc #include "fs.h"
12433d6423SLionel Sambuc #include <fcntl.h>
13433d6423SLionel Sambuc #include <string.h>
14433d6423SLionel Sambuc #include <stdio.h>
15433d6423SLionel Sambuc #include <signal.h>
16433d6423SLionel Sambuc #include <assert.h>
17433d6423SLionel Sambuc #include <stdlib.h>
18433d6423SLionel Sambuc #include <sys/ioc_memory.h>
19433d6423SLionel Sambuc #include <sys/svrctl.h>
20433d6423SLionel Sambuc #include <sys/select.h>
21433d6423SLionel Sambuc #include <minix/callnr.h>
22433d6423SLionel Sambuc #include <minix/com.h>
23433d6423SLionel Sambuc #include <minix/const.h>
24433d6423SLionel Sambuc #include <minix/endpoint.h>
25433d6423SLionel Sambuc #include <minix/safecopies.h>
26433d6423SLionel Sambuc #include <minix/debug.h>
27433d6423SLionel Sambuc #include <minix/vfsif.h>
28433d6423SLionel Sambuc #include "file.h"
29433d6423SLionel Sambuc #include "vmnt.h"
30433d6423SLionel Sambuc #include "vnode.h"
31433d6423SLionel Sambuc 
32433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS
33433d6423SLionel Sambuc EXTERN unsigned long calls_stats[NR_VFS_CALLS];
34433d6423SLionel Sambuc #endif
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc /* Thread related prototypes */
37433d6423SLionel Sambuc static void do_reply(struct worker_thread *wp);
38433d6423SLionel Sambuc static void do_work(void);
39433d6423SLionel Sambuc static void do_init_root(void);
40433d6423SLionel Sambuc static void handle_work(void (*func)(void));
41433d6423SLionel Sambuc 
425055c7eaSDavid van Moolenbroek static int get_work(void);
43433d6423SLionel Sambuc static void service_pm(void);
44433d6423SLionel Sambuc static int unblock(struct fproc *rfp);
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc /* SEF functions and variables. */
47433d6423SLionel Sambuc static void sef_local_startup(void);
48433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *info);
49728b0e5bSDavid van Moolenbroek static int sef_cb_init_lu(int type, sef_init_info_t *info);
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc /*===========================================================================*
52433d6423SLionel Sambuc  *				main					     *
53433d6423SLionel Sambuc  *===========================================================================*/
main(void)54433d6423SLionel Sambuc int main(void)
55433d6423SLionel Sambuc {
56433d6423SLionel Sambuc /* This is the main program of the file system.  The main loop consists of
57433d6423SLionel Sambuc  * three major activities: getting new work, processing the work, and sending
58433d6423SLionel Sambuc  * the reply.  This loop never terminates as long as the file system runs.
59433d6423SLionel Sambuc  */
60433d6423SLionel Sambuc   int transid;
61433d6423SLionel Sambuc   struct worker_thread *wp;
62433d6423SLionel Sambuc 
63433d6423SLionel Sambuc   /* SEF local startup. */
64433d6423SLionel Sambuc   sef_local_startup();
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc   printf("Started VFS: %d worker thread(s)\n", NR_WTHREADS);
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc   /* This is the main loop that gets work, processes it, and sends replies. */
69433d6423SLionel Sambuc   while (TRUE) {
70728b0e5bSDavid van Moolenbroek 	worker_yield();	/* let other threads run */
71728b0e5bSDavid van Moolenbroek 
72433d6423SLionel Sambuc 	send_work();
735055c7eaSDavid van Moolenbroek 
745055c7eaSDavid van Moolenbroek 	/* The get_work() function returns TRUE if we have a new message to
755055c7eaSDavid van Moolenbroek 	 * process. It returns FALSE if it spawned other thread activities.
765055c7eaSDavid van Moolenbroek 	 */
775055c7eaSDavid van Moolenbroek 	if (!get_work())
785055c7eaSDavid van Moolenbroek 		continue;
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 	transid = TRNS_GET_ID(m_in.m_type);
81433d6423SLionel Sambuc 	if (IS_VFS_FS_TRANSID(transid)) {
82433d6423SLionel Sambuc 		wp = worker_get((thread_t) transid - VFS_TRANSID);
83433d6423SLionel Sambuc 		if (wp == NULL || wp->w_fp == NULL) {
84433d6423SLionel Sambuc 			printf("VFS: spurious message %d from endpoint %d\n",
85433d6423SLionel Sambuc 				m_in.m_type, m_in.m_source);
86433d6423SLionel Sambuc 			continue;
87433d6423SLionel Sambuc 		}
88433d6423SLionel Sambuc 		m_in.m_type = TRNS_DEL_ID(m_in.m_type);
89433d6423SLionel Sambuc 		do_reply(wp);
90433d6423SLionel Sambuc 		continue;
91433d6423SLionel Sambuc 	} else if (who_e == PM_PROC_NR) { /* Calls from PM */
92433d6423SLionel Sambuc 		/* Special control messages from PM */
93433d6423SLionel Sambuc 		service_pm();
94433d6423SLionel Sambuc 		continue;
95433d6423SLionel Sambuc 	} else if (is_notify(call_nr)) {
96433d6423SLionel Sambuc 		/* A task ipc_notify()ed us */
97433d6423SLionel Sambuc 		switch (who_e) {
98433d6423SLionel Sambuc 		case DS_PROC_NR:
99433d6423SLionel Sambuc 			/* Start a thread to handle DS events, if no thread
100433d6423SLionel Sambuc 			 * is pending or active for it already. DS is not
101433d6423SLionel Sambuc 			 * supposed to issue calls to VFS or be the subject of
102433d6423SLionel Sambuc 			 * postponed PM requests, so this should be no problem.
103433d6423SLionel Sambuc 			 */
104433d6423SLionel Sambuc 			if (worker_can_start(fp))
105433d6423SLionel Sambuc 				handle_work(ds_event);
106433d6423SLionel Sambuc 			break;
107433d6423SLionel Sambuc 		case KERNEL:
108433d6423SLionel Sambuc 			mthread_stacktraces();
109433d6423SLionel Sambuc 			break;
110433d6423SLionel Sambuc 		case CLOCK:
111433d6423SLionel Sambuc 			/* Timer expired. Used only for select(). Check it. */
112433d6423SLionel Sambuc 			expire_timers(m_in.m_notify.timestamp);
113433d6423SLionel Sambuc 			break;
114433d6423SLionel Sambuc 		default:
115433d6423SLionel Sambuc 			printf("VFS: ignoring notification from %d\n", who_e);
116433d6423SLionel Sambuc 		}
117433d6423SLionel Sambuc 		continue;
118433d6423SLionel Sambuc 	} else if (who_p < 0) { /* i.e., message comes from a task */
119433d6423SLionel Sambuc 		/* We're going to ignore this message. Tasks should
120433d6423SLionel Sambuc 		 * send ipc_notify()s only.
121433d6423SLionel Sambuc 		 */
122433d6423SLionel Sambuc 		 printf("VFS: ignoring message from %d (%d)\n", who_e, call_nr);
123433d6423SLionel Sambuc 		 continue;
124433d6423SLionel Sambuc 	}
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc 	if (IS_BDEV_RS(call_nr)) {
127433d6423SLionel Sambuc 		/* We've got results for a block device request. */
128433d6423SLionel Sambuc 		bdev_reply();
129433d6423SLionel Sambuc 	} else if (IS_CDEV_RS(call_nr)) {
130433d6423SLionel Sambuc 		/* We've got results for a character device request. */
131433d6423SLionel Sambuc 		cdev_reply();
132*e3b8d4bbSDavid van Moolenbroek 	} else if (IS_SDEV_RS(call_nr)) {
133*e3b8d4bbSDavid van Moolenbroek 		/* We've got results for a socket driver request. */
134*e3b8d4bbSDavid van Moolenbroek 		sdev_reply();
135433d6423SLionel Sambuc 	} else {
136433d6423SLionel Sambuc 		/* Normal syscall. This spawns a new thread. */
137433d6423SLionel Sambuc 		handle_work(do_work);
138433d6423SLionel Sambuc 	}
139433d6423SLionel Sambuc   }
140433d6423SLionel Sambuc   return(OK);				/* shouldn't come here */
141433d6423SLionel Sambuc }
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc /*===========================================================================*
144433d6423SLionel Sambuc  *			       handle_work				     *
145433d6423SLionel Sambuc  *===========================================================================*/
handle_work(void (* func)(void))146433d6423SLionel Sambuc static void handle_work(void (*func)(void))
147433d6423SLionel Sambuc {
148433d6423SLionel Sambuc /* Handle asynchronous device replies and new system calls. If the originating
149433d6423SLionel Sambuc  * endpoint is an FS endpoint, take extra care not to get in deadlock. */
150433d6423SLionel Sambuc   struct vmnt *vmp = NULL;
151433d6423SLionel Sambuc   endpoint_t proc_e;
152433d6423SLionel Sambuc   int use_spare = FALSE;
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc   proc_e = m_in.m_source;
155433d6423SLionel Sambuc 
156433d6423SLionel Sambuc   if (fp->fp_flags & FP_SRV_PROC) {
157433d6423SLionel Sambuc 	vmp = find_vmnt(proc_e);
158433d6423SLionel Sambuc 	if (vmp != NULL) {
159433d6423SLionel Sambuc 		/* A callback from an FS endpoint. Can do only one at once. */
160433d6423SLionel Sambuc 		if (vmp->m_flags & VMNT_CALLBACK) {
161433d6423SLionel Sambuc 			replycode(proc_e, EAGAIN);
162433d6423SLionel Sambuc 			return;
163433d6423SLionel Sambuc 		}
164433d6423SLionel Sambuc 		/* Already trying to resolve a deadlock? Can't handle more. */
165433d6423SLionel Sambuc 		if (worker_available() == 0) {
166433d6423SLionel Sambuc 			replycode(proc_e, EAGAIN);
167433d6423SLionel Sambuc 			return;
168433d6423SLionel Sambuc 		}
169433d6423SLionel Sambuc 		/* A thread is available. Set callback flag. */
170433d6423SLionel Sambuc 		vmp->m_flags |= VMNT_CALLBACK;
171433d6423SLionel Sambuc 		if (vmp->m_flags & VMNT_MOUNTING) {
172433d6423SLionel Sambuc 			vmp->m_flags |= VMNT_FORCEROOTBSF;
173433d6423SLionel Sambuc 		}
174433d6423SLionel Sambuc 	}
175433d6423SLionel Sambuc 
176433d6423SLionel Sambuc 	/* Use the spare thread to handle this request if needed. */
177433d6423SLionel Sambuc 	use_spare = TRUE;
178433d6423SLionel Sambuc   }
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc   worker_start(fp, func, &m_in, use_spare);
181433d6423SLionel Sambuc }
182433d6423SLionel Sambuc 
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc /*===========================================================================*
185433d6423SLionel Sambuc  *			       do_reply				             *
186433d6423SLionel Sambuc  *===========================================================================*/
do_reply(struct worker_thread * wp)187433d6423SLionel Sambuc static void do_reply(struct worker_thread *wp)
188433d6423SLionel Sambuc {
189433d6423SLionel Sambuc   struct vmnt *vmp = NULL;
190433d6423SLionel Sambuc 
191433d6423SLionel Sambuc   if(who_e != VM_PROC_NR && (vmp = find_vmnt(who_e)) == NULL)
192433d6423SLionel Sambuc 	panic("Couldn't find vmnt for endpoint %d", who_e);
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc   if (wp->w_task != who_e) {
195433d6423SLionel Sambuc 	printf("VFS: tid %d: expected %d to reply, not %d\n",
196433d6423SLionel Sambuc 		wp->w_tid, wp->w_task, who_e);
19729e004d2SDavid van Moolenbroek 	return;
19829e004d2SDavid van Moolenbroek   }
19929e004d2SDavid van Moolenbroek   /* It should be impossible to trigger the following case, but it is here for
20029e004d2SDavid van Moolenbroek    * consistency reasons: worker_stop() resets w_sendrec but not w_task.
20129e004d2SDavid van Moolenbroek    */
20229e004d2SDavid van Moolenbroek   if (wp->w_sendrec == NULL) {
20329e004d2SDavid van Moolenbroek 	printf("VFS: tid %d: late reply from %d ignored\n", wp->w_tid, who_e);
20429e004d2SDavid van Moolenbroek 	return;
205433d6423SLionel Sambuc   }
206433d6423SLionel Sambuc   *wp->w_sendrec = m_in;
20729e004d2SDavid van Moolenbroek   wp->w_sendrec = NULL;
208433d6423SLionel Sambuc   wp->w_task = NONE;
209433d6423SLionel Sambuc   if(vmp) vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */
210433d6423SLionel Sambuc   worker_signal(wp); /* Continue this thread */
211433d6423SLionel Sambuc }
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc /*===========================================================================*
214433d6423SLionel Sambuc  *			       do_pending_pipe				     *
215433d6423SLionel Sambuc  *===========================================================================*/
do_pending_pipe(void)216433d6423SLionel Sambuc static void do_pending_pipe(void)
217433d6423SLionel Sambuc {
218232819ddSDavid van Moolenbroek   vir_bytes buf;
219232819ddSDavid van Moolenbroek   size_t nbytes, cum_io;
220232819ddSDavid van Moolenbroek   int r, op, fd;
221433d6423SLionel Sambuc   struct filp *f;
222433d6423SLionel Sambuc   tll_access_t locktype;
223433d6423SLionel Sambuc 
224232819ddSDavid van Moolenbroek   assert(fp->fp_blocked_on == FP_BLOCKED_ON_NONE);
225232819ddSDavid van Moolenbroek 
226232819ddSDavid van Moolenbroek   /*
227232819ddSDavid van Moolenbroek    * We take all our needed resumption state from the m_in message, which is
228232819ddSDavid van Moolenbroek    * filled by unblock().  Since this is an internal resumption, there is no
229232819ddSDavid van Moolenbroek    * need to perform extensive checks on the message fields.
230232819ddSDavid van Moolenbroek    */
231232819ddSDavid van Moolenbroek   fd = job_m_in.m_lc_vfs_readwrite.fd;
232232819ddSDavid van Moolenbroek   buf = job_m_in.m_lc_vfs_readwrite.buf;
233232819ddSDavid van Moolenbroek   nbytes = job_m_in.m_lc_vfs_readwrite.len;
234232819ddSDavid van Moolenbroek   cum_io = job_m_in.m_lc_vfs_readwrite.cum_io;
235232819ddSDavid van Moolenbroek 
236232819ddSDavid van Moolenbroek   f = fp->fp_filp[fd];
237433d6423SLionel Sambuc   assert(f != NULL);
238433d6423SLionel Sambuc 
239433d6423SLionel Sambuc   locktype = (job_call_nr == VFS_READ) ? VNODE_READ : VNODE_WRITE;
240433d6423SLionel Sambuc   op = (job_call_nr == VFS_READ) ? READING : WRITING;
241433d6423SLionel Sambuc   lock_filp(f, locktype);
242433d6423SLionel Sambuc 
243232819ddSDavid van Moolenbroek   r = rw_pipe(op, who_e, f, job_call_nr, fd, buf, nbytes, cum_io);
244433d6423SLionel Sambuc 
245179bddcfSDavid van Moolenbroek   if (r != SUSPEND) { /* Do we have results to report? */
246179bddcfSDavid van Moolenbroek 	/* Process is writing, but there is no reader. Send a SIGPIPE signal.
247179bddcfSDavid van Moolenbroek 	 * This should match the corresponding code in read_write().
248179bddcfSDavid van Moolenbroek 	 */
249179bddcfSDavid van Moolenbroek 	if (r == EPIPE && op == WRITING) {
250179bddcfSDavid van Moolenbroek 		if (!(f->filp_flags & O_NOSIGPIPE))
251179bddcfSDavid van Moolenbroek 			sys_kill(fp->fp_endpoint, SIGPIPE);
252179bddcfSDavid van Moolenbroek 	}
253179bddcfSDavid van Moolenbroek 
254433d6423SLionel Sambuc 	replycode(fp->fp_endpoint, r);
255179bddcfSDavid van Moolenbroek   }
256433d6423SLionel Sambuc 
257433d6423SLionel Sambuc   unlock_filp(f);
258433d6423SLionel Sambuc }
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc /*===========================================================================*
261433d6423SLionel Sambuc  *			       do_work					     *
262433d6423SLionel Sambuc  *===========================================================================*/
do_work(void)263433d6423SLionel Sambuc static void do_work(void)
264433d6423SLionel Sambuc {
265433d6423SLionel Sambuc   unsigned int call_index;
266433d6423SLionel Sambuc   int error;
267433d6423SLionel Sambuc 
268433d6423SLionel Sambuc   if (fp->fp_pid == PID_FREE) {
269433d6423SLionel Sambuc 	/* Process vanished before we were able to handle request.
270433d6423SLionel Sambuc 	 * Replying has no use. Just drop it.
271433d6423SLionel Sambuc 	 */
272433d6423SLionel Sambuc 	return;
273433d6423SLionel Sambuc   }
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc   memset(&job_m_out, 0, sizeof(job_m_out));
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc   /* At this point we assume that we're dealing with a call that has been
278433d6423SLionel Sambuc    * made specifically to VFS. Typically it will be a POSIX call from a
279433d6423SLionel Sambuc    * normal process, but we also handle a few calls made by drivers such
280433d6423SLionel Sambuc    * such as UDS and VND through here. Call the internal function that
281433d6423SLionel Sambuc    * does the work.
282433d6423SLionel Sambuc    */
283433d6423SLionel Sambuc   if (IS_VFS_CALL(job_call_nr)) {
284433d6423SLionel Sambuc 	call_index = (unsigned int) (job_call_nr - VFS_BASE);
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc 	if (call_index < NR_VFS_CALLS && call_vec[call_index] != NULL) {
287433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS
288433d6423SLionel Sambuc 		calls_stats[call_index]++;
289433d6423SLionel Sambuc #endif
290433d6423SLionel Sambuc 		error = (*call_vec[call_index])();
291433d6423SLionel Sambuc 	} else
292433d6423SLionel Sambuc 		error = ENOSYS;
293433d6423SLionel Sambuc   } else
294433d6423SLionel Sambuc 	error = ENOSYS;
295433d6423SLionel Sambuc 
296433d6423SLionel Sambuc   /* Copy the results back to the user and send reply. */
297433d6423SLionel Sambuc   if (error != SUSPEND) reply(&job_m_out, fp->fp_endpoint, error);
298433d6423SLionel Sambuc }
299433d6423SLionel Sambuc 
300433d6423SLionel Sambuc /*===========================================================================*
301728b0e5bSDavid van Moolenbroek  *				sef_cb_lu_prepare			     *
302728b0e5bSDavid van Moolenbroek  *===========================================================================*/
sef_cb_lu_prepare(int state)303728b0e5bSDavid van Moolenbroek static int sef_cb_lu_prepare(int state)
304728b0e5bSDavid van Moolenbroek {
305728b0e5bSDavid van Moolenbroek /* This function is called to decide whether we can enter the given live
306728b0e5bSDavid van Moolenbroek  * update state, and to prepare for such an update. If we are requested to
307728b0e5bSDavid van Moolenbroek  * update to a request-free or protocol-free state, make sure there is no work
308728b0e5bSDavid van Moolenbroek  * pending or being processed, and shut down all worker threads.
309728b0e5bSDavid van Moolenbroek  */
310728b0e5bSDavid van Moolenbroek 
311728b0e5bSDavid van Moolenbroek   switch (state) {
312728b0e5bSDavid van Moolenbroek   case SEF_LU_STATE_REQUEST_FREE:
313728b0e5bSDavid van Moolenbroek   case SEF_LU_STATE_PROTOCOL_FREE:
314728b0e5bSDavid van Moolenbroek 	if (!worker_idle()) {
315728b0e5bSDavid van Moolenbroek 		printf("VFS: worker threads not idle, blocking update\n");
316728b0e5bSDavid van Moolenbroek 		break;
317728b0e5bSDavid van Moolenbroek 	}
318728b0e5bSDavid van Moolenbroek 
319728b0e5bSDavid van Moolenbroek 	worker_cleanup();
320728b0e5bSDavid van Moolenbroek 
321728b0e5bSDavid van Moolenbroek 	return OK;
322728b0e5bSDavid van Moolenbroek   }
323728b0e5bSDavid van Moolenbroek 
324728b0e5bSDavid van Moolenbroek   return ENOTREADY;
325728b0e5bSDavid van Moolenbroek }
326728b0e5bSDavid van Moolenbroek 
327728b0e5bSDavid van Moolenbroek /*===========================================================================*
328728b0e5bSDavid van Moolenbroek  *			       sef_cb_lu_state_changed			     *
329728b0e5bSDavid van Moolenbroek  *===========================================================================*/
sef_cb_lu_state_changed(int old_state,int state)330728b0e5bSDavid van Moolenbroek static void sef_cb_lu_state_changed(int old_state, int state)
331728b0e5bSDavid van Moolenbroek {
332728b0e5bSDavid van Moolenbroek /* Worker threads (especially their stacks) pose a serious problem for state
333728b0e5bSDavid van Moolenbroek  * transfer during live update, and therefore, we shut down all worker threads
334728b0e5bSDavid van Moolenbroek  * during live update and restart them afterwards. This function is called in
335728b0e5bSDavid van Moolenbroek  * the old VFS instance when the state changed. We use it to restart worker
336728b0e5bSDavid van Moolenbroek  * threads after a failed live update.
337728b0e5bSDavid van Moolenbroek  */
338728b0e5bSDavid van Moolenbroek 
339728b0e5bSDavid van Moolenbroek   if (state != SEF_LU_STATE_NULL)
340728b0e5bSDavid van Moolenbroek 	return;
341728b0e5bSDavid van Moolenbroek 
342728b0e5bSDavid van Moolenbroek   switch (old_state) {
343728b0e5bSDavid van Moolenbroek   case SEF_LU_STATE_REQUEST_FREE:
344728b0e5bSDavid van Moolenbroek   case SEF_LU_STATE_PROTOCOL_FREE:
345728b0e5bSDavid van Moolenbroek 	worker_init();
346728b0e5bSDavid van Moolenbroek   }
347728b0e5bSDavid van Moolenbroek }
348728b0e5bSDavid van Moolenbroek 
349728b0e5bSDavid van Moolenbroek /*===========================================================================*
350728b0e5bSDavid van Moolenbroek  *				sef_cb_init_lu				     *
351728b0e5bSDavid van Moolenbroek  *===========================================================================*/
sef_cb_init_lu(int type,sef_init_info_t * info)352728b0e5bSDavid van Moolenbroek static int sef_cb_init_lu(int type, sef_init_info_t *info)
353728b0e5bSDavid van Moolenbroek {
354728b0e5bSDavid van Moolenbroek /* This function is called in the new VFS instance during a live update. */
355728b0e5bSDavid van Moolenbroek   int r;
356728b0e5bSDavid van Moolenbroek 
357728b0e5bSDavid van Moolenbroek   /* Perform regular state transfer. */
358728b0e5bSDavid van Moolenbroek   if ((r = SEF_CB_INIT_LU_DEFAULT(type, info)) != OK)
359728b0e5bSDavid van Moolenbroek 	return r;
360728b0e5bSDavid van Moolenbroek 
361728b0e5bSDavid van Moolenbroek   /* Recreate worker threads, if necessary. */
362728b0e5bSDavid van Moolenbroek   switch (info->prepare_state) {
363728b0e5bSDavid van Moolenbroek   case SEF_LU_STATE_REQUEST_FREE:
364728b0e5bSDavid van Moolenbroek   case SEF_LU_STATE_PROTOCOL_FREE:
365728b0e5bSDavid van Moolenbroek 	worker_init();
366728b0e5bSDavid van Moolenbroek   }
367728b0e5bSDavid van Moolenbroek 
368728b0e5bSDavid van Moolenbroek   return OK;
369728b0e5bSDavid van Moolenbroek }
370728b0e5bSDavid van Moolenbroek 
371728b0e5bSDavid van Moolenbroek /*===========================================================================*
372433d6423SLionel Sambuc  *			       sef_local_startup			     *
373433d6423SLionel Sambuc  *===========================================================================*/
sef_local_startup(void)374728b0e5bSDavid van Moolenbroek static void sef_local_startup(void)
375433d6423SLionel Sambuc {
376433d6423SLionel Sambuc   /* Register init callbacks. */
377433d6423SLionel Sambuc   sef_setcb_init_fresh(sef_cb_init_fresh);
3783f82ac6aSCristiano Giuffrida   sef_setcb_init_restart(SEF_CB_INIT_RESTART_STATEFUL);
379433d6423SLionel Sambuc 
380728b0e5bSDavid van Moolenbroek   /* Register live update callbacks. */
381728b0e5bSDavid van Moolenbroek   sef_setcb_init_lu(sef_cb_init_lu);
382728b0e5bSDavid van Moolenbroek   sef_setcb_lu_prepare(sef_cb_lu_prepare);
383728b0e5bSDavid van Moolenbroek   sef_setcb_lu_state_changed(sef_cb_lu_state_changed);
384728b0e5bSDavid van Moolenbroek   sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
385728b0e5bSDavid van Moolenbroek 
386433d6423SLionel Sambuc   /* Let SEF perform startup. */
387433d6423SLionel Sambuc   sef_startup();
388433d6423SLionel Sambuc }
389433d6423SLionel Sambuc 
390433d6423SLionel Sambuc /*===========================================================================*
391433d6423SLionel Sambuc  *				sef_cb_init_fresh			     *
392433d6423SLionel Sambuc  *===========================================================================*/
sef_cb_init_fresh(int UNUSED (type),sef_init_info_t * info)393433d6423SLionel Sambuc static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
394433d6423SLionel Sambuc {
395433d6423SLionel Sambuc /* Initialize the virtual file server. */
396433d6423SLionel Sambuc   int s, i;
397433d6423SLionel Sambuc   struct fproc *rfp;
398433d6423SLionel Sambuc   message mess;
399433d6423SLionel Sambuc   struct rprocpub rprocpub[NR_BOOT_PROCS];
400433d6423SLionel Sambuc 
401433d6423SLionel Sambuc   self = NULL;
402433d6423SLionel Sambuc   verbose = 0;
403433d6423SLionel Sambuc 
404433d6423SLionel Sambuc   /* Initialize proc endpoints to NONE */
405433d6423SLionel Sambuc   for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
406433d6423SLionel Sambuc 	rfp->fp_endpoint = NONE;
407433d6423SLionel Sambuc 	rfp->fp_pid = PID_FREE;
408433d6423SLionel Sambuc   }
409433d6423SLionel Sambuc 
410433d6423SLionel Sambuc   /* Initialize the process table with help of the process manager messages.
411433d6423SLionel Sambuc    * Expect one message for each system process with its slot number and pid.
412433d6423SLionel Sambuc    * When no more processes follow, the magic process number NONE is sent.
413433d6423SLionel Sambuc    * Then, stop and synchronize with the PM.
414433d6423SLionel Sambuc    */
415433d6423SLionel Sambuc   do {
416433d6423SLionel Sambuc 	if ((s = sef_receive(PM_PROC_NR, &mess)) != OK)
417433d6423SLionel Sambuc 		panic("VFS: couldn't receive from PM: %d", s);
418433d6423SLionel Sambuc 
419433d6423SLionel Sambuc 	if (mess.m_type != VFS_PM_INIT)
420433d6423SLionel Sambuc 		panic("unexpected message from PM: %d", mess.m_type);
421433d6423SLionel Sambuc 
422433d6423SLionel Sambuc 	if (NONE == mess.VFS_PM_ENDPT) break;
423433d6423SLionel Sambuc 
424433d6423SLionel Sambuc 	rfp = &fproc[mess.VFS_PM_SLOT];
425433d6423SLionel Sambuc 	rfp->fp_flags = FP_NOFLAGS;
426433d6423SLionel Sambuc 	rfp->fp_pid = mess.VFS_PM_PID;
427433d6423SLionel Sambuc 	rfp->fp_endpoint = mess.VFS_PM_ENDPT;
428433d6423SLionel Sambuc 	rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
429433d6423SLionel Sambuc 	rfp->fp_realuid = (uid_t) SYS_UID;
430433d6423SLionel Sambuc 	rfp->fp_effuid = (uid_t) SYS_UID;
431433d6423SLionel Sambuc 	rfp->fp_realgid = (gid_t) SYS_GID;
432433d6423SLionel Sambuc 	rfp->fp_effgid = (gid_t) SYS_GID;
433433d6423SLionel Sambuc 	rfp->fp_umask = ~0;
434433d6423SLionel Sambuc   } while (TRUE);			/* continue until process NONE */
435433d6423SLionel Sambuc   mess.m_type = OK;			/* tell PM that we succeeded */
436433d6423SLionel Sambuc   s = ipc_send(PM_PROC_NR, &mess);		/* send synchronization message */
437433d6423SLionel Sambuc 
438433d6423SLionel Sambuc   system_hz = sys_hz();
439433d6423SLionel Sambuc 
440433d6423SLionel Sambuc   /* Subscribe to block and character driver events. */
441433d6423SLionel Sambuc   s = ds_subscribe("drv\\.[bc]..\\..*", DSF_INITIAL | DSF_OVERWRITE);
442433d6423SLionel Sambuc   if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s);
443433d6423SLionel Sambuc 
444433d6423SLionel Sambuc   /* Initialize worker threads */
445433d6423SLionel Sambuc   worker_init();
446433d6423SLionel Sambuc 
447433d6423SLionel Sambuc   /* Initialize global locks */
448433d6423SLionel Sambuc   if (mthread_mutex_init(&bsf_lock, NULL) != 0)
449433d6423SLionel Sambuc 	panic("VFS: couldn't initialize block special file lock");
450433d6423SLionel Sambuc 
451433d6423SLionel Sambuc   init_dmap();			/* Initialize device table. */
452*e3b8d4bbSDavid van Moolenbroek   init_smap();			/* Initialize socket table. */
453433d6423SLionel Sambuc 
454433d6423SLionel Sambuc   /* Map all the services in the boot image. */
455433d6423SLionel Sambuc   if ((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
456433d6423SLionel Sambuc 			    (vir_bytes) rprocpub, sizeof(rprocpub))) != OK){
457433d6423SLionel Sambuc 	panic("sys_safecopyfrom failed: %d", s);
458433d6423SLionel Sambuc   }
459433d6423SLionel Sambuc   for (i = 0; i < NR_BOOT_PROCS; i++) {
460433d6423SLionel Sambuc 	if (rprocpub[i].in_use) {
461433d6423SLionel Sambuc 		if ((s = map_service(&rprocpub[i])) != OK) {
462433d6423SLionel Sambuc 			panic("VFS: unable to map service: %d", s);
463433d6423SLionel Sambuc 		}
464433d6423SLionel Sambuc 	}
465433d6423SLionel Sambuc   }
466433d6423SLionel Sambuc 
467433d6423SLionel Sambuc   /* Initialize locks and initial values for all processes. */
468433d6423SLionel Sambuc   for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
469433d6423SLionel Sambuc 	if (mutex_init(&rfp->fp_lock, NULL) != 0)
470433d6423SLionel Sambuc 		panic("unable to initialize fproc lock");
471433d6423SLionel Sambuc 	rfp->fp_worker = NULL;
472433d6423SLionel Sambuc #if LOCK_DEBUG
473433d6423SLionel Sambuc 	rfp->fp_vp_rdlocks = 0;
474433d6423SLionel Sambuc 	rfp->fp_vmnt_rdlocks = 0;
475433d6423SLionel Sambuc #endif
476433d6423SLionel Sambuc 
477433d6423SLionel Sambuc 	/* Initialize process directories. mount_fs will set them to the
478433d6423SLionel Sambuc 	 * correct values.
479433d6423SLionel Sambuc 	 */
480433d6423SLionel Sambuc 	for (i = 0; i < OPEN_MAX; i++)
481433d6423SLionel Sambuc 		rfp->fp_filp[i] = NULL;
482433d6423SLionel Sambuc 	rfp->fp_rd = NULL;
483433d6423SLionel Sambuc 	rfp->fp_wd = NULL;
484433d6423SLionel Sambuc   }
485433d6423SLionel Sambuc 
486433d6423SLionel Sambuc   init_vnodes();		/* init vnodes */
487433d6423SLionel Sambuc   init_vmnts();			/* init vmnt structures */
488433d6423SLionel Sambuc   init_select();		/* init select() structures */
489433d6423SLionel Sambuc   init_filps();			/* Init filp structures */
490433d6423SLionel Sambuc 
491f859061eSDavid van Moolenbroek   /* Mount PFS and initial file system root. */
492433d6423SLionel Sambuc   worker_start(fproc_addr(VFS_PROC_NR), do_init_root, &mess /*unused*/,
493433d6423SLionel Sambuc 	FALSE /*use_spare*/);
494433d6423SLionel Sambuc 
495433d6423SLionel Sambuc   return(OK);
496433d6423SLionel Sambuc }
497433d6423SLionel Sambuc 
498433d6423SLionel Sambuc /*===========================================================================*
499433d6423SLionel Sambuc  *			       do_init_root				     *
500433d6423SLionel Sambuc  *===========================================================================*/
do_init_root(void)501433d6423SLionel Sambuc static void do_init_root(void)
502433d6423SLionel Sambuc {
503f859061eSDavid van Moolenbroek   char *mount_type, *mount_label;
504433d6423SLionel Sambuc   int r;
505f859061eSDavid van Moolenbroek 
5067eb698eaSDavid van Moolenbroek   /* Disallow requests from e.g. init(8) while doing the initial mounting. */
5077eb698eaSDavid van Moolenbroek   worker_allow(FALSE);
508f859061eSDavid van Moolenbroek 
5097eb698eaSDavid van Moolenbroek   /* Mount the pipe file server. */
510f859061eSDavid van Moolenbroek   mount_pfs();
511f859061eSDavid van Moolenbroek 
512f859061eSDavid van Moolenbroek   /* Mount the root file system. */
513f859061eSDavid van Moolenbroek   mount_type = "mfs";       /* FIXME: use boot image process name instead */
514f859061eSDavid van Moolenbroek   mount_label = "fs_imgrd"; /* FIXME: obtain this from RS */
515433d6423SLionel Sambuc 
516433d6423SLionel Sambuc   r = mount_fs(DEV_IMGRD, "bootramdisk", "/", MFS_PROC_NR, 0, mount_type,
517433d6423SLionel Sambuc 	mount_label);
518433d6423SLionel Sambuc   if (r != OK)
519433d6423SLionel Sambuc 	panic("Failed to initialize root");
5207eb698eaSDavid van Moolenbroek 
5217eb698eaSDavid van Moolenbroek   /* All done with mounting, allow requests now. */
5227eb698eaSDavid van Moolenbroek   worker_allow(TRUE);
523433d6423SLionel Sambuc }
524433d6423SLionel Sambuc 
525433d6423SLionel Sambuc /*===========================================================================*
526433d6423SLionel Sambuc  *				lock_proc				     *
527433d6423SLionel Sambuc  *===========================================================================*/
lock_proc(struct fproc * rfp)528433d6423SLionel Sambuc void lock_proc(struct fproc *rfp)
529433d6423SLionel Sambuc {
530433d6423SLionel Sambuc   int r;
531433d6423SLionel Sambuc   struct worker_thread *org_self;
532433d6423SLionel Sambuc 
533433d6423SLionel Sambuc   r = mutex_trylock(&rfp->fp_lock);
534433d6423SLionel Sambuc   if (r == 0) return;
535433d6423SLionel Sambuc 
536433d6423SLionel Sambuc   org_self = worker_suspend();
537433d6423SLionel Sambuc 
538433d6423SLionel Sambuc   if ((r = mutex_lock(&rfp->fp_lock)) != 0)
539433d6423SLionel Sambuc 	panic("unable to lock fproc lock: %d", r);
540433d6423SLionel Sambuc 
541433d6423SLionel Sambuc   worker_resume(org_self);
542433d6423SLionel Sambuc }
543433d6423SLionel Sambuc 
544433d6423SLionel Sambuc /*===========================================================================*
545433d6423SLionel Sambuc  *				unlock_proc				     *
546433d6423SLionel Sambuc  *===========================================================================*/
unlock_proc(struct fproc * rfp)547433d6423SLionel Sambuc void unlock_proc(struct fproc *rfp)
548433d6423SLionel Sambuc {
549433d6423SLionel Sambuc   int r;
550433d6423SLionel Sambuc 
551433d6423SLionel Sambuc   if ((r = mutex_unlock(&rfp->fp_lock)) != 0)
552433d6423SLionel Sambuc 	panic("Failed to unlock: %d", r);
553433d6423SLionel Sambuc }
554433d6423SLionel Sambuc 
555433d6423SLionel Sambuc /*===========================================================================*
556433d6423SLionel Sambuc  *				thread_cleanup				     *
557433d6423SLionel Sambuc  *===========================================================================*/
thread_cleanup(void)558433d6423SLionel Sambuc void thread_cleanup(void)
559433d6423SLionel Sambuc {
560433d6423SLionel Sambuc /* Perform cleanup actions for a worker thread. */
561433d6423SLionel Sambuc 
562433d6423SLionel Sambuc #if LOCK_DEBUG
563433d6423SLionel Sambuc   check_filp_locks_by_me();
564433d6423SLionel Sambuc   check_vnode_locks_by_me(fp);
565433d6423SLionel Sambuc   check_vmnt_locks_by_me(fp);
566433d6423SLionel Sambuc #endif
567433d6423SLionel Sambuc 
568433d6423SLionel Sambuc   if (fp->fp_flags & FP_SRV_PROC) {
569433d6423SLionel Sambuc 	struct vmnt *vmp;
570433d6423SLionel Sambuc 
571433d6423SLionel Sambuc 	if ((vmp = find_vmnt(fp->fp_endpoint)) != NULL) {
572433d6423SLionel Sambuc 		vmp->m_flags &= ~VMNT_CALLBACK;
573433d6423SLionel Sambuc 	}
574433d6423SLionel Sambuc   }
575433d6423SLionel Sambuc }
576433d6423SLionel Sambuc 
577433d6423SLionel Sambuc /*===========================================================================*
578433d6423SLionel Sambuc  *				get_work				     *
579433d6423SLionel Sambuc  *===========================================================================*/
get_work(void)5805055c7eaSDavid van Moolenbroek static int get_work(void)
581433d6423SLionel Sambuc {
5825055c7eaSDavid van Moolenbroek   /* Normally wait for new input.  However, if 'reviving' is nonzero, a
5835055c7eaSDavid van Moolenbroek    * suspended process must be awakened.  Return TRUE if there is a message to
5845055c7eaSDavid van Moolenbroek    * process (usually newly received, but possibly a resumed request), or FALSE
5855055c7eaSDavid van Moolenbroek    * if a thread for other activities has been spawned instead.
586433d6423SLionel Sambuc    */
5875055c7eaSDavid van Moolenbroek   int r, proc_p;
588433d6423SLionel Sambuc   register struct fproc *rp;
589433d6423SLionel Sambuc 
5905055c7eaSDavid van Moolenbroek   if (reviving != 0) {
591433d6423SLionel Sambuc 	/* Find a suspended process. */
592433d6423SLionel Sambuc 	for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++)
5935055c7eaSDavid van Moolenbroek 		if (rp->fp_pid != PID_FREE && (rp->fp_flags & FP_REVIVED))
5945055c7eaSDavid van Moolenbroek 			return unblock(rp); /* So main loop can process job */
595433d6423SLionel Sambuc 
596433d6423SLionel Sambuc 	panic("VFS: get_work couldn't revive anyone");
597433d6423SLionel Sambuc   }
598433d6423SLionel Sambuc 
599433d6423SLionel Sambuc   for(;;) {
600433d6423SLionel Sambuc 	/* Normal case.  No one to revive. Get a useful request. */
6017eb698eaSDavid van Moolenbroek 	if ((r = sef_receive(ANY, &m_in)) != OK) {
602433d6423SLionel Sambuc 		panic("VFS: sef_receive error: %d", r);
603433d6423SLionel Sambuc 	}
604433d6423SLionel Sambuc 
605433d6423SLionel Sambuc 	proc_p = _ENDPOINT_P(m_in.m_source);
606433d6423SLionel Sambuc 	if (proc_p < 0 || proc_p >= NR_PROCS) fp = NULL;
607433d6423SLionel Sambuc 	else fp = &fproc[proc_p];
608433d6423SLionel Sambuc 
609433d6423SLionel Sambuc 	/* Negative who_p is never used to access the fproc array. Negative
610433d6423SLionel Sambuc 	 * numbers (kernel tasks) are treated in a special way.
611433d6423SLionel Sambuc 	 */
612433d6423SLionel Sambuc 	if (fp && fp->fp_endpoint == NONE) {
613433d6423SLionel Sambuc 		printf("VFS: ignoring request from %d: NONE endpoint %d (%d)\n",
614433d6423SLionel Sambuc 			m_in.m_source, who_p, m_in.m_type);
615433d6423SLionel Sambuc 		continue;
616433d6423SLionel Sambuc 	}
617433d6423SLionel Sambuc 
618433d6423SLionel Sambuc 	/* Internal consistency check; our mental image of process numbers and
619433d6423SLionel Sambuc 	 * endpoints must match with how the rest of the system thinks of them.
620433d6423SLionel Sambuc 	 */
621433d6423SLionel Sambuc 	if (fp && fp->fp_endpoint != who_e) {
622433d6423SLionel Sambuc 		if (fproc[who_p].fp_endpoint == NONE)
623433d6423SLionel Sambuc 			printf("slot unknown even\n");
624433d6423SLionel Sambuc 
625433d6423SLionel Sambuc 		panic("VFS: receive endpoint inconsistent (source %d, who_p "
626433d6423SLionel Sambuc 			"%d, stored ep %d, who_e %d).\n", m_in.m_source, who_p,
627433d6423SLionel Sambuc 			fproc[who_p].fp_endpoint, who_e);
628433d6423SLionel Sambuc 	}
629433d6423SLionel Sambuc 
6305055c7eaSDavid van Moolenbroek 	return TRUE;
631433d6423SLionel Sambuc   }
6325055c7eaSDavid van Moolenbroek   /* NOTREACHED */
633433d6423SLionel Sambuc }
634433d6423SLionel Sambuc 
635433d6423SLionel Sambuc /*===========================================================================*
636433d6423SLionel Sambuc  *				reply					     *
637433d6423SLionel Sambuc  *===========================================================================*/
reply(message * m_out,endpoint_t whom,int result)638*e3b8d4bbSDavid van Moolenbroek void reply(message *m_out, endpoint_t whom, int result)
639433d6423SLionel Sambuc {
640433d6423SLionel Sambuc /* Send a reply to a user process.  If the send fails, just ignore it. */
641433d6423SLionel Sambuc   int r;
642433d6423SLionel Sambuc 
643433d6423SLionel Sambuc   m_out->m_type = result;
644433d6423SLionel Sambuc   r = ipc_sendnb(whom, m_out);
645433d6423SLionel Sambuc   if (r != OK) {
646433d6423SLionel Sambuc 	printf("VFS: %d couldn't send reply %d to %d: %d\n", mthread_self(),
647433d6423SLionel Sambuc 		result, whom, r);
648433d6423SLionel Sambuc 	util_stacktrace();
649433d6423SLionel Sambuc   }
650433d6423SLionel Sambuc }
651433d6423SLionel Sambuc 
652433d6423SLionel Sambuc /*===========================================================================*
653433d6423SLionel Sambuc  *				replycode				     *
654433d6423SLionel Sambuc  *===========================================================================*/
replycode(endpoint_t whom,int result)655433d6423SLionel Sambuc void replycode(endpoint_t whom, int result)
656433d6423SLionel Sambuc {
657433d6423SLionel Sambuc /* Send a reply to a user process.  If the send fails, just ignore it. */
658433d6423SLionel Sambuc   message m_out;
659433d6423SLionel Sambuc 
660433d6423SLionel Sambuc   memset(&m_out, 0, sizeof(m_out));
661433d6423SLionel Sambuc 
662433d6423SLionel Sambuc   reply(&m_out, whom, result);
663433d6423SLionel Sambuc }
664433d6423SLionel Sambuc 
665433d6423SLionel Sambuc /*===========================================================================*
666433d6423SLionel Sambuc  *				service_pm_postponed			     *
667433d6423SLionel Sambuc  *===========================================================================*/
service_pm_postponed(void)668433d6423SLionel Sambuc void service_pm_postponed(void)
669433d6423SLionel Sambuc {
670433d6423SLionel Sambuc   int r, term_signal;
671433d6423SLionel Sambuc   vir_bytes core_path;
672433d6423SLionel Sambuc   vir_bytes exec_path, stack_frame, pc, newsp, ps_str;
673433d6423SLionel Sambuc   size_t exec_path_len, stack_frame_len;
674433d6423SLionel Sambuc   endpoint_t proc_e;
675433d6423SLionel Sambuc   message m_out;
676433d6423SLionel Sambuc 
677433d6423SLionel Sambuc   memset(&m_out, 0, sizeof(m_out));
678433d6423SLionel Sambuc 
679433d6423SLionel Sambuc   switch(job_call_nr) {
680433d6423SLionel Sambuc   case VFS_PM_EXEC:
681433d6423SLionel Sambuc 	proc_e = job_m_in.VFS_PM_ENDPT;
682433d6423SLionel Sambuc 	exec_path = (vir_bytes) job_m_in.VFS_PM_PATH;
683433d6423SLionel Sambuc 	exec_path_len = (size_t) job_m_in.VFS_PM_PATH_LEN;
684433d6423SLionel Sambuc 	stack_frame = (vir_bytes) job_m_in.VFS_PM_FRAME;
685433d6423SLionel Sambuc 	stack_frame_len = (size_t) job_m_in.VFS_PM_FRAME_LEN;
686433d6423SLionel Sambuc 	ps_str = (vir_bytes) job_m_in.VFS_PM_PS_STR;
687433d6423SLionel Sambuc 
688433d6423SLionel Sambuc 	assert(proc_e == fp->fp_endpoint);
689433d6423SLionel Sambuc 
690433d6423SLionel Sambuc 	r = pm_exec(exec_path, exec_path_len, stack_frame, stack_frame_len,
691433d6423SLionel Sambuc 		&pc, &newsp, &ps_str);
692433d6423SLionel Sambuc 
693433d6423SLionel Sambuc 	/* Reply status to PM */
694433d6423SLionel Sambuc 	m_out.m_type = VFS_PM_EXEC_REPLY;
695433d6423SLionel Sambuc 	m_out.VFS_PM_ENDPT = proc_e;
696433d6423SLionel Sambuc 	m_out.VFS_PM_PC = (void *) pc;
697433d6423SLionel Sambuc 	m_out.VFS_PM_STATUS = r;
698433d6423SLionel Sambuc 	m_out.VFS_PM_NEWSP = (void *) newsp;
699433d6423SLionel Sambuc 	m_out.VFS_PM_NEWPS_STR = ps_str;
700433d6423SLionel Sambuc 
701433d6423SLionel Sambuc 	break;
702433d6423SLionel Sambuc 
703433d6423SLionel Sambuc   case VFS_PM_EXIT:
704433d6423SLionel Sambuc 	proc_e = job_m_in.VFS_PM_ENDPT;
705433d6423SLionel Sambuc 
706433d6423SLionel Sambuc 	assert(proc_e == fp->fp_endpoint);
707433d6423SLionel Sambuc 
708433d6423SLionel Sambuc 	pm_exit();
709433d6423SLionel Sambuc 
710433d6423SLionel Sambuc 	/* Reply dummy status to PM for synchronization */
711433d6423SLionel Sambuc 	m_out.m_type = VFS_PM_EXIT_REPLY;
712433d6423SLionel Sambuc 	m_out.VFS_PM_ENDPT = proc_e;
713433d6423SLionel Sambuc 
714433d6423SLionel Sambuc 	break;
715433d6423SLionel Sambuc 
716433d6423SLionel Sambuc   case VFS_PM_DUMPCORE:
717433d6423SLionel Sambuc 	proc_e = job_m_in.VFS_PM_ENDPT;
718433d6423SLionel Sambuc 	term_signal = job_m_in.VFS_PM_TERM_SIG;
719433d6423SLionel Sambuc 	core_path = (vir_bytes) job_m_in.VFS_PM_PATH;
720433d6423SLionel Sambuc 
7219f15e7b3SDavid van Moolenbroek 	/* A zero signal used to indicate that a coredump should be generated
7229f15e7b3SDavid van Moolenbroek 	 * without terminating the target process, but this was broken in so
7239f15e7b3SDavid van Moolenbroek 	 * many ways that we no longer support this. Userland should implement
7249f15e7b3SDavid van Moolenbroek 	 * this functionality itself, for example through ptrace(2).
7259f15e7b3SDavid van Moolenbroek 	 */
7269f15e7b3SDavid van Moolenbroek 	if (term_signal == 0)
7279f15e7b3SDavid van Moolenbroek 		panic("no termination signal given for coredump!");
7289f15e7b3SDavid van Moolenbroek 
729433d6423SLionel Sambuc 	assert(proc_e == fp->fp_endpoint);
730433d6423SLionel Sambuc 
731433d6423SLionel Sambuc 	r = pm_dumpcore(term_signal, core_path);
732433d6423SLionel Sambuc 
733433d6423SLionel Sambuc 	/* Reply status to PM */
734433d6423SLionel Sambuc 	m_out.m_type = VFS_PM_CORE_REPLY;
735433d6423SLionel Sambuc 	m_out.VFS_PM_ENDPT = proc_e;
736433d6423SLionel Sambuc 	m_out.VFS_PM_STATUS = r;
737433d6423SLionel Sambuc 
738433d6423SLionel Sambuc 	break;
739433d6423SLionel Sambuc 
740433d6423SLionel Sambuc   case VFS_PM_UNPAUSE:
741433d6423SLionel Sambuc 	proc_e = job_m_in.VFS_PM_ENDPT;
742433d6423SLionel Sambuc 
743433d6423SLionel Sambuc 	assert(proc_e == fp->fp_endpoint);
744433d6423SLionel Sambuc 
745433d6423SLionel Sambuc 	unpause();
746433d6423SLionel Sambuc 
747433d6423SLionel Sambuc 	m_out.m_type = VFS_PM_UNPAUSE_REPLY;
748433d6423SLionel Sambuc 	m_out.VFS_PM_ENDPT = proc_e;
749433d6423SLionel Sambuc 
750433d6423SLionel Sambuc 	break;
751433d6423SLionel Sambuc 
752433d6423SLionel Sambuc   default:
753433d6423SLionel Sambuc 	panic("Unhandled postponed PM call %d", job_m_in.m_type);
754433d6423SLionel Sambuc   }
755433d6423SLionel Sambuc 
756433d6423SLionel Sambuc   r = ipc_send(PM_PROC_NR, &m_out);
757433d6423SLionel Sambuc   if (r != OK)
758433d6423SLionel Sambuc 	panic("service_pm_postponed: ipc_send failed: %d", r);
759433d6423SLionel Sambuc }
760433d6423SLionel Sambuc 
761433d6423SLionel Sambuc /*===========================================================================*
762433d6423SLionel Sambuc  *				service_pm				     *
763433d6423SLionel Sambuc  *===========================================================================*/
service_pm(void)764433d6423SLionel Sambuc static void service_pm(void)
765433d6423SLionel Sambuc {
766433d6423SLionel Sambuc /* Process a request from PM. This function is called from the main thread, and
767433d6423SLionel Sambuc  * may therefore not block. Any requests that may require blocking the calling
768433d6423SLionel Sambuc  * thread must be executed in a separate thread. Aside from VFS_PM_REBOOT, all
769433d6423SLionel Sambuc  * requests from PM involve another, target process: for example, PM tells VFS
770433d6423SLionel Sambuc  * that a process is performing a setuid() call. For some requests however,
771433d6423SLionel Sambuc  * that other process may not be idle, and in that case VFS must serialize the
772433d6423SLionel Sambuc  * PM request handling with any operation is it handling for that target
773433d6423SLionel Sambuc  * process. As it happens, the requests that may require blocking are also the
774433d6423SLionel Sambuc  * ones where the target process may not be idle. For both these reasons, such
775433d6423SLionel Sambuc  * requests are run in worker threads associated to the target process.
776433d6423SLionel Sambuc  */
777433d6423SLionel Sambuc   struct fproc *rfp;
778433d6423SLionel Sambuc   int r, slot;
779433d6423SLionel Sambuc   message m_out;
780433d6423SLionel Sambuc 
781433d6423SLionel Sambuc   memset(&m_out, 0, sizeof(m_out));
782433d6423SLionel Sambuc 
783433d6423SLionel Sambuc   switch (call_nr) {
784433d6423SLionel Sambuc   case VFS_PM_SETUID:
785433d6423SLionel Sambuc 	{
786433d6423SLionel Sambuc 		endpoint_t proc_e;
787433d6423SLionel Sambuc 		uid_t euid, ruid;
788433d6423SLionel Sambuc 
789433d6423SLionel Sambuc 		proc_e = m_in.VFS_PM_ENDPT;
790433d6423SLionel Sambuc 		euid = m_in.VFS_PM_EID;
791433d6423SLionel Sambuc 		ruid = m_in.VFS_PM_RID;
792433d6423SLionel Sambuc 
793433d6423SLionel Sambuc 		pm_setuid(proc_e, euid, ruid);
794433d6423SLionel Sambuc 
795433d6423SLionel Sambuc 		m_out.m_type = VFS_PM_SETUID_REPLY;
796433d6423SLionel Sambuc 		m_out.VFS_PM_ENDPT = proc_e;
797433d6423SLionel Sambuc 	}
798433d6423SLionel Sambuc 	break;
799433d6423SLionel Sambuc 
800433d6423SLionel Sambuc   case VFS_PM_SETGID:
801433d6423SLionel Sambuc 	{
802433d6423SLionel Sambuc 		endpoint_t proc_e;
803433d6423SLionel Sambuc 		gid_t egid, rgid;
804433d6423SLionel Sambuc 
805433d6423SLionel Sambuc 		proc_e = m_in.VFS_PM_ENDPT;
806433d6423SLionel Sambuc 		egid = m_in.VFS_PM_EID;
807433d6423SLionel Sambuc 		rgid = m_in.VFS_PM_RID;
808433d6423SLionel Sambuc 
809433d6423SLionel Sambuc 		pm_setgid(proc_e, egid, rgid);
810433d6423SLionel Sambuc 
811433d6423SLionel Sambuc 		m_out.m_type = VFS_PM_SETGID_REPLY;
812433d6423SLionel Sambuc 		m_out.VFS_PM_ENDPT = proc_e;
813433d6423SLionel Sambuc 	}
814433d6423SLionel Sambuc 	break;
815433d6423SLionel Sambuc 
816433d6423SLionel Sambuc   case VFS_PM_SETSID:
817433d6423SLionel Sambuc 	{
818433d6423SLionel Sambuc 		endpoint_t proc_e;
819433d6423SLionel Sambuc 
820433d6423SLionel Sambuc 		proc_e = m_in.VFS_PM_ENDPT;
821433d6423SLionel Sambuc 		pm_setsid(proc_e);
822433d6423SLionel Sambuc 
823433d6423SLionel Sambuc 		m_out.m_type = VFS_PM_SETSID_REPLY;
824433d6423SLionel Sambuc 		m_out.VFS_PM_ENDPT = proc_e;
825433d6423SLionel Sambuc 	}
826433d6423SLionel Sambuc 	break;
827433d6423SLionel Sambuc 
828433d6423SLionel Sambuc   case VFS_PM_EXEC:
829433d6423SLionel Sambuc   case VFS_PM_EXIT:
830433d6423SLionel Sambuc   case VFS_PM_DUMPCORE:
831433d6423SLionel Sambuc   case VFS_PM_UNPAUSE:
832433d6423SLionel Sambuc 	{
833433d6423SLionel Sambuc 		endpoint_t proc_e = m_in.VFS_PM_ENDPT;
834433d6423SLionel Sambuc 
835433d6423SLionel Sambuc 		if(isokendpt(proc_e, &slot) != OK) {
836433d6423SLionel Sambuc 			printf("VFS: proc ep %d not ok\n", proc_e);
837433d6423SLionel Sambuc 			return;
838433d6423SLionel Sambuc 		}
839433d6423SLionel Sambuc 
840433d6423SLionel Sambuc 		rfp = &fproc[slot];
841433d6423SLionel Sambuc 
842433d6423SLionel Sambuc 		/* PM requests on behalf of a proc are handled after the
843433d6423SLionel Sambuc 		 * system call that might be in progress for that proc has
844433d6423SLionel Sambuc 		 * finished. If the proc is not busy, we start a new thread.
845433d6423SLionel Sambuc 		 */
846433d6423SLionel Sambuc 		worker_start(rfp, NULL, &m_in, FALSE /*use_spare*/);
847433d6423SLionel Sambuc 
848433d6423SLionel Sambuc 		return;
849433d6423SLionel Sambuc 	}
850433d6423SLionel Sambuc   case VFS_PM_FORK:
851433d6423SLionel Sambuc   case VFS_PM_SRV_FORK:
852433d6423SLionel Sambuc 	{
853433d6423SLionel Sambuc 		endpoint_t pproc_e, proc_e;
854433d6423SLionel Sambuc 		pid_t child_pid;
855433d6423SLionel Sambuc 		uid_t reuid;
856433d6423SLionel Sambuc 		gid_t regid;
857433d6423SLionel Sambuc 
858433d6423SLionel Sambuc 		pproc_e = m_in.VFS_PM_PENDPT;
859433d6423SLionel Sambuc 		proc_e = m_in.VFS_PM_ENDPT;
860433d6423SLionel Sambuc 		child_pid = m_in.VFS_PM_CPID;
861433d6423SLionel Sambuc 		reuid = m_in.VFS_PM_REUID;
862433d6423SLionel Sambuc 		regid = m_in.VFS_PM_REGID;
863433d6423SLionel Sambuc 
864433d6423SLionel Sambuc 		pm_fork(pproc_e, proc_e, child_pid);
865433d6423SLionel Sambuc 		m_out.m_type = VFS_PM_FORK_REPLY;
866433d6423SLionel Sambuc 
867433d6423SLionel Sambuc 		if (call_nr == VFS_PM_SRV_FORK) {
868433d6423SLionel Sambuc 			m_out.m_type = VFS_PM_SRV_FORK_REPLY;
869433d6423SLionel Sambuc 			pm_setuid(proc_e, reuid, reuid);
870433d6423SLionel Sambuc 			pm_setgid(proc_e, regid, regid);
871433d6423SLionel Sambuc 		}
872433d6423SLionel Sambuc 
873433d6423SLionel Sambuc 		m_out.VFS_PM_ENDPT = proc_e;
874433d6423SLionel Sambuc 	}
875433d6423SLionel Sambuc 	break;
876433d6423SLionel Sambuc   case VFS_PM_SETGROUPS:
877433d6423SLionel Sambuc 	{
878433d6423SLionel Sambuc 		endpoint_t proc_e;
879433d6423SLionel Sambuc 		int group_no;
880433d6423SLionel Sambuc 		gid_t *group_addr;
881433d6423SLionel Sambuc 
882433d6423SLionel Sambuc 		proc_e = m_in.VFS_PM_ENDPT;
883433d6423SLionel Sambuc 		group_no = m_in.VFS_PM_GROUP_NO;
884433d6423SLionel Sambuc 		group_addr = (gid_t *) m_in.VFS_PM_GROUP_ADDR;
885433d6423SLionel Sambuc 
886433d6423SLionel Sambuc 		pm_setgroups(proc_e, group_no, group_addr);
887433d6423SLionel Sambuc 
888433d6423SLionel Sambuc 		m_out.m_type = VFS_PM_SETGROUPS_REPLY;
889433d6423SLionel Sambuc 		m_out.VFS_PM_ENDPT = proc_e;
890433d6423SLionel Sambuc 	}
891433d6423SLionel Sambuc 	break;
892433d6423SLionel Sambuc 
893433d6423SLionel Sambuc   case VFS_PM_REBOOT:
894433d6423SLionel Sambuc 	/* Reboot requests are not considered postponed PM work and are instead
895433d6423SLionel Sambuc 	 * handled from a separate worker thread that is associated with PM's
896433d6423SLionel Sambuc 	 * process. PM makes no regular VFS calls, and thus, from VFS's
897433d6423SLionel Sambuc 	 * perspective, PM is always idle. Therefore, we can safely do this.
898433d6423SLionel Sambuc 	 * We do assume that PM sends us only one VFS_PM_REBOOT message at
899433d6423SLionel Sambuc 	 * once, or ever for that matter. :)
900433d6423SLionel Sambuc 	 */
901433d6423SLionel Sambuc 	worker_start(fproc_addr(PM_PROC_NR), pm_reboot, &m_in,
902433d6423SLionel Sambuc 		FALSE /*use_spare*/);
903433d6423SLionel Sambuc 
904433d6423SLionel Sambuc 	return;
905433d6423SLionel Sambuc 
906433d6423SLionel Sambuc     default:
907433d6423SLionel Sambuc 	printf("VFS: don't know how to handle PM request %d\n", call_nr);
908433d6423SLionel Sambuc 
909433d6423SLionel Sambuc 	return;
910433d6423SLionel Sambuc   }
911433d6423SLionel Sambuc 
912433d6423SLionel Sambuc   r = ipc_send(PM_PROC_NR, &m_out);
913433d6423SLionel Sambuc   if (r != OK)
914433d6423SLionel Sambuc 	panic("service_pm: ipc_send failed: %d", r);
915433d6423SLionel Sambuc }
916433d6423SLionel Sambuc 
917433d6423SLionel Sambuc 
918433d6423SLionel Sambuc /*===========================================================================*
919433d6423SLionel Sambuc  *				unblock					     *
920433d6423SLionel Sambuc  *===========================================================================*/
921a0814afbSRichard Sailer static int
unblock(struct fproc * rfp)922a0814afbSRichard Sailer unblock(struct fproc *rfp)
923433d6423SLionel Sambuc {
924433d6423SLionel Sambuc /* Unblock a process that was previously blocked on a pipe or a lock.  This is
925433d6423SLionel Sambuc  * done by reconstructing the original request and continuing/repeating it.
926433d6423SLionel Sambuc  * This function returns TRUE when it has restored a request for execution, and
927433d6423SLionel Sambuc  * FALSE if the caller should continue looking for work to do.
928433d6423SLionel Sambuc  */
929433d6423SLionel Sambuc   int blocked_on;
930433d6423SLionel Sambuc 
931433d6423SLionel Sambuc   blocked_on = rfp->fp_blocked_on;
932433d6423SLionel Sambuc 
933433d6423SLionel Sambuc   /* Reconstruct the original request from the saved data. */
934433d6423SLionel Sambuc   memset(&m_in, 0, sizeof(m_in));
935433d6423SLionel Sambuc   m_in.m_source = rfp->fp_endpoint;
936232819ddSDavid van Moolenbroek   switch (blocked_on) {
937232819ddSDavid van Moolenbroek   case FP_BLOCKED_ON_PIPE:
938232819ddSDavid van Moolenbroek 	assert(rfp->fp_pipe.callnr == VFS_READ ||
939232819ddSDavid van Moolenbroek 	    rfp->fp_pipe.callnr == VFS_WRITE);
940232819ddSDavid van Moolenbroek 	m_in.m_type = rfp->fp_pipe.callnr;
941232819ddSDavid van Moolenbroek 	m_in.m_lc_vfs_readwrite.fd = rfp->fp_pipe.fd;
942232819ddSDavid van Moolenbroek 	m_in.m_lc_vfs_readwrite.buf = rfp->fp_pipe.buf;
943232819ddSDavid van Moolenbroek 	m_in.m_lc_vfs_readwrite.len = rfp->fp_pipe.nbytes;
944232819ddSDavid van Moolenbroek 	m_in.m_lc_vfs_readwrite.cum_io = rfp->fp_pipe.cum_io;
945433d6423SLionel Sambuc 	break;
946232819ddSDavid van Moolenbroek   case FP_BLOCKED_ON_FLOCK:
947232819ddSDavid van Moolenbroek 	assert(rfp->fp_flock.cmd == F_SETLKW);
948232819ddSDavid van Moolenbroek 	m_in.m_type = VFS_FCNTL;
949232819ddSDavid van Moolenbroek 	m_in.m_lc_vfs_fcntl.fd = rfp->fp_flock.fd;
950232819ddSDavid van Moolenbroek 	m_in.m_lc_vfs_fcntl.cmd = rfp->fp_flock.cmd;
951232819ddSDavid van Moolenbroek 	m_in.m_lc_vfs_fcntl.arg_ptr = rfp->fp_flock.arg;
952433d6423SLionel Sambuc 	break;
953433d6423SLionel Sambuc   default:
954232819ddSDavid van Moolenbroek 	panic("unblocking call blocked on %d ??", blocked_on);
955433d6423SLionel Sambuc   }
956433d6423SLionel Sambuc 
957433d6423SLionel Sambuc   rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;	/* no longer blocked */
958433d6423SLionel Sambuc   rfp->fp_flags &= ~FP_REVIVED;
959433d6423SLionel Sambuc   reviving--;
960433d6423SLionel Sambuc   assert(reviving >= 0);
961433d6423SLionel Sambuc 
962433d6423SLionel Sambuc   /* Pending pipe reads/writes cannot be repeated as is, and thus require a
963433d6423SLionel Sambuc    * special resumption procedure.
964433d6423SLionel Sambuc    */
965433d6423SLionel Sambuc   if (blocked_on == FP_BLOCKED_ON_PIPE) {
966433d6423SLionel Sambuc 	worker_start(rfp, do_pending_pipe, &m_in, FALSE /*use_spare*/);
967433d6423SLionel Sambuc 	return(FALSE);	/* Retrieve more work */
968433d6423SLionel Sambuc   }
969433d6423SLionel Sambuc 
970433d6423SLionel Sambuc   /* A lock request. Repeat the original request as though it just came in. */
971433d6423SLionel Sambuc   fp = rfp;
972433d6423SLionel Sambuc   return(TRUE);	/* We've unblocked a process */
973433d6423SLionel Sambuc }
974