1 /* 2 * a loop that gets messages requesting work, carries out the work, and sends 3 * replies. 4 * 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 8 * 9 */ 10 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/const.h> 24 #include <minix/endpoint.h> 25 #include <minix/safecopies.h> 26 #include <minix/debug.h> 27 #include <minix/vfsif.h> 28 #include "file.h" 29 #include "scratchpad.h" 30 #include "vmnt.h" 31 #include "vnode.h" 32 33 #if ENABLE_SYSCALL_STATS 34 EXTERN unsigned long calls_stats[NR_VFS_CALLS]; 35 #endif 36 37 /* Thread related prototypes */ 38 static void do_reply(struct worker_thread *wp); 39 static void do_work(void); 40 static void do_init_root(void); 41 static void handle_work(void (*func)(void)); 42 static void reply(message *m_out, endpoint_t whom, int result); 43 44 static void get_work(void); 45 static void service_pm(void); 46 static int unblock(struct fproc *rfp); 47 48 /* SEF functions and variables. */ 49 static void sef_local_startup(void); 50 static int sef_cb_init_fresh(int type, sef_init_info_t *info); 51 52 /*===========================================================================* 53 * main * 54 *===========================================================================*/ 55 int main(void) 56 { 57 /* This is the main program of the file system. The main loop consists of 58 * three major activities: getting new work, processing the work, and sending 59 * the reply. This loop never terminates as long as the file system runs. 60 */ 61 int transid; 62 struct worker_thread *wp; 63 64 /* SEF local startup. */ 65 sef_local_startup(); 66 67 printf("Started VFS: %d worker thread(s)\n", NR_WTHREADS); 68 69 if (OK != (sys_getkinfo(&kinfo))) 70 panic("couldn't get kernel kinfo"); 71 72 /* This is the main loop that gets work, processes it, and sends replies. */ 73 while (TRUE) { 74 yield_all(); /* let other threads run */ 75 self = NULL; 76 send_work(); 77 get_work(); 78 79 transid = TRNS_GET_ID(m_in.m_type); 80 if (IS_VFS_FS_TRANSID(transid)) { 81 wp = worker_get((thread_t) transid - VFS_TRANSID); 82 if (wp == NULL || wp->w_fp == NULL) { 83 printf("VFS: spurious message %d from endpoint %d\n", 84 m_in.m_type, m_in.m_source); 85 continue; 86 } 87 m_in.m_type = TRNS_DEL_ID(m_in.m_type); 88 do_reply(wp); 89 continue; 90 } else if (who_e == PM_PROC_NR) { /* Calls from PM */ 91 /* Special control messages from PM */ 92 service_pm(); 93 continue; 94 } else if (is_notify(call_nr)) { 95 /* A task ipc_notify()ed us */ 96 switch (who_e) { 97 case DS_PROC_NR: 98 /* Start a thread to handle DS events, if no thread 99 * is pending or active for it already. DS is not 100 * supposed to issue calls to VFS or be the subject of 101 * postponed PM requests, so this should be no problem. 102 */ 103 if (worker_can_start(fp)) 104 handle_work(ds_event); 105 break; 106 case KERNEL: 107 mthread_stacktraces(); 108 break; 109 case CLOCK: 110 /* Timer expired. Used only for select(). Check it. */ 111 expire_timers(m_in.m_notify.timestamp); 112 break; 113 default: 114 printf("VFS: ignoring notification from %d\n", who_e); 115 } 116 continue; 117 } else if (who_p < 0) { /* i.e., message comes from a task */ 118 /* We're going to ignore this message. Tasks should 119 * send ipc_notify()s only. 120 */ 121 printf("VFS: ignoring message from %d (%d)\n", who_e, call_nr); 122 continue; 123 } 124 125 if (IS_BDEV_RS(call_nr)) { 126 /* We've got results for a block device request. */ 127 bdev_reply(); 128 } else if (IS_CDEV_RS(call_nr)) { 129 /* We've got results for a character device request. */ 130 cdev_reply(); 131 } else { 132 /* Normal syscall. This spawns a new thread. */ 133 handle_work(do_work); 134 } 135 } 136 return(OK); /* shouldn't come here */ 137 } 138 139 /*===========================================================================* 140 * handle_work * 141 *===========================================================================*/ 142 static void handle_work(void (*func)(void)) 143 { 144 /* Handle asynchronous device replies and new system calls. If the originating 145 * endpoint is an FS endpoint, take extra care not to get in deadlock. */ 146 struct vmnt *vmp = NULL; 147 endpoint_t proc_e; 148 int use_spare = FALSE; 149 150 proc_e = m_in.m_source; 151 152 if (fp->fp_flags & FP_SRV_PROC) { 153 vmp = find_vmnt(proc_e); 154 if (vmp != NULL) { 155 /* A callback from an FS endpoint. Can do only one at once. */ 156 if (vmp->m_flags & VMNT_CALLBACK) { 157 replycode(proc_e, EAGAIN); 158 return; 159 } 160 /* Already trying to resolve a deadlock? Can't handle more. */ 161 if (worker_available() == 0) { 162 replycode(proc_e, EAGAIN); 163 return; 164 } 165 /* A thread is available. Set callback flag. */ 166 vmp->m_flags |= VMNT_CALLBACK; 167 if (vmp->m_flags & VMNT_MOUNTING) { 168 vmp->m_flags |= VMNT_FORCEROOTBSF; 169 } 170 } 171 172 /* Use the spare thread to handle this request if needed. */ 173 use_spare = TRUE; 174 } 175 176 worker_start(fp, func, &m_in, use_spare); 177 } 178 179 180 /*===========================================================================* 181 * do_reply * 182 *===========================================================================*/ 183 static void do_reply(struct worker_thread *wp) 184 { 185 struct vmnt *vmp = NULL; 186 187 if(who_e != VM_PROC_NR && (vmp = find_vmnt(who_e)) == NULL) 188 panic("Couldn't find vmnt for endpoint %d", who_e); 189 190 if (wp->w_task != who_e) { 191 printf("VFS: tid %d: expected %d to reply, not %d\n", 192 wp->w_tid, wp->w_task, who_e); 193 } 194 *wp->w_sendrec = m_in; 195 wp->w_task = NONE; 196 if(vmp) vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */ 197 worker_signal(wp); /* Continue this thread */ 198 } 199 200 /*===========================================================================* 201 * do_pending_pipe * 202 *===========================================================================*/ 203 static void do_pending_pipe(void) 204 { 205 int r, op; 206 struct filp *f; 207 tll_access_t locktype; 208 209 f = scratch(fp).file.filp; 210 assert(f != NULL); 211 scratch(fp).file.filp = NULL; 212 213 locktype = (job_call_nr == VFS_READ) ? VNODE_READ : VNODE_WRITE; 214 op = (job_call_nr == VFS_READ) ? READING : WRITING; 215 lock_filp(f, locktype); 216 217 r = rw_pipe(op, who_e, f, scratch(fp).io.io_buffer, scratch(fp).io.io_nbytes); 218 219 if (r != SUSPEND) { /* Do we have results to report? */ 220 /* Process is writing, but there is no reader. Send a SIGPIPE signal. 221 * This should match the corresponding code in read_write(). 222 */ 223 if (r == EPIPE && op == WRITING) { 224 if (!(f->filp_flags & O_NOSIGPIPE)) 225 sys_kill(fp->fp_endpoint, SIGPIPE); 226 } 227 228 replycode(fp->fp_endpoint, r); 229 } 230 231 unlock_filp(f); 232 } 233 234 /*===========================================================================* 235 * do_work * 236 *===========================================================================*/ 237 static void do_work(void) 238 { 239 unsigned int call_index; 240 int error; 241 242 if (fp->fp_pid == PID_FREE) { 243 /* Process vanished before we were able to handle request. 244 * Replying has no use. Just drop it. 245 */ 246 return; 247 } 248 249 memset(&job_m_out, 0, sizeof(job_m_out)); 250 251 /* At this point we assume that we're dealing with a call that has been 252 * made specifically to VFS. Typically it will be a POSIX call from a 253 * normal process, but we also handle a few calls made by drivers such 254 * such as UDS and VND through here. Call the internal function that 255 * does the work. 256 */ 257 if (IS_VFS_CALL(job_call_nr)) { 258 call_index = (unsigned int) (job_call_nr - VFS_BASE); 259 260 if (call_index < NR_VFS_CALLS && call_vec[call_index] != NULL) { 261 #if ENABLE_SYSCALL_STATS 262 calls_stats[call_index]++; 263 #endif 264 error = (*call_vec[call_index])(); 265 } else 266 error = ENOSYS; 267 } else 268 error = ENOSYS; 269 270 /* Copy the results back to the user and send reply. */ 271 if (error != SUSPEND) reply(&job_m_out, fp->fp_endpoint, error); 272 } 273 274 /*===========================================================================* 275 * sef_local_startup * 276 *===========================================================================*/ 277 static void sef_local_startup() 278 { 279 /* Register init callbacks. */ 280 sef_setcb_init_fresh(sef_cb_init_fresh); 281 sef_setcb_init_restart(sef_cb_init_fail); 282 283 /* No live update support for now. */ 284 285 /* Let SEF perform startup. */ 286 sef_startup(); 287 } 288 289 /*===========================================================================* 290 * sef_cb_init_fresh * 291 *===========================================================================*/ 292 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) 293 { 294 /* Initialize the virtual file server. */ 295 int s, i; 296 struct fproc *rfp; 297 message mess; 298 struct rprocpub rprocpub[NR_BOOT_PROCS]; 299 300 self = NULL; 301 verbose = 0; 302 303 /* Initialize proc endpoints to NONE */ 304 for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { 305 rfp->fp_endpoint = NONE; 306 rfp->fp_pid = PID_FREE; 307 } 308 309 /* Initialize the process table with help of the process manager messages. 310 * Expect one message for each system process with its slot number and pid. 311 * When no more processes follow, the magic process number NONE is sent. 312 * Then, stop and synchronize with the PM. 313 */ 314 do { 315 if ((s = sef_receive(PM_PROC_NR, &mess)) != OK) 316 panic("VFS: couldn't receive from PM: %d", s); 317 318 if (mess.m_type != VFS_PM_INIT) 319 panic("unexpected message from PM: %d", mess.m_type); 320 321 if (NONE == mess.VFS_PM_ENDPT) break; 322 323 rfp = &fproc[mess.VFS_PM_SLOT]; 324 rfp->fp_flags = FP_NOFLAGS; 325 rfp->fp_pid = mess.VFS_PM_PID; 326 rfp->fp_endpoint = mess.VFS_PM_ENDPT; 327 rfp->fp_grant = GRANT_INVALID; 328 rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; 329 rfp->fp_realuid = (uid_t) SYS_UID; 330 rfp->fp_effuid = (uid_t) SYS_UID; 331 rfp->fp_realgid = (gid_t) SYS_GID; 332 rfp->fp_effgid = (gid_t) SYS_GID; 333 rfp->fp_umask = ~0; 334 } while (TRUE); /* continue until process NONE */ 335 mess.m_type = OK; /* tell PM that we succeeded */ 336 s = ipc_send(PM_PROC_NR, &mess); /* send synchronization message */ 337 338 system_hz = sys_hz(); 339 340 /* Subscribe to block and character driver events. */ 341 s = ds_subscribe("drv\\.[bc]..\\..*", DSF_INITIAL | DSF_OVERWRITE); 342 if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s); 343 344 /* Initialize worker threads */ 345 worker_init(); 346 347 /* Initialize global locks */ 348 if (mthread_mutex_init(&bsf_lock, NULL) != 0) 349 panic("VFS: couldn't initialize block special file lock"); 350 351 init_dmap(); /* Initialize device table. */ 352 353 /* Map all the services in the boot image. */ 354 if ((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, 355 (vir_bytes) rprocpub, sizeof(rprocpub))) != OK){ 356 panic("sys_safecopyfrom failed: %d", s); 357 } 358 for (i = 0; i < NR_BOOT_PROCS; i++) { 359 if (rprocpub[i].in_use) { 360 if ((s = map_service(&rprocpub[i])) != OK) { 361 panic("VFS: unable to map service: %d", s); 362 } 363 } 364 } 365 366 /* Initialize locks and initial values for all processes. */ 367 for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { 368 if (mutex_init(&rfp->fp_lock, NULL) != 0) 369 panic("unable to initialize fproc lock"); 370 rfp->fp_worker = NULL; 371 #if LOCK_DEBUG 372 rfp->fp_vp_rdlocks = 0; 373 rfp->fp_vmnt_rdlocks = 0; 374 #endif 375 376 /* Initialize process directories. mount_fs will set them to the 377 * correct values. 378 */ 379 for (i = 0; i < OPEN_MAX; i++) 380 rfp->fp_filp[i] = NULL; 381 rfp->fp_rd = NULL; 382 rfp->fp_wd = NULL; 383 } 384 385 init_vnodes(); /* init vnodes */ 386 init_vmnts(); /* init vmnt structures */ 387 init_select(); /* init select() structures */ 388 init_filps(); /* Init filp structures */ 389 390 /* Mount PFS and initial file system root. */ 391 worker_start(fproc_addr(VFS_PROC_NR), do_init_root, &mess /*unused*/, 392 FALSE /*use_spare*/); 393 394 return(OK); 395 } 396 397 /*===========================================================================* 398 * do_init_root * 399 *===========================================================================*/ 400 static void do_init_root(void) 401 { 402 char *mount_type, *mount_label; 403 int r; 404 405 /* Disallow requests from e.g. init(8) while doing the initial mounting. */ 406 worker_allow(FALSE); 407 408 /* Mount the pipe file server. */ 409 mount_pfs(); 410 411 /* Mount the root file system. */ 412 mount_type = "mfs"; /* FIXME: use boot image process name instead */ 413 mount_label = "fs_imgrd"; /* FIXME: obtain this from RS */ 414 415 r = mount_fs(DEV_IMGRD, "bootramdisk", "/", MFS_PROC_NR, 0, mount_type, 416 mount_label); 417 if (r != OK) 418 panic("Failed to initialize root"); 419 420 /* All done with mounting, allow requests now. */ 421 worker_allow(TRUE); 422 } 423 424 /*===========================================================================* 425 * lock_proc * 426 *===========================================================================*/ 427 void lock_proc(struct fproc *rfp) 428 { 429 int r; 430 struct worker_thread *org_self; 431 432 r = mutex_trylock(&rfp->fp_lock); 433 if (r == 0) return; 434 435 org_self = worker_suspend(); 436 437 if ((r = mutex_lock(&rfp->fp_lock)) != 0) 438 panic("unable to lock fproc lock: %d", r); 439 440 worker_resume(org_self); 441 } 442 443 /*===========================================================================* 444 * unlock_proc * 445 *===========================================================================*/ 446 void unlock_proc(struct fproc *rfp) 447 { 448 int r; 449 450 if ((r = mutex_unlock(&rfp->fp_lock)) != 0) 451 panic("Failed to unlock: %d", r); 452 } 453 454 /*===========================================================================* 455 * thread_cleanup * 456 *===========================================================================*/ 457 void thread_cleanup(void) 458 { 459 /* Perform cleanup actions for a worker thread. */ 460 461 #if LOCK_DEBUG 462 check_filp_locks_by_me(); 463 check_vnode_locks_by_me(fp); 464 check_vmnt_locks_by_me(fp); 465 #endif 466 467 if (fp->fp_flags & FP_SRV_PROC) { 468 struct vmnt *vmp; 469 470 if ((vmp = find_vmnt(fp->fp_endpoint)) != NULL) { 471 vmp->m_flags &= ~VMNT_CALLBACK; 472 } 473 } 474 } 475 476 /*===========================================================================* 477 * get_work * 478 *===========================================================================*/ 479 static void get_work() 480 { 481 /* Normally wait for new input. However, if 'reviving' is 482 * nonzero, a suspended process must be awakened. 483 */ 484 int r, found_one, proc_p; 485 register struct fproc *rp; 486 487 while (reviving != 0) { 488 found_one = FALSE; 489 490 /* Find a suspended process. */ 491 for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) 492 if (rp->fp_pid != PID_FREE && (rp->fp_flags & FP_REVIVED)) { 493 found_one = TRUE; /* Found a suspended process */ 494 if (unblock(rp)) 495 return; /* So main loop can process job */ 496 send_work(); 497 } 498 499 if (!found_one) /* Consistency error */ 500 panic("VFS: get_work couldn't revive anyone"); 501 } 502 503 for(;;) { 504 /* Normal case. No one to revive. Get a useful request. */ 505 if ((r = sef_receive(ANY, &m_in)) != OK) { 506 panic("VFS: sef_receive error: %d", r); 507 } 508 509 proc_p = _ENDPOINT_P(m_in.m_source); 510 if (proc_p < 0 || proc_p >= NR_PROCS) fp = NULL; 511 else fp = &fproc[proc_p]; 512 513 if (m_in.m_type == EDEADSRCDST) { 514 printf("VFS: failed ipc_sendrec\n"); 515 return; /* Failed 'ipc_sendrec' */ 516 } 517 518 /* Negative who_p is never used to access the fproc array. Negative 519 * numbers (kernel tasks) are treated in a special way. 520 */ 521 if (fp && fp->fp_endpoint == NONE) { 522 printf("VFS: ignoring request from %d: NONE endpoint %d (%d)\n", 523 m_in.m_source, who_p, m_in.m_type); 524 continue; 525 } 526 527 /* Internal consistency check; our mental image of process numbers and 528 * endpoints must match with how the rest of the system thinks of them. 529 */ 530 if (fp && fp->fp_endpoint != who_e) { 531 if (fproc[who_p].fp_endpoint == NONE) 532 printf("slot unknown even\n"); 533 534 panic("VFS: receive endpoint inconsistent (source %d, who_p " 535 "%d, stored ep %d, who_e %d).\n", m_in.m_source, who_p, 536 fproc[who_p].fp_endpoint, who_e); 537 } 538 539 return; 540 } 541 } 542 543 /*===========================================================================* 544 * reply * 545 *===========================================================================*/ 546 static void reply(message *m_out, endpoint_t whom, int result) 547 { 548 /* Send a reply to a user process. If the send fails, just ignore it. */ 549 int r; 550 551 m_out->m_type = result; 552 r = ipc_sendnb(whom, m_out); 553 if (r != OK) { 554 printf("VFS: %d couldn't send reply %d to %d: %d\n", mthread_self(), 555 result, whom, r); 556 util_stacktrace(); 557 } 558 } 559 560 /*===========================================================================* 561 * replycode * 562 *===========================================================================*/ 563 void replycode(endpoint_t whom, int result) 564 { 565 /* Send a reply to a user process. If the send fails, just ignore it. */ 566 message m_out; 567 568 memset(&m_out, 0, sizeof(m_out)); 569 570 reply(&m_out, whom, result); 571 } 572 573 /*===========================================================================* 574 * service_pm_postponed * 575 *===========================================================================*/ 576 void service_pm_postponed(void) 577 { 578 int r, term_signal; 579 vir_bytes core_path; 580 vir_bytes exec_path, stack_frame, pc, newsp, ps_str; 581 size_t exec_path_len, stack_frame_len; 582 endpoint_t proc_e; 583 message m_out; 584 585 memset(&m_out, 0, sizeof(m_out)); 586 587 switch(job_call_nr) { 588 case VFS_PM_EXEC: 589 proc_e = job_m_in.VFS_PM_ENDPT; 590 exec_path = (vir_bytes) job_m_in.VFS_PM_PATH; 591 exec_path_len = (size_t) job_m_in.VFS_PM_PATH_LEN; 592 stack_frame = (vir_bytes) job_m_in.VFS_PM_FRAME; 593 stack_frame_len = (size_t) job_m_in.VFS_PM_FRAME_LEN; 594 ps_str = (vir_bytes) job_m_in.VFS_PM_PS_STR; 595 596 assert(proc_e == fp->fp_endpoint); 597 598 r = pm_exec(exec_path, exec_path_len, stack_frame, stack_frame_len, 599 &pc, &newsp, &ps_str); 600 601 /* Reply status to PM */ 602 m_out.m_type = VFS_PM_EXEC_REPLY; 603 m_out.VFS_PM_ENDPT = proc_e; 604 m_out.VFS_PM_PC = (void *) pc; 605 m_out.VFS_PM_STATUS = r; 606 m_out.VFS_PM_NEWSP = (void *) newsp; 607 m_out.VFS_PM_NEWPS_STR = ps_str; 608 609 break; 610 611 case VFS_PM_EXIT: 612 proc_e = job_m_in.VFS_PM_ENDPT; 613 614 assert(proc_e == fp->fp_endpoint); 615 616 pm_exit(); 617 618 /* Reply dummy status to PM for synchronization */ 619 m_out.m_type = VFS_PM_EXIT_REPLY; 620 m_out.VFS_PM_ENDPT = proc_e; 621 622 break; 623 624 case VFS_PM_DUMPCORE: 625 proc_e = job_m_in.VFS_PM_ENDPT; 626 term_signal = job_m_in.VFS_PM_TERM_SIG; 627 core_path = (vir_bytes) job_m_in.VFS_PM_PATH; 628 629 assert(proc_e == fp->fp_endpoint); 630 631 r = pm_dumpcore(term_signal, core_path); 632 633 /* Reply status to PM */ 634 m_out.m_type = VFS_PM_CORE_REPLY; 635 m_out.VFS_PM_ENDPT = proc_e; 636 m_out.VFS_PM_STATUS = r; 637 638 break; 639 640 case VFS_PM_UNPAUSE: 641 proc_e = job_m_in.VFS_PM_ENDPT; 642 643 assert(proc_e == fp->fp_endpoint); 644 645 unpause(); 646 647 m_out.m_type = VFS_PM_UNPAUSE_REPLY; 648 m_out.VFS_PM_ENDPT = proc_e; 649 650 break; 651 652 default: 653 panic("Unhandled postponed PM call %d", job_m_in.m_type); 654 } 655 656 r = ipc_send(PM_PROC_NR, &m_out); 657 if (r != OK) 658 panic("service_pm_postponed: ipc_send failed: %d", r); 659 } 660 661 /*===========================================================================* 662 * service_pm * 663 *===========================================================================*/ 664 static void service_pm(void) 665 { 666 /* Process a request from PM. This function is called from the main thread, and 667 * may therefore not block. Any requests that may require blocking the calling 668 * thread must be executed in a separate thread. Aside from VFS_PM_REBOOT, all 669 * requests from PM involve another, target process: for example, PM tells VFS 670 * that a process is performing a setuid() call. For some requests however, 671 * that other process may not be idle, and in that case VFS must serialize the 672 * PM request handling with any operation is it handling for that target 673 * process. As it happens, the requests that may require blocking are also the 674 * ones where the target process may not be idle. For both these reasons, such 675 * requests are run in worker threads associated to the target process. 676 */ 677 struct fproc *rfp; 678 int r, slot; 679 message m_out; 680 681 memset(&m_out, 0, sizeof(m_out)); 682 683 switch (call_nr) { 684 case VFS_PM_SETUID: 685 { 686 endpoint_t proc_e; 687 uid_t euid, ruid; 688 689 proc_e = m_in.VFS_PM_ENDPT; 690 euid = m_in.VFS_PM_EID; 691 ruid = m_in.VFS_PM_RID; 692 693 pm_setuid(proc_e, euid, ruid); 694 695 m_out.m_type = VFS_PM_SETUID_REPLY; 696 m_out.VFS_PM_ENDPT = proc_e; 697 } 698 break; 699 700 case VFS_PM_SETGID: 701 { 702 endpoint_t proc_e; 703 gid_t egid, rgid; 704 705 proc_e = m_in.VFS_PM_ENDPT; 706 egid = m_in.VFS_PM_EID; 707 rgid = m_in.VFS_PM_RID; 708 709 pm_setgid(proc_e, egid, rgid); 710 711 m_out.m_type = VFS_PM_SETGID_REPLY; 712 m_out.VFS_PM_ENDPT = proc_e; 713 } 714 break; 715 716 case VFS_PM_SETSID: 717 { 718 endpoint_t proc_e; 719 720 proc_e = m_in.VFS_PM_ENDPT; 721 pm_setsid(proc_e); 722 723 m_out.m_type = VFS_PM_SETSID_REPLY; 724 m_out.VFS_PM_ENDPT = proc_e; 725 } 726 break; 727 728 case VFS_PM_EXEC: 729 case VFS_PM_EXIT: 730 case VFS_PM_DUMPCORE: 731 case VFS_PM_UNPAUSE: 732 { 733 endpoint_t proc_e = m_in.VFS_PM_ENDPT; 734 735 if(isokendpt(proc_e, &slot) != OK) { 736 printf("VFS: proc ep %d not ok\n", proc_e); 737 return; 738 } 739 740 rfp = &fproc[slot]; 741 742 /* PM requests on behalf of a proc are handled after the 743 * system call that might be in progress for that proc has 744 * finished. If the proc is not busy, we start a new thread. 745 */ 746 worker_start(rfp, NULL, &m_in, FALSE /*use_spare*/); 747 748 return; 749 } 750 case VFS_PM_FORK: 751 case VFS_PM_SRV_FORK: 752 { 753 endpoint_t pproc_e, proc_e; 754 pid_t child_pid; 755 uid_t reuid; 756 gid_t regid; 757 758 pproc_e = m_in.VFS_PM_PENDPT; 759 proc_e = m_in.VFS_PM_ENDPT; 760 child_pid = m_in.VFS_PM_CPID; 761 reuid = m_in.VFS_PM_REUID; 762 regid = m_in.VFS_PM_REGID; 763 764 pm_fork(pproc_e, proc_e, child_pid); 765 m_out.m_type = VFS_PM_FORK_REPLY; 766 767 if (call_nr == VFS_PM_SRV_FORK) { 768 m_out.m_type = VFS_PM_SRV_FORK_REPLY; 769 pm_setuid(proc_e, reuid, reuid); 770 pm_setgid(proc_e, regid, regid); 771 } 772 773 m_out.VFS_PM_ENDPT = proc_e; 774 } 775 break; 776 case VFS_PM_SETGROUPS: 777 { 778 endpoint_t proc_e; 779 int group_no; 780 gid_t *group_addr; 781 782 proc_e = m_in.VFS_PM_ENDPT; 783 group_no = m_in.VFS_PM_GROUP_NO; 784 group_addr = (gid_t *) m_in.VFS_PM_GROUP_ADDR; 785 786 pm_setgroups(proc_e, group_no, group_addr); 787 788 m_out.m_type = VFS_PM_SETGROUPS_REPLY; 789 m_out.VFS_PM_ENDPT = proc_e; 790 } 791 break; 792 793 case VFS_PM_REBOOT: 794 /* Reboot requests are not considered postponed PM work and are instead 795 * handled from a separate worker thread that is associated with PM's 796 * process. PM makes no regular VFS calls, and thus, from VFS's 797 * perspective, PM is always idle. Therefore, we can safely do this. 798 * We do assume that PM sends us only one VFS_PM_REBOOT message at 799 * once, or ever for that matter. :) 800 */ 801 worker_start(fproc_addr(PM_PROC_NR), pm_reboot, &m_in, 802 FALSE /*use_spare*/); 803 804 return; 805 806 default: 807 printf("VFS: don't know how to handle PM request %d\n", call_nr); 808 809 return; 810 } 811 812 r = ipc_send(PM_PROC_NR, &m_out); 813 if (r != OK) 814 panic("service_pm: ipc_send failed: %d", r); 815 } 816 817 818 /*===========================================================================* 819 * unblock * 820 *===========================================================================*/ 821 static int unblock(rfp) 822 struct fproc *rfp; 823 { 824 /* Unblock a process that was previously blocked on a pipe or a lock. This is 825 * done by reconstructing the original request and continuing/repeating it. 826 * This function returns TRUE when it has restored a request for execution, and 827 * FALSE if the caller should continue looking for work to do. 828 */ 829 int blocked_on; 830 831 blocked_on = rfp->fp_blocked_on; 832 833 /* Reconstruct the original request from the saved data. */ 834 memset(&m_in, 0, sizeof(m_in)); 835 m_in.m_source = rfp->fp_endpoint; 836 m_in.m_type = rfp->fp_block_callnr; 837 switch (m_in.m_type) { 838 case VFS_READ: 839 case VFS_WRITE: 840 assert(blocked_on == FP_BLOCKED_ON_PIPE); 841 m_in.m_lc_vfs_readwrite.fd = scratch(rfp).file.fd_nr; 842 m_in.m_lc_vfs_readwrite.buf = scratch(rfp).io.io_buffer; 843 m_in.m_lc_vfs_readwrite.len = scratch(rfp).io.io_nbytes; 844 break; 845 case VFS_FCNTL: 846 assert(blocked_on == FP_BLOCKED_ON_LOCK); 847 m_in.m_lc_vfs_fcntl.fd = scratch(rfp).file.fd_nr; 848 m_in.m_lc_vfs_fcntl.cmd = scratch(rfp).io.io_nbytes; 849 m_in.m_lc_vfs_fcntl.arg_ptr = scratch(rfp).io.io_buffer; 850 assert(m_in.m_lc_vfs_fcntl.cmd == F_SETLKW); 851 break; 852 default: 853 panic("unblocking call %d blocked on %d ??", m_in.m_type, blocked_on); 854 } 855 856 rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; /* no longer blocked */ 857 rfp->fp_flags &= ~FP_REVIVED; 858 reviving--; 859 assert(reviving >= 0); 860 861 /* This should not be device I/O. If it is, it'll 'leak' grants. */ 862 assert(!GRANT_VALID(rfp->fp_grant)); 863 864 /* Pending pipe reads/writes cannot be repeated as is, and thus require a 865 * special resumption procedure. 866 */ 867 if (blocked_on == FP_BLOCKED_ON_PIPE) { 868 worker_start(rfp, do_pending_pipe, &m_in, FALSE /*use_spare*/); 869 return(FALSE); /* Retrieve more work */ 870 } 871 872 /* A lock request. Repeat the original request as though it just came in. */ 873 fp = rfp; 874 return(TRUE); /* We've unblocked a process */ 875 } 876