164412Smckusick /*- 264412Smckusick * Copyright (c) 1993 The Regents of the University of California. 364412Smckusick * All rights reserved. 464412Smckusick * 564412Smckusick * %sccs.include.redist.c% 664412Smckusick * 7*65602Smckusick * @(#)ufs_readwrite.c 8.5 (Berkeley) 01/11/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 15*65602Smckusick #define READ_S "lfs_read" 1664412Smckusick #define WRITE lfs_write 17*65602Smckusick #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 25*65602Smckusick #define READ_S "ffs_read" 2664412Smckusick #define WRITE ffs_write 27*65602Smckusick #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; 5065470Sbostic int nextsize, 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) 60*65602Smckusick panic("%s: mode", READ_S); 6164412Smckusick 6264412Smckusick if (vp->v_type == VLNK) { 6364412Smckusick if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen) 64*65602Smckusick panic("%s: short symlink", READ_S); 6564412Smckusick } else if (vp->v_type != VREG && vp->v_type != VDIR) 66*65602Smckusick 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 8964412Smckusick if (lblktosize(fs, nextlbn) > ip->i_size) { 9064412Smckusick error = bread(vp, lbn, size, NOCRED, &bp); 9164412Smckusick } else { 9264412Smckusick if (doclusterread) { 9364412Smckusick error = cluster_read(vp, 9464412Smckusick ip->i_size, lbn, size, NOCRED, &bp); 9564412Smckusick } else if (lbn - 1 == vp->v_lastr) { 9664412Smckusick nextsize = BLKSIZE(fs, ip, nextlbn); 9764412Smckusick error = breadn(vp, lbn, 9864412Smckusick size, &nextlbn, &nextsize, 1, NOCRED, &bp); 9964412Smckusick } else { 10064412Smckusick error = bread(vp, lbn, size, NOCRED, &bp); 10164412Smckusick } 10264412Smckusick } 10364412Smckusick #endif 10464412Smckusick if (error) 10564412Smckusick break; 10664412Smckusick vp->v_lastr = lbn; 10764412Smckusick 10864412Smckusick /* 10964412Smckusick * We should only get non-zero b_resid when an I/O error 11064412Smckusick * has occurred, which should cause us to break above. 11164412Smckusick * However, if the short read did not cause an error, 11264412Smckusick * then we want to ensure that we do not uiomove bad 11364412Smckusick * or uninitialized data. 11464412Smckusick */ 11564412Smckusick size -= bp->b_resid; 11664412Smckusick if (size < xfersize) { 11764412Smckusick if (size == 0) 11864412Smckusick break; 11964412Smckusick xfersize = size; 12064412Smckusick } 12164412Smckusick if (error = 12264519Sbostic uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio)) 12364412Smckusick break; 12464412Smckusick 12564412Smckusick if (S_ISREG(mode) && (xfersize + blkoffset == fs->fs_bsize || 12664412Smckusick uio->uio_offset == ip->i_size)) 12764412Smckusick bp->b_flags |= B_AGE; 12864412Smckusick brelse(bp); 12964412Smckusick } 13064412Smckusick if (bp != NULL) 13164412Smckusick brelse(bp); 13264601Sbostic ip->i_flag |= IN_ACCESS; 13364412Smckusick return (error); 13464412Smckusick } 13564412Smckusick 13664412Smckusick /* 13764412Smckusick * Vnode op for writing. 13864412Smckusick */ 13964412Smckusick WRITE(ap) 14064412Smckusick struct vop_write_args /* { 14164412Smckusick struct vnode *a_vp; 14264412Smckusick struct uio *a_uio; 14364412Smckusick int a_ioflag; 14464412Smckusick struct ucred *a_cred; 14564412Smckusick } */ *ap; 14664412Smckusick { 14764412Smckusick register struct vnode *vp; 14864412Smckusick register struct uio *uio; 14964412Smckusick register struct inode *ip; 15064412Smckusick register FS *fs; 15164412Smckusick struct buf *bp; 15264412Smckusick struct proc *p; 15364412Smckusick daddr_t lbn; 15464412Smckusick off_t osize; 15565470Sbostic int blkoffset, error, flags, ioflag, resid, size, xfersize; 15664412Smckusick 15764412Smckusick ioflag = ap->a_ioflag; 15864412Smckusick uio = ap->a_uio; 15964412Smckusick vp = ap->a_vp; 16064412Smckusick ip = VTOI(vp); 16164412Smckusick 16264412Smckusick #ifdef DIAGNOSTIC 16364412Smckusick if (uio->uio_rw != UIO_WRITE) 164*65602Smckusick panic("%s: mode", WRITE_S); 16564412Smckusick #endif 16664412Smckusick 16764412Smckusick switch (vp->v_type) { 16864412Smckusick case VREG: 16964412Smckusick if (ioflag & IO_APPEND) 17064412Smckusick uio->uio_offset = ip->i_size; 17164412Smckusick if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size) 17264412Smckusick return (EPERM); 17364412Smckusick /* FALLTHROUGH */ 17464412Smckusick case VLNK: 17564412Smckusick break; 17664412Smckusick case VDIR: 17764412Smckusick if ((ioflag & IO_SYNC) == 0) 178*65602Smckusick panic("%s: nonsync dir write", WRITE_S); 17964412Smckusick break; 18064412Smckusick default: 181*65602Smckusick panic("%s: type", WRITE_S); 18264412Smckusick } 18364412Smckusick 18464412Smckusick fs = ip->I_FS; 18564412Smckusick if (uio->uio_offset < 0 || 18664412Smckusick (u_quad_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize) 18764412Smckusick return (EFBIG); 18864412Smckusick /* 18964412Smckusick * Maybe this should be above the vnode op call, but so long as 19064412Smckusick * file servers have no limits, I don't think it matters. 19164412Smckusick */ 19264412Smckusick p = uio->uio_procp; 19364412Smckusick if (vp->v_type == VREG && p && 19464412Smckusick uio->uio_offset + uio->uio_resid > 19564412Smckusick p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 19664412Smckusick psignal(p, SIGXFSZ); 19764412Smckusick return (EFBIG); 19864412Smckusick } 19964412Smckusick 20064412Smckusick resid = uio->uio_resid; 20164412Smckusick osize = ip->i_size; 20264412Smckusick flags = ioflag & IO_SYNC ? B_SYNC : 0; 20364412Smckusick 20464412Smckusick for (error = 0; uio->uio_resid > 0;) { 20564412Smckusick lbn = lblkno(fs, uio->uio_offset); 20664412Smckusick blkoffset = blkoff(fs, uio->uio_offset); 20764412Smckusick xfersize = fs->fs_bsize - blkoffset; 20864412Smckusick if (uio->uio_resid < xfersize) 20964412Smckusick xfersize = uio->uio_resid; 21064412Smckusick #ifdef LFS_READWRITE 21164412Smckusick (void)lfs_check(vp, lbn); 21264412Smckusick error = lfs_balloc(vp, xfersize, lbn, &bp); 21364412Smckusick #else 21464412Smckusick if (fs->fs_bsize > xfersize) 21564412Smckusick flags |= B_CLRBUF; 21664412Smckusick else 21764412Smckusick flags &= ~B_CLRBUF; 21864412Smckusick 21964412Smckusick error = ffs_balloc(ip, 22064412Smckusick lbn, blkoffset + xfersize, ap->a_cred, &bp, flags); 22164412Smckusick #endif 22264412Smckusick if (error) 22364412Smckusick break; 22464412Smckusick if (uio->uio_offset + xfersize > ip->i_size) { 22564412Smckusick ip->i_size = uio->uio_offset + xfersize; 22664412Smckusick vnode_pager_setsize(vp, (u_long)ip->i_size); 22764412Smckusick } 22864412Smckusick (void)vnode_pager_uncache(vp); 22964412Smckusick 23064412Smckusick size = BLKSIZE(fs, ip, lbn) - bp->b_resid; 23164412Smckusick if (size < xfersize) 23264412Smckusick xfersize = size; 23364412Smckusick 23464412Smckusick error = 23564519Sbostic uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio); 23664412Smckusick #ifdef LFS_READWRITE 23764412Smckusick (void)VOP_BWRITE(bp); 23864412Smckusick #else 23964412Smckusick if (ioflag & IO_SYNC) 24064412Smckusick (void)bwrite(bp); 24164412Smckusick else if (xfersize + blkoffset == fs->fs_bsize) 24264412Smckusick if (doclusterwrite) 24364412Smckusick cluster_write(bp, ip->i_size); 24464412Smckusick else { 24564412Smckusick bp->b_flags |= B_AGE; 24664412Smckusick bawrite(bp); 24764412Smckusick } 24864412Smckusick else 24964412Smckusick bdwrite(bp); 25064412Smckusick #endif 25164412Smckusick if (error || xfersize == 0) 25264412Smckusick break; 25364601Sbostic ip->i_flag |= IN_CHANGE | IN_UPDATE; 25464412Smckusick } 25564412Smckusick /* 25664412Smckusick * If we successfully wrote any data, and we are not the superuser 25764412Smckusick * we clear the setuid and setgid bits as a precaution against 25864412Smckusick * tampering. 25964412Smckusick */ 26064412Smckusick if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0) 26164412Smckusick ip->i_mode &= ~(ISUID | ISGID); 26264412Smckusick if (error) { 26364412Smckusick if (ioflag & IO_UNIT) { 26464412Smckusick (void)VOP_TRUNCATE(vp, osize, 26564412Smckusick ioflag & IO_SYNC, ap->a_cred, uio->uio_procp); 26664412Smckusick uio->uio_offset -= resid - uio->uio_resid; 26764412Smckusick uio->uio_resid = resid; 26864412Smckusick } 26964412Smckusick } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) 27064412Smckusick error = VOP_UPDATE(vp, &time, &time, 1); 27164412Smckusick return (error); 27264412Smckusick } 273