1*64412Smckusick /*- 2*64412Smckusick * Copyright (c) 1993 The Regents of the University of California. 3*64412Smckusick * All rights reserved. 4*64412Smckusick * 5*64412Smckusick * %sccs.include.redist.c% 6*64412Smckusick * 7*64412Smckusick * @(#)ufs_readwrite.c 8.1 (Berkeley) 09/05/93 8*64412Smckusick */ 9*64412Smckusick 10*64412Smckusick #ifdef LFS_READWRITE 11*64412Smckusick #define BLKSIZE(a, b, c) blksize(a) 12*64412Smckusick #define FS struct lfs 13*64412Smckusick #define I_FS i_lfs 14*64412Smckusick #define READ lfs_read 15*64412Smckusick #define WRITE lfs_write 16*64412Smckusick #define fs_bsize lfs_bsize 17*64412Smckusick #define fs_maxfilesize lfs_maxfilesize 18*64412Smckusick #else 19*64412Smckusick #define BLKSIZE(a, b, c) blksize(a, b, c) 20*64412Smckusick #define FS struct fs 21*64412Smckusick #define I_FS i_fs 22*64412Smckusick #define READ ffs_read 23*64412Smckusick #define WRITE ffs_write 24*64412Smckusick #endif 25*64412Smckusick 26*64412Smckusick /* 27*64412Smckusick * Vnode op for reading. 28*64412Smckusick */ 29*64412Smckusick /* ARGSUSED */ 30*64412Smckusick READ(ap) 31*64412Smckusick struct vop_read_args /* { 32*64412Smckusick struct vnode *a_vp; 33*64412Smckusick struct uio *a_uio; 34*64412Smckusick int a_ioflag; 35*64412Smckusick struct ucred *a_cred; 36*64412Smckusick } */ *ap; 37*64412Smckusick { 38*64412Smckusick register struct vnode *vp; 39*64412Smckusick register struct inode *ip; 40*64412Smckusick register struct uio *uio; 41*64412Smckusick register FS *fs; 42*64412Smckusick struct buf *bp; 43*64412Smckusick daddr_t lbn, nextlbn; 44*64412Smckusick off_t bytesinfile; 45*64412Smckusick long size, xfersize, blkoffset; 46*64412Smckusick int type, nextsize, error; 47*64412Smckusick u_short mode; 48*64412Smckusick 49*64412Smckusick vp = ap->a_vp; 50*64412Smckusick ip = VTOI(vp); 51*64412Smckusick mode = ip->i_mode; 52*64412Smckusick uio = ap->a_uio; 53*64412Smckusick 54*64412Smckusick #ifdef DIAGNOSTIC 55*64412Smckusick if (uio->uio_rw != UIO_READ) 56*64412Smckusick panic("%s: mode", READ); 57*64412Smckusick 58*64412Smckusick if (vp->v_type == VLNK) { 59*64412Smckusick if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen) 60*64412Smckusick panic("%s: short symlink", READ); 61*64412Smckusick } else if (vp->v_type != VREG && vp->v_type != VDIR) 62*64412Smckusick panic("%s: type", READ); 63*64412Smckusick #endif 64*64412Smckusick fs = ip->I_FS; 65*64412Smckusick if ((u_quad_t)uio->uio_offset > fs->fs_maxfilesize) 66*64412Smckusick return (EFBIG); 67*64412Smckusick 68*64412Smckusick for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { 69*64412Smckusick if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0) 70*64412Smckusick break; 71*64412Smckusick lbn = lblkno(fs, uio->uio_offset); 72*64412Smckusick nextlbn = lbn + 1; 73*64412Smckusick size = BLKSIZE(fs, ip, lbn); 74*64412Smckusick blkoffset = blkoff(fs, uio->uio_offset); 75*64412Smckusick xfersize = fs->fs_bsize - blkoffset; 76*64412Smckusick if (uio->uio_resid < xfersize) 77*64412Smckusick xfersize = uio->uio_resid; 78*64412Smckusick if (bytesinfile < xfersize) 79*64412Smckusick xfersize = bytesinfile; 80*64412Smckusick 81*64412Smckusick #ifdef LFS_READWRITE 82*64412Smckusick (void)lfs_check(vp, lbn); 83*64412Smckusick error = cluster_read(vp, ip->i_size, lbn, size, NOCRED, &bp); 84*64412Smckusick #else 85*64412Smckusick if (lblktosize(fs, nextlbn) > ip->i_size) { 86*64412Smckusick error = bread(vp, lbn, size, NOCRED, &bp); 87*64412Smckusick } else { 88*64412Smckusick if (doclusterread) { 89*64412Smckusick error = cluster_read(vp, 90*64412Smckusick ip->i_size, lbn, size, NOCRED, &bp); 91*64412Smckusick } else if (lbn - 1 == vp->v_lastr) { 92*64412Smckusick nextsize = BLKSIZE(fs, ip, nextlbn); 93*64412Smckusick error = breadn(vp, lbn, 94*64412Smckusick size, &nextlbn, &nextsize, 1, NOCRED, &bp); 95*64412Smckusick } else { 96*64412Smckusick error = bread(vp, lbn, size, NOCRED, &bp); 97*64412Smckusick } 98*64412Smckusick } 99*64412Smckusick #endif 100*64412Smckusick if (error) 101*64412Smckusick break; 102*64412Smckusick vp->v_lastr = lbn; 103*64412Smckusick 104*64412Smckusick /* 105*64412Smckusick * We should only get non-zero b_resid when an I/O error 106*64412Smckusick * has occurred, which should cause us to break above. 107*64412Smckusick * However, if the short read did not cause an error, 108*64412Smckusick * then we want to ensure that we do not uiomove bad 109*64412Smckusick * or uninitialized data. 110*64412Smckusick */ 111*64412Smckusick size -= bp->b_resid; 112*64412Smckusick if (size < xfersize) { 113*64412Smckusick if (size == 0) 114*64412Smckusick break; 115*64412Smckusick xfersize = size; 116*64412Smckusick } 117*64412Smckusick if (error = 118*64412Smckusick uiomove(bp->b_un.b_addr + blkoffset, (int)xfersize, uio)) 119*64412Smckusick break; 120*64412Smckusick 121*64412Smckusick if (S_ISREG(mode) && (xfersize + blkoffset == fs->fs_bsize || 122*64412Smckusick uio->uio_offset == ip->i_size)) 123*64412Smckusick bp->b_flags |= B_AGE; 124*64412Smckusick brelse(bp); 125*64412Smckusick } 126*64412Smckusick if (bp != NULL) 127*64412Smckusick brelse(bp); 128*64412Smckusick ip->i_flag |= IACC; 129*64412Smckusick return (error); 130*64412Smckusick } 131*64412Smckusick 132*64412Smckusick /* 133*64412Smckusick * Vnode op for writing. 134*64412Smckusick */ 135*64412Smckusick WRITE(ap) 136*64412Smckusick struct vop_write_args /* { 137*64412Smckusick struct vnode *a_vp; 138*64412Smckusick struct uio *a_uio; 139*64412Smckusick int a_ioflag; 140*64412Smckusick struct ucred *a_cred; 141*64412Smckusick } */ *ap; 142*64412Smckusick { 143*64412Smckusick register struct vnode *vp; 144*64412Smckusick register struct uio *uio; 145*64412Smckusick register struct inode *ip; 146*64412Smckusick register FS *fs; 147*64412Smckusick struct buf *bp; 148*64412Smckusick struct proc *p; 149*64412Smckusick daddr_t lbn; 150*64412Smckusick off_t osize; 151*64412Smckusick int blkoffset, error, flags, ioflag, newblock, resid, size, xfersize; 152*64412Smckusick 153*64412Smckusick ioflag = ap->a_ioflag; 154*64412Smckusick uio = ap->a_uio; 155*64412Smckusick vp = ap->a_vp; 156*64412Smckusick ip = VTOI(vp); 157*64412Smckusick 158*64412Smckusick #ifdef DIAGNOSTIC 159*64412Smckusick if (uio->uio_rw != UIO_WRITE) 160*64412Smckusick panic("%s: mode", WRITE); 161*64412Smckusick #endif 162*64412Smckusick 163*64412Smckusick switch (vp->v_type) { 164*64412Smckusick case VREG: 165*64412Smckusick if (ioflag & IO_APPEND) 166*64412Smckusick uio->uio_offset = ip->i_size; 167*64412Smckusick if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size) 168*64412Smckusick return (EPERM); 169*64412Smckusick /* FALLTHROUGH */ 170*64412Smckusick case VLNK: 171*64412Smckusick break; 172*64412Smckusick case VDIR: 173*64412Smckusick if ((ioflag & IO_SYNC) == 0) 174*64412Smckusick panic("%s: nonsync dir write", WRITE); 175*64412Smckusick break; 176*64412Smckusick default: 177*64412Smckusick panic("%s: type", WRITE); 178*64412Smckusick } 179*64412Smckusick 180*64412Smckusick fs = ip->I_FS; 181*64412Smckusick if (uio->uio_offset < 0 || 182*64412Smckusick (u_quad_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize) 183*64412Smckusick return (EFBIG); 184*64412Smckusick /* 185*64412Smckusick * Maybe this should be above the vnode op call, but so long as 186*64412Smckusick * file servers have no limits, I don't think it matters. 187*64412Smckusick */ 188*64412Smckusick p = uio->uio_procp; 189*64412Smckusick if (vp->v_type == VREG && p && 190*64412Smckusick uio->uio_offset + uio->uio_resid > 191*64412Smckusick p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 192*64412Smckusick psignal(p, SIGXFSZ); 193*64412Smckusick return (EFBIG); 194*64412Smckusick } 195*64412Smckusick 196*64412Smckusick resid = uio->uio_resid; 197*64412Smckusick osize = ip->i_size; 198*64412Smckusick flags = ioflag & IO_SYNC ? B_SYNC : 0; 199*64412Smckusick 200*64412Smckusick for (error = 0; uio->uio_resid > 0;) { 201*64412Smckusick lbn = lblkno(fs, uio->uio_offset); 202*64412Smckusick blkoffset = blkoff(fs, uio->uio_offset); 203*64412Smckusick xfersize = fs->fs_bsize - blkoffset; 204*64412Smckusick if (uio->uio_resid < xfersize) 205*64412Smckusick xfersize = uio->uio_resid; 206*64412Smckusick #ifdef LFS_READWRITE 207*64412Smckusick (void)lfs_check(vp, lbn); 208*64412Smckusick error = lfs_balloc(vp, xfersize, lbn, &bp); 209*64412Smckusick #else 210*64412Smckusick if (fs->fs_bsize > xfersize) 211*64412Smckusick flags |= B_CLRBUF; 212*64412Smckusick else 213*64412Smckusick flags &= ~B_CLRBUF; 214*64412Smckusick 215*64412Smckusick error = ffs_balloc(ip, 216*64412Smckusick lbn, blkoffset + xfersize, ap->a_cred, &bp, flags); 217*64412Smckusick #endif 218*64412Smckusick if (error) 219*64412Smckusick break; 220*64412Smckusick if (uio->uio_offset + xfersize > ip->i_size) { 221*64412Smckusick ip->i_size = uio->uio_offset + xfersize; 222*64412Smckusick vnode_pager_setsize(vp, (u_long)ip->i_size); 223*64412Smckusick } 224*64412Smckusick (void)vnode_pager_uncache(vp); 225*64412Smckusick 226*64412Smckusick size = BLKSIZE(fs, ip, lbn) - bp->b_resid; 227*64412Smckusick if (size < xfersize) 228*64412Smckusick xfersize = size; 229*64412Smckusick 230*64412Smckusick error = 231*64412Smckusick uiomove(bp->b_un.b_addr + blkoffset, (int)xfersize, uio); 232*64412Smckusick #ifdef LFS_READWRITE 233*64412Smckusick (void)VOP_BWRITE(bp); 234*64412Smckusick #else 235*64412Smckusick if (ioflag & IO_SYNC) 236*64412Smckusick (void)bwrite(bp); 237*64412Smckusick else if (xfersize + blkoffset == fs->fs_bsize) 238*64412Smckusick if (doclusterwrite) 239*64412Smckusick cluster_write(bp, ip->i_size); 240*64412Smckusick else { 241*64412Smckusick bp->b_flags |= B_AGE; 242*64412Smckusick bawrite(bp); 243*64412Smckusick } 244*64412Smckusick else 245*64412Smckusick bdwrite(bp); 246*64412Smckusick #endif 247*64412Smckusick if (error || xfersize == 0) 248*64412Smckusick break; 249*64412Smckusick ip->i_flag |= IUPD | ICHG; 250*64412Smckusick } 251*64412Smckusick /* 252*64412Smckusick * If we successfully wrote any data, and we are not the superuser 253*64412Smckusick * we clear the setuid and setgid bits as a precaution against 254*64412Smckusick * tampering. 255*64412Smckusick */ 256*64412Smckusick if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0) 257*64412Smckusick ip->i_mode &= ~(ISUID | ISGID); 258*64412Smckusick if (error) { 259*64412Smckusick if (ioflag & IO_UNIT) { 260*64412Smckusick (void)VOP_TRUNCATE(vp, osize, 261*64412Smckusick ioflag & IO_SYNC, ap->a_cred, uio->uio_procp); 262*64412Smckusick uio->uio_offset -= resid - uio->uio_resid; 263*64412Smckusick uio->uio_resid = resid; 264*64412Smckusick } 265*64412Smckusick } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) 266*64412Smckusick error = VOP_UPDATE(vp, &time, &time, 1); 267*64412Smckusick return (error); 268*64412Smckusick } 269