/* * MPSAFE */ static int vn_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) { struct vnode *vp; int error, ioflag; KASSERT(uio->uio_td == curthread, ("uio_td %p is not p %p", uio->uio_td, curthread)); vp = (struct vnode *)fp->f_data; ioflag = IO_UNIT; if (vp->v_type == VREG && ((fp->f_flag & O_APPEND) || (flags & O_FAPPEND))) { ioflag |= IO_APPEND; } if (flags & O_FBLOCKING) { /* ioflag &= ~IO_NDELAY; */ } else if (flags & O_FNONBLOCKING) { ioflag |= IO_NDELAY; } else if (fp->f_flag & FNONBLOCK) { ioflag |= IO_NDELAY; } if (fp->f_flag & O_DIRECT) { ioflag |= IO_DIRECT; } if (flags & O_FASYNCWRITE) { /* ioflag &= ~IO_SYNC; */ } else if (flags & O_FSYNCWRITE) { ioflag |= IO_SYNC; } else if (fp->f_flag & O_FSYNC) { ioflag |= IO_SYNC; } if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)) ioflag |= IO_SYNC; if ((flags & O_FOFFSET) == 0) uio->uio_offset = vn_get_fpf_offset(fp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); ioflag |= sequential_heuristic(uio, fp); error = VOP_WRITE(vp, uio, ioflag, cred); fp->f_nextoff = uio->uio_offset; vn_unlock(vp); if ((flags & O_FOFFSET) == 0) vn_set_fpf_offset(fp, uio->uio_offset); return (error); }
/* * union_write(struct vnode *a_vp, struct uio *a_uio, int a_ioflag, * struct ucred *a_cred) */ static int union_write(struct vop_read_args *ap) { struct union_node *un = VTOUNION(ap->a_vp); struct thread *td = ap->a_uio->uio_td; struct vnode *uppervp; int error; if ((uppervp = union_lock_upper(un, td)) == NULLVP) panic("union: missing upper layer in write"); /* * Since our VM pages are associated with our vnode rather then * the real vnode, and since we do not run our reads and writes * through our own VM cache, we have a VM/VFS coherency problem. * We solve them by invalidating or flushing the associated VM * pages prior to allowing a normal read or write to occur. * * VM-backed writes (UIO_NOCOPY) have to be converted to normal * writes because we are not cache-coherent. Normal writes need * to be made coherent with our VM-backing store, which we do by * first flushing any dirty VM pages associated with the write * range, and then destroying any clean VM pages associated with * the write range. */ if (ap->a_uio->uio_segflg == UIO_NOCOPY) { ap->a_uio->uio_segflg = UIO_SYSSPACE; } else if (ap->a_vp->v_flag & VOBJBUF) { union_vm_coherency(ap->a_vp, ap->a_uio, 1); } error = VOP_WRITE(uppervp, ap->a_uio, ap->a_ioflag, ap->a_cred); /* * the size of the underlying object may be changed by the * write. */ if (error == 0) { off_t cur = ap->a_uio->uio_offset; if (cur > un->un_uppersz) union_newsize(ap->a_vp, cur, VNOVAL); } union_unlock_upper(uppervp, td); return (error); }
/* * Read from the controlling terminal (/dev/tty). The tty is refed as * of the cttyvp(), but the ref can get ripped out from under us if * the controlling terminal is revoked while we are blocked on the lock, * so use vget() instead of vn_lock(). */ static int cttywrite(struct dev_write_args *ap) { struct proc *p = curproc; struct vnode *ttyvp; int error; KKASSERT(p); ttyvp = cttyvp(p); if (ttyvp == NULL) return (EIO); if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) { error = VOP_WRITE(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED); vput(ttyvp); } return (error); }
static int swap_file_write(struct chip_swap *swap, struct block_state *blk_state) { struct block_space *blk_space; struct thread *td; struct mount *mp; struct vnode *vp; struct uio auio; struct iovec aiov; if (swap == NULL || blk_state == NULL) return (-1); blk_space = blk_state->blk_sp; if (blk_state->offset == -1) { blk_state->offset = swap->swap_offset; swap->swap_offset += swap->blk_size; } nand_debug(NDBG_SIM,"saving %p[%p] at %x\n", blk_space, blk_space->blk_ptr, blk_state->offset); bzero(&aiov, sizeof(aiov)); bzero(&auio, sizeof(auio)); aiov.iov_base = blk_space->blk_ptr; aiov.iov_len = swap->blk_size; td = curthread; vp = swap->swap_vp; auio.uio_iov = &aiov; auio.uio_offset = blk_state->offset; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_iovcnt = 1; auio.uio_resid = swap->blk_size; auio.uio_td = td; vn_start_write(vp, &mp, V_WAIT); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); VOP_WRITE(vp, &auio, IO_UNIT, swap->swap_cred); VOP_UNLOCK(vp, 0); vn_finished_write(mp); return (0); }
/* * Update the disk quota in the quota file. */ static int ufs_dqsync(struct vnode *vp, struct ufs_dquot *dq) { struct vnode *dqvp; struct iovec aiov; struct uio auio; int error; if (dq == NODQUOT) panic("dqsync: dquot"); if ((dq->dq_flags & DQ_MOD) == 0) return (0); if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP) panic("dqsync: file"); if (vp != dqvp) vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY); while (dq->dq_flags & DQ_LOCK) { dq->dq_flags |= DQ_WANT; (void) tsleep((caddr_t)dq, 0, "dqsync", 0); if ((dq->dq_flags & DQ_MOD) == 0) { if (vp != dqvp) vn_unlock(dqvp); return (0); } } dq->dq_flags |= DQ_LOCK; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; aiov.iov_base = (caddr_t)&dq->dq_dqb; aiov.iov_len = sizeof (struct ufs_dqblk); auio.uio_resid = sizeof (struct ufs_dqblk); auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct ufs_dqblk)); auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_td = NULL; error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]); if (auio.uio_resid && error == 0) error = EIO; if (dq->dq_flags & DQ_WANT) wakeup((caddr_t)dq); dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT); if (vp != dqvp) vn_unlock(dqvp); return (error); }
int smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount, cred_t *cr) { int error; *lcount = uiop->uio_resid; uiop->uio_llimit = MAXOFFSET_T; (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct); VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); *lcount -= uiop->uio_resid; return (error); }
int swap_out(paddr_t paddr, int swap_index) { int result; struct uio u; // struct vnode *swap_vnode; result = vfs_open(SWAP_DEVICE, O_RDWR, &swap_vnode); mk_kuio(&u, paddr, PAGE_SIZE, swap_index * PAGE_SIZE, UIO_WRITE); result = VOP_WRITE(swap_vnode, &u); if (result) { return result; } vfs_close(swap_vnode); return 0; }
static void swaponepagein(int idx, struct addrspace* as) { (void) as; // 3. clear their tlb entries if present TODO cm_setEntryDirtyState(COREMAP(idx),true); struct page* pg = findPageFromCoreMap(COREMAP(idx), idx); int spl = splhigh(); int tlbpos = tlb_probe(pg->pt_pagebase * PAGE_SIZE, 0); if (tlbpos >= 0) { tlb_write(TLBHI_INVALID(tlbpos), TLBLO_INVALID(), tlbpos); } else { //kprintf("was not on tlb\n"); } splx(spl); int swapPageindex = getOneSwapPage(); kprintf("Swap in :\tswap= %x,\tpage=%x \n",swapPageindex,pg->pt_virtbase); //kprintf("Swap in page Vaddr = %x\n", pg->pt_virtbase); struct iovec iov; struct uio kuio; iov.iov_kbase = (void*) PADDR_TO_KVADDR(cm_getEntryPaddr(idx)); iov.iov_len = PAGE_SIZE; // length of the memory space kuio.uio_iov = &iov; kuio.uio_iovcnt = 1; kuio.uio_resid = PAGE_SIZE; // amount to write to the file kuio.uio_space = NULL; kuio.uio_offset = swap_map[swapPageindex].se_paddr * PAGE_SIZE; kuio.uio_segflg = UIO_SYSSPACE; kuio.uio_rw = UIO_WRITE; //kprintf("before write \n"); // 4. write them to disk spinlock_release(&coremap_lock); int result = VOP_WRITE(swap_vnode, &kuio); spinlock_acquire(&coremap_lock); if (result) { // release lock on the vnode panic("WRITE FAILED!\n"); return; } cm_setEntryDirtyState(COREMAP(idx),false); //kprintf("write complete\n"); pg->pt_state = PT_STATE_SWAPPED; pg->pt_pagebase = swap_map[swapPageindex].se_paddr; }
static int unionfs_write(void *v) { struct vop_write_args *ap = v; int error; struct unionfs_node *unp; struct vnode *tvp; /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */ unp = VTOUNIONFS(ap->a_vp); tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */ return (error); }
int write(int fd, userptr_t buf, size_t buflen, int *err) { int ret; if ( fd < 0 || fd > OPEN_MAX) { *err = EBADF; return -1; } if (curthread->ft[fd] == NULL) { *err = EBADF; return -1; } if (buf == NULL) { *err = EFAULT; return -1; } lock_acquire(curthread->ft[fd]->lock); struct iovec iov; struct uio uio; iov.iov_ubase = buf; iov.iov_len = buflen; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = curthread->ft[fd]->offset; uio.uio_resid = buflen; uio.uio_segflg = UIO_USERSPACE; uio.uio_space = curthread->t_addrspace; uio.uio_rw=UIO_WRITE; if((ret = VOP_WRITE(curthread->ft[fd]->vn,&uio))!=0) { *err = ret; return -1; } int diff = uio.uio_offset - curthread->ft[fd]->offset ; curthread->ft[fd]->offset=uio.uio_offset; lock_release(curthread->ft[fd]->lock); *err=0; return diff; }
static int zfsfuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { file_info_t *info = (file_info_t *)(uintptr_t) fi->fh; vnode_t *vp = info->vp; ASSERT(vp != NULL); ASSERT(VTOZ(vp) != NULL); ASSERT(VTOZ(vp)->z_id == ino); vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); iovec_t iovec; uio_t uio; uio.uio_iov = &iovec; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_fmode = 0; uio.uio_llimit = RLIM64_INFINITY; iovec.iov_base = (void *) buf; iovec.iov_len = size; uio.uio_resid = iovec.iov_len; uio.uio_loffset = off; cred_t cred; zfsfuse_getcred(req, &cred); int error = VOP_WRITE(vp, &uio, info->flags, &cred, NULL); ZFS_EXIT(zfsvfs); if(!error) { /* When not using direct_io, we must always write 'size' bytes */ VERIFY(uio.uio_resid == 0); fuse_reply_write(req, size - uio.uio_resid); } return error; }
/* * swap_io: Does one swap I/O. Panics on failure. * * Synchronization: none specifically. The physical page should be * marked "pinned" (locked) so it won't be touched by other people. */ static void swap_io(paddr_t pa, off_t swapaddr, enum uio_rw rw) { struct iovec iov; struct uio u; vaddr_t va; int result; KASSERT(lock_do_i_hold(global_paging_lock)); KASSERT(pa != INVALID_PADDR); KASSERT(swapaddr % PAGE_SIZE == 0); KASSERT(coremap_pageispinned(pa)); KASSERT(bitmap_isset(swapmap, swapaddr / PAGE_SIZE)); va = coremap_map_swap_page(pa); uio_kinit(&iov, &u, (char *)va, PAGE_SIZE, swapaddr, rw); if (rw==UIO_READ) { result = VOP_READ(swapstore, &u); } else { result = VOP_WRITE(swapstore, &u); } coremap_unmap_swap_page(va, pa); if (result==EIO) { panic("swap: EIO on swapfile (offset %ld)\n", (long)swapaddr); } else if (result==EINVAL) { panic("swap: EINVAL from swapfile (offset %ld)\n", (long)swapaddr); } else if (result) { panic("swap: Error %d from swapfile (offset %ld)\n", result, (long)swapaddr); } }
int sys_write(int filehandle, userptr_t buf, size_t size, int *retval) { struct uio io; int r; r = check_fd_access(filehandle, curthread->t_fdt, F_WRITE); if (r) return r; mk_uio(&io, buf, size, curthread->t_fdt->fd[filehandle]->fp, UIO_WRITE); r = VOP_WRITE(curthread->t_fdt->fd[filehandle]->vn, &io); if (r) { return r; } *retval = io.uio_offset - curthread->t_fdt->fd[filehandle]->fp; curthread->t_fdt->fd[filehandle]->fp = io.uio_offset; return 0; }
STATIC inline ssize_t __xfs_file_write( struct kiocb *iocb, const char __user *buf, int ioflags, size_t count, loff_t pos) { struct iovec iov = {(void __user *)buf, count}; struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; vnode_t *vp = vn_from_inode(inode); ssize_t rval; BUG_ON(iocb->ki_pos != pos); if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval); return rval; }
int sys_write(int fd, const void *buf, size_t nbytes) { struct sys_filemapping *mpg; struct uio ku; char *kbuf; int result; mpg = resolvefd(fd); if (mpg==NULL) return -EBADF; /* check flags */ if (!((mpg->flags & O_WRONLY) || (mpg->flags & O_RDWR))) return -1; kbuf = (char *) kmalloc(nbytes); if (kbuf==NULL) return -ENOMEM; result = copyin(buf, kbuf, nbytes); if (result) { kfree(kbuf); return -result; } mk_kuio(&ku, kbuf, nbytes, mpg->offset, UIO_WRITE); result = VOP_WRITE(mpg->vn, &ku); if (result) return -result; mpg->offset += nbytes; kfree(kbuf); return nbytes; }
int _write(int filehandle,void *buf, size_t size,int* retval){ if(filehandle < 0 || filehandle > MAX_FILE_FILETAB){ *retval = -1; return EBADF; } if(curthread->fdesc[filehandle] == NULL) { *retval = -1; return EBADF; } if(! (curthread->fdesc[filehandle]->flags != O_WRONLY || curthread->fdesc[filehandle]->flags!=O_RDWR) ) { *retval = -1; return EINVAL; } lock_acquire(curthread->fdesc[filehandle]->f_lock); struct uio writeuio; struct iovec iov; size_t size1; char *buffer = (char*)kmalloc(size); copyinstr((userptr_t)buf,buffer,strlen(buffer),&size1); uio_kinit(&iov, &writeuio, (void*) buffer, size, curthread->fdesc[filehandle]->offset, UIO_WRITE); int result=VOP_WRITE(curthread->fdesc[filehandle]->vnode, &writeuio); if (result) { kfree(buffer); lock_release(curthread->fdesc[filehandle]->f_lock); *retval = -1; return result; } curthread->fdesc[filehandle]->offset = writeuio.uio_offset; *retval = size - writeuio.uio_resid; kfree(buffer); lock_release(curthread->fdesc[filehandle]->f_lock); return 0; }
int sys_write(int fdesc,userptr_t ubuf,unsigned int nbytes,int *retval) { struct iovec iov; struct uio u; int res; //DEBUG(DB_SYSCALL,"Syscall: write(%d,%x,%d)\n",fdesc,(unsigned int)ubuf,nbytes); /* only stdout and stderr writes are currently implemented */ if (!((fdesc==STDOUT_FILENO)||(fdesc==STDERR_FILENO))) { return EUNIMP; } KASSERT(curproc != NULL); KASSERT(curproc->console != NULL); KASSERT(curproc->p_addrspace != NULL); /* set up a uio structure to refer to the user program's buffer (ubuf) */ iov.iov_ubase = ubuf; iov.iov_len = nbytes; u.uio_iov = &iov; u.uio_iovcnt = 1; u.uio_offset = 0; /* not needed for the console */ u.uio_resid = nbytes; u.uio_segflg = UIO_USERSPACE; u.uio_rw = UIO_WRITE; u.uio_space = curproc->p_addrspace; res = VOP_WRITE(curproc->console,&u); if (res) { return res; } /* pass back the number of bytes actually written */ *retval = nbytes - u.uio_resid; KASSERT(*retval >= 0); return 0; }
STATIC inline ssize_t __xfs_file_writev( struct file *file, const struct iovec *iov, int ioflags, unsigned long nr_segs, loff_t *ppos) { struct inode *inode = file->f_mapping->host; vnode_t *vp = vn_from_inode(inode); struct kiocb kiocb; ssize_t rval; init_sync_kiocb(&kiocb, file); kiocb.ki_pos = *ppos; if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval); *ppos = kiocb.ki_pos; return rval; }
int write_page(void* kbuf, off_t* newoffset, int index){ (void)index; struct iovec iovectr; struct uio uiovar; off_t offset; KASSERT(sw_vn != NULL); offset = index * PAGE_SIZE; uio_kinit(&iovectr, &uiovar, kbuf, PAGE_SIZE, offset, UIO_WRITE); spinlock_release(&cm_lock); int ret = VOP_WRITE(sw_vn, &uiovar); spinlock_acquire(&cm_lock); if(ret){ return 1; } *newoffset = offset; return 0; }
/* * Package up an I/O request on a vnode into a uio and do it. * * MPSAFE */ int vn_rdwr(enum uio_rw rw, struct vnode *vp, caddr_t base, int len, off_t offset, enum uio_seg segflg, int ioflg, struct ucred *cred, int *aresid) { struct uio auio; struct iovec aiov; struct ccms_lock ccms_lock; int error; if ((ioflg & IO_NODELOCKED) == 0) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); auio.uio_iov = &aiov; auio.uio_iovcnt = 1; aiov.iov_base = base; aiov.iov_len = len; auio.uio_resid = len; auio.uio_offset = offset; auio.uio_segflg = segflg; auio.uio_rw = rw; auio.uio_td = curthread; ccms_lock_get_uio(&vp->v_ccms, &ccms_lock, &auio); if (rw == UIO_READ) { error = VOP_READ(vp, &auio, ioflg, cred); } else { error = VOP_WRITE(vp, &auio, ioflg, cred); } ccms_lock_put(&vp->v_ccms, &ccms_lock); if (aresid) *aresid = auio.uio_resid; else if (auio.uio_resid && error == 0) error = EIO; if ((ioflg & IO_NODELOCKED) == 0) vn_unlock(vp); return (error); }
static void swap_io( paddr_t paddr, off_t offset, enum uio_rw op ) { struct iovec iov; struct uio uio; vaddr_t vaddr; int res; KASSERT( lock_do_i_hold( giant_paging_lock ) ); KASSERT( curthread->t_vmp_count == 0 || curthread->t_clone ); //get the virtual address. vaddr = PADDR_TO_KVADDR( paddr ); //init the uio request. uio_kinit( &iov, &uio, (char *)vaddr, PAGE_SIZE, offset, op ); //perform the request. res = (op == UIO_READ) ? VOP_READ( vn_sw, &uio ) : VOP_WRITE( vn_sw, &uio ); //if we have a problem ... bail. if( res ) panic( "swap_io: failed to perform a VOP." ); }
/* * Package up an I/O request on a vnode into a uio and do it. */ int vn_rdwr(enum uio_rw rw, struct vnode *vp, caddr_t base, int len, off_t offset, enum uio_seg segflg, int ioflg, struct ucred *cred, size_t *aresid, struct proc *p) { struct uio auio; struct iovec aiov; int error; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; aiov.iov_base = base; aiov.iov_len = len; auio.uio_resid = len; auio.uio_offset = offset; auio.uio_segflg = segflg; auio.uio_rw = rw; auio.uio_procp = p; if ((ioflg & IO_NODELOCKED) == 0) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (rw == UIO_READ) { error = VOP_READ(vp, &auio, ioflg, cred); } else { error = VOP_WRITE(vp, &auio, ioflg, cred); } if ((ioflg & IO_NODELOCKED) == 0) VOP_UNLOCK(vp, 0, p); if (aresid) *aresid = auio.uio_resid; else if (auio.uio_resid && error == 0) error = EIO; return (error); }
/* * This is now called from local media FS's to operate against their * own vnodes if they fail to implement VOP_PUTPAGES. * * This is typically called indirectly via the pageout daemon and * clustering has already typically occurred, so in general we ask the * underlying filesystem to write the data out asynchronously rather * then delayed. */ int vnode_pager_generic_putpages(struct vnode *vp, vm_page_t *ma, int bytecount, int flags, int *rtvals) { int i; vm_object_t object; vm_page_t m; int count; int maxsize, ncount; vm_ooffset_t poffset; struct uio auio; struct iovec aiov; int error; int ioflags; int ppscheck = 0; static struct timeval lastfail; static int curfail; object = vp->v_object; count = bytecount / PAGE_SIZE; for (i = 0; i < count; i++) rtvals[i] = VM_PAGER_ERROR; if ((int64_t)ma[0]->pindex < 0) { printf("vnode_pager_putpages: attempt to write meta-data!!! -- 0x%lx(%lx)\n", (long)ma[0]->pindex, (u_long)ma[0]->dirty); rtvals[0] = VM_PAGER_BAD; return VM_PAGER_BAD; } maxsize = count * PAGE_SIZE; ncount = count; poffset = IDX_TO_OFF(ma[0]->pindex); /* * If the page-aligned write is larger then the actual file we * have to invalidate pages occurring beyond the file EOF. However, * there is an edge case where a file may not be page-aligned where * the last page is partially invalid. In this case the filesystem * may not properly clear the dirty bits for the entire page (which * could be VM_PAGE_BITS_ALL due to the page having been mmap()d). * With the page locked we are free to fix-up the dirty bits here. * * We do not under any circumstances truncate the valid bits, as * this will screw up bogus page replacement. */ VM_OBJECT_WLOCK(object); if (maxsize + poffset > object->un_pager.vnp.vnp_size) { if (object->un_pager.vnp.vnp_size > poffset) { int pgoff; maxsize = object->un_pager.vnp.vnp_size - poffset; ncount = btoc(maxsize); if ((pgoff = (int)maxsize & PAGE_MASK) != 0) { /* * If the object is locked and the following * conditions hold, then the page's dirty * field cannot be concurrently changed by a * pmap operation. */ m = ma[ncount - 1]; vm_page_assert_sbusied(m); KASSERT(!pmap_page_is_write_mapped(m), ("vnode_pager_generic_putpages: page %p is not read-only", m)); vm_page_clear_dirty(m, pgoff, PAGE_SIZE - pgoff); } } else { maxsize = 0; ncount = 0; } if (ncount < count) { for (i = ncount; i < count; i++) { rtvals[i] = VM_PAGER_BAD; } } } VM_OBJECT_WUNLOCK(object); /* * pageouts are already clustered, use IO_ASYNC to force a bawrite() * rather then a bdwrite() to prevent paging I/O from saturating * the buffer cache. Dummy-up the sequential heuristic to cause * large ranges to cluster. If neither IO_SYNC or IO_ASYNC is set, * the system decides how to cluster. */ ioflags = IO_VMIO; if (flags & (VM_PAGER_PUT_SYNC | VM_PAGER_PUT_INVAL)) ioflags |= IO_SYNC; else if ((flags & VM_PAGER_CLUSTER_OK) == 0) ioflags |= IO_ASYNC; ioflags |= (flags & VM_PAGER_PUT_INVAL) ? IO_INVAL: 0; ioflags |= (flags & VM_PAGER_PUT_NOREUSE) ? IO_NOREUSE : 0; ioflags |= IO_SEQMAX << IO_SEQSHIFT; aiov.iov_base = (caddr_t) 0; aiov.iov_len = maxsize; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = poffset; auio.uio_segflg = UIO_NOCOPY; auio.uio_rw = UIO_WRITE; auio.uio_resid = maxsize; auio.uio_td = (struct thread *) 0; error = VOP_WRITE(vp, &auio, ioflags, curthread->td_ucred); PCPU_INC(cnt.v_vnodeout); PCPU_ADD(cnt.v_vnodepgsout, ncount); if (error) { if ((ppscheck = ppsratecheck(&lastfail, &curfail, 1))) printf("vnode_pager_putpages: I/O error %d\n", error); } if (auio.uio_resid) { if (ppscheck || ppsratecheck(&lastfail, &curfail, 1)) printf("vnode_pager_putpages: residual I/O %zd at %lu\n", auio.uio_resid, (u_long)ma[0]->pindex); } for (i = 0; i < ncount; i++) { rtvals[i] = VM_PAGER_OK; } return rtvals[0]; }
static int zfs_replay_write(void *arg1, char *arg2, boolean_t byteswap) { zfsvfs_t *zfsvfs = (zfsvfs_t *)arg1; lr_write_t *lr = (lr_write_t *)arg2; char *data = (char *)(lr + 1); /* data follows lr_write_t */ znode_t *zp; int error; #ifndef LINUX_PORT ssize_t resid; #else uio_t uio; int vflg = 0; struct iovec iov; #endif if (byteswap) byteswap_uint64_array(lr, sizeof (*lr)); if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) { /* * As we can log writes out of order, it's possible the * file has been removed. In this case just drop the write * and return success. */ if (error == ENOENT) error = 0; return (error); } #ifndef LINUX_PORT offset = lr->lr_offset; length = lr->lr_length; iov.iov_base = (void *) data; iov.iov_len = lr->lr_length; /* This may be a write from a dmu_sync() for a whole block, * and may extend beyond the current end of the file. * We can't just replay what was written for this TX_WRITE as * a future TX_WRITE2 may extend the eof and the data for that * write needs to be there. So we write the whole block and * reduce the eof. This needs to be done within the single dmu * transaction created within vn_rdwr -> zfs_write. So a possible * new end of file is passed through in zfsvfs->z_replay_eof */ zfsvfs->z_replay_eof = 0; /* 0 means don't change end of file */ /* If it's a dmu_sync() block, write the whole block */ if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) { uint64_t blocksize = BP_GET_LSIZE(&lr->lr_blkptr); if (length < blocksize) { offset -= offset % blocksize; length = blocksize; } if (zp->z_size < eod) zfsvfs->z_replay_eof = eod; } error = vn_rdwr(UIO_WRITE, ZTOV(zp), data, length, offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid); #else iov.iov_base = (void *) data; iov.iov_len = lr->lr_length; uio.uio_iov = &iov; uio.uio_resid = lr->lr_length; uio.uio_iovcnt = 1; uio.uio_loffset = (offset_t)lr->lr_offset; uio.uio_limit = MAXOFFSET_T; uio.uio_segflg = UIO_SYSSPACE; error = VOP_WRITE(ZTOV(zp), &uio, vflg, NULL , NULL); #endif VN_RELE(ZTOV(zp)); zfsvfs->z_replay_eof = 0; /* safety */ return (error); }
/* * Update the disk quota in the quota file. */ static int dqsync(struct vnode *vp, struct dquot *dq) { uint8_t buf[sizeof(struct dqblk64)]; off_t base, recsize; struct vnode *dqvp; struct iovec aiov; struct uio auio; int error; struct mount *mp; struct ufsmount *ump; #ifdef DEBUG_VFS_LOCKS if (vp != NULL) ASSERT_VOP_ELOCKED(vp, "dqsync"); #endif mp = NULL; error = 0; if (dq == NODQUOT) panic("dqsync: dquot"); if ((ump = dq->dq_ump) == NULL) return (0); UFS_LOCK(ump); if ((dqvp = ump->um_quotas[dq->dq_type]) == NULLVP) { if (vp == NULL) { UFS_UNLOCK(ump); return (0); } else panic("dqsync: file"); } vref(dqvp); UFS_UNLOCK(ump); DQI_LOCK(dq); if ((dq->dq_flags & DQ_MOD) == 0) { DQI_UNLOCK(dq); vrele(dqvp); return (0); } DQI_UNLOCK(dq); (void) vn_start_secondary_write(dqvp, &mp, V_WAIT); if (vp != dqvp) vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY); DQI_LOCK(dq); DQI_WAIT(dq, PINOD+2, "dqsync"); if ((dq->dq_flags & DQ_MOD) == 0) goto out; dq->dq_flags |= DQ_LOCK; DQI_UNLOCK(dq); /* * Write the quota record to the quota file, performing any * necessary conversions. See dqget() for additional details. */ if (ump->um_qflags[dq->dq_type] & QTF_64BIT) { dq_dqb64(dq, (struct dqblk64 *)buf); recsize = sizeof(struct dqblk64); base = sizeof(struct dqhdr64); } else { dq_dqb32(dq, (struct dqblk32 *)buf); recsize = sizeof(struct dqblk32); base = 0; } auio.uio_iov = &aiov; auio.uio_iovcnt = 1; aiov.iov_base = buf; aiov.iov_len = recsize; auio.uio_resid = recsize; auio.uio_offset = base + dq->dq_id * recsize; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_td = (struct thread *)0; error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]); if (auio.uio_resid && error == 0) error = EIO; DQI_LOCK(dq); DQI_WAKEUP(dq); dq->dq_flags &= ~DQ_MOD; out: DQI_UNLOCK(dq); if (vp != dqvp) vput(dqvp); else vrele(dqvp); vn_finished_secondary_write(mp); return (error); }
/* * Write a directory entry after a call to namei, using the parameters * that it left in nameidata. The argument ip is the inode which the new * directory entry will refer to. Dvp is a pointer to the directory to * be written, which was left locked by namei. Remaining parameters * (ulr_offset, ulr_count) indicate how the space for the new * entry is to be obtained. */ int ext2fs_direnter(struct inode *ip, struct vnode *dvp, const struct ufs_lookup_results *ulr, struct componentname *cnp) { struct ext2fs_direct *ep, *nep; struct inode *dp; struct buf *bp; struct ext2fs_direct newdir; struct iovec aiov; struct uio auio; u_int dsize; int error, loc, newentrysize, spacefree; char *dirbuf; struct ufsmount *ump = VFSTOUFS(dvp->v_mount); int dirblksiz = ump->um_dirblksiz; dp = VTOI(dvp); newdir.e2d_ino = h2fs32(ip->i_number); newdir.e2d_namlen = cnp->cn_namelen; if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 && (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) { newdir.e2d_type = inot2ext2dt(IFTODT(ip->i_e2fs_mode)); } else { newdir.e2d_type = 0; } memcpy(newdir.e2d_name, cnp->cn_nameptr, (unsigned)cnp->cn_namelen + 1); newentrysize = EXT2FS_DIRSIZ(cnp->cn_namelen); if (ulr->ulr_count == 0) { /* * If ulr_count is 0, then namei could find no * space in the directory. Here, ulr_offset will * be on a directory block boundary and we will write the * new entry into a fresh block. */ if (ulr->ulr_offset & (dirblksiz - 1)) panic("ext2fs_direnter: newblk"); auio.uio_offset = ulr->ulr_offset; newdir.e2d_reclen = h2fs16(dirblksiz); auio.uio_resid = newentrysize; aiov.iov_len = newentrysize; aiov.iov_base = (void *)&newdir; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_WRITE; UIO_SETUP_SYSSPACE(&auio); error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); if (dirblksiz > dvp->v_mount->mnt_stat.f_bsize) /* XXX should grow with balloc() */ panic("ext2fs_direnter: frag size"); else if (!error) { error = ext2fs_setsize(dp, roundup(ext2fs_size(dp), dirblksiz)); if (error) return (error); dp->i_flag |= IN_CHANGE; uvm_vnp_setsize(dvp, ext2fs_size(dp)); } return (error); } /* * If ulr_count is non-zero, then namei found space * for the new entry in the range ulr_offset to * ulr_offset + ulr_count in the directory. * To use this space, we may have to compact the entries located * there, by copying them together towards the beginning of the * block, leaving the free space in one usable chunk at the end. */ /* * Get the block containing the space for the new directory entry. */ if ((error = ext2fs_blkatoff(dvp, (off_t)ulr->ulr_offset, &dirbuf, &bp)) != 0) return (error); /* * Find space for the new entry. In the simple case, the entry at * offset base will have the space. If it does not, then namei * arranged that compacting the region ulr_offset to * ulr_offset + ulr_count would yield the * space. */ ep = (struct ext2fs_direct *)dirbuf; dsize = EXT2FS_DIRSIZ(ep->e2d_namlen); spacefree = fs2h16(ep->e2d_reclen) - dsize; for (loc = fs2h16(ep->e2d_reclen); loc < ulr->ulr_count; ) { nep = (struct ext2fs_direct *)(dirbuf + loc); if (ep->e2d_ino) { /* trim the existing slot */ ep->e2d_reclen = h2fs16(dsize); ep = (struct ext2fs_direct *)((char *)ep + dsize); } else { /* overwrite; nothing there; header is ours */ spacefree += dsize; } dsize = EXT2FS_DIRSIZ(nep->e2d_namlen); spacefree += fs2h16(nep->e2d_reclen) - dsize; loc += fs2h16(nep->e2d_reclen); memcpy((void *)ep, (void *)nep, dsize); } /* * Update the pointer fields in the previous entry (if any), * copy in the new entry, and write out the block. */ if (ep->e2d_ino == 0) { #ifdef DIAGNOSTIC if (spacefree + dsize < newentrysize) panic("ext2fs_direnter: compact1"); #endif newdir.e2d_reclen = h2fs16(spacefree + dsize); } else { #ifdef DIAGNOSTIC if (spacefree < newentrysize) { printf("ext2fs_direnter: compact2 %u %u", (u_int)spacefree, (u_int)newentrysize); panic("ext2fs_direnter: compact2"); } #endif newdir.e2d_reclen = h2fs16(spacefree); ep->e2d_reclen = h2fs16(dsize); ep = (struct ext2fs_direct *)((char *)ep + dsize); } memcpy((void *)ep, (void *)&newdir, (u_int)newentrysize); error = VOP_BWRITE(bp->b_vp, bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; if (!error && ulr->ulr_endoff && ulr->ulr_endoff < ext2fs_size(dp)) error = ext2fs_truncate(dvp, (off_t)ulr->ulr_endoff, IO_SYNC, cnp->cn_cred); return (error); }
int sys_write(int fdesc,userptr_t ubuf,unsigned int nbytes,int *retval) { struct iovec iov; struct uio u; struct filedescriptor *fDescriptor; int res; int bytesWrite; if(!ubuf){ return EFAULT; } fDescriptor = getFileDescriptor(fdesc, curthread->t_fdManager); if(fDescriptor == NULL){ return EBADF; } DEBUG(DB_SYSCALL,"Syscall: write(%d,%x,%d)\n",fdesc,(unsigned int)ubuf,nbytes); /* only stdout and stderr writes are currently implemented */ if (!((fdesc==STDOUT_FILENO)||(fdesc==STDERR_FILENO))) { return EUNIMP; } KASSERT(curproc != NULL); KASSERT(curproc->console != NULL); KASSERT(curproc->p_addrspace != NULL); /* set up a uio structure to refer to the user program's buffer (ubuf) */ iov.iov_ubase = ubuf; iov.iov_len = nbytes; u.uio_iov = &iov; u.uio_iovcnt = 1; u.uio_offset = fDescriptor->fdoff; /* not needed for the console */ u.uio_resid = nbytes; u.uio_segflg = UIO_USERSPACE; u.uio_rw = UIO_WRITE; u.uio_space = curproc->p_addrspace; bytesWrite = u.uio_resid; lock_acquire(fDescriptor->fdlock); res = VOP_WRITE(fDescriptor->fdvnode,&u); lock_release(fDescriptor->fdlock); bytesWrite = u.uio_resid; if(bytesWrite==0){ return 0; } if (res) { return res; } /* pass back the number of bytes actually written */ *retval = nbytes - u.uio_resid; KASSERT(*retval >= 0); fDescriptor->fdoff += nbytes; return 0; }
/* * Real work associated with removing an extended attribute from a vnode. * Assumes the attribute lock has already been grabbed. */ static int ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name, struct ucred *cred, struct thread *td) { struct ufs_extattr_list_entry *attribute; struct ufs_extattr_header ueh; struct iovec local_aiov; struct uio local_aio; struct mount *mp = vp->v_mount; struct ufsmount *ump = VFSTOUFS(mp); struct inode *ip = VTOI(vp); off_t base_offset; int error = 0, ioflag; if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) return (EOPNOTSUPP); if (!ufs_extattr_valid_attrname(attrnamespace, name)) return (EINVAL); error = extattr_check_cred(vp, attrnamespace, cred, td, VWRITE); if (error) return (error); attribute = ufs_extattr_find_attr(ump, attrnamespace, name); if (!attribute) return (ENOATTR); /* * Find base offset of header in file based on file header size, and * data header size + maximum data size, indexed by inode number. */ base_offset = sizeof(struct ufs_extattr_fileheader) + ip->i_number * (sizeof(struct ufs_extattr_header) + attribute->uele_fileheader.uef_size); /* * Check to see if currently defined. */ bzero(&ueh, sizeof(struct ufs_extattr_header)); local_aiov.iov_base = (caddr_t) &ueh; local_aiov.iov_len = sizeof(struct ufs_extattr_header); local_aio.uio_iov = &local_aiov; local_aio.uio_iovcnt = 1; local_aio.uio_rw = UIO_READ; local_aio.uio_segflg = UIO_SYSSPACE; local_aio.uio_td = td; local_aio.uio_offset = base_offset; local_aio.uio_resid = sizeof(struct ufs_extattr_header); /* * Don't need to get the lock on the backing vnode if the vnode we're * modifying is it, as we already hold the lock. */ if (attribute->uele_backing_vnode != vp) vn_lock(attribute->uele_backing_vnode, LK_EXCLUSIVE | LK_RETRY); error = VOP_READ(attribute->uele_backing_vnode, &local_aio, IO_NODELOCKED, ump->um_extattr.uepm_ucred); if (error) goto vopunlock_exit; /* Defined? */ if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) { error = ENOATTR; goto vopunlock_exit; } /* Valid for the current inode generation? */ if (ueh.ueh_i_gen != ip->i_gen) { /* * The inode itself has a different generation number than * the attribute data. For now, the best solution is to * coerce this to undefined, and let it get cleaned up by * the next write or extattrctl clean. */ printf("ufs_extattr_rm (%s): inode number inconsistency (%d, %jd)\n", mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen); error = ENOATTR; goto vopunlock_exit; } /* Flag it as not in use. */ ueh.ueh_flags = 0; ueh.ueh_len = 0; local_aiov.iov_base = (caddr_t) &ueh; local_aiov.iov_len = sizeof(struct ufs_extattr_header); local_aio.uio_iov = &local_aiov; local_aio.uio_iovcnt = 1; local_aio.uio_rw = UIO_WRITE; local_aio.uio_segflg = UIO_SYSSPACE; local_aio.uio_td = td; local_aio.uio_offset = base_offset; local_aio.uio_resid = sizeof(struct ufs_extattr_header); ioflag = IO_NODELOCKED; if (ufs_extattr_sync) ioflag |= IO_SYNC; error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag, ump->um_extattr.uepm_ucred); if (error) goto vopunlock_exit; if (local_aio.uio_resid != 0) error = ENXIO; vopunlock_exit: VOP_UNLOCK(attribute->uele_backing_vnode, 0); return (error); }
int swap_pagein( u_int32_t paddr, int rw, u_int32_t mem, u_int32_t file, u_int32_t offset, int swap, int swap_index) { int result; int fillamt; struct uio u; struct addrspace *as; // struct vnode *swap_vnode; as = curthread->t_vmspace; if(swap == 1) { result = vfs_open(SWAP_DEVICE, O_RDWR, &swap_vnode); mk_kuio(&u, paddr, PAGE_SIZE, swap_index * PAGE_SIZE, UIO_READ); result = VOP_READ(swap_vnode, &u); if (result) { return result; } vfs_close(swap_vnode); } else { /* Open the file. */ struct vnode *v; result = vfs_open(as->as_progname, O_RDONLY, &v); if (result) { return result; } mk_kuio_pd(&u, paddr, mem, file, offset, rw); if(rw == UIO_READ) { result = VOP_READ(v, &u) ; } else { result = VOP_WRITE(v, &u); } if (u.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on segment - file truncated?\n"); return ENOEXEC; } /* Fill the rest of the memory space (if any) with zeros */ fillamt = mem - file; if (fillamt > 0) { u.uio_resid += fillamt; u.uio_rw = UIO_READ; result = uiomovezeros(fillamt, &u); } if (result==EIO) { panic("swap: EIO on swapfile (offset %ld)\n", (long)as->as_offset1); } else if (result==EINVAL) { panic("swap: EINVAL from swapfile (offset %ld)\n", (long)as->as_offset1); } else if (result) { panic("swap: Error %d from swapfile (offset %ld)\n", result, (long)as->as_offset1); } /* Done with the file now. */ vfs_close(v); return 0; } }
/* * Flush all pending data to disk. This operation will block. */ static int alq_doio(struct alq *alq) { struct thread *td; struct mount *mp; struct vnode *vp; struct uio auio; struct iovec aiov[2]; int totlen; int iov; int vfslocked; int wrapearly; KASSERT((HAS_PENDING_DATA(alq)), ("%s: queue empty!", __func__)); vp = alq->aq_vp; td = curthread; totlen = 0; iov = 1; wrapearly = alq->aq_wrapearly; bzero(&aiov, sizeof(aiov)); bzero(&auio, sizeof(auio)); /* Start the write from the location of our buffer tail pointer. */ aiov[0].iov_base = alq->aq_entbuf + alq->aq_writetail; if (alq->aq_writetail < alq->aq_writehead) { /* Buffer not wrapped. */ totlen = aiov[0].iov_len = alq->aq_writehead - alq->aq_writetail; } else if (alq->aq_writehead == 0) { /* Buffer not wrapped (special case to avoid an empty iov). */ totlen = aiov[0].iov_len = alq->aq_buflen - alq->aq_writetail - wrapearly; } else { /* * Buffer wrapped, requires 2 aiov entries: * - first is from writetail to end of buffer * - second is from start of buffer to writehead */ aiov[0].iov_len = alq->aq_buflen - alq->aq_writetail - wrapearly; iov++; aiov[1].iov_base = alq->aq_entbuf; aiov[1].iov_len = alq->aq_writehead; totlen = aiov[0].iov_len + aiov[1].iov_len; } alq->aq_flags |= AQ_FLUSHING; ALQ_UNLOCK(alq); auio.uio_iov = &aiov[0]; auio.uio_offset = 0; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_iovcnt = iov; auio.uio_resid = totlen; auio.uio_td = td; /* * Do all of the junk required to write now. */ vfslocked = VFS_LOCK_GIANT(vp->v_mount); vn_start_write(vp, &mp, V_WAIT); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* * XXX: VOP_WRITE error checks are ignored. */ #ifdef MAC if (mac_vnode_check_write(alq->aq_cred, NOCRED, vp) == 0) #endif VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, alq->aq_cred); VOP_UNLOCK(vp, 0); vn_finished_write(mp); VFS_UNLOCK_GIANT(vfslocked); ALQ_LOCK(alq); alq->aq_flags &= ~AQ_FLUSHING; /* Adjust writetail as required, taking into account wrapping. */ alq->aq_writetail = (alq->aq_writetail + totlen + wrapearly) % alq->aq_buflen; alq->aq_freebytes += totlen + wrapearly; /* * If we just flushed part of the buffer which wrapped, reset the * wrapearly indicator. */ if (wrapearly) alq->aq_wrapearly = 0; /* * If we just flushed the buffer completely, reset indexes to 0 to * minimise buffer wraps. * This is also required to ensure alq_getn() can't wedge itself. */ if (!HAS_PENDING_DATA(alq)) alq->aq_writehead = alq->aq_writetail = 0; KASSERT((alq->aq_writetail >= 0 && alq->aq_writetail < alq->aq_buflen), ("%s: aq_writetail < 0 || aq_writetail >= aq_buflen", __func__)); if (alq->aq_flags & AQ_WANTED) { alq->aq_flags &= ~AQ_WANTED; return (1); } return(0); }