/*===========================================================================* * do_pending_pipe * *===========================================================================*/ static void *do_pending_pipe(void *arg) { int r, op; struct job my_job; struct filp *f; tll_access_t locktype; my_job = *((struct job *) arg); fp = my_job.j_fp; lock_proc(fp, 1 /* force lock */); f = scratch(fp).file.filp; assert(f != NULL); scratch(fp).file.filp = NULL; locktype = (job_call_nr == READ) ? VNODE_READ : VNODE_WRITE; op = (job_call_nr == READ) ? READING : WRITING; lock_filp(f, locktype); r = rw_pipe(op, who_e, f, scratch(fp).io.io_buffer, scratch(fp).io.io_nbytes); if (r != SUSPEND) /* Do we have results to report? */ reply(fp->fp_endpoint, r); unlock_filp(f); thread_cleanup(fp); return(NULL); }
/*===========================================================================* * do_pending_pipe * *===========================================================================*/ static void do_pending_pipe(void) { int r, op; struct filp *f; tll_access_t locktype; f = fp->fp_filp[fp->fp_fd]; assert(f != NULL); locktype = (job_call_nr == VFS_READ) ? VNODE_READ : VNODE_WRITE; op = (job_call_nr == VFS_READ) ? READING : WRITING; lock_filp(f, locktype); r = rw_pipe(op, who_e, f, fp->fp_io_buffer, fp->fp_io_nbytes); if (r != SUSPEND) { /* Do we have results to report? */ /* Process is writing, but there is no reader. Send a SIGPIPE signal. * This should match the corresponding code in read_write(). */ if (r == EPIPE && op == WRITING) { if (!(f->filp_flags & O_NOSIGPIPE)) sys_kill(fp->fp_endpoint, SIGPIPE); } replycode(fp->fp_endpoint, r); } unlock_filp(f); }
/*===========================================================================* * do_pending_pipe * *===========================================================================*/ static void do_pending_pipe(void) { vir_bytes buf; size_t nbytes, cum_io; int r, op, fd; struct filp *f; tll_access_t locktype; assert(fp->fp_blocked_on == FP_BLOCKED_ON_NONE); /* * We take all our needed resumption state from the m_in message, which is * filled by unblock(). Since this is an internal resumption, there is no * need to perform extensive checks on the message fields. */ fd = job_m_in.m_lc_vfs_readwrite.fd; buf = job_m_in.m_lc_vfs_readwrite.buf; nbytes = job_m_in.m_lc_vfs_readwrite.len; cum_io = job_m_in.m_lc_vfs_readwrite.cum_io; f = fp->fp_filp[fd]; assert(f != NULL); locktype = (job_call_nr == VFS_READ) ? VNODE_READ : VNODE_WRITE; op = (job_call_nr == VFS_READ) ? READING : WRITING; lock_filp(f, locktype); r = rw_pipe(op, who_e, f, job_call_nr, fd, buf, nbytes, cum_io); if (r != SUSPEND) { /* Do we have results to report? */ /* Process is writing, but there is no reader. Send a SIGPIPE signal. * This should match the corresponding code in read_write(). */ if (r == EPIPE && op == WRITING) { if (!(f->filp_flags & O_NOSIGPIPE)) sys_kill(fp->fp_endpoint, SIGPIPE); } replycode(fp->fp_endpoint, r); } unlock_filp(f); }
/*===========================================================================* * get_work * *===========================================================================*/ PRIVATE void get_work() { /* Normally wait for new input. However, if 'reviving' is * nonzero, a suspended process must be awakened. */ int r, found_one, fd_nr; struct filp *f; register struct fproc *rp; while (reviving != 0) { found_one= FALSE; /* Revive a suspended process. */ for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) if (rp->fp_pid != PID_FREE && rp->fp_revived == REVIVING) { int blocked_on = rp->fp_blocked_on; found_one= TRUE; who_p = (int)(rp - fproc); who_e = rp->fp_endpoint; call_nr = rp->fp_block_callnr; m_in.fd = rp->fp_block_fd; m_in.buffer = rp->fp_buffer; m_in.nbytes = rp->fp_nbytes; /*no longer hanging*/ rp->fp_blocked_on = FP_BLOCKED_ON_NONE; rp->fp_revived = NOT_REVIVING; reviving--; /* This should be a pipe I/O, not a device I/O. * If it is, it'll 'leak' grants. */ assert(!GRANT_VALID(rp->fp_grant)); if (blocked_on == FP_BLOCKED_ON_PIPE) { fp= rp; fd_nr= rp->fp_block_fd; f= get_filp(fd_nr); assert(f != NULL); r= rw_pipe((call_nr == READ) ? READING : WRITING, who_e, fd_nr, f, rp->fp_buffer, rp->fp_nbytes); if (r != SUSPEND) reply(who_e, r); continue; } return; } if (!found_one) panic("get_work couldn't revive anyone"); } for(;;) { int r; /* Normal case. No one to revive. */ if ((r=sef_receive(ANY, &m_in)) != OK) panic("fs sef_receive error: %d", r); who_e = m_in.m_source; who_p = _ENDPOINT_P(who_e); /* * negative who_p is never used to access the fproc array. Negative numbers * (kernel tasks) are treated in a special way */ if(who_p >= (int)(sizeof(fproc) / sizeof(struct fproc))) panic("receive process out of range: %d", who_p); if(who_p >= 0 && fproc[who_p].fp_endpoint == NONE) { printf("FS: ignoring request from %d, endpointless slot %d (%d)\n", m_in.m_source, who_p, m_in.m_type); continue; } if(who_p >= 0 && fproc[who_p].fp_endpoint != who_e) { if(fproc[who_p].fp_endpoint == NONE) { printf("slot unknown even\n"); } printf("FS: receive endpoint inconsistent (source %d, who_p %d, stored ep %d, who_e %d).\n", m_in.m_source, who_p, fproc[who_p].fp_endpoint, who_e); #if 0 panic("FS: inconsistent endpoint "); #endif continue; } call_nr = m_in.m_type; return; } }
/*===========================================================================* * read_write * *===========================================================================*/ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, vir_bytes buf, size_t size, endpoint_t for_e) { register struct vnode *vp; off_t position, res_pos; unsigned int cum_io, cum_io_incr, res_cum_io; int op, r; dev_t dev; position = f->filp_pos; vp = f->filp_vno; r = OK; cum_io = 0; assert(rw_flag == READING || rw_flag == WRITING || rw_flag == PEEKING); if (size > SSIZE_MAX) return(EINVAL); op = (rw_flag == READING ? CDEV_READ : CDEV_WRITE); if (S_ISFIFO(vp->v_mode)) { /* Pipes */ if (rfp->fp_cum_io_partial != 0) { panic("VFS: read_write: fp_cum_io_partial not clear"); } if(rw_flag == PEEKING) { printf("read_write: peek on pipe makes no sense\n"); return EINVAL; } r = rw_pipe(rw_flag, for_e, f, buf, size); } else if (S_ISCHR(vp->v_mode)) { /* Character special files. */ if(rw_flag == PEEKING) { printf("read_write: peek on char device makes no sense\n"); return EINVAL; } if (vp->v_sdev == NO_DEV) panic("VFS: read_write tries to access char dev NO_DEV"); dev = vp->v_sdev; r = cdev_io(op, dev, for_e, buf, position, size, f->filp_flags); if (r >= 0) { /* This should no longer happen: all calls are asynchronous. */ printf("VFS: I/O to device %llx succeeded immediately!?\n", dev); cum_io = r; position += r; r = OK; } else if (r == SUSPEND) { /* FIXME: multiple read/write operations on a single filp * should be serialized. They currently aren't; in order to * achieve a similar effect, we optimistically advance the file * position here. This works under the following assumptions: * - character drivers that use the seek position at all, * expose a view of a statically-sized range of bytes, i.e., * they are basically byte-granular block devices; * - if short I/O or an error is returned, all subsequent calls * will return (respectively) EOF and an error; * - the application never checks its own file seek position, * or does not care that it may end up having seeked beyond * the number of bytes it has actually read; * - communication to the character driver is FIFO (this one * is actually true! whew). * Many improvements are possible here, but in the end, * anything short of queuing concurrent operations will be * suboptimal - so we settle for this hack for now. */ position += size; } } else if (S_ISBLK(vp->v_mode)) { /* Block special files. */ if (vp->v_sdev == NO_DEV) panic("VFS: read_write tries to access block dev NO_DEV"); lock_bsf(); if(rw_flag == PEEKING) { r = req_bpeek(vp->v_bfs_e, vp->v_sdev, position, size); } else { r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, position, size, buf, rw_flag, &res_pos, &res_cum_io); if (r == OK) { position = res_pos; cum_io += res_cum_io; } } unlock_bsf(); } else { /* Regular files */ if (rw_flag == WRITING) { /* Check for O_APPEND flag. */ if (f->filp_flags & O_APPEND) position = vp->v_size; } /* Issue request */ if(rw_flag == PEEKING) { r = req_peek(vp->v_fs_e, vp->v_inode_nr, position, size); } else { off_t new_pos; r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position, rw_flag, for_e, buf, size, &new_pos, &cum_io_incr); if (r >= 0) { position = new_pos; cum_io += cum_io_incr; } } } /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (S_ISREG(vp->v_mode) || S_ISDIR(vp->v_mode)) { if (position > vp->v_size) { vp->v_size = position; } } } f->filp_pos = position; if (r == EPIPE && rw_flag == WRITING) { /* Process is writing, but there is no reader. Tell the kernel to * generate s SIGPIPE signal. */ if (!(f->filp_flags & O_NOSIGPIPE)) { sys_kill(rfp->fp_endpoint, SIGPIPE); } } if (r == OK) { return(cum_io); } return(r); }