xfs_bmap_btree.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,360 行 · 第 1/5 页

C
2,360
字号
	XFS_BMBT_TRACE_CURSOR(cur, ENTRY);	XFS_BMBT_TRACE_ARGI(cur, level);	if (level == cur->bc_nlevels - 1) {		XFS_BMBT_TRACE_CURSOR(cur, EXIT);		*stat = 0;		return 0;	}	lbp = cur->bc_bufs[level];	left = XFS_BUF_TO_BMBT_BLOCK(lbp);#ifdef DEBUG	if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) {		XFS_BMBT_TRACE_CURSOR(cur, ERROR);		return error;	}#endif	if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) {		XFS_BMBT_TRACE_CURSOR(cur, EXIT);		*stat = 0;		return 0;	}	if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) {		XFS_BMBT_TRACE_CURSOR(cur, EXIT);		*stat = 0;		return 0;	}	mp = cur->bc_mp;	if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0,			&rbp, XFS_BMAP_BTREE_REF))) {		XFS_BMBT_TRACE_CURSOR(cur, ERROR);		return error;	}	right = XFS_BUF_TO_BMBT_BLOCK(rbp);	if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) {		XFS_BMBT_TRACE_CURSOR(cur, ERROR);		return error;	}	if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) {		XFS_BMBT_TRACE_CURSOR(cur, EXIT);		*stat = 0;		return 0;	}	if (level > 0) {		lkp = XFS_BMAP_KEY_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur);		lpp = XFS_BMAP_PTR_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur);		rkp = XFS_BMAP_KEY_IADDR(right, 1, cur);		rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);#ifdef DEBUG		for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) {			if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) {				XFS_BMBT_TRACE_CURSOR(cur, ERROR);				return error;			}		}#endif		memmove(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));		memmove(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));#ifdef DEBUG		if ((error = xfs_btree_check_lptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) {			XFS_BMBT_TRACE_CURSOR(cur, ERROR);			return error;		}#endif		*rkp = *lkp;		*rpp = *lpp; /* INT_: direct copy */		xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1);		xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1);	} else {		lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur);		rrp = XFS_BMAP_REC_IADDR(right, 1, cur);		memmove(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));		*rrp = *lrp;		xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1);		INT_SET(key.br_startoff, ARCH_CONVERT,			xfs_bmbt_disk_get_startoff(rrp));		rkp = &key;	}	INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1);	xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS);	INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1);#ifdef DEBUG	if (level > 0)		xfs_btree_check_key(XFS_BTNUM_BMAP, rkp, rkp + 1);	else		xfs_btree_check_rec(XFS_BTNUM_BMAP, rrp, rrp + 1);#endif	xfs_bmbt_log_block(cur, rbp, XFS_BB_NUMRECS);	if ((error = xfs_btree_dup_cursor(cur, &tcur))) {		XFS_BMBT_TRACE_CURSOR(cur, ERROR);		return error;	}	i = xfs_btree_lastrec(tcur, level);	XFS_WANT_CORRUPTED_GOTO(i == 1, error0);	if ((error = xfs_bmbt_increment(tcur, level, &i))) {		XFS_BMBT_TRACE_CURSOR(tcur, ERROR);		goto error1;	}	XFS_WANT_CORRUPTED_GOTO(i == 1, error0);	if ((error = xfs_bmbt_updkey(tcur, rkp, level + 1))) {		XFS_BMBT_TRACE_CURSOR(tcur, ERROR);		goto error1;	}	xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);	XFS_BMBT_TRACE_CURSOR(cur, EXIT);	*stat = 1;	return 0;error0:	XFS_BMBT_TRACE_CURSOR(cur, ERROR);error1:	xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);	return error;}/* * Determine the extent state. *//* ARGSUSED */STATIC xfs_exntst_txfs_extent_state(	xfs_filblks_t		blks,	int			extent_flag){	if (extent_flag) {		ASSERT(blks != 0);	/* saved for DMIG */		return XFS_EXT_UNWRITTEN;	}	return XFS_EXT_NORM;}/* * Split cur/level block in half. * Return new block number and its first record (to be inserted into parent). */STATIC int					/* error */xfs_bmbt_split(	xfs_btree_cur_t		*cur,	int			level,	xfs_fsblock_t		*bnop,	xfs_bmbt_key_t		*keyp,	xfs_btree_cur_t		**curp,	int			*stat)		/* success/failure */{	xfs_alloc_arg_t		args;		/* block allocation args */	int			error;		/* error return value */#ifdef XFS_BMBT_TRACE	static char		fname[] = "xfs_bmbt_split";#endif	int			i;		/* loop counter */	xfs_fsblock_t		lbno;		/* left sibling block number */	xfs_buf_t		*lbp;		/* left buffer pointer */	xfs_bmbt_block_t	*left;		/* left btree block */	xfs_bmbt_key_t		*lkp;		/* left btree key */	xfs_bmbt_ptr_t		*lpp;		/* left address pointer */	xfs_bmbt_rec_t		*lrp;		/* left record pointer */	xfs_buf_t		*rbp;		/* right buffer pointer */	xfs_bmbt_block_t	*right;		/* right btree block */	xfs_bmbt_key_t		*rkp;		/* right btree key */	xfs_bmbt_ptr_t		*rpp;		/* right address pointer */	xfs_bmbt_block_t	*rrblock;	/* right-right btree block */	xfs_buf_t		*rrbp;		/* right-right buffer pointer */	xfs_bmbt_rec_t		*rrp;		/* right record pointer */	XFS_BMBT_TRACE_CURSOR(cur, ENTRY);	XFS_BMBT_TRACE_ARGIFK(cur, level, *bnop, keyp);	args.tp = cur->bc_tp;	args.mp = cur->bc_mp;	lbp = cur->bc_bufs[level];	lbno = XFS_DADDR_TO_FSB(args.mp, XFS_BUF_ADDR(lbp));	left = XFS_BUF_TO_BMBT_BLOCK(lbp);	args.fsbno = cur->bc_private.b.firstblock;	if (args.fsbno == NULLFSBLOCK) {		args.fsbno = lbno;		args.type = XFS_ALLOCTYPE_START_BNO;	} else if (cur->bc_private.b.flist->xbf_low)		args.type = XFS_ALLOCTYPE_FIRST_AG;	else		args.type = XFS_ALLOCTYPE_NEAR_BNO;	args.mod = args.minleft = args.alignment = args.total = args.isfl =		args.userdata = args.minalignslop = 0;	args.minlen = args.maxlen = args.prod = 1;	args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL;	if (!args.wasdel && xfs_trans_get_block_res(args.tp) == 0) {		XFS_BMBT_TRACE_CURSOR(cur, ERROR);		return XFS_ERROR(ENOSPC);	}	if ((error = xfs_alloc_vextent(&args))) {		XFS_BMBT_TRACE_CURSOR(cur, ERROR);		return error;	}	if (args.fsbno == NULLFSBLOCK) {		XFS_BMBT_TRACE_CURSOR(cur, EXIT);		*stat = 0;		return 0;	}	ASSERT(args.len == 1);	cur->bc_private.b.firstblock = args.fsbno;	cur->bc_private.b.allocated++;	cur->bc_private.b.ip->i_d.di_nblocks++;	xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE);	XFS_TRANS_MOD_DQUOT_BYINO(args.mp, args.tp, cur->bc_private.b.ip,			XFS_TRANS_DQ_BCOUNT, 1L);	rbp = xfs_btree_get_bufl(args.mp, args.tp, args.fsbno, 0);	right = XFS_BUF_TO_BMBT_BLOCK(rbp);#ifdef DEBUG	if ((error = xfs_btree_check_lblock(cur, left, level, rbp))) {		XFS_BMBT_TRACE_CURSOR(cur, ERROR);		return error;	}#endif	INT_SET(right->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC);	right->bb_level = left->bb_level; /* INT_: direct copy */	INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2));	if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) &&	    cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1)		INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1);	i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1;	if (level > 0) {		lkp = XFS_BMAP_KEY_IADDR(left, i, cur);		lpp = XFS_BMAP_PTR_IADDR(left, i, cur);		rkp = XFS_BMAP_KEY_IADDR(right, 1, cur);		rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);#ifdef DEBUG		for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) {			if ((error = xfs_btree_check_lptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) {				XFS_BMBT_TRACE_CURSOR(cur, ERROR);				return error;			}		}#endif		memcpy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));		memcpy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));		xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));		xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));		keyp->br_startoff = INT_GET(rkp->br_startoff, ARCH_CONVERT);	} else {		lrp = XFS_BMAP_REC_IADDR(left, i, cur);		rrp = XFS_BMAP_REC_IADDR(right, 1, cur);		memcpy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));		xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));		keyp->br_startoff = xfs_bmbt_disk_get_startoff(rrp);	}	INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT)));	right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */	INT_SET(left->bb_rightsib, ARCH_CONVERT, args.fsbno);	INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno);	xfs_bmbt_log_block(cur, rbp, XFS_BB_ALL_BITS);	xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB);	if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) {		if ((error = xfs_btree_read_bufl(args.mp, args.tp,				INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, &rrbp,				XFS_BMAP_BTREE_REF))) {			XFS_BMBT_TRACE_CURSOR(cur, ERROR);			return error;		}		rrblock = XFS_BUF_TO_BMBT_BLOCK(rrbp);		if ((error = xfs_btree_check_lblock(cur, rrblock, level, rrbp))) {			XFS_BMBT_TRACE_CURSOR(cur, ERROR);			return error;		}		INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, args.fsbno);		xfs_bmbt_log_block(cur, rrbp, XFS_BB_LEFTSIB);	}	if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) {		xfs_btree_setbuf(cur, level, rbp);		cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT);	}	if (level + 1 < cur->bc_nlevels) {		if ((error = xfs_btree_dup_cursor(cur, curp))) {			XFS_BMBT_TRACE_CURSOR(cur, ERROR);			return error;		}		(*curp)->bc_ptrs[level + 1]++;	}	*bnop = args.fsbno;	XFS_BMBT_TRACE_CURSOR(cur, EXIT);	*stat = 1;	return 0;}/* * Update keys for the record. */STATIC intxfs_bmbt_updkey(	xfs_btree_cur_t		*cur,	xfs_bmbt_key_t		*keyp,	/* on-disk format */	int			level){	xfs_bmbt_block_t	*block;	xfs_buf_t		*bp;#ifdef DEBUG	int			error;#endif#ifdef XFS_BMBT_TRACE	static char		fname[] = "xfs_bmbt_updkey";#endif	xfs_bmbt_key_t		*kp;	int			ptr;	ASSERT(level >= 1);	XFS_BMBT_TRACE_CURSOR(cur, ENTRY);	XFS_BMBT_TRACE_ARGIK(cur, level, keyp);	for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) {		block = xfs_bmbt_get_block(cur, level, &bp);#ifdef DEBUG		if ((error = xfs_btree_check_lblock(cur, block, level, bp))) {			XFS_BMBT_TRACE_CURSOR(cur, ERROR);			return error;		}#endif		ptr = cur->bc_ptrs[level];		kp = XFS_BMAP_KEY_IADDR(block, ptr, cur);		*kp = *keyp;		xfs_bmbt_log_keys(cur, bp, ptr, ptr);	}	XFS_BMBT_TRACE_CURSOR(cur, EXIT);	return 0;}/* * Convert on-disk form of btree root to in-memory form. */voidxfs_bmdr_to_bmbt(	xfs_bmdr_block_t	*dblock,	int			dblocklen,	xfs_bmbt_block_t	*rblock,	int			rblocklen){	int			dmxr;	xfs_bmbt_key_t		*fkp;	xfs_bmbt_ptr_t		*fpp;	xfs_bmbt_key_t		*tkp;	xfs_bmbt_ptr_t		*tpp;	INT_SET(rblock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC);	rblock->bb_level = dblock->bb_level;	/* both in on-disk format */	ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) > 0);	rblock->bb_numrecs = dblock->bb_numrecs;/* both in on-disk format */	INT_SET(rblock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO);	INT_SET(rblock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO);	dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0);	fkp = XFS_BTREE_KEY_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr);	tkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen);	fpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr);	tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen);	dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT);	memcpy(tkp, fkp, sizeof(*fkp) * dmxr);	memcpy(tpp, fpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */}/* * Decrement cursor by one record at the level. * For nonzero levels the leaf-ward information is untouched. */int						/* error */xfs_bmbt_decrement(	xfs_btree_cur_t		*cur,	int			level,	int			*stat)		/* success/failure */{	xfs_bmbt_block_t	*block;	xfs_buf_t		*bp;	int			error;		/* error return value */#ifdef XFS_BMBT_TRACE	static char		fname[] = "xfs_bmbt_decrement";#endif	xfs_fsblock_t		fsbno;	int			lev;	xfs_mount_t		*mp;	xfs_trans_t		*tp;	XFS_BMBT_TRACE_CURSOR(cur, ENTRY);	XFS_BMBT_TRACE_ARGI(cur, level);	ASSERT(level < cur->bc_nlevels);	if (level < cur->bc_nlevels - 1)		xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA);	if (--cur->bc_ptrs[level] > 0) {		XFS_BMBT_TRACE_CURSOR(cur, EXIT);		*stat = 1;		return 0;	}	block = xfs_bmbt_get_block(cur, level, &bp);#ifdef DEBUG	if ((error = xfs_btree_check_lblock(cur, block, level, bp))) {		XFS_BMBT_TRACE_CURSOR(cur, ERROR);		return error;	}#endif	if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) {		XFS_BMBT_TRACE_CURSOR(cur, EXIT);		*stat = 0;		return 0;	}	for (lev = level + 1; lev < cur->bc_nlevels; lev++) {		if (--cur->bc_ptrs[lev] > 0)			break;		if (lev < cur->bc_nlevels - 1)			xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA);	}	if (lev == cur->bc_nlevels) {		XFS_BMBT_TRACE_CURSOR(cur, EXIT);		*stat = 0;		return 0;	}	tp = cur->bc_tp;	mp = cur->bc_mp;	for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) {		fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT);		if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp,				XFS_BMAP_BTREE_REF))) {			XFS_BMBT_TRACE_CURSOR(cur, ERROR);			return error;		}		lev--;		xfs_btree_setbuf(cur, lev, bp);		block = XFS_BUF_TO_BMBT_BLOCK(bp);		if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) {			XFS_BMBT_TRACE_CURSOR(cur, ERROR);			return error;		}		cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT);	}	XFS_BMBT_TRACE_CURSOR(cur, EXIT);	*stat = 1;	return 0;}/* * Delete the record pointed to by cur. */int					/* error */xfs_bmbt_delete(	xfs_btree_cur_t	*cur,	int		*stat)		/* success/failure */{	int		error;		/* error return value */#ifdef XFS_BMBT_TRACE	static char	fname[] = "xfs_bmbt_delete";#endif	int		i;	int		level;	XFS_BMBT_TRACE_CURSOR(cur, ENTRY);	for (level = 0, i = 2; i == 2; level++) {		if ((error = xfs_bmbt_delrec(cur, level, &i))) {			XFS_BMBT_TRACE_CURSOR(cur, ERROR);			return error;		}	}	if (i == 0) {		for (level = 1; level < cur->bc_nlevels; level++) {			if (cur->bc_ptrs[level] == 0) {				if ((error = xfs_bmbt_decrement(cur, level,						&i))) {					XFS_BMBT_TRACE_CURSOR(cur, ERROR);					return error;				}				break;			}		}	}	XFS_BMBT_TRACE_CURSOR(cur, EXIT);	*stat = i;	return 0;}/* * Convert a compressed bmap extent record to an uncompressed form. * This code must be in sync with the routines xfs_bmbt_get_startoff,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?