1 /*- 2 * Copyright (c) 1993 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ufs_readwrite.c 8.5 (Berkeley) 01/11/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 nextsize, 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 { 92 if (doclusterread) { 93 error = cluster_read(vp, 94 ip->i_size, lbn, size, NOCRED, &bp); 95 } else if (lbn - 1 == vp->v_lastr) { 96 nextsize = BLKSIZE(fs, ip, nextlbn); 97 error = breadn(vp, lbn, 98 size, &nextlbn, &nextsize, 1, NOCRED, &bp); 99 } else { 100 error = bread(vp, lbn, size, NOCRED, &bp); 101 } 102 } 103 #endif 104 if (error) 105 break; 106 vp->v_lastr = lbn; 107 108 /* 109 * We should only get non-zero b_resid when an I/O error 110 * has occurred, which should cause us to break above. 111 * However, if the short read did not cause an error, 112 * then we want to ensure that we do not uiomove bad 113 * or uninitialized data. 114 */ 115 size -= bp->b_resid; 116 if (size < xfersize) { 117 if (size == 0) 118 break; 119 xfersize = size; 120 } 121 if (error = 122 uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio)) 123 break; 124 125 if (S_ISREG(mode) && (xfersize + blkoffset == fs->fs_bsize || 126 uio->uio_offset == ip->i_size)) 127 bp->b_flags |= B_AGE; 128 brelse(bp); 129 } 130 if (bp != NULL) 131 brelse(bp); 132 ip->i_flag |= IN_ACCESS; 133 return (error); 134 } 135 136 /* 137 * Vnode op for writing. 138 */ 139 WRITE(ap) 140 struct vop_write_args /* { 141 struct vnode *a_vp; 142 struct uio *a_uio; 143 int a_ioflag; 144 struct ucred *a_cred; 145 } */ *ap; 146 { 147 register struct vnode *vp; 148 register struct uio *uio; 149 register struct inode *ip; 150 register FS *fs; 151 struct buf *bp; 152 struct proc *p; 153 daddr_t lbn; 154 off_t osize; 155 int blkoffset, error, flags, ioflag, resid, size, xfersize; 156 157 ioflag = ap->a_ioflag; 158 uio = ap->a_uio; 159 vp = ap->a_vp; 160 ip = VTOI(vp); 161 162 #ifdef DIAGNOSTIC 163 if (uio->uio_rw != UIO_WRITE) 164 panic("%s: mode", WRITE_S); 165 #endif 166 167 switch (vp->v_type) { 168 case VREG: 169 if (ioflag & IO_APPEND) 170 uio->uio_offset = ip->i_size; 171 if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size) 172 return (EPERM); 173 /* FALLTHROUGH */ 174 case VLNK: 175 break; 176 case VDIR: 177 if ((ioflag & IO_SYNC) == 0) 178 panic("%s: nonsync dir write", WRITE_S); 179 break; 180 default: 181 panic("%s: type", WRITE_S); 182 } 183 184 fs = ip->I_FS; 185 if (uio->uio_offset < 0 || 186 (u_quad_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize) 187 return (EFBIG); 188 /* 189 * Maybe this should be above the vnode op call, but so long as 190 * file servers have no limits, I don't think it matters. 191 */ 192 p = uio->uio_procp; 193 if (vp->v_type == VREG && p && 194 uio->uio_offset + uio->uio_resid > 195 p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 196 psignal(p, SIGXFSZ); 197 return (EFBIG); 198 } 199 200 resid = uio->uio_resid; 201 osize = ip->i_size; 202 flags = ioflag & IO_SYNC ? B_SYNC : 0; 203 204 for (error = 0; uio->uio_resid > 0;) { 205 lbn = lblkno(fs, uio->uio_offset); 206 blkoffset = blkoff(fs, uio->uio_offset); 207 xfersize = fs->fs_bsize - blkoffset; 208 if (uio->uio_resid < xfersize) 209 xfersize = uio->uio_resid; 210 #ifdef LFS_READWRITE 211 (void)lfs_check(vp, lbn); 212 error = lfs_balloc(vp, xfersize, lbn, &bp); 213 #else 214 if (fs->fs_bsize > xfersize) 215 flags |= B_CLRBUF; 216 else 217 flags &= ~B_CLRBUF; 218 219 error = ffs_balloc(ip, 220 lbn, blkoffset + xfersize, ap->a_cred, &bp, flags); 221 #endif 222 if (error) 223 break; 224 if (uio->uio_offset + xfersize > ip->i_size) { 225 ip->i_size = uio->uio_offset + xfersize; 226 vnode_pager_setsize(vp, (u_long)ip->i_size); 227 } 228 (void)vnode_pager_uncache(vp); 229 230 size = BLKSIZE(fs, ip, lbn) - bp->b_resid; 231 if (size < xfersize) 232 xfersize = size; 233 234 error = 235 uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio); 236 #ifdef LFS_READWRITE 237 (void)VOP_BWRITE(bp); 238 #else 239 if (ioflag & IO_SYNC) 240 (void)bwrite(bp); 241 else if (xfersize + blkoffset == fs->fs_bsize) 242 if (doclusterwrite) 243 cluster_write(bp, ip->i_size); 244 else { 245 bp->b_flags |= B_AGE; 246 bawrite(bp); 247 } 248 else 249 bdwrite(bp); 250 #endif 251 if (error || xfersize == 0) 252 break; 253 ip->i_flag |= IN_CHANGE | IN_UPDATE; 254 } 255 /* 256 * If we successfully wrote any data, and we are not the superuser 257 * we clear the setuid and setgid bits as a precaution against 258 * tampering. 259 */ 260 if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0) 261 ip->i_mode &= ~(ISUID | ISGID); 262 if (error) { 263 if (ioflag & IO_UNIT) { 264 (void)VOP_TRUNCATE(vp, osize, 265 ioflag & IO_SYNC, ap->a_cred, uio->uio_procp); 266 uio->uio_offset -= resid - uio->uio_resid; 267 uio->uio_resid = resid; 268 } 269 } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) 270 error = VOP_UPDATE(vp, &time, &time, 1); 271 return (error); 272 } 273