-/*
- * Vnode op for reading.
- */
-/* ARGSUSED */
-ffs_read(ap)
- struct vop_read_args /* {
- struct vnode *a_vp;
- struct uio *a_uio;
- int a_ioflag;
- struct ucred *a_cred;
- } */ *ap;
-{
- register struct vnode *vp = ap->a_vp;
- register struct inode *ip = VTOI(vp);
- register struct uio *uio = ap->a_uio;
- register struct fs *fs;
- struct buf *bp;
- daddr_t lbn, bn, rablock;
- off_t diff;
- int type, rasize, error = 0;
- long size, n, on;
-
- type = ip->i_mode & IFMT;
-#ifdef DIAGNOSTIC
- if (uio->uio_rw != UIO_READ)
- panic("ffs_read mode");
- if (type != IFDIR && type != IFREG && type != IFLNK)
- panic("ffs_read type");
- if (type == IFLNK && (int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
- panic("read short symlink");
-#endif
- if (uio->uio_resid == 0)
- return (0);
- fs = ip->i_fs;
- if ((u_quad_t)uio->uio_offset > fs->fs_maxfilesize)
- return (EFBIG);
- ip->i_flag |= IACC;
- 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 (doclusterread && lblktosize(fs, rablock) <= ip->i_size) {
- error = cluster_read(vp, ip->i_size, lbn, size,
- NOCRED, &bp);
- } else if (vp->v_lastr + 1 == lbn &&
- lblktosize(fs, rablock) < ip->i_size) {
- rasize = blksize(fs, ip, rablock);
- error = breadn(vp, lbn, size, &rablock,
- &rasize, 1, NOCRED, &bp);
- } else
- error = bread(vp, 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 (type == IFREG &&
- (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.
- */
-ffs_write(ap)
- struct vop_write_args /* {
- struct vnode *a_vp;
- struct uio *a_uio;
- int a_ioflag;
- struct ucred *a_cred;
- } */ *ap;
-{
- register struct vnode *vp = ap->a_vp;
- register struct uio *uio = ap->a_uio;
- register struct inode *ip = VTOI(vp);
- register struct fs *fs;
- struct proc *p = uio->uio_procp;
- int ioflag = ap->a_ioflag;
- struct timeval tv;
- struct buf *bp;
- daddr_t lbn, bn;
- off_t osize;
- int n, on, flags;
- int size, resid, error = 0;
-
-#ifdef DIAGNOSTIC
- if (uio->uio_rw != UIO_WRITE)
- panic("ffs_write mode");
-#endif
- switch (vp->v_type) {
- case VREG:
- if (ioflag & IO_APPEND)
- uio->uio_offset = ip->i_size;
- if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
- return (EPERM);
- /* fall through */
- case VLNK:
- break;
-
- case VDIR:
- if ((ioflag & IO_SYNC) == 0)
- panic("ffs_write nonsync dir write");
- break;
-
- default:
- panic("ffs_write type");
- }
- if (uio->uio_resid == 0)
- return (0);
- fs = ip->i_fs;
- if (uio->uio_offset < 0 ||
- (u_quad_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
- return (EFBIG);
- /*
- * 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;
- 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 = ffs_balloc(ip, lbn, on + n, ap->a_cred, &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, (u_long)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) {
- if (doclusterwrite) {
- cluster_write(bp, ip->i_size);
- } else {
- bp->b_flags |= B_AGE;
- bawrite(bp);
- }
- } else
- bdwrite(bp);
- ip->i_flag |= IUPD|ICHG;
- if (ap->a_cred && ap->a_cred->cr_uid != 0)
- ip->i_mode &= ~(ISUID|ISGID);
- } while (error == 0 && uio->uio_resid > 0 && n != 0);
- if (error && (ioflag & IO_UNIT)) {
- (void)VOP_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred,
- uio->uio_procp);
- uio->uio_offset -= resid - uio->uio_resid;
- uio->uio_resid = resid;
- }
- if (!error && (ioflag & IO_SYNC)) {
- tv = time;
- error = VOP_UPDATE(vp, &tv, &tv, 1);
- }
- return (error);
-}