tar: use utime() to restore timestamps
[minix.git] / servers / vfs / main.c
blob1ba96cfbaddf72377cffe1abd0078a04ae2de555
1 /*
2 * a loop that gets messages requesting work, carries out the work, and sends
3 * replies.
5 * The entry points into this file are:
6 * main: main program of the Virtual File System
7 * reply: send a reply to a process after the requested work is done
9 */
11 #include "fs.h"
12 #include <fcntl.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <signal.h>
16 #include <assert.h>
17 #include <stdlib.h>
18 #include <sys/ioc_memory.h>
19 #include <sys/svrctl.h>
20 #include <sys/select.h>
21 #include <minix/callnr.h>
22 #include <minix/com.h>
23 #include <minix/keymap.h>
24 #include <minix/const.h>
25 #include <minix/endpoint.h>
26 #include <minix/safecopies.h>
27 #include <minix/debug.h>
28 #include <minix/vfsif.h>
29 #include "file.h"
30 #include "dmap.h"
31 #include "fproc.h"
32 #include "scratchpad.h"
33 #include "vmnt.h"
34 #include "vnode.h"
35 #include "job.h"
36 #include "param.h"
38 #if ENABLE_SYSCALL_STATS
39 EXTERN unsigned long calls_stats[NCALLS];
40 #endif
42 /* Thread related prototypes */
43 static void *do_async_dev_result(void *arg);
44 static void *do_control_msgs(void *arg);
45 static void *do_dev_event(void *arg);
46 static void *do_fs_reply(struct job *job);
47 static void *do_work(void *arg);
48 static void *do_pm(void *arg);
49 static void *do_init_root(void *arg);
50 static void handle_work(void *(*func)(void *arg));
52 static void get_work(void);
53 static void lock_pm(void);
54 static void unlock_pm(void);
55 static void service_pm(void);
56 static void service_pm_postponed(void);
57 static int unblock(struct fproc *rfp);
59 /* SEF functions and variables. */
60 static void sef_local_startup(void);
61 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
62 static mutex_t pm_lock;
63 static endpoint_t receive_from;
65 /*===========================================================================*
66 * main *
67 *===========================================================================*/
68 int main(void)
70 /* This is the main program of the file system. The main loop consists of
71 * three major activities: getting new work, processing the work, and sending
72 * the reply. This loop never terminates as long as the file system runs.
74 int transid;
75 struct job *job;
77 /* SEF local startup. */
78 sef_local_startup();
80 printf("Started VFS: %d worker thread(s)\n", NR_WTHREADS);
82 if (OK != (sys_getkinfo(&kinfo)))
83 panic("couldn't get kernel kinfo");
85 /* This is the main loop that gets work, processes it, and sends replies. */
86 while (TRUE) {
87 yield_all(); /* let other threads run */
88 self = NULL;
89 job = NULL;
90 send_work();
91 get_work();
93 transid = TRNS_GET_ID(m_in.m_type);
94 if (IS_VFS_FS_TRANSID(transid)) {
95 job = worker_getjob( (thread_t) transid - VFS_TRANSID);
96 if (job == NULL) {
97 printf("VFS: spurious message %d from endpoint %d\n",
98 m_in.m_type, m_in.m_source);
99 continue;
101 m_in.m_type = TRNS_DEL_ID(m_in.m_type);
104 if (job != NULL) {
105 do_fs_reply(job);
106 continue;
107 } else if (who_e == PM_PROC_NR) { /* Calls from PM */
108 /* Special control messages from PM */
109 sys_worker_start(do_pm);
110 continue;
111 } else if (is_notify(call_nr)) {
112 /* A task notify()ed us */
113 if (who_e == DS_PROC_NR)
114 handle_work(ds_event);
115 else if (who_e == KERNEL)
116 mthread_stacktraces();
117 else if (fp != NULL && (fp->fp_flags & FP_SRV_PROC))
118 handle_work(do_dev_event);
119 else
120 sys_worker_start(do_control_msgs);
121 continue;
122 } else if (who_p < 0) { /* i.e., message comes from a task */
123 /* We're going to ignore this message. Tasks should
124 * send notify()s only.
126 printf("VFS: ignoring message from %d (%d)\n", who_e, call_nr);
127 continue;
130 /* At this point we either have results from an asynchronous device
131 * or a new system call. In both cases a new worker thread has to be
132 * started and there might not be one available from the pool. This is
133 * not a problem (requests/replies are simply queued), except when
134 * they're from an FS endpoint, because these can cause a deadlock.
135 * handle_work() takes care of the details. */
136 if (IS_DRV_REPLY(call_nr)) {
137 /* We've got results for a device request */
139 struct dmap *dp;
141 dp = get_dmap(who_e);
142 if (dp != NULL) {
143 if (dev_style_asyn(dp->dmap_style)) {
144 handle_work(do_async_dev_result);
146 } else {
147 if (dp->dmap_servicing == NONE) {
148 printf("Got spurious dev reply from %d",
149 who_e);
150 } else {
151 dev_reply(dp);
154 continue;
156 printf("VFS: ignoring dev reply from unknown driver %d\n",
157 who_e);
158 } else {
159 /* Normal syscall. */
160 handle_work(do_work);
163 return(OK); /* shouldn't come here */
166 /*===========================================================================*
167 * handle_work *
168 *===========================================================================*/
169 static void handle_work(void *(*func)(void *arg))
171 /* Handle asynchronous device replies and new system calls. If the originating
172 * endpoint is an FS endpoint, take extra care not to get in deadlock. */
173 struct vmnt *vmp = NULL;
174 endpoint_t proc_e;
176 proc_e = m_in.m_source;
178 if (fp->fp_flags & FP_SRV_PROC) {
179 vmp = find_vmnt(proc_e);
180 if (vmp != NULL) {
181 /* A call back or dev result from an FS
182 * endpoint. Set call back flag. Can do only
183 * one call back at a time.
185 if (vmp->m_flags & VMNT_CALLBACK) {
186 reply(proc_e, EAGAIN);
187 return;
189 vmp->m_flags |= VMNT_CALLBACK;
190 if (vmp->m_flags & VMNT_MOUNTING) {
191 vmp->m_flags |= VMNT_FORCEROOTBSF;
195 if (worker_available() == 0) {
196 if (!deadlock_resolving) {
197 deadlock_resolving = 1;
198 dl_worker_start(func);
199 return;
202 if (vmp != NULL) {
203 /* Already trying to resolve a deadlock, can't
204 * handle more, sorry */
206 reply(proc_e, EAGAIN);
207 return;
212 worker_start(func);
215 /*===========================================================================*
216 * do_async_dev_result *
217 *===========================================================================*/
218 static void *do_async_dev_result(void *arg)
220 endpoint_t endpt;
221 struct job my_job;
223 my_job = *((struct job *) arg);
224 fp = my_job.j_fp;
226 /* An asynchronous character driver has results for us */
227 if (job_call_nr == DEV_REVIVE) {
228 endpt = job_m_in.REP_ENDPT;
229 if (endpt == VFS_PROC_NR)
230 endpt = find_suspended_ep(job_m_in.m_source,
231 job_m_in.REP_IO_GRANT);
233 if (endpt == NONE) {
234 printf("VFS: proc with grant %d from %d not found\n",
235 job_m_in.REP_IO_GRANT, job_m_in.m_source);
236 } else if (job_m_in.REP_STATUS == SUSPEND) {
237 printf("VFS: got SUSPEND on DEV_REVIVE: not reviving proc\n");
238 } else
239 revive(endpt, job_m_in.REP_STATUS);
241 else if (job_call_nr == DEV_OPEN_REPL) open_reply();
242 else if (job_call_nr == DEV_REOPEN_REPL) reopen_reply();
243 else if (job_call_nr == DEV_CLOSE_REPL) close_reply();
244 else if (job_call_nr == DEV_SEL_REPL1)
245 select_reply1(job_m_in.m_source, job_m_in.DEV_MINOR,
246 job_m_in.DEV_SEL_OPS);
247 else if (job_call_nr == DEV_SEL_REPL2)
248 select_reply2(job_m_in.m_source, job_m_in.DEV_MINOR,
249 job_m_in.DEV_SEL_OPS);
251 thread_cleanup(fp);
252 return(NULL);
255 /*===========================================================================*
256 * do_control_msgs *
257 *===========================================================================*/
258 static void *do_control_msgs(void *arg)
260 struct job my_job;
262 my_job = *((struct job *) arg);
263 fp = my_job.j_fp;
265 /* Check for special control messages. */
266 if (job_m_in.m_source == CLOCK) {
267 /* Alarm timer expired. Used only for select(). Check it. */
268 expire_timers(job_m_in.NOTIFY_TIMESTAMP);
271 thread_cleanup(NULL);
272 return(NULL);
275 /*===========================================================================*
276 * do_dev_event *
277 *===========================================================================*/
278 static void *do_dev_event(void *arg)
280 /* Device notifies us of an event. */
281 struct job my_job;
283 my_job = *((struct job *) arg);
284 fp = my_job.j_fp;
286 dev_status(job_m_in.m_source);
288 thread_cleanup(fp);
289 return(NULL);
292 /*===========================================================================*
293 * do_fs_reply *
294 *===========================================================================*/
295 static void *do_fs_reply(struct job *job)
297 struct vmnt *vmp;
298 struct worker_thread *wp;
300 if ((vmp = find_vmnt(who_e)) == NULL)
301 panic("Couldn't find vmnt for endpoint %d", who_e);
303 wp = worker_get(job->j_fp->fp_wtid);
305 if (wp == NULL) {
306 printf("VFS: spurious reply from %d\n", who_e);
307 return(NULL);
310 if (wp->w_task != who_e) {
311 printf("VFS: expected %d to reply, not %d\n", wp->w_task, who_e);
312 return(NULL);
314 *wp->w_fs_sendrec = m_in;
315 wp->w_task = NONE;
316 vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */
317 worker_signal(wp); /* Continue this thread */
318 return(NULL);
321 /*===========================================================================*
322 * lock_pm *
323 *===========================================================================*/
324 static void lock_pm(void)
326 struct fproc *org_fp;
327 struct worker_thread *org_self;
329 /* First try to get it right off the bat */
330 if (mutex_trylock(&pm_lock) == 0)
331 return;
333 org_fp = fp;
334 org_self = self;
336 if (mutex_lock(&pm_lock) != 0)
337 panic("Could not obtain lock on pm\n");
339 fp = org_fp;
340 self = org_self;
343 /*===========================================================================*
344 * unlock_pm *
345 *===========================================================================*/
346 static void unlock_pm(void)
348 if (mutex_unlock(&pm_lock) != 0)
349 panic("Could not release lock on pm");
352 /*===========================================================================*
353 * do_pm *
354 *===========================================================================*/
355 static void *do_pm(void *arg __unused)
357 lock_pm();
358 service_pm();
359 unlock_pm();
361 thread_cleanup(NULL);
362 return(NULL);
365 /*===========================================================================*
366 * do_pending_pipe *
367 *===========================================================================*/
368 static void *do_pending_pipe(void *arg)
370 int r, op;
371 struct job my_job;
372 struct filp *f;
373 tll_access_t locktype;
375 my_job = *((struct job *) arg);
376 fp = my_job.j_fp;
378 lock_proc(fp, 1 /* force lock */);
380 f = scratch(fp).file.filp;
381 assert(f != NULL);
382 scratch(fp).file.filp = NULL;
384 locktype = (job_call_nr == READ) ? VNODE_READ : VNODE_WRITE;
385 op = (job_call_nr == READ) ? READING : WRITING;
386 lock_filp(f, locktype);
388 r = rw_pipe(op, who_e, f, scratch(fp).io.io_buffer, scratch(fp).io.io_nbytes);
390 if (r != SUSPEND) /* Do we have results to report? */
391 reply(fp->fp_endpoint, r);
393 unlock_filp(f);
394 thread_cleanup(fp);
395 unlock_proc(fp);
396 return(NULL);
399 /*===========================================================================*
400 * do_dummy *
401 *===========================================================================*/
402 void *do_dummy(void *arg)
404 struct job my_job;
405 int r;
407 my_job = *((struct job *) arg);
408 fp = my_job.j_fp;
410 if ((r = mutex_trylock(&fp->fp_lock)) == 0) {
411 thread_cleanup(fp);
412 unlock_proc(fp);
413 } else {
414 /* Proc is busy, let that worker thread carry out the work */
415 thread_cleanup(NULL);
417 return(NULL);
420 /*===========================================================================*
421 * do_work *
422 *===========================================================================*/
423 static void *do_work(void *arg)
425 int error;
426 struct job my_job;
428 my_job = *((struct job *) arg);
429 fp = my_job.j_fp;
431 lock_proc(fp, 0); /* This proc is busy */
433 if (job_call_nr == MAPDRIVER) {
434 error = do_mapdriver();
435 } else if (job_call_nr == COMMON_GETSYSINFO) {
436 error = do_getsysinfo();
437 } else if (IS_PFS_VFS_RQ(job_call_nr)) {
438 if (who_e != PFS_PROC_NR) {
439 printf("VFS: only PFS is allowed to make nested VFS calls\n");
440 error = ENOSYS;
441 } else if (job_call_nr <= PFS_BASE ||
442 job_call_nr >= PFS_BASE + PFS_NREQS) {
443 error = ENOSYS;
444 } else {
445 job_call_nr -= PFS_BASE;
446 error = (*pfs_call_vec[job_call_nr])();
448 } else {
449 /* We're dealing with a POSIX system call from a normal
450 * process. Call the internal function that does the work.
452 if (job_call_nr < 0 || job_call_nr >= NCALLS) {
453 error = ENOSYS;
454 } else if (fp->fp_pid == PID_FREE) {
455 /* Process vanished before we were able to handle request.
456 * Replying has no use. Just drop it. */
457 error = SUSPEND;
458 } else {
459 #if ENABLE_SYSCALL_STATS
460 calls_stats[job_call_nr]++;
461 #endif
462 error = (*call_vec[job_call_nr])();
466 /* Copy the results back to the user and send reply. */
467 if (error != SUSPEND) reply(fp->fp_endpoint, error);
469 thread_cleanup(fp);
470 unlock_proc(fp);
471 return(NULL);
474 /*===========================================================================*
475 * sef_local_startup *
476 *===========================================================================*/
477 static void sef_local_startup()
479 /* Register init callbacks. */
480 sef_setcb_init_fresh(sef_cb_init_fresh);
481 sef_setcb_init_restart(sef_cb_init_fail);
483 /* No live update support for now. */
485 /* Let SEF perform startup. */
486 sef_startup();
489 /*===========================================================================*
490 * sef_cb_init_fresh *
491 *===========================================================================*/
492 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
494 /* Initialize the virtual file server. */
495 int s, i;
496 struct fproc *rfp;
497 message mess;
498 struct rprocpub rprocpub[NR_BOOT_PROCS];
500 force_sync = 0;
501 receive_from = ANY;
502 self = NULL;
503 verbose = 0;
505 /* Initialize proc endpoints to NONE */
506 for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
507 rfp->fp_endpoint = NONE;
508 rfp->fp_pid = PID_FREE;
511 /* Initialize the process table with help of the process manager messages.
512 * Expect one message for each system process with its slot number and pid.
513 * When no more processes follow, the magic process number NONE is sent.
514 * Then, stop and synchronize with the PM.
516 do {
517 if ((s = sef_receive(PM_PROC_NR, &mess)) != OK)
518 panic("VFS: couldn't receive from PM: %d", s);
520 if (mess.m_type != PM_INIT)
521 panic("unexpected message from PM: %d", mess.m_type);
523 if (NONE == mess.PM_PROC) break;
525 rfp = &fproc[mess.PM_SLOT];
526 rfp->fp_flags = FP_NOFLAGS;
527 rfp->fp_pid = mess.PM_PID;
528 rfp->fp_endpoint = mess.PM_PROC;
529 rfp->fp_grant = GRANT_INVALID;
530 rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
531 rfp->fp_realuid = (uid_t) SYS_UID;
532 rfp->fp_effuid = (uid_t) SYS_UID;
533 rfp->fp_realgid = (gid_t) SYS_GID;
534 rfp->fp_effgid = (gid_t) SYS_GID;
535 rfp->fp_umask = ~0;
536 } while (TRUE); /* continue until process NONE */
537 mess.m_type = OK; /* tell PM that we succeeded */
538 s = send(PM_PROC_NR, &mess); /* send synchronization message */
540 /* All process table entries have been set. Continue with initialization. */
541 fp = &fproc[_ENDPOINT_P(VFS_PROC_NR)];/* During init all communication with
542 * FSes is on behalf of myself */
543 init_dmap(); /* Initialize device table. */
544 system_hz = sys_hz();
546 /* Map all the services in the boot image. */
547 if ((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
548 (vir_bytes) rprocpub, sizeof(rprocpub))) != OK){
549 panic("sys_safecopyfrom failed: %d", s);
551 for (i = 0; i < NR_BOOT_PROCS; i++) {
552 if (rprocpub[i].in_use) {
553 if ((s = map_service(&rprocpub[i])) != OK) {
554 panic("VFS: unable to map service: %d", s);
559 /* Subscribe to block and character driver events. */
560 s = ds_subscribe("drv\\.[bc]..\\..*", DSF_INITIAL | DSF_OVERWRITE);
561 if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s);
563 /* Initialize worker threads */
564 for (i = 0; i < NR_WTHREADS; i++) {
565 worker_init(&workers[i]);
567 worker_init(&sys_worker); /* exclusive system worker thread */
568 worker_init(&dl_worker); /* exclusive worker thread to resolve deadlocks */
570 /* Initialize global locks */
571 if (mthread_mutex_init(&pm_lock, NULL) != 0)
572 panic("VFS: couldn't initialize pm lock mutex");
573 if (mthread_mutex_init(&exec_lock, NULL) != 0)
574 panic("VFS: couldn't initialize exec lock");
575 if (mthread_mutex_init(&bsf_lock, NULL) != 0)
576 panic("VFS: couldn't initialize block special file lock");
578 /* Initialize event resources for boot procs and locks for all procs */
579 for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
580 if (mutex_init(&rfp->fp_lock, NULL) != 0)
581 panic("unable to initialize fproc lock");
582 #if LOCK_DEBUG
583 rfp->fp_vp_rdlocks = 0;
584 rfp->fp_vmnt_rdlocks = 0;
585 #endif
588 init_dmap_locks(); /* init dmap locks */
589 init_vnodes(); /* init vnodes */
590 init_vmnts(); /* init vmnt structures */
591 init_select(); /* init select() structures */
592 init_filps(); /* Init filp structures */
593 mount_pfs(); /* mount Pipe File Server */
594 worker_start(do_init_root); /* mount initial ramdisk as file system root */
595 yield(); /* force do_init_root to start */
596 self = NULL;
598 return(OK);
601 /*===========================================================================*
602 * do_init_root *
603 *===========================================================================*/
604 static void *do_init_root(void *arg)
606 struct fproc *rfp;
607 struct job my_job;
608 int r;
609 char *mount_label = "fs_imgrd"; /* FIXME: obtain this from RS */
611 my_job = *((struct job *) arg);
612 fp = my_job.j_fp;
614 lock_proc(fp, 1 /* force lock */); /* This proc is busy */
615 lock_pm();
617 /* Initialize process directories. mount_fs will set them to the correct
618 * values */
619 for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
620 FD_ZERO(&(rfp->fp_filp_inuse));
621 rfp->fp_rd = NULL;
622 rfp->fp_wd = NULL;
625 receive_from = MFS_PROC_NR;
626 r = mount_fs(DEV_IMGRD, "bootramdisk", "/", MFS_PROC_NR, 0, mount_label);
627 if (r != OK)
628 panic("Failed to initialize root");
629 receive_from = ANY;
631 unlock_pm();
632 thread_cleanup(fp);
633 unlock_proc(fp);
634 return(NULL);
637 /*===========================================================================*
638 * lock_proc *
639 *===========================================================================*/
640 void lock_proc(struct fproc *rfp, int force_lock)
642 int r;
643 struct fproc *org_fp;
644 struct worker_thread *org_self;
646 r = mutex_trylock(&rfp->fp_lock);
648 /* Were we supposed to obtain this lock immediately? */
649 if (force_lock) {
650 assert(r == 0);
651 return;
654 if (r == 0) return;
656 org_fp = fp;
657 org_self = self;
659 if ((r = mutex_lock(&rfp->fp_lock)) != 0)
660 panic("unable to lock fproc lock: %d", r);
662 fp = org_fp;
663 self = org_self;
666 /*===========================================================================*
667 * unlock_proc *
668 *===========================================================================*/
669 void unlock_proc(struct fproc *rfp)
671 int r;
673 if ((r = mutex_unlock(&rfp->fp_lock)) != 0)
674 panic("Failed to unlock: %d", r);
677 /*===========================================================================*
678 * thread_cleanup *
679 *===========================================================================*/
680 void thread_cleanup(struct fproc *rfp)
682 /* Clean up worker thread. Skip parts if this thread is not associated
683 * with a particular process (i.e., rfp is NULL) */
685 #if LOCK_DEBUG
686 if (rfp != NULL) {
687 check_filp_locks_by_me();
688 check_vnode_locks_by_me(rfp);
689 check_vmnt_locks_by_me(rfp);
691 #endif
693 if (rfp != NULL && rfp->fp_flags & FP_PM_PENDING) { /* Postponed PM call */
694 job_m_in = rfp->fp_job.j_m_in;
695 rfp->fp_flags &= ~FP_PM_PENDING;
696 service_pm_postponed();
699 #if LOCK_DEBUG
700 if (rfp != NULL) {
701 check_filp_locks_by_me();
702 check_vnode_locks_by_me(rfp);
703 check_vmnt_locks_by_me(rfp);
705 #endif
707 if (rfp != NULL) {
708 rfp->fp_flags &= ~FP_DROP_WORK;
709 if (rfp->fp_flags & FP_SRV_PROC) {
710 struct vmnt *vmp;
712 if ((vmp = find_vmnt(rfp->fp_endpoint)) != NULL) {
713 vmp->m_flags &= ~VMNT_CALLBACK;
718 if (deadlock_resolving) {
719 if (self->w_tid == dl_worker.w_tid)
720 deadlock_resolving = 0;
724 /*===========================================================================*
725 * get_work *
726 *===========================================================================*/
727 static void get_work()
729 /* Normally wait for new input. However, if 'reviving' is
730 * nonzero, a suspended process must be awakened.
732 int r, found_one, proc_p;
733 register struct fproc *rp;
735 while (reviving != 0) {
736 found_one = FALSE;
738 /* Find a suspended process. */
739 for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++)
740 if (rp->fp_pid != PID_FREE && (rp->fp_flags & FP_REVIVED)) {
741 found_one = TRUE; /* Found a suspended process */
742 if (unblock(rp))
743 return; /* So main loop can process job */
744 send_work();
747 if (!found_one) /* Consistency error */
748 panic("VFS: get_work couldn't revive anyone");
751 for(;;) {
752 /* Normal case. No one to revive. Get a useful request. */
753 if ((r = sef_receive(receive_from, &m_in)) != OK) {
754 panic("VFS: sef_receive error: %d", r);
757 proc_p = _ENDPOINT_P(m_in.m_source);
758 if (proc_p < 0 || proc_p >= NR_PROCS) fp = NULL;
759 else fp = &fproc[proc_p];
761 if (m_in.m_type == EDEADSRCDST) return; /* Failed 'sendrec' */
763 /* Negative who_p is never used to access the fproc array. Negative
764 * numbers (kernel tasks) are treated in a special way.
766 if (who_p >= (int)(sizeof(fproc) / sizeof(struct fproc)))
767 panic("receive process out of range: %d", who_p);
768 if (who_p >= 0 && fproc[who_p].fp_endpoint == NONE) {
769 printf("VFS: ignoring request from %d: NONE endpoint %d (%d)\n",
770 m_in.m_source, who_p, m_in.m_type);
771 continue;
774 /* Internal consistency check; our mental image of process numbers and
775 * endpoints must match with how the rest of the system thinks of them.
777 if (who_p >= 0 && fproc[who_p].fp_endpoint != who_e) {
778 if (fproc[who_p].fp_endpoint == NONE)
779 printf("slot unknown even\n");
781 printf("VFS: receive endpoint inconsistent (source %d, who_p "
782 "%d, stored ep %d, who_e %d).\n", m_in.m_source, who_p,
783 fproc[who_p].fp_endpoint, who_e);
784 panic("VFS: inconsistent endpoint ");
787 return;
791 /*===========================================================================*
792 * reply *
793 *===========================================================================*/
794 void reply(endpoint_t whom, int result)
796 /* Send a reply to a user process. If the send fails, just ignore it. */
797 int r;
799 m_out.reply_type = result;
800 r = sendnb(whom, &m_out);
801 if (r != OK) {
802 printf("VFS: %d couldn't send reply %d to %d: %d\n", mthread_self(),
803 result, whom, r);
804 util_stacktrace();
808 /*===========================================================================*
809 * service_pm_postponed *
810 *===========================================================================*/
811 static void service_pm_postponed(void)
813 int r;
814 vir_bytes pc, newsp;
816 switch(job_call_nr) {
817 case PM_EXEC:
819 endpoint_t proc_e;
820 vir_bytes exec_path, stack_frame;
821 size_t exec_path_len, stack_frame_len;
823 proc_e = job_m_in.PM_PROC;
824 exec_path = (vir_bytes) job_m_in.PM_PATH;
825 exec_path_len = (size_t) job_m_in.PM_PATH_LEN;
826 stack_frame = (vir_bytes) job_m_in.PM_FRAME;
827 stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN;
829 r = pm_exec(proc_e, exec_path, exec_path_len, stack_frame,
830 stack_frame_len, &pc, &newsp, job_m_in.PM_EXECFLAGS);
832 /* Reply status to PM */
833 m_out.m_type = PM_EXEC_REPLY;
834 m_out.PM_PROC = proc_e;
835 m_out.PM_PC = (void*) pc;
836 m_out.PM_STATUS = r;
837 m_out.PM_NEWSP = (void *) newsp;
839 break;
841 case PM_EXIT:
843 endpoint_t proc_e;
844 proc_e = job_m_in.PM_PROC;
846 pm_exit(proc_e);
848 /* Reply dummy status to PM for synchronization */
849 m_out.m_type = PM_EXIT_REPLY;
850 m_out.PM_PROC = proc_e;
852 break;
854 case PM_DUMPCORE:
856 endpoint_t proc_e, traced_proc_e;
857 int term_signal;
858 vir_bytes core_path;
860 proc_e = job_m_in.PM_PROC;
861 traced_proc_e = job_m_in.PM_TRACED_PROC;
862 if(job_m_in.PM_PROC != job_m_in.PM_TRACED_PROC) {
863 /* dumpcore request */
864 term_signal = 0;
865 } else {
866 /* dumpcore on exit */
867 term_signal = job_m_in.PM_TERM_SIG;
869 core_path = (vir_bytes) job_m_in.PM_PATH;
871 r = pm_dumpcore(proc_e, term_signal, core_path);
873 /* Reply status to PM */
874 m_out.m_type = PM_CORE_REPLY;
875 m_out.PM_PROC = proc_e;
876 m_out.PM_TRACED_PROC = traced_proc_e;
877 m_out.PM_STATUS = r;
879 break;
881 default:
882 panic("Unhandled postponed PM call %d", job_m_in.m_type);
885 r = send(PM_PROC_NR, &m_out);
886 if (r != OK)
887 panic("service_pm_postponed: send failed: %d", r);
890 /*===========================================================================*
891 * service_pm *
892 *===========================================================================*/
893 static void service_pm()
895 int r, slot;
897 switch (job_call_nr) {
898 case PM_SETUID:
900 endpoint_t proc_e;
901 uid_t euid, ruid;
903 proc_e = job_m_in.PM_PROC;
904 euid = job_m_in.PM_EID;
905 ruid = job_m_in.PM_RID;
907 pm_setuid(proc_e, euid, ruid);
909 m_out.m_type = PM_SETUID_REPLY;
910 m_out.PM_PROC = proc_e;
912 break;
914 case PM_SETGID:
916 endpoint_t proc_e;
917 gid_t egid, rgid;
919 proc_e = job_m_in.PM_PROC;
920 egid = job_m_in.PM_EID;
921 rgid = job_m_in.PM_RID;
923 pm_setgid(proc_e, egid, rgid);
925 m_out.m_type = PM_SETGID_REPLY;
926 m_out.PM_PROC = proc_e;
928 break;
930 case PM_SETSID:
932 endpoint_t proc_e;
934 proc_e = job_m_in.PM_PROC;
935 pm_setsid(proc_e);
937 m_out.m_type = PM_SETSID_REPLY;
938 m_out.PM_PROC = proc_e;
940 break;
942 case PM_EXEC:
943 case PM_EXIT:
944 case PM_DUMPCORE:
946 endpoint_t proc_e = job_m_in.PM_PROC;
948 if(isokendpt(proc_e, &slot) != OK) {
949 printf("VFS: proc ep %d not ok\n", proc_e);
950 return;
953 fp = &fproc[slot];
955 if (fp->fp_flags & FP_PENDING) {
956 /* This process has a request pending, but PM wants it
957 * gone. Forget about the pending request and satisfy
958 * PM's request instead. Note that a pending request
959 * AND an EXEC request are mutually exclusive. Also, PM
960 * should send only one request/process at a time.
962 assert(fp->fp_job.j_m_in.m_source != PM_PROC_NR);
965 /* PM requests on behalf of a proc are handled after the
966 * system call that might be in progress for that proc has
967 * finished. If the proc is not busy, we start a dummy call.
969 if (!(fp->fp_flags & FP_PENDING) &&
970 mutex_trylock(&fp->fp_lock) == 0) {
971 mutex_unlock(&fp->fp_lock);
972 worker_start(do_dummy);
973 fp->fp_flags |= FP_DROP_WORK;
976 fp->fp_job.j_m_in = job_m_in;
977 fp->fp_flags |= FP_PM_PENDING;
979 return;
981 case PM_FORK:
982 case PM_SRV_FORK:
984 endpoint_t pproc_e, proc_e;
985 pid_t child_pid;
986 uid_t reuid;
987 gid_t regid;
989 pproc_e = job_m_in.PM_PPROC;
990 proc_e = job_m_in.PM_PROC;
991 child_pid = job_m_in.PM_CPID;
992 reuid = job_m_in.PM_REUID;
993 regid = job_m_in.PM_REGID;
995 pm_fork(pproc_e, proc_e, child_pid);
996 m_out.m_type = PM_FORK_REPLY;
998 if (job_call_nr == PM_SRV_FORK) {
999 m_out.m_type = PM_SRV_FORK_REPLY;
1000 pm_setuid(proc_e, reuid, reuid);
1001 pm_setgid(proc_e, regid, regid);
1004 m_out.PM_PROC = proc_e;
1006 break;
1007 case PM_SETGROUPS:
1009 endpoint_t proc_e;
1010 int group_no;
1011 gid_t *group_addr;
1013 proc_e = job_m_in.PM_PROC;
1014 group_no = job_m_in.PM_GROUP_NO;
1015 group_addr = (gid_t *) job_m_in.PM_GROUP_ADDR;
1017 pm_setgroups(proc_e, group_no, group_addr);
1019 m_out.m_type = PM_SETGROUPS_REPLY;
1020 m_out.PM_PROC = proc_e;
1022 break;
1024 case PM_UNPAUSE:
1026 endpoint_t proc_e;
1028 proc_e = job_m_in.PM_PROC;
1030 unpause(proc_e);
1032 m_out.m_type = PM_UNPAUSE_REPLY;
1033 m_out.PM_PROC = proc_e;
1035 break;
1037 case PM_REBOOT:
1038 pm_reboot();
1040 /* Reply dummy status to PM for synchronization */
1041 m_out.m_type = PM_REBOOT_REPLY;
1043 break;
1045 default:
1046 printf("VFS: don't know how to handle PM request %d\n", job_call_nr);
1048 return;
1051 r = send(PM_PROC_NR, &m_out);
1052 if (r != OK)
1053 panic("service_pm: send failed: %d", r);
1058 /*===========================================================================*
1059 * unblock *
1060 *===========================================================================*/
1061 static int unblock(rfp)
1062 struct fproc *rfp;
1064 int blocked_on;
1066 fp = rfp;
1067 blocked_on = rfp->fp_blocked_on;
1068 m_in.m_source = rfp->fp_endpoint;
1069 m_in.m_type = rfp->fp_block_callnr;
1070 m_in.fd = scratch(fp).file.fd_nr;
1071 m_in.buffer = scratch(fp).io.io_buffer;
1072 m_in.nbytes = scratch(fp).io.io_nbytes;
1074 rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; /* no longer blocked */
1075 rfp->fp_flags &= ~FP_REVIVED;
1076 reviving--;
1077 assert(reviving >= 0);
1079 /* This should be a pipe I/O, not a device I/O. If it is, it'll 'leak'
1080 * grants.
1082 assert(!GRANT_VALID(rfp->fp_grant));
1084 /* Pending pipe reads/writes can be handled directly */
1085 if (blocked_on == FP_BLOCKED_ON_PIPE) {
1086 worker_start(do_pending_pipe);
1087 yield(); /* Give thread a chance to run */
1088 self = NULL;
1089 return(0); /* Retrieve more work */
1092 return(1); /* We've unblocked a process */