- default:
- panic("ffs_write type");
- }
- if (uio->uio_resid == 0)
- return (0);
- fs = ip->i_fs;
- if (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) {
- bp->b_flags |= B_AGE;
- bawrite(bp);
- } else
- bdwrite(bp);
- ip->i_flag |= IUPD|ICHG;
- if (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);
-}