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