- dev = (dev_t)ip->i_rdev;
- if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
- mem_no != major(dev)) ) {
- u.u_error = EINVAL;
- return;
- }
- type = ip->i_mode & IFMT;
- if (type == IFCHR) {
- ip->i_flag |= IUPD|ICHG;
- CHARGE(sc_tio * u.u_count);
- (*cdevsw[major(dev)].d_write)(dev);
- return;
- }
- if (u.u_count == 0)
- return;
- if ((ip->i_mode & IFMT) == IFREG &&
- u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
- psignal(u.u_procp, SIGXFSZ);
- u.u_error = EMFILE;
- return;
- }
- if (type!=IFBLK) {
- dev = ip->i_dev;
- fs = ip->i_fs;
- bsize = fs->fs_bsize;
- } else
- bsize = BLKDEV_IOSIZE;
- do {
- lbn = u.u_offset / bsize;
- on = u.u_offset % bsize;
- n = MIN((unsigned)(bsize - on), u.u_count);
- if (type != IFBLK) {
- bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
- if (u.u_error || (long)bn<0)
- return;
- if(u.u_offset + n > ip->i_size &&
- (type == IFDIR || type == IFREG || type == IFLNK))
- ip->i_size = u.u_offset + n;
- size = blksize(fs, ip, lbn);
- } else {
- size = bsize;
- bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
- }
- count = howmany(size, DEV_BSIZE);
- for (i = 0; i < count; i += CLSIZE)
- if (mfind(dev, bn + i))
- munhash(dev, bn + i);
- if (n == bsize)
- bp = getblk(dev, bn, size);
- else
- bp = bread(dev, bn, size);
- if (u.u_segflg != 1) {
- if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
- u.u_error = EFAULT;
- goto bad;
- }
- } else
- bcopy(u.u_base, bp->b_un.b_addr + on, n);
- u.u_base += n;
- u.u_offset += n;
- u.u_count -= n;
-bad:
- ;
- if (u.u_error != 0)
- brelse(bp);
- else {
- if ((ip->i_mode&IFMT) == IFDIR)
- /*
- * Writing to clear a directory entry.
- * Must insure the write occurs before
- * the inode is freed, or may end up
- * pointing at a new (different) file
- * if inode is quickly allocated again
- * and system crashes.
- */
- bwrite(bp);
- else if (n + on == bsize) {
- bp->b_flags |= B_AGE;
- bawrite(bp);
- } else
- bdwrite(bp);
- }
- ip->i_flag |= IUPD|ICHG;
- if (u.u_ruid != 0)
- ip->i_mode &= ~(ISUID|ISGID);
- } while (u.u_error == 0 && u.u_count != 0);
-}
-
-/*
- * Move n bytes at byte location
- * &bp->b_un.b_addr[o] to/from (flag) the
- * user/kernel (u.segflg) area starting at u.base.
- * Update all the arguments by the number
- * of bytes moved.
- */
-iomove(cp, n, flag)
- register caddr_t cp;
- register unsigned n;
-{
- register int t;
-
- if (n==0)
- return;
- if (u.u_segflg != 1) {
- if (flag==B_WRITE)
- t = copyin(u.u_base, (caddr_t)cp, n);
- else
- t = copyout((caddr_t)cp, u.u_base, n);
- if (t) {
- u.u_error = EFAULT;
- return;
- }
- } else
- if (flag == B_WRITE)
- bcopy(u.u_base, (caddr_t)cp, n);
- else
- bcopy((caddr_t)cp, u.u_base, n);
- u.u_base += n;
- u.u_offset += n;
- u.u_count -= n;
-}
-
-readip(ip, uio)
- register struct inode *ip;
- register struct uio *uio;
-{
- register struct iovec *iov = uio->uio_iov;
- struct buf *bp;
- struct fs *fs;
- dev_t dev;
- daddr_t lbn, bn;
- off_t diff;
- register int on, type;
- register unsigned n;
- int size;
- long bsize;
- extern int mem_no;
- int error = 0;
-
- uio->uio_resid = 0;
- if (uio->uio_iovcnt == 0)
- return (0);
- dev = (dev_t)ip->i_rdev;
- if (uio->uio_offset < 0 &&
- ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) {
- error = EINVAL;
- goto bad;
- }
- ip->i_flag |= IACC;
- type = ip->i_mode&IFMT;
- if (type == IFCHR) {
- register c = u.u_count;
- error = (*cdevsw[major(dev)].d_read)(dev, uio);
- CHARGE(sc_tio * (c - u.u_count));
- return (error);
- }
- if (type != IFBLK) {
- dev = ip->i_dev;
- fs = ip->i_fs;
- bsize = fs->fs_bsize;
- } else
- bsize = BLKDEV_IOSIZE;
-nextiov:
- if (uio->uio_iovcnt == 0)
- goto getresid;
- if (iov->iov_len > 0)
- do {
- lbn = uio->uio_offset / bsize;
- on = uio->uio_offset % bsize;
- n = MIN((unsigned)(bsize - on), iov->iov_len);
- if (type != IFBLK) {
- diff = ip->i_size - uio->uio_offset;
- if (diff <= 0)
- return;
- if (diff < n)
- n = diff;
- bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
- if (u.u_error)
- goto getresid;
- size = blksize(fs, ip, lbn);
- } else {
- size = bsize;
- bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
- rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
- rasize = bsize;
- }
- if ((long)bn<0) {
- bp = geteblk(size);
- clrbuf(bp);
- } else if (ip->i_lastr + 1 == lbn)
- bp = breada(dev, bn, size, rablock, rasize);
- else
- bp = bread(dev, bn, size);
- ip->i_lastr = lbn;
- n = MIN(n, size - bp->b_resid);
- if (n != 0) {
- if (uio->uio_segflg != 1) {
- if (copyout(bp->b_un.b_addr+on, iov->iov_base, n)) {
- error = EFAULT;
- goto getresid;
- }
- } else
- bcopy(bp->b_un.b_addr + on, iov->iov_base, n);
- iov->iov_base += n;
- uio->uio_offset += n;
- iov->iov_len -= n;
-bad:
- ;
- }
- if (n + on == bsize || uio->uio_offset == ip->i_size)
- bp->b_flags |= B_AGE;
- brelse(bp);
- } while (u.u_error == 0 && iov->iov_len != 0 && n != 0);
- if (u.u_error == 0 && n > 0) {
- iov++;
- uio->uio_iovcnt--;
- goto nextiov;
- }
-getresid:
- while (uio->uio_iovcnt > 0) {
- uio->uio_resid += iov->iov_len;
- iov++;
- uio->uio_iovcnt--;
- }
- return (error);