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