/*===========================================================================* * 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); }
static int cdev_ioctl(struct file *filp, unsigned int request, char *argp) { int status; dev_t device = filp->f_dev; unlock_filp(filp); signals_off(); status = (*cdevsw[major(device)].d_ioctl)(device, request, argp, GENFLAG(filp), curproc); if (status == 0) { #if 1 if (request == TIOCSCTTY) { {int ret = proc_controlt(-1,-1,(int)filp); assert(ret == 0);} } #endif } else { errno = status; status = -1; } signals_on(); /* HBXX - Race condition, can receive a signal during the return and next unlock_filp() */ lock_filp(filp); return status; }
int mmap_exec(u_int k, int envid, int execonly) { /* munmap all non-MAP_INHERIT regions */ struct Mmap *m2, *m = mmap_list.lh_first; if (!execonly) return 0; while (m) if (m->mmap_flags & MAP_INHERIT) { /* not implemented - need to set up a region of vm to mmap data */ assert(0); m = m->mmap_link.le_next; } else { m2 = m->mmap_link.le_next; assert(msync(m->mmap_addr, m->mmap_len, 0) == 0); if (m->mmap_filp) { lock_filp(m->mmap_filp); filp_refcount_dec(m->mmap_filp); if (filp_refcount_get(m->mmap_filp) == 0) { unlock_filp(m->mmap_filp); close_filp(m->mmap_filp); } else unlock_filp(m->mmap_filp); } m = m2; } return 0; }
/*===========================================================================* * 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_filp_gc * *===========================================================================*/ void *do_filp_gc(void *UNUSED(arg)) { struct filp *f; struct vnode *vp; for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { if (!(f->filp_state & FS_INVALIDATED)) continue; if (f->filp_mode == FILP_CLOSED || f->filp_vno == NULL) { /* File was already closed before gc could kick in */ assert(f->filp_count <= 0); f->filp_state &= ~FS_INVALIDATED; f->filp_count = 0; continue; } assert(f->filp_vno != NULL); vp = f->filp_vno; /* Synchronize with worker thread that might hold a lock on the vp */ lock_vnode(vp, VNODE_OPCL); unlock_vnode(vp); /* If garbage collection was invoked due to a failed device open * request, then common_open has already cleaned up and we have * nothing to do. */ if (!(f->filp_state & FS_INVALIDATED)) { continue; } /* If garbage collection was invoked due to a failed device close * request, the close_filp has already cleaned up and we have nothing * to do. */ if (f->filp_mode != FILP_CLOSED) { assert(f->filp_count == 0); f->filp_count = 1; /* So lock_filp and close_filp will do * their job */ lock_filp(f, VNODE_READ); close_filp(f); } f->filp_state &= ~FS_INVALIDATED; } thread_cleanup(NULL); return(NULL); }
int mmap_fork(u_int k, int envid, int NewPid) { /* increase the refcounts */ struct Mmap *m = mmap_list.lh_first; while (m) { if (m->mmap_filp) { lock_filp(m->mmap_filp); filp_refcount_inc(m->mmap_filp); unlock_filp(m->mmap_filp); } m = m->mmap_link.le_next; } return 0; }
static inline void close_filp(struct file *filp) { int fd; for (fd = NR_OPEN - 1; fd >= 0; fd--) if (__current->fd[fd] == NULL) { __current->fd[fd] = filp; break; } assert(fd >= 0); __current->cloexec_flag[fd] = 0; lock_filp(filp); filp_refcount_inc(filp); unlock_filp(filp); close(fd); }
static int cdev_write(struct file *filp, char *buffer, int nbyte, int blocking) { int status; dev_t dev = filp->f_dev; struct uio uio; struct iovec iov[4]; char buf[CLALLOCSZ*8]; int i; demand(filp, bogus filp); unlock_filp(filp); signals_off(); DPRINTF(CLU_LEVEL, ("cdev_write: filp: %08x offset: %qd nbyte: %d\n", (int)filp, filp->f_pos, nbyte)); assert(nbyte <= CLALLOCSZ*8); memcpy(buf,buffer,nbyte); iov[0].iov_base = buf; iov[0].iov_len = nbyte; uio.uio_iov = iov; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = nbyte; uio.uio_rw = UIO_WRITE; k0printf("Write: %d: ",uio.uio_resid); for (i = 0; i < uio.uio_resid; i++) k0printf(">%d (%c)",(unsigned int)buf[i],buf[i]); EnterCritical(); status = (*cdevsw[major(dev)].d_write)(dev, &uio, GENFLAG(filp)); ExitCritical(); k0printf("Read: %d: ",nbyte - uio.uio_resid); if (status == 0) { status = nbyte - uio.uio_resid; } else { errno = status; status = -1; } signals_on(); /* HBXX - Race condition, can receive a signal during the return and next unlock_filp() */ lock_filp(filp); return status; }
static int cdev_read(struct file *filp, char *buffer, int nbyte, int blocking) { int status; dev_t dev = filp->f_dev; struct uio uio; struct iovec iov[4]; demand(filp, bogus filp); DPRINTF(CLU_LEVEL, ("cdev_read: filp: %08x offset: %qd nbyte: %d\n", (int)filp, filp->f_pos, nbyte)); /* if (nbyte > CLALLOCSZ) {fprintf(stderr,"ncdev_read, warn large nbyte\n");} */ iov[0].iov_base = buffer; iov[0].iov_len = nbyte; uio.uio_iov = iov; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = nbyte; uio.uio_rw = UIO_READ; signals_off(); unlock_filp(filp); EnterCritical(); status = (*cdevsw[major(dev)].d_read)(dev, &uio, GENFLAG(filp)); ExitCritical(); signals_on(); k0printf("Read: %d: ",nbyte - uio.uio_resid); if (status == 0) { status = nbyte - uio.uio_resid; } else { errno = status; status = -1; } /* HBXX - Race condition, can receive a signal during the return and next unlock_filp() */ lock_filp(filp); #if 0 if (status >= 0) { extern void pr_uio(); kprintf("read(%d,%d) ",major(dev),minor(dev)); pr_uio(&uio); } #endif return status; }
void mmap_exit(void *arg) { /* munmap all regions */ struct Mmap *m2, *m = mmap_list.lh_first; while (m) { m2 = m->mmap_link.le_next; assert(msync(m->mmap_addr, m->mmap_len, 0) == 0); if (m->mmap_filp) { lock_filp(m->mmap_filp); filp_refcount_dec(m->mmap_filp); if (filp_refcount_get(m->mmap_filp) == 0) { unlock_filp(m->mmap_filp); close_filp(m->mmap_filp); } else unlock_filp(m->mmap_filp); } m = m2; } }
/*===========================================================================* * 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); }
/*===========================================================================* * free_proc * *===========================================================================*/ static void free_proc(int flags) { int i; register struct fproc *rfp; register struct filp *rfilp; register struct vnode *vp; dev_t dev; if (fp->fp_endpoint == NONE) panic("free_proc: already free"); if (fp_is_blocked(fp)) unpause(); /* Loop on file descriptors, closing any that are open. */ for (i = 0; i < OPEN_MAX; i++) { (void) close_fd(fp, i); } /* Release root and working directories. */ if (fp->fp_rd) { put_vnode(fp->fp_rd); fp->fp_rd = NULL; } if (fp->fp_wd) { put_vnode(fp->fp_wd); fp->fp_wd = NULL; } /* The rest of these actions is only done when processes actually exit. */ if (!(flags & FP_EXITING)) return; fp->fp_flags |= FP_EXITING; /* Check if any process is SUSPENDed on this driver. * If a driver exits, unmap its entries in the dmap table. * (unmapping has to be done after the first step, because the * dmap table is used in the first step.) */ unsuspend_by_endpt(fp->fp_endpoint); dmap_unmap_by_endpt(fp->fp_endpoint); worker_stop_by_endpt(fp->fp_endpoint); /* Unblock waiting threads */ vmnt_unmap_by_endpt(fp->fp_endpoint); /* Invalidate open files if this * was an active FS */ /* If a session leader exits and it has a controlling tty, then revoke * access to its controlling tty from all other processes using it. */ if ((fp->fp_flags & FP_SESLDR) && fp->fp_tty != 0) { dev = fp->fp_tty; for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if(rfp->fp_pid == PID_FREE) continue; if (rfp->fp_tty == dev) rfp->fp_tty = 0; for (i = 0; i < OPEN_MAX; i++) { if ((rfilp = rfp->fp_filp[i]) == NULL) continue; if (rfilp->filp_mode == FILP_CLOSED) continue; vp = rfilp->filp_vno; if (!S_ISCHR(vp->v_mode)) continue; if (vp->v_sdev != dev) continue; lock_filp(rfilp, VNODE_READ); (void) cdev_close(dev); /* Ignore any errors. */ /* FIXME: missing select check */ rfilp->filp_mode = FILP_CLOSED; unlock_filp(rfilp); } } } /* Exit done. Mark slot as free. */ fp->fp_endpoint = NONE; fp->fp_pid = PID_FREE; fp->fp_flags = FP_NOFLAGS; }
int munmap(void *addr, size_t len) { struct Mmap *m; struct mmap_ustruct *mus; void *nextaddr; size_t nextlen; OSCALLENTER(OSCALL_munmap); /* page-ify */ len += (((u_int)addr) & PGMASK); addr = (void*)PGROUNDDOWN((u_int)addr); len = PGROUNDUP(len); /* impossible to do what man page says! */ #if 0 if ((((u_int)addr) & PGMASK) || len < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } #endif if (len == 0) { OSCALLEXIT(OSCALL_munmap); return 0; } nextlen = len; do { /* get info on the to-be-freed region */ mus = (struct mmap_ustruct *)mregion_get_ustruct(addr); if (!mus) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } m = &(mus->m); if (addr+len > m->mmap_addr+m->mmap_len) len -= addr+len - (m->mmap_addr+m->mmap_len); /* something strange, shouldn't happen */ if (addr >= m->mmap_addr+m->mmap_len || addr+len <= m->mmap_addr) { OSCALLEXIT(OSCALL_munmap); return 0; } /* if completely freed */ if (addr <= m->mmap_addr && len >= m->mmap_len) { __vm_free_region((u_int)m->mmap_addr, m->mmap_len, CAP_ROOT); /* XXX - error check */ __free(m->mmap_addr); /* if wasn't __malloc'd then this will do nothing */ LIST_REMOVE(m, mmap_link); if (m->mmap_filp) { lock_filp(m->mmap_filp); filp_refcount_dec(m->mmap_filp); if (filp_refcount_get(m->mmap_filp) == 0) { unlock_filp(m->mmap_filp); close_filp(m->mmap_filp); } else unlock_filp(m->mmap_filp); } exos_pinned_free(mus); /* retore original handler to region */ if (mregion_alloc(addr, len, mus->oldmru) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } } /* if the end is freed */ else if (addr > m->mmap_addr && addr+len >= m->mmap_addr+m->mmap_len) { m->mmap_len = addr-m->mmap_addr; __vm_free_region((u_int)addr, len, CAP_ROOT); /* XXX - error check */ __free2(addr, 0); /* if wasn't __malloc'd then this will do nothing */ /* retore original handler to region */ if (mregion_alloc(addr, len, mus->oldmru) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } } /* if the beginning is freed */ else if (addr <= m->mmap_addr && addr+len < m->mmap_addr+m->mmap_len) { __vm_free_region((u_int)addr, len, CAP_ROOT); /* XXX - error check */ __free2(m->mmap_addr, addr+len - m->mmap_addr); m->mmap_len = m->mmap_addr+m->mmap_len - (addr+len); m->mmap_addr = addr+len; /* retore original handler to region */ if (mregion_alloc(addr, len, mus->oldmru) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } } /* if the middle is freed */ else { __vm_free_region((u_int)addr, len, CAP_ROOT); /* XXX - error check */ /* retore original handler to region */ if (mregion_alloc(addr, len, mus->oldmru) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } assert(0); /* XXX - too much trouble right now */ } nextaddr = addr+len; nextlen -= len; addr = nextaddr; len = nextlen; } while (len > 0); OSCALLEXIT(OSCALL_munmap); return 0; }
void *mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset) { u_int pageoff; caddr_t ret; off_t pos = offset; size_t size = len; struct Mmap *m; struct stat sb; struct file *filp; struct mmap_ustruct *mus; OSCALLENTER(OSCALL_mmap); if (!mmap_inited) mmap_init(); /* if given a bad fd then return */ if (fd != -1 && fstat (fd, &sb) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t )-1; } if ((flags & MAP_COPY) && (flags & MAP_ANON)) flags &= ~MAP_COPY; /* OpenBSD 2.1 code */ /* * Align the file position to a page boundary, * and save its page offset component. */ pageoff = (pos & PGMASK); pos -= pageoff; /* Adjust size for rounding (on both ends). */ size += pageoff; /* low end... */ size = PGROUNDUP(size); /* hi end */ /* Do not allow mappings that cause address wrap... */ if ((ssize_t)size < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* * Check for illegal addresses. Watch out for address wrap... */ if (flags & MAP_FIXED) { /* * The specified address must have the same remainder * as the file offset taken modulo NBPG, so it * should be aligned after adjustment by pageoff. */ addr -= pageoff; if ((u_int)addr & PGMASK) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* Address range must be all in user VM space. */ if (UTOP > 0 && (u_int)addr + size > UTOP) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } if ((u_int)addr > (u_int)addr + size) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } } if ((flags & MAP_ANON) == 0) { if (fd < 0 || fd > NR_OPEN || __current->fd[fd] == NULL) { errno = EBADF; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* * XXX hack to handle use of /dev/zero to map anon * memory (ala SunOS). */ if (S_ISCHR(__current->fd[fd]->f_mode) && mmap_iszerodev(__current->fd[fd]->f_dev)) { flags |= MAP_ANON; goto is_anon; } /* * Only files and cdevs are mappable, and cdevs does not * provide private mappings of any kind. */ if (!S_ISREG(__current->fd[fd]->f_mode) && (!S_ISCHR(__current->fd[fd]->f_mode) || (flags & (MAP_PRIVATE|MAP_COPY)))) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* * Ensure that file and memory protections are * compatible. Note that we only worry about * writability if mapping is shared; in this case, * current and max prot are dictated by the open file. * XXX use the vnode instead? Problem is: what * credentials do we use for determination? * What if proc does a setuid? */ if (((__current->fd[fd]->f_flags & O_ACCMODE) == O_WRONLY) && (prot & PROT_READ)) { errno = EACCES; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* * If we are sharing potential changes (either via MAP_SHARED * or via the implicit sharing of character device mappings), * and we are trying to get write permission although we * opened it without asking for it, bail out. */ if (((flags & MAP_SHARED) != 0 || S_ISCHR(__current->fd[fd]->f_mode)) && ((__current->fd[fd]->f_flags & O_ACCMODE) == O_RDONLY) && (prot & PROT_WRITE) != 0) { errno = EACCES; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } } else { /* * (flags & MAP_ANON) == TRUE * Mapping blank space is trivial. */ if (fd != -1) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } is_anon: pos = 0; } if (size == 0) { OSCALLEXIT(OSCALL_mmap); return addr; } if (fd >= 0) filp = __current->fd[fd]; else filp = NULL; if ((flags & MAP_FIXED) == 0) { addr = __malloc(size); if (addr == NULL) { __free(addr); errno = ENOMEM; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } } mus = exos_pinned_malloc(sizeof(*mus)); if (mus == NULL) { if ((flags & MAP_FIXED) == 0) __free(addr); errno = ENOMEM; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } m = &(mus->m); m->mmap_addr = addr; m->mmap_len = size; m->mmap_prot = prot; m->mmap_flags = flags; m->mmap_offset = pos; m->mmap_filp = filp; m->mmap_dev = ((fd != -1) ? sb.st_dev : 0); LIST_INSERT_HEAD (&mmap_list, m, mmap_link); mus->mru.handler = mmap_fault_handler; mus->oldmru = mregion_get_ustruct(addr); /* XXX - check return value */ if (__vm_free_region((u_int)addr, size, 0) < 0 || mregion_alloc(addr, size, (struct mregion_ustruct*)mus) != 0) { if ((flags & MAP_FIXED) == 0) __free(addr); exos_pinned_free(mus); errno = ENOMEM; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } if (filp) { lock_filp(filp); filp_refcount_inc(filp); unlock_filp(filp); } if (flags & MAP_COPY) ret = __mmap(addr, size, prot, flags, fd, pos, 0, __envid); else ret = addr + pageoff; OSCALLEXIT(OSCALL_mmap); return ret; }
static int pty_read(struct file *filp, char *buffer, int nbyte, int blocking) { struct pty *pty; struct pipe *pipeb; #if 0 int final = 0,len; #else int total; #endif int foundnl,master; demand(filp, bogus filp); DPRINTF(CLU_LEVEL, ("pty_read: filp: %08x offset: %qd nbyte: %d\n", (int)filp, filp->f_pos, nbyte)); pty = GETPTYP(filp); /* lock_pty(pty); */ master = filp->f_pos; demand (master == 1 || master == 0,master flag set improperly); pipeb = &(pty->pipe[master]); if (!(PTY_BUSY(1 - master,pty)) && pipeb->length == PTY_BUFFER_SIZE) { /* someone closed the other end, and nothing to read */ return 0; } if (pipeb->length == PTY_BUFFER_SIZE && CHECKNB(filp)) { errno = EWOULDBLOCK; return -1; } while(pipeb->length == PTY_BUFFER_SIZE) { /* we block if cant read anything */ unlock_filp(filp); wk_waitfor_value_lt (&pipeb->length, PTY_BUFFER_SIZE, 0); #if 0 yield(-1); #endif lock_filp(filp); } if (!(PTY_BUSY(1 - master,pty)) && pipeb->length == PTY_BUFFER_SIZE) { /* someone closed the other end, and nothing to read */ return 0; } lock_pipepty(pipeb); if (master) { /* master pty does not have line discipline */ total = piperead(pipeb,buffer,nbyte,0,&foundnl); } else { /* slave pty have line discipline */ total = piperead(pipeb,buffer,nbyte,1,&foundnl); } unlock_pipepty(pipeb); /* unlock_pty(pty); */ /* if (master) pr_ptyp(pty); */ return total; }