if (bpp != NULL) { bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0); bp->b_blkno = fsbtodb(fs, newb); if (flags & B_CLRBUF) clrbuf(bp); *bpp = bp; }
bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0); bp->b_blkno = fsbtodb(fs, newb); if (flags & B_CLRBUF) clrbuf(bp); *bpp = bp;
ext2fs_buf_alloc(struct inode *ip, daddr_t bn, int size, struct ucred *cred,     struct buf **bpp, int flags){	struct m_ext2fs *fs;	ufs_daddr_t nb;	struct buf *bp, *nbp;	struct vnode *vp = ITOV(ip);	struct indir indirs[NIADDR + 2];	ufs_daddr_t newb, lbn, *bap, pref;	int num, i, error;	u_int deallocated;	ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];	int unwindidx = -1;	UVMHIST_FUNC("ext2fs_buf_alloc"); UVMHIST_CALLED(ubchist);	UVMHIST_LOG(ubchist, "bn 0x%x", bn,0,0,0);	if (bpp != NULL) {		*bpp = NULL;	}	if (bn < 0)		return (EFBIG);	fs = ip->i_e2fs;	lbn = bn;	/*	 * The first NDADDR blocks are direct blocks	 */	if (bn < NDADDR) {		nb = fs2h32(ip->i_e2fs_blocks[bn]);		if (nb != 0) {			/*			 * the block is already allocated, just read it.			 */			if (bpp != NULL) {				error = bread(vp, bn, fs->e2fs_bsize, NOCRED,					      &bp);				if (error) {					brelse(bp);					return (error);				}				*bpp = bp;			}			return (0);		}		/*		 * allocate a new direct block.		 */		error = ext2fs_alloc(ip, bn,		    ext2fs_blkpref(ip, bn, bn, &ip->i_e2fs_blocks[0]),		    cred, &newb);		if (error)			return (error);		ip->i_e2fs_last_lblk = lbn;		ip->i_e2fs_last_blk = newb;		ip->i_e2fs_blocks[bn] = h2fs32(newb);		ip->i_flag |= IN_CHANGE | IN_UPDATE;		if (bpp != NULL) {			bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0);			bp->b_blkno = fsbtodb(fs, newb);			if (flags & B_CLRBUF)				clrbuf(bp);			*bpp = bp;		}		return (0);	}	/*	 * Determine the number of levels of indirection.	 */	pref = 0;	if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0)		return(error);#ifdef DIAGNOSTIC	if (num < 1)		panic ("ext2fs_balloc: ufs_getlbns returned indirect block");#endif	/*	 * Fetch the first indirect block allocating if necessary.	 */	--num;	nb = fs2h32(ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]);	allocib = NULL;	allocblk = allociblk;	if (nb == 0) {		pref = ext2fs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);		error = ext2fs_alloc(ip, lbn, pref, cred, &newb);		if (error)			return (error);		nb = newb;		*allocblk++ = nb;		ip->i_e2fs_last_blk = newb;		bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0);		bp->b_blkno = fsbtodb(fs, newb);		clrbuf(bp);		/*		 * Write synchronously so that indirect blocks		 * never point at garbage.		 */		if ((error = bwrite(bp)) != 0)			goto fail;		unwindidx = 0;		allocib = &ip->i_e2fs_blocks[NDADDR + indirs[0].in_off];		*allocib = h2fs32(newb);		ip->i_flag |= IN_CHANGE | IN_UPDATE;	}	/*	 * Fetch through the indirect blocks, allocating as necessary.	 */	for (i = 1;;) {		error = bread(vp,		    indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);		if (error) {			brelse(bp);			goto fail;		}		bap = (ufs_daddr_t *)bp->b_data;		nb = fs2h32(bap[indirs[i].in_off]);		if (i == num)			break;		i++;		if (nb != 0) {			brelse(bp);			continue;		}		pref = ext2fs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);		error = ext2fs_alloc(ip, lbn, pref, cred, &newb);		if (error) {			brelse(bp);			goto fail;		}		nb = newb;		*allocblk++ = nb;		ip->i_e2fs_last_blk = newb;		nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0);		nbp->b_blkno = fsbtodb(fs, nb);		clrbuf(nbp);		/*		 * Write synchronously so that indirect blocks		 * never point at garbage.		 */		if ((error = bwrite(nbp)) != 0) {			brelse(bp);			goto fail;		}		if (unwindidx < 0)			unwindidx = i - 1;		bap[indirs[i - 1].in_off] = h2fs32(nb);		/*		 * If required, write synchronously, otherwise use		 * delayed write.		 */		if (flags & B_SYNC) {			bwrite(bp);		} else {			bdwrite(bp);		}	}	/*	 * Get the data block, allocating if necessary.	 */	if (nb == 0) {		pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);		error = ext2fs_alloc(ip, lbn, pref, cred, &newb);		if (error) {			brelse(bp);			goto fail;		}		nb = newb;		*allocblk++ = nb;		ip->i_e2fs_last_lblk = lbn;		ip->i_e2fs_last_blk = newb;		bap[indirs[num].in_off] = h2fs32(nb);		/*		 * If required, write synchronously, otherwise use		 * delayed write.		 */		if (flags & B_SYNC) {			bwrite(bp);		} else {			bdwrite(bp);		}		if (bpp != NULL) {			nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);			nbp->b_blkno = fsbtodb(fs, nb);			if (flags & B_CLRBUF)				clrbuf(nbp);			*bpp = nbp;		}		return (0);	}	brelse(bp);	if (bpp != NULL) {		if (flags & B_CLRBUF) {			error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED,				      &nbp);			if (error) {				brelse(nbp);				goto fail;			}		} else {			nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);			nbp->b_blkno = fsbtodb(fs, nb);		}		*bpp = nbp;	}	return (0);fail:	/*	 * If we have failed part way through block allocation, we	 * have to deallocate any indirect blocks that we have allocated.	 */	for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {		ext2fs_blkfree(ip, *blkp);		deallocated += fs->e2fs_bsize;	}	if (unwindidx >= 0) {		if (unwindidx == 0) {			*allocib = 0;		} else {			int r;				r = bread(vp, indirs[unwindidx].in_lbn, 			    (int)fs->e2fs_bsize, NOCRED, &bp);			if (r) {				panic("Could not unwind indirect block, error %d", r);				brelse(bp);			} else {				bap = (ufs_daddr_t *)bp->b_data;				bap[indirs[unwindidx].in_off] = 0;				if (flags & B_SYNC)					bwrite(bp);				else					bdwrite(bp);			}		}		for (i = unwindidx + 1; i <= num; i++) {			bp = getblk(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize,			    0, 0);			bp->b_flags |= B_INVAL;			brelse(bp);		}	}	if (deallocated) {		ip->i_e2fs_nblock -= btodb(deallocated);		ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE;	}	return error;}