-/*
- * Vnode op for reading.
- */
-/* ARGSUSED */
-ufs_read(vp, uio, ioflag, cred)
- struct vnode *vp;
- register struct uio *uio;
- int ioflag;
- struct ucred *cred;
-{
- register struct inode *ip = VTOI(vp);
- register struct fs *fs;
- struct buf *bp;
- daddr_t lbn, bn, rablock;
- int size, diff, error = 0;
- long n, on, type;
-
-#ifdef DIAGNOSTIC
- if (uio->uio_rw != UIO_READ)
- panic("ufs_read mode");
- type = ip->i_mode & IFMT;
- if (type != IFDIR && type != IFREG && type != IFLNK)
- panic("ufs_read type");
-#endif
- if (uio->uio_resid == 0)
- return (0);
- if (uio->uio_offset < 0)
- return (EINVAL);
- ip->i_flag |= IACC;
- fs = ip->i_fs;
- do {
- lbn = lblkno(fs, uio->uio_offset);
- on = blkoff(fs, uio->uio_offset);
- n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid);
- diff = ip->i_size - uio->uio_offset;
- if (diff <= 0)
- return (0);
- if (diff < n)
- n = diff;
- size = blksize(fs, ip, lbn);
- rablock = lbn + 1;
- if (vp->v_lastr + 1 == lbn &&
- lblktosize(fs, rablock) < ip->i_size)
- error = breada(ITOV(ip), lbn, size, rablock,
- blksize(fs, ip, rablock), NOCRED, &bp);
- else
- error = bread(ITOV(ip), lbn, size, NOCRED, &bp);
- vp->v_lastr = lbn;
- n = MIN(n, size - bp->b_resid);
- if (error) {
- brelse(bp);
- return (error);
- }
- error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
- if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size)
- bp->b_flags |= B_AGE;
- brelse(bp);
- } while (error == 0 && uio->uio_resid > 0 && n != 0);
- return (error);
-}
-
-/*
- * Vnode op for writing.
- */
-ufs_write(vp, uio, ioflag, cred)
- register struct vnode *vp;
- struct uio *uio;
- int ioflag;
- struct ucred *cred;
-{
- struct proc *p = uio->uio_procp;
- register struct inode *ip = VTOI(vp);
- register struct fs *fs;
- struct buf *bp;
- daddr_t lbn, bn;
- u_long osize;
- int n, on, flags;
- int size, resid, error = 0;
-
-#ifdef DIAGNOSTIC
- if (uio->uio_rw != UIO_WRITE)
- panic("ufs_write mode");
-#endif
- switch (vp->v_type) {
- case VREG:
- if (ioflag & IO_APPEND)
- uio->uio_offset = ip->i_size;
- /* fall through */
- case VLNK:
- break;
-
- case VDIR:
- if ((ioflag & IO_SYNC) == 0)
- panic("ufs_write nonsync dir write");
- break;
-
- default:
- panic("ufs_write type");
- }
- if (uio->uio_offset < 0)
- return (EINVAL);
- if (uio->uio_resid == 0)
- return (0);
- /*
- * Maybe this should be above the vnode op call, but so long as
- * file servers have no limits, i don't think it matters
- */
- if (vp->v_type == VREG && p &&
- uio->uio_offset + uio->uio_resid >
- p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
- psignal(p, SIGXFSZ);
- return (EFBIG);
- }
- resid = uio->uio_resid;
- osize = ip->i_size;
- fs = ip->i_fs;
- flags = 0;
- if (ioflag & IO_SYNC)
- flags = B_SYNC;
- do {
- lbn = lblkno(fs, uio->uio_offset);
- on = blkoff(fs, uio->uio_offset);
- n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid);
- if (n < fs->fs_bsize)
- flags |= B_CLRBUF;
- else
- flags &= ~B_CLRBUF;
- if (error = balloc(ip, lbn, (int)(on + n), &bp, flags))
- break;
- bn = bp->b_blkno;
- if (uio->uio_offset + n > ip->i_size) {
- ip->i_size = uio->uio_offset + n;
- vnode_pager_setsize(vp, ip->i_size);
- }
- size = blksize(fs, ip, lbn);
- (void) vnode_pager_uncache(vp);
- n = MIN(n, size - bp->b_resid);
- error = uiomove(bp->b_un.b_addr + on, n, uio);
- if (ioflag & IO_SYNC)
- (void) bwrite(bp);
- else if (n + on == fs->fs_bsize) {
- bp->b_flags |= B_AGE;
- bawrite(bp);
- } else
- bdwrite(bp);
- ip->i_flag |= IUPD|ICHG;
- if (cred->cr_uid != 0)
- ip->i_mode &= ~(ISUID|ISGID);
- } while (error == 0 && uio->uio_resid > 0 && n != 0);
- if (error && (ioflag & IO_UNIT)) {
- (void) itrunc(ip, osize, ioflag & IO_SYNC);
- uio->uio_offset -= resid - uio->uio_resid;
- uio->uio_resid = resid;
- }
- if (!error && (ioflag & IO_SYNC))
- error = iupdat(ip, &time, &time, 1);
- return (error);
-}
-