FreeBSD/sys/fs/ext2fs/ext2_vnops.c
/*
 * this function handles ext4 extents block mapping
 */
this function handles ext4 extents block mapping
this function handles ext4 extents block mapping
static int
ext4_ext_read(struct vop_read_args *ap)
{
	static unsigned char zeroes[EXT2_MAX_BLOCK_SIZE];
	struct vnode *vp;
	struct inode *ip;
	struct uio *uio;
	struct m_ext2fs *fs;
	struct buf *bp;
	struct ext4_extent nex, *ep;
	struct ext4_extent_path path;
	daddr_t lbn, newblk;
	off_t bytesinfile;
	int cache_type;
	ssize_t orig_resid;
	int error;
	long size, xfersize, blkoffset;
	vp = ap->a_vp;
	ip = VTOI(vp);
	uio = ap->a_uio;
	memset(&path, 0, sizeof(path));
	orig_resid = uio->uio_resid;
	KASSERT(orig_resid >= 0, ("%s: uio->uio_resid < 0", __func__));
	if (orig_resid == 0)
		return (0);
	KASSERT(uio->uio_offset >= 0, ("%s: uio->uio_offset < 0", __func__));
	fs = ip->i_e2fs;
	if (uio->uio_offset < ip->i_size && uio->uio_offset >= fs->e2fs_maxfilesize)
		return (EOVERFLOW);
	while (uio->uio_resid > 0) {
		if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
			break;
		lbn = lblkno(fs, uio->uio_offset);
		size = blksize(fs, ip, lbn);
		blkoffset = blkoff(fs, uio->uio_offset);
		xfersize = fs->e2fs_fsize - blkoffset;
		xfersize = MIN(xfersize, uio->uio_resid);
		xfersize = MIN(xfersize, bytesinfile);
		cache_type = ext4_ext_in_cache(ip, lbn, &nex);
		switch (cache_type) {
		case EXT4_EXT_CACHE_NO:
			ext4_ext_find_extent(fs, ip, lbn, &path);
			if (path.ep_is_sparse)
				ep = &path.ep_sparse_ext;
			else
				ep = path.ep_ext;
			if (ep == NULL)
				return (EIO);
			ext4_ext_put_cache(ip, ep,
			    path.ep_is_sparse ? EXT4_EXT_CACHE_GAP : EXT4_EXT_CACHE_IN);
			newblk = lbn - ep->e_blk + (ep->e_start_lo |
			    (daddr_t)ep->e_start_hi << 32);
			if (path.ep_bp != NULL) {
				brelse(path.ep_bp);
				path.ep_bp = NULL;
			}
			break;
		case EXT4_EXT_CACHE_GAP:
			break;
		case EXT4_EXT_CACHE_IN:
			newblk = lbn - nex.e_blk + (nex.e_start_lo |
			    (daddr_t)nex.e_start_hi << 32);
			break;
		default:
			panic("%s: invalid cache type", __func__);
		}
		if (cache_type == EXT4_EXT_CACHE_GAP ||
		    (cache_type == EXT4_EXT_CACHE_NO && path.ep_is_sparse)) {
			if (xfersize > sizeof(zeroes))
				xfersize = sizeof(zeroes);
			error = uiomove(zeroes, xfersize, uio);
			if (error)
				return (error);
		} else {
			error = bread(ip->i_devvp, fsbtodb(fs, newblk), size,
			    NOCRED, &bp);
			if (error) {
				brelse(bp);
				return (error);
			}
			size -= bp->b_resid;
			if (size < xfersize) {
				if (size == 0) {
					bqrelse(bp);
					break;
				}
				xfersize = size;
			}
			error = uiomove(bp->b_data + blkoffset, xfersize, uio);
			bqrelse(bp);
			if (error)
				return (error);
		}
	}
	return (0);
}
static int ext4_ext_read ( struct vop_read_args * ap ) { static unsigned char zeroes [ EXT2_MAX_BLOCK_SIZE ] ; struct vnode * vp ; struct inode * ip ; struct uio * uio ; struct m_ext2fs * fs ; struct buf * bp ; struct ext4_extent nex , * ep ; struct ext4_extent_path path ; daddr_t lbn , newblk ; off_t bytesinfile ; int cache_type ; ssize_t orig_resid ; int error ; long size , xfersize , blkoffset ; vp = ap -> a_vp ; ip = VTOI ( vp ) ; uio = ap -> a_uio ; memset ( & path , 0 , sizeof ( path ) ) ; orig_resid = uio -> uio_resid ; KASSERT ( orig_resid >= 0 , ( " " , __func__ ) ) ; if ( orig_resid == 0 ) return ( 0 ) ; KASSERT ( uio -> uio_offset >= 0 , ( " " , __func__ ) ) ; fs = ip -> i_e2fs ; if ( uio -> uio_offset < ip -> i_size && uio -> uio_offset >= fs -> e2fs_maxfilesize ) return ( EOVERFLOW ) ; while ( uio -> uio_resid > 0 ) { if ( ( bytesinfile = ip -> i_size - uio -> uio_offset ) <= 0 ) break ; lbn = lblkno ( fs , uio -> uio_offset ) ; size = blksize ( fs , ip , lbn ) ; blkoffset = blkoff ( fs , uio -> uio_offset ) ; xfersize = fs -> e2fs_fsize - blkoffset ; xfersize = MIN ( xfersize , uio -> uio_resid ) ; xfersize = MIN ( xfersize , bytesinfile ) ; cache_type = ext4_ext_in_cache ( ip , lbn , & nex ) ; switch ( cache_type ) { case EXT4_EXT_CACHE_NO : ext4_ext_find_extent ( fs , ip , lbn , & path ) ; if ( path . ep_is_sparse ) ep = & path . ep_sparse_ext ; else ep = path . ep_ext ; if ( ep == NULL ) return ( EIO ) ; ext4_ext_put_cache ( ip , ep , path . ep_is_sparse ? EXT4_EXT_CACHE_GAP : EXT4_EXT_CACHE_IN ) ; newblk = lbn - ep -> e_blk + ( ep -> e_start_lo | ( daddr_t ) ep -> e_start_hi << 32 ) ; if ( path . ep_bp != NULL ) { brelse ( path . ep_bp ) ; path . ep_bp = NULL ; } break ; case EXT4_EXT_CACHE_GAP : break ; case EXT4_EXT_CACHE_IN : newblk = lbn - nex . e_blk + ( nex . e_start_lo | ( daddr_t ) nex . e_start_hi << 32 ) ; break ; default : panic ( " " , __func__ ) ; } if ( cache_type == EXT4_EXT_CACHE_GAP || ( cache_type == EXT4_EXT_CACHE_NO && path . ep_is_sparse ) ) { if ( xfersize > sizeof ( zeroes ) ) xfersize = sizeof ( zeroes ) ; error = uiomove ( zeroes , xfersize , uio ) ; if ( error ) return ( error ) ; } else { error = bread ( ip -> i_devvp , fsbtodb ( fs , newblk ) , size , NOCRED , & bp ) ; if ( error ) { brelse ( bp ) ; return ( error ) ; } size -= bp -> b_resid ; if ( size < xfersize ) { if ( size == 0 ) { bqrelse ( bp ) ; break ; } xfersize = size ; } error = uiomove ( bp -> b_data + blkoffset , xfersize , uio ) ; bqrelse ( bp ) ; if ( error ) return ( error ) ; } } return ( 0 ) ; }
this function handles ext4 extents block mapping
this function handles ext4 extents block mapping
/* get block from ext4 extent cache */ /* block has not been allocated yet */