164412Smckusick /*- 2*65798Sbostic * Copyright (c) 1993 3*65798Sbostic * The Regents of the University of California. All rights reserved. 464412Smckusick * 564412Smckusick * %sccs.include.redist.c% 664412Smckusick * 7*65798Sbostic * @(#)ufs_readwrite.c 8.7 (Berkeley) 01/21/94 864412Smckusick */ 964412Smckusick 1064412Smckusick #ifdef LFS_READWRITE 1164412Smckusick #define BLKSIZE(a, b, c) blksize(a) 1264412Smckusick #define FS struct lfs 1364412Smckusick #define I_FS i_lfs 1464412Smckusick #define READ lfs_read 1565602Smckusick #define READ_S "lfs_read" 1664412Smckusick #define WRITE lfs_write 1765602Smckusick #define WRITE_S "lfs_write" 1864412Smckusick #define fs_bsize lfs_bsize 1964412Smckusick #define fs_maxfilesize lfs_maxfilesize 2064412Smckusick #else 2164412Smckusick #define BLKSIZE(a, b, c) blksize(a, b, c) 2264412Smckusick #define FS struct fs 2364412Smckusick #define I_FS i_fs 2464412Smckusick #define READ ffs_read 2565602Smckusick #define READ_S "ffs_read" 2664412Smckusick #define WRITE ffs_write 2765602Smckusick #define WRITE_S "ffs_write" 2864412Smckusick #endif 2964412Smckusick 3064412Smckusick /* 3164412Smckusick * Vnode op for reading. 3264412Smckusick */ 3364412Smckusick /* ARGSUSED */ 3464412Smckusick READ(ap) 3564412Smckusick struct vop_read_args /* { 3664412Smckusick struct vnode *a_vp; 3764412Smckusick struct uio *a_uio; 3864412Smckusick int a_ioflag; 3964412Smckusick struct ucred *a_cred; 4064412Smckusick } */ *ap; 4164412Smckusick { 4264412Smckusick register struct vnode *vp; 4364412Smckusick register struct inode *ip; 4464412Smckusick register struct uio *uio; 4564412Smckusick register FS *fs; 4664412Smckusick struct buf *bp; 4764412Smckusick daddr_t lbn, nextlbn; 4864412Smckusick off_t bytesinfile; 4964412Smckusick long size, xfersize, blkoffset; 5065720Sbostic int error; 5164412Smckusick u_short mode; 5264412Smckusick 5364412Smckusick vp = ap->a_vp; 5464412Smckusick ip = VTOI(vp); 5564412Smckusick mode = ip->i_mode; 5664412Smckusick uio = ap->a_uio; 5764412Smckusick 5864412Smckusick #ifdef DIAGNOSTIC 5964412Smckusick if (uio->uio_rw != UIO_READ) 6065602Smckusick panic("%s: mode", READ_S); 6164412Smckusick 6264412Smckusick if (vp->v_type == VLNK) { 6364412Smckusick if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen) 6465602Smckusick panic("%s: short symlink", READ_S); 6564412Smckusick } else if (vp->v_type != VREG && vp->v_type != VDIR) 6665602Smckusick panic("%s: type %d", READ_S, vp->v_type); 6764412Smckusick #endif 6864412Smckusick fs = ip->I_FS; 6964412Smckusick if ((u_quad_t)uio->uio_offset > fs->fs_maxfilesize) 7064412Smckusick return (EFBIG); 7164412Smckusick 7264412Smckusick for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { 7364412Smckusick if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0) 7464412Smckusick break; 7564412Smckusick lbn = lblkno(fs, uio->uio_offset); 7664412Smckusick nextlbn = lbn + 1; 7764412Smckusick size = BLKSIZE(fs, ip, lbn); 7864412Smckusick blkoffset = blkoff(fs, uio->uio_offset); 7964412Smckusick xfersize = fs->fs_bsize - blkoffset; 8064412Smckusick if (uio->uio_resid < xfersize) 8164412Smckusick xfersize = uio->uio_resid; 8264412Smckusick if (bytesinfile < xfersize) 8364412Smckusick xfersize = bytesinfile; 8464412Smckusick 8564412Smckusick #ifdef LFS_READWRITE 8664412Smckusick (void)lfs_check(vp, lbn); 8764412Smckusick error = cluster_read(vp, ip->i_size, lbn, size, NOCRED, &bp); 8864412Smckusick #else 8965720Sbostic if (lblktosize(fs, nextlbn) > ip->i_size) 9064412Smckusick error = bread(vp, lbn, size, NOCRED, &bp); 9165720Sbostic else if (doclusterread) 9265720Sbostic error = cluster_read(vp, 9365720Sbostic ip->i_size, lbn, size, NOCRED, &bp); 9465720Sbostic else if (lbn - 1 == vp->v_lastr) { 9565720Sbostic int nextsize = BLKSIZE(fs, ip, nextlbn); 9665720Sbostic error = breadn(vp, lbn, 9765720Sbostic size, &nextlbn, &nextsize, 1, NOCRED, &bp); 9865720Sbostic } else 9965720Sbostic error = bread(vp, lbn, size, NOCRED, &bp); 10064412Smckusick #endif 10164412Smckusick if (error) 10264412Smckusick break; 10364412Smckusick vp->v_lastr = lbn; 10464412Smckusick 10564412Smckusick /* 10664412Smckusick * We should only get non-zero b_resid when an I/O error 10764412Smckusick * has occurred, which should cause us to break above. 10864412Smckusick * However, if the short read did not cause an error, 10964412Smckusick * then we want to ensure that we do not uiomove bad 11064412Smckusick * or uninitialized data. 11164412Smckusick */ 11264412Smckusick size -= bp->b_resid; 11364412Smckusick if (size < xfersize) { 11464412Smckusick if (size == 0) 11564412Smckusick break; 11664412Smckusick xfersize = size; 11764412Smckusick } 11864412Smckusick if (error = 11964519Sbostic uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio)) 12064412Smckusick break; 12164412Smckusick 12264412Smckusick if (S_ISREG(mode) && (xfersize + blkoffset == fs->fs_bsize || 12364412Smckusick uio->uio_offset == ip->i_size)) 12464412Smckusick bp->b_flags |= B_AGE; 12564412Smckusick brelse(bp); 12664412Smckusick } 12764412Smckusick if (bp != NULL) 12864412Smckusick brelse(bp); 12964601Sbostic ip->i_flag |= IN_ACCESS; 13064412Smckusick return (error); 13164412Smckusick } 13264412Smckusick 13364412Smckusick /* 13464412Smckusick * Vnode op for writing. 13564412Smckusick */ 13664412Smckusick WRITE(ap) 13764412Smckusick struct vop_write_args /* { 13864412Smckusick struct vnode *a_vp; 13964412Smckusick struct uio *a_uio; 14064412Smckusick int a_ioflag; 14164412Smckusick struct ucred *a_cred; 14264412Smckusick } */ *ap; 14364412Smckusick { 14464412Smckusick register struct vnode *vp; 14564412Smckusick register struct uio *uio; 14664412Smckusick register struct inode *ip; 14764412Smckusick register FS *fs; 14864412Smckusick struct buf *bp; 14964412Smckusick struct proc *p; 15064412Smckusick daddr_t lbn; 15164412Smckusick off_t osize; 15265470Sbostic int blkoffset, error, flags, ioflag, resid, size, xfersize; 15364412Smckusick 15464412Smckusick ioflag = ap->a_ioflag; 15564412Smckusick uio = ap->a_uio; 15664412Smckusick vp = ap->a_vp; 15764412Smckusick ip = VTOI(vp); 15864412Smckusick 15964412Smckusick #ifdef DIAGNOSTIC 16064412Smckusick if (uio->uio_rw != UIO_WRITE) 16165602Smckusick panic("%s: mode", WRITE_S); 16264412Smckusick #endif 16364412Smckusick 16464412Smckusick switch (vp->v_type) { 16564412Smckusick case VREG: 16664412Smckusick if (ioflag & IO_APPEND) 16764412Smckusick uio->uio_offset = ip->i_size; 16864412Smckusick if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size) 16964412Smckusick return (EPERM); 17064412Smckusick /* FALLTHROUGH */ 17164412Smckusick case VLNK: 17264412Smckusick break; 17364412Smckusick case VDIR: 17464412Smckusick if ((ioflag & IO_SYNC) == 0) 17565602Smckusick panic("%s: nonsync dir write", WRITE_S); 17664412Smckusick break; 17764412Smckusick default: 17865602Smckusick panic("%s: type", WRITE_S); 17964412Smckusick } 18064412Smckusick 18164412Smckusick fs = ip->I_FS; 18264412Smckusick if (uio->uio_offset < 0 || 18364412Smckusick (u_quad_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize) 18464412Smckusick return (EFBIG); 18564412Smckusick /* 18664412Smckusick * Maybe this should be above the vnode op call, but so long as 18764412Smckusick * file servers have no limits, I don't think it matters. 18864412Smckusick */ 18964412Smckusick p = uio->uio_procp; 19064412Smckusick if (vp->v_type == VREG && p && 19164412Smckusick uio->uio_offset + uio->uio_resid > 19264412Smckusick p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 19364412Smckusick psignal(p, SIGXFSZ); 19464412Smckusick return (EFBIG); 19564412Smckusick } 19664412Smckusick 19764412Smckusick resid = uio->uio_resid; 19864412Smckusick osize = ip->i_size; 19964412Smckusick flags = ioflag & IO_SYNC ? B_SYNC : 0; 20064412Smckusick 20164412Smckusick for (error = 0; uio->uio_resid > 0;) { 20264412Smckusick lbn = lblkno(fs, uio->uio_offset); 20364412Smckusick blkoffset = blkoff(fs, uio->uio_offset); 20464412Smckusick xfersize = fs->fs_bsize - blkoffset; 20564412Smckusick if (uio->uio_resid < xfersize) 20664412Smckusick xfersize = uio->uio_resid; 20764412Smckusick #ifdef LFS_READWRITE 20864412Smckusick (void)lfs_check(vp, lbn); 20964412Smckusick error = lfs_balloc(vp, xfersize, lbn, &bp); 21064412Smckusick #else 21164412Smckusick if (fs->fs_bsize > xfersize) 21264412Smckusick flags |= B_CLRBUF; 21364412Smckusick else 21464412Smckusick flags &= ~B_CLRBUF; 21564412Smckusick 21664412Smckusick error = ffs_balloc(ip, 21764412Smckusick lbn, blkoffset + xfersize, ap->a_cred, &bp, flags); 21864412Smckusick #endif 21964412Smckusick if (error) 22064412Smckusick break; 22164412Smckusick if (uio->uio_offset + xfersize > ip->i_size) { 22264412Smckusick ip->i_size = uio->uio_offset + xfersize; 22364412Smckusick vnode_pager_setsize(vp, (u_long)ip->i_size); 22464412Smckusick } 22564412Smckusick (void)vnode_pager_uncache(vp); 22664412Smckusick 22764412Smckusick size = BLKSIZE(fs, ip, lbn) - bp->b_resid; 22864412Smckusick if (size < xfersize) 22964412Smckusick xfersize = size; 23064412Smckusick 23164412Smckusick error = 23264519Sbostic uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio); 23364412Smckusick #ifdef LFS_READWRITE 23464412Smckusick (void)VOP_BWRITE(bp); 23564412Smckusick #else 23664412Smckusick if (ioflag & IO_SYNC) 23764412Smckusick (void)bwrite(bp); 23864412Smckusick else if (xfersize + blkoffset == fs->fs_bsize) 23964412Smckusick if (doclusterwrite) 24064412Smckusick cluster_write(bp, ip->i_size); 24164412Smckusick else { 24264412Smckusick bp->b_flags |= B_AGE; 24364412Smckusick bawrite(bp); 24464412Smckusick } 24564412Smckusick else 24664412Smckusick bdwrite(bp); 24764412Smckusick #endif 24864412Smckusick if (error || xfersize == 0) 24964412Smckusick break; 25064601Sbostic ip->i_flag |= IN_CHANGE | IN_UPDATE; 25164412Smckusick } 25264412Smckusick /* 25364412Smckusick * If we successfully wrote any data, and we are not the superuser 25464412Smckusick * we clear the setuid and setgid bits as a precaution against 25564412Smckusick * tampering. 25664412Smckusick */ 25764412Smckusick if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0) 25864412Smckusick ip->i_mode &= ~(ISUID | ISGID); 25964412Smckusick if (error) { 26064412Smckusick if (ioflag & IO_UNIT) { 26164412Smckusick (void)VOP_TRUNCATE(vp, osize, 26264412Smckusick ioflag & IO_SYNC, ap->a_cred, uio->uio_procp); 26364412Smckusick uio->uio_offset -= resid - uio->uio_resid; 26464412Smckusick uio->uio_resid = resid; 26564412Smckusick } 26664412Smckusick } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) 26764412Smckusick error = VOP_UPDATE(vp, &time, &time, 1); 26864412Smckusick return (error); 26964412Smckusick } 270