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