void *win; vsize_t bytelen;
ext2fs_read(v)	void *v;{	struct vop_read_args /* {		struct vnode *a_vp;		struct uio *a_uio;		int a_ioflag;		struct ucred *a_cred;	} */ *ap = v;	struct vnode *vp;	struct inode *ip;	struct uio *uio;	struct m_ext2fs *fs;	struct buf *bp;	void *win;	vsize_t bytelen;	ufs_daddr_t lbn, nextlbn;	off_t bytesinfile;	long size, xfersize, blkoffset;	int error;	vp = ap->a_vp;	ip = VTOI(vp);	uio = ap->a_uio;#ifdef DIAGNOSTIC	if (uio->uio_rw != UIO_READ)		panic("%s: mode", "ext2fs_read");	if (vp->v_type == VLNK) {		if ((int)ip->i_e2fs_size < vp->v_mount->mnt_maxsymlinklen ||			(vp->v_mount->mnt_maxsymlinklen == 0 &&			 ip->i_e2fs_nblock == 0))			panic("%s: short symlink", "ext2fs_read");	} else if (vp->v_type != VREG && vp->v_type != VDIR)		panic("%s: type %d", "ext2fs_read", vp->v_type);#endif	fs = ip->i_e2fs;	if ((u_int64_t)uio->uio_offset >		((u_int64_t)0x80000000 * fs->e2fs_bsize - 1))		return (EFBIG);	if (uio->uio_resid == 0)		return (0);	if (vp->v_type == VREG) {		error = 0;		while (uio->uio_resid > 0) {			bytelen = MIN(ip->i_e2fs_size - uio->uio_offset,			    uio->uio_resid);			if (bytelen == 0) {				break;			}			win = ubc_alloc(&vp->v_uobj, uio->uio_offset,					&bytelen, UBC_READ);			error = uiomove(win, bytelen, uio);			ubc_release(win, 0);			if (error) {				break;			}		}		goto out;	}	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {		if ((bytesinfile = ip->i_e2fs_size - uio->uio_offset) <= 0)			break;		lbn = lblkno(fs, uio->uio_offset);		nextlbn = lbn + 1;		size = fs->e2fs_bsize;		blkoffset = blkoff(fs, uio->uio_offset);		xfersize = fs->e2fs_bsize - blkoffset;		if (uio->uio_resid < xfersize)			xfersize = uio->uio_resid;		if (bytesinfile < xfersize)			xfersize = bytesinfile;		if (lblktosize(fs, nextlbn) >= ip->i_e2fs_size)			error = bread(vp, lbn, size, NOCRED, &bp);		else if (doclusterread)			error = cluster_read(vp, &ip->i_ci,				ip->i_e2fs_size, lbn, size, NOCRED, &bp);		else if (lbn - 1 == ip->i_ci.ci_lastr) {			int nextsize = fs->e2fs_bsize;			error = breadn(vp, lbn,				size, &nextlbn, &nextsize, 1, NOCRED, &bp);		} else			error = bread(vp, lbn, size, NOCRED, &bp);		if (error)			break;		ip->i_ci.ci_lastr = lbn;		/*		 * We should only get non-zero b_resid when an I/O error		 * has occurred, which should cause us to break above.		 * However, if the short read did not cause an error,		 * then we want to ensure that we do not uiomove bad		 * or uninitialized data.		 */		size -= bp->b_resid;		if (size < xfersize) {			if (size == 0)				break;			xfersize = size;		}		error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);		if (error)			break;		brelse(bp);	}	if (bp != NULL)		brelse(bp);out:	if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {		ip->i_flag |= IN_ACCESS;		if ((ap->a_ioflag & IO_SYNC) == IO_SYNC)			error = ext2fs_update(ip, NULL, NULL, 1);	}	return (error);}