FreeBSD/sys/fs/ext2fs/ext2_bmap.c
/*
 * Indirect blocks are now on the vnode for the file.  They are given negative
 * logical block numbers.  Indirect blocks are addressed by the negative
 * address of the first data block to which they point.  Double indirect blocks
 * are addressed by one less than the address of the first indirect block to
 * which they point.  Triple indirect blocks are addressed by one less than
 * the address of the first double indirect block to which they point.
 *
 * ext2_bmaparray does the bmap conversion, and if requested returns the
 * array of logical blocks which must be traversed to get to a block.
 * Each entry contains the offset into that block that gets you to the
 * next block and the disk address of the block (if it is assigned).
 */
Indirect blocks are now on the vnode for the file.  They are given negative
logical block numbers.  Indirect blocks are addressed by the negative
address of the first data block to which they point.  Double indirect blocks
are addressed by one less than the address of the first indirect block to
which they point.  Triple indirect blocks are addressed by one less than
the address of the first double indirect block to which they point.

ext2_bmaparray does the bmap conversion, and if requested returns the
array of logical blocks which must be traversed to get to a block.
Each entry contains the offset into that block that gets you to the
next block and the disk address of the block (if it is assigned).
Indirect blocks are now on the vnode for the file . They are given negative logical block numbers . Indirect blocks are addressed by the negative address of the first data block to which they point . Double indirect blocks are addressed by one less than the address of the first indirect block to which they point . Triple indirect blocks are addressed by one less than the address of the first double indirect block to which they point . ext2_bmaparray does the bmap conversion and if requested returns the array of logical blocks which must be traversed to get to a block . Each entry contains the offset into that block that gets you to the next block and the disk address of the block ( if it is assigned ) .
int
ext2_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, int *runp, int *runb)
{
	struct inode *ip;
	struct buf *bp;
	struct ext2mount *ump;
	struct mount *mp;
	struct indir a[NIADDR+1], *ap;
	daddr_t daddr;
	e2fs_lbn_t metalbn;
	int error, num, maxrun = 0, bsize;
	int *nump;
	ap = NULL;
	ip = VTOI(vp);
	mp = vp->v_mount;
	ump = VFSTOEXT2(mp);
	bsize = EXT2_BLOCK_SIZE(ump->um_e2fs);
	if (runp) {
		maxrun = mp->mnt_iosize_max / bsize - 1;
		*runp = 0;
	}
	if (runb) {
		*runb = 0;
	}
	ap = a;
	nump = &num;
	error = ext2_getlbns(vp, bn, ap, nump);
	if (error)
		return (error);
	num = *nump;
	if (num == 0) {
		*bnp = blkptrtodb(ump, ip->i_db[bn]);
		if (*bnp == 0) {
			*bnp = -1;
		} else if (runp) {
			daddr_t bnb = bn;
			for (++bn; bn < NDADDR && *runp < maxrun &&
			    is_sequential(ump, ip->i_db[bn - 1], ip->i_db[bn]);
			    ++bn, ++*runp);
			bn = bnb;
			if (runb && (bn > 0)) {
				for (--bn; (bn >= 0) && (*runb < maxrun) &&
					is_sequential(ump, ip->i_db[bn],
						ip->i_db[bn + 1]);
						--bn, ++*runb);
			}
		}
		return (0);
	}
	daddr = ip->i_ib[ap->in_off];
	for (bp = NULL, ++ap; --num; ++ap) {
		metalbn = ap->in_lbn;
		if ((daddr == 0 && !incore(&vp->v_bufobj, metalbn)) || metalbn == bn)
			break;
		if (bp)
			bqrelse(bp);
		bp = getblk(vp, metalbn, bsize, 0, 0, 0);
		if ((bp->b_flags & B_CACHE) == 0) {
#ifdef INVARIANTS
			if (!daddr)
				panic("ext2_bmaparray: indirect block not in cache");
#endif
			bp->b_blkno = blkptrtodb(ump, daddr);
			bp->b_iocmd = BIO_READ;
			bp->b_flags &= ~B_INVAL;
			bp->b_ioflags &= ~BIO_ERROR;
			vfs_busy_pages(bp, 0);
			bp->b_iooffset = dbtob(bp->b_blkno);
			bstrategy(bp);
#ifdef RACCT
			if (racct_enable) {
				PROC_LOCK(curproc);
				racct_add_buf(curproc, bp, 0);
				PROC_UNLOCK(curproc);
			}
#endif
			curthread->td_ru.ru_inblock++;
			error = bufwait(bp);
			if (error) {
				brelse(bp);
				return (error);
			}
		}
		daddr = ((e2fs_daddr_t *)bp->b_data)[ap->in_off];
		if (num == 1 && daddr && runp) {
			for (bn = ap->in_off + 1;
			    bn < MNINDIR(ump) && *runp < maxrun &&
			    is_sequential(ump,
			    ((e2fs_daddr_t *)bp->b_data)[bn - 1],
			    ((e2fs_daddr_t *)bp->b_data)[bn]);
			    ++bn, ++*runp);
			bn = ap->in_off;
			if (runb && bn) {
				for (--bn; bn >= 0 && *runb < maxrun &&
					is_sequential(ump,
					((e2fs_daddr_t *)bp->b_data)[bn],
					((e2fs_daddr_t *)bp->b_data)[bn + 1]);
					--bn, ++*runb);
			}
		}
	}
	if (bp)
		bqrelse(bp);
	if ((ip->i_flags & SF_SNAPSHOT) && daddr > 0 && daddr < ump->um_seqinc){
		*bnp = -1;
		return (0);
	}
	*bnp = blkptrtodb(ump, daddr);
	if (*bnp == 0) {
		*bnp = -1;
	}
	return (0);
}
int ext2_bmaparray ( struct vnode * vp , daddr_t bn , daddr_t * bnp , int * runp , int * runb ) { struct inode * ip ; struct buf * bp ; struct ext2mount * ump ; struct mount * mp ; struct indir a [ NIADDR + 1 ] , * ap ; daddr_t daddr ; e2fs_lbn_t metalbn ; int error , num , maxrun = 0 , bsize ; int * nump ; ap = NULL ; ip = VTOI ( vp ) ; mp = vp -> v_mount ; ump = VFSTOEXT2 ( mp ) ; bsize = EXT2_BLOCK_SIZE ( ump -> um_e2fs ) ; if ( runp ) { maxrun = mp -> mnt_iosize_max / bsize - 1 ; * runp = 0 ; } if ( runb ) { * runb = 0 ; } ap = a ; nump = & num ; error = ext2_getlbns ( vp , bn , ap , nump ) ; if ( error ) return ( error ) ; num = * nump ; if ( num == 0 ) { * bnp = blkptrtodb ( ump , ip -> i_db [ bn ] ) ; if ( * bnp == 0 ) { * bnp = -1 ; } else if ( runp ) { daddr_t bnb = bn ; for ( ++ bn ; bn < NDADDR && * runp < maxrun && is_sequential ( ump , ip -> i_db [ bn - 1 ] , ip -> i_db [ bn ] ) ; ++ bn , ++ * runp ) ; bn = bnb ; if ( runb && ( bn > 0 ) ) { for ( -- bn ; ( bn >= 0 ) && ( * runb < maxrun ) && is_sequential ( ump , ip -> i_db [ bn ] , ip -> i_db [ bn + 1 ] ) ; -- bn , ++ * runb ) ; } } return ( 0 ) ; } daddr = ip -> i_ib [ ap -> in_off ] ; for ( bp = NULL , ++ ap ; -- num ; ++ ap ) { metalbn = ap -> in_lbn ; if ( ( daddr == 0 && ! incore ( & vp -> v_bufobj , metalbn ) ) || metalbn == bn ) break ; if ( bp ) bqrelse ( bp ) ; bp = getblk ( vp , metalbn , bsize , 0 , 0 , 0 ) ; if ( ( bp -> b_flags & B_CACHE ) == 0 ) { #ifdef INVARIANTS if ( ! daddr ) panic ( " " ) ; #endif bp -> b_blkno = blkptrtodb ( ump , daddr ) ; bp -> b_iocmd = BIO_READ ; bp -> b_flags &= ~ B_INVAL ; bp -> b_ioflags &= ~ BIO_ERROR ; vfs_busy_pages ( bp , 0 ) ; bp -> b_iooffset = dbtob ( bp -> b_blkno ) ; bstrategy ( bp ) ; #ifdef RACCT if ( racct_enable ) { PROC_LOCK ( curproc ) ; racct_add_buf ( curproc , bp , 0 ) ; PROC_UNLOCK ( curproc ) ; } #endif curthread -> td_ru . ru_inblock ++ ; error = bufwait ( bp ) ; if ( error ) { brelse ( bp ) ; return ( error ) ; } } daddr = ( ( e2fs_daddr_t * ) bp -> b_data ) [ ap -> in_off ] ; if ( num == 1 && daddr && runp ) { for ( bn = ap -> in_off + 1 ; bn < MNINDIR ( ump ) && * runp < maxrun && is_sequential ( ump , ( ( e2fs_daddr_t * ) bp -> b_data ) [ bn - 1 ] , ( ( e2fs_daddr_t * ) bp -> b_data ) [ bn ] ) ; ++ bn , ++ * runp ) ; bn = ap -> in_off ; if ( runb && bn ) { for ( -- bn ; bn >= 0 && * runb < maxrun && is_sequential ( ump , ( ( e2fs_daddr_t * ) bp -> b_data ) [ bn ] , ( ( e2fs_daddr_t * ) bp -> b_data ) [ bn + 1 ] ) ; -- bn , ++ * runb ) ; } } } if ( bp ) bqrelse ( bp ) ; if ( ( ip -> i_flags & SF_SNAPSHOT ) && daddr > 0 && daddr < ump -> um_seqinc ) { * bnp = -1 ; return ( 0 ) ; } * bnp = blkptrtodb ( ump , daddr ) ; if ( * bnp == 0 ) { * bnp = -1 ; } return ( 0 ) ; }
Indirect blocks are now on the vnode for the file.
Indirect blocks are now on the vnode for the file .
/* Get disk address out of indirect block array */ /*
		 * Exit the loop if there is no disk address assigned yet and
		 * the indirect block isn't in the cache, or if we were
		 * looking for an indirect block and we've found it.
		 */ /*
		 * If we get here, we've either got the block in the cache
		 * or we have a disk address for it, go fetch it.
		 */ /*
	 * Since this is FFS independent code, we are out of scope for the
	 * definitions of BLK_NOCOPY and BLK_SNAP, but we do know that they
	 * will fall in the range 1..um_seqinc, so we use that test and
	 * return a request for a zeroed out buffer if attempts are made
	 * to read a BLK_NOCOPY or BLK_SNAP block.
	 */