/*===========================================================================* * blockdriver_reply * *===========================================================================*/ void blockdriver_reply(message *m_ptr, int ipc_status, int reply) { /* Reply to a block request sent to the driver. */ endpoint_t caller_e; long id; int r; if (reply == EDONTREPLY) return; caller_e = m_ptr->m_source; id = m_ptr->BDEV_ID; memset(m_ptr, 0, sizeof(*m_ptr)); m_ptr->m_type = BDEV_REPLY; m_ptr->BDEV_STATUS = reply; m_ptr->BDEV_ID = id; /* If we would block sending the message, send it asynchronously. The NOREPLY * flag is set because the caller may also issue a SENDREC (mixing sync and * async comm), and the asynchronous reply could otherwise end up satisfying * the SENDREC's receive part, after which our next SENDNB call would fail. */ if (IPC_STATUS_CALL(ipc_status) == SENDREC) r = sendnb(caller_e, m_ptr); else r = asynsend3(caller_e, m_ptr, AMF_NOREPLY); if (r != OK) printf("blockdriver_reply: unable to send reply to %d: %d\n", caller_e, r); }
/*===========================================================================* * sef_cb_signal_manager * *===========================================================================*/ PRIVATE int sef_cb_signal_manager(endpoint_t target, int signo) { /* Process system signal on behalf of the kernel. */ int target_p; struct rproc *rp; struct rprocpub *rpub; message m; /* Lookup slot. */ if(rs_isokendpt(target, &target_p) != OK || rproc_ptr[target_p] == NULL) { if(rs_verbose) printf("RS: ignoring spurious signal %d for process %d\n", signo, target); return OK; /* clear the signal */ } rp = rproc_ptr[target_p]; rpub = rp->r_pub; /* Don't bother if a termination signal has already been processed. */ if((rp->r_flags & RS_TERMINATED) && !(rp->r_flags & RS_EXITING)) { return EDEADEPT; /* process is gone */ } /* Ignore external signals for inactive service instances. */ if( !(rp->r_flags & RS_ACTIVE) && !(rp->r_flags & RS_EXITING)) { if(rs_verbose) printf("RS: ignoring signal %d for inactive %s\n", signo, srv_to_string(rp)); return OK; /* clear the signal */ } if(rs_verbose) printf("RS: %s got %s signal %d\n", srv_to_string(rp), SIGS_IS_TERMINATION(signo) ? "termination" : "non-termination",signo); /* Print stacktrace if necessary. */ if(SIGS_IS_STACKTRACE(signo)) { sys_sysctl_stacktrace(target); } /* In case of termination signal handle the event. */ if(SIGS_IS_TERMINATION(signo)) { rp->r_flags |= RS_TERMINATED; terminate_service(rp); return EDEADEPT; /* process is now gone */ } /* Translate every non-termination signal into a message. */ m.m_type = SIGS_SIGNAL_RECEIVED; m.SIGS_SIG_NUM = signo; asynsend3(rpub->endpoint, &m, AMF_NOREPLY); return OK; /* signal has been delivered */ }
static void activate(void) { assert(!active); assert(first_queued); active = first_queued; first_queued = first_queued->next; if(asynsend3(VFS_PROC_NR, &active->reqmsg, AMF_NOREPLY) != OK) panic("VM: asynsend to VFS failed"); }
/* * For the current event of the given process, as determined by its flags, send * a process event message to the next subscriber, or resume handling the * event itself if there are no more subscribers to notify. */ static void resume_event(struct mproc * rmp) { message m; unsigned int i, event; int r; assert(rmp->mp_flags & IN_USE); assert(rmp->mp_flags & EVENT_CALL); assert(rmp->mp_eventsub != NO_EVENTSUB); /* Which event should we be concerned about? */ if (rmp->mp_flags & EXITING) event = PROC_EVENT_EXIT; else if (rmp->mp_flags & UNPAUSED) event = PROC_EVENT_SIGNAL; else panic("unknown event for flags %x", rmp->mp_flags); /* * If there are additional services interested in this event, send a * message to the next one. */ for (i = rmp->mp_eventsub; i < nsubs; i++, rmp->mp_eventsub++) { if (subs[i].mask & event) { memset(&m, 0, sizeof(m)); m.m_type = PROC_EVENT; m.m_pm_lsys_proc_event.endpt = rmp->mp_endpoint; m.m_pm_lsys_proc_event.event = event; r = asynsend3(subs[i].endpt, &m, AMF_NOREPLY); if (r != OK) panic("asynsend failed: %d", r); assert(subs[i].waiting < NR_PROCS); subs[i].waiting++; return; } } /* No more subscribers to be notified, resume the actual event. */ rmp->mp_flags &= ~EVENT_CALL; rmp->mp_eventsub = NO_EVENTSUB; if (event == PROC_EVENT_EXIT) exit_restart(rmp); else if (event == PROC_EVENT_SIGNAL) restart_sigs(rmp); }
/*===========================================================================* * send_reply * *===========================================================================*/ static void send_reply(endpoint_t endpt, message *m_ptr, int ipc_status) { /* Send a reply message to a request. */ int r; /* If we would block sending the message, send it asynchronously. The NOREPLY * flag is set because the caller may also issue a SENDREC (mixing sync and * async comm), and the asynchronous reply could otherwise end up satisfying * the SENDREC's receive part, after which our next SENDNB call would fail. */ if (IPC_STATUS_CALL(ipc_status) == SENDREC) r = ipc_sendnb(endpt, m_ptr); else r = asynsend3(endpt, m_ptr, AMF_NOREPLY); if (r != OK) printf("blockdriver: unable to send reply to %d: %d\n", endpt, r); }
/*===========================================================================* * sendmsg * *===========================================================================*/ static int sendmsg(struct vmnt *vmp, endpoint_t dst, struct worker_thread *wp) { /* This is the low level function that sends requests. * Currently to FSes or VM. */ int r, transid; if(vmp) vmp->m_comm.c_cur_reqs++; /* One more request awaiting a reply */ transid = wp->w_tid + VFS_TRANSID; wp->w_sendrec->m_type = TRNS_ADD_ID(wp->w_sendrec->m_type, transid); wp->w_task = dst; if ((r = asynsend3(dst, wp->w_sendrec, AMF_NOREPLY)) != OK) { printf("VFS: sendmsg: error sending message. " "dest: %d req_nr: %d err: %d\n", dst, wp->w_sendrec->m_type, r); util_stacktrace(); return(r); } return(r); }
/*===========================================================================* * drv_sendrec * *===========================================================================*/ int drv_sendrec(endpoint_t drv_e, message *reqmp) { int r; struct dmap *dp; /* For the CTTY_MAJOR case, we would actually have to lock the device * entry being redirected to. However, the CTTY major only hosts a * character device while this function is used only for block devices. * Thus, we can simply deny the request immediately. */ if (drv_e == CTTY_ENDPT) { printf("VFS: /dev/tty is not a block device!\n"); return EIO; } if ((dp = get_dmap(drv_e)) == NULL) panic("driver endpoint %d invalid", drv_e); lock_dmap(dp); if (dp->dmap_servicing != INVALID_THREAD) panic("driver locking inconsistency"); dp->dmap_servicing = self->w_tid; self->w_task = drv_e; self->w_drv_sendrec = reqmp; if ((r = asynsend3(drv_e, self->w_drv_sendrec, AMF_NOREPLY)) == OK) { /* Yield execution until we've received the reply */ worker_wait(); } else { printf("VFS: drv_sendrec: error sending msg to driver %d: %d\n", drv_e, r); util_stacktrace(); } dp->dmap_servicing = INVALID_THREAD; self->w_task = NONE; self->w_drv_sendrec = NULL; unlock_dmap(dp); return(OK); }
/*===========================================================================* * do_vm_call * *===========================================================================*/ int do_vm_call(void) { /* A call that VM does to VFS. * We must reply with the fixed type VM_VFS_REPLY (and put our result info * in the rest of the message) so VM can tell the difference between a * request from VFS and a reply to this call. */ int req = job_m_in.VFS_VMCALL_REQ; int req_fd = job_m_in.VFS_VMCALL_FD; u32_t req_id = job_m_in.VFS_VMCALL_REQID; endpoint_t ep = job_m_in.VFS_VMCALL_ENDPOINT; u64_t offset = job_m_in.VFS_VMCALL_OFFSET; u32_t length = job_m_in.VFS_VMCALL_LENGTH; int result = OK; int slot; struct fproc *rfp, *vmf; struct filp *f = NULL; int r; if(job_m_in.m_source != VM_PROC_NR) return ENOSYS; if(isokendpt(ep, &slot) != OK) rfp = NULL; else rfp = &fproc[slot]; vmf = fproc_addr(VM_PROC_NR); assert(fp == vmf); assert(rfp != vmf); switch(req) { case VMVFSREQ_FDLOOKUP: { int procfd; /* Lookup fd in referenced process. */ if(!rfp) { printf("VFS: why isn't ep %d here?!\n", ep); result = ESRCH; goto reqdone; } if((result = dupvm(rfp, req_fd, &procfd, &f)) != OK) { #if 0 /* Noisy diagnostic for mmap() by ld.so */ printf("vfs: dupvm failed\n"); #endif goto reqdone; } if(S_ISBLK(f->filp_vno->v_mode)) { assert(f->filp_vno->v_sdev != NO_DEV); job_m_out.VMV_DEV = f->filp_vno->v_sdev; job_m_out.VMV_INO = VMC_NO_INODE; job_m_out.VMV_SIZE_PAGES = LONG_MAX; } else { job_m_out.VMV_DEV = f->filp_vno->v_dev; job_m_out.VMV_INO = f->filp_vno->v_inode_nr; job_m_out.VMV_SIZE_PAGES = roundup(f->filp_vno->v_size, PAGE_SIZE)/PAGE_SIZE; } job_m_out.VMV_FD = procfd; result = OK; break; } case VMVFSREQ_FDCLOSE: { result = close_fd(fp, req_fd); if(result != OK) { printf("VFS: VM fd close for fd %d, %d (%d)\n", req_fd, fp->fp_endpoint, result); } break; } case VMVFSREQ_FDIO: { result = actual_lseek(fp, req_fd, SEEK_SET, offset, NULL); if(result == OK) { result = actual_read_write_peek(fp, PEEKING, req_fd, /* vir_bytes */ 0, length); } break; } default: panic("VFS: bad request code from VM\n"); break; } reqdone: if(f) unlock_filp(f); /* fp is VM still. */ assert(fp == vmf); job_m_out.VMV_ENDPOINT = ep; job_m_out.VMV_RESULT = result; job_m_out.VMV_REQID = req_id; /* Reply asynchronously as VM may not be able to receive * an ipc_sendnb() message. */ job_m_out.m_type = VM_VFS_REPLY; r = asynsend3(VM_PROC_NR, &job_m_out, 0); if(r != OK) printf("VFS: couldn't asynsend3() to VM\n"); /* VFS does not reply any further */ return SUSPEND; }