⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfs_alloc_btree.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 */STATIC voidxfs_alloc_log_ptrs(	xfs_btree_cur_t		*cur,	/* btree cursor */	xfs_buf_t		*bp,	/* buffer containing btree block */	int			pfirst,	/* index of first pointer to log */	int			plast)	/* index of last pointer to log */{	xfs_alloc_block_t	*block;	/* btree block to log from */	int			first;	/* first byte offset logged */	int			last;	/* last byte offset logged */	xfs_alloc_ptr_t		*pp;	/* block-pointer pointer in btree blk */	block = XFS_BUF_TO_ALLOC_BLOCK(bp);	pp = XFS_ALLOC_PTR_ADDR(block, 1, cur);	first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block);	last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block);	xfs_trans_log_buf(cur->bc_tp, bp, first, last);}/* * Log records from a btree block (leaf). */STATIC voidxfs_alloc_log_recs(	xfs_btree_cur_t		*cur,	/* btree cursor */	xfs_buf_t		*bp,	/* buffer containing btree block */	int			rfirst,	/* index of first record to log */	int			rlast)	/* index of last record to log */{	xfs_alloc_block_t	*block;	/* btree block to log from */	int			first;	/* first byte offset logged */	int			last;	/* last byte offset logged */	xfs_alloc_rec_t		*rp;	/* record pointer for btree block */	block = XFS_BUF_TO_ALLOC_BLOCK(bp);	rp = XFS_ALLOC_REC_ADDR(block, 1, cur);#ifdef DEBUG	{		xfs_agf_t	*agf;		xfs_alloc_rec_t	*p;		agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);		for (p = &rp[rfirst - 1]; p <= &rp[rlast - 1]; p++)			ASSERT(be32_to_cpu(p->ar_startblock) +			       be32_to_cpu(p->ar_blockcount) <=			       be32_to_cpu(agf->agf_length));	}#endif	first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block);	last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block);	xfs_trans_log_buf(cur->bc_tp, bp, first, last);}/* * Lookup the record.  The cursor is made to point to it, based on dir. * Return 0 if can't find any such record, 1 for success. */STATIC int				/* error */xfs_alloc_lookup(	xfs_btree_cur_t		*cur,	/* btree cursor */	xfs_lookup_t		dir,	/* <=, ==, or >= */	int			*stat)	/* success/failure */{	xfs_agblock_t		agbno;	/* a.g. relative btree block number */	xfs_agnumber_t		agno;	/* allocation group number */	xfs_alloc_block_t	*block=NULL;	/* current btree block */	int			diff;	/* difference for the current key */	int			error;	/* error return value */	int			keyno=0;	/* current key number */	int			level;	/* level in the btree */	xfs_mount_t		*mp;	/* file system mount point */	XFS_STATS_INC(xs_abt_lookup);	/*	 * Get the allocation group header, and the root block number.	 */	mp = cur->bc_mp;	{		xfs_agf_t	*agf;	/* a.g. freespace header */		agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);		agno = be32_to_cpu(agf->agf_seqno);		agbno = be32_to_cpu(agf->agf_roots[cur->bc_btnum]);	}	/*	 * Iterate over each level in the btree, starting at the root.	 * For each level above the leaves, find the key we need, based	 * on the lookup record, then follow the corresponding block	 * pointer down to the next level.	 */	for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) {		xfs_buf_t	*bp;	/* buffer pointer for btree block */		xfs_daddr_t	d;	/* disk address of btree block */		/*		 * Get the disk address we're looking for.		 */		d = XFS_AGB_TO_DADDR(mp, agno, agbno);		/*		 * If the old buffer at this level is for a different block,		 * throw it away, otherwise just use it.		 */		bp = cur->bc_bufs[level];		if (bp && XFS_BUF_ADDR(bp) != d)			bp = NULL;		if (!bp) {			/*			 * Need to get a new buffer.  Read it, then			 * set it in the cursor, releasing the old one.			 */			if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, agno,					agbno, 0, &bp, XFS_ALLOC_BTREE_REF)))				return error;			xfs_btree_setbuf(cur, level, bp);			/*			 * Point to the btree block, now that we have the buffer			 */			block = XFS_BUF_TO_ALLOC_BLOCK(bp);			if ((error = xfs_btree_check_sblock(cur, block, level,					bp)))				return error;		} else			block = XFS_BUF_TO_ALLOC_BLOCK(bp);		/*		 * If we already had a key match at a higher level, we know		 * we need to use the first entry in this block.		 */		if (diff == 0)			keyno = 1;		/*		 * Otherwise we need to search this block.  Do a binary search.		 */		else {			int		high;	/* high entry number */			xfs_alloc_key_t	*kkbase=NULL;/* base of keys in block */			xfs_alloc_rec_t	*krbase=NULL;/* base of records in block */			int		low;	/* low entry number */			/*			 * Get a pointer to keys or records.			 */			if (level > 0)				kkbase = XFS_ALLOC_KEY_ADDR(block, 1, cur);			else				krbase = XFS_ALLOC_REC_ADDR(block, 1, cur);			/*			 * Set low and high entry numbers, 1-based.			 */			low = 1;			if (!(high = be16_to_cpu(block->bb_numrecs))) {				/*				 * If the block is empty, the tree must				 * be an empty leaf.				 */				ASSERT(level == 0 && cur->bc_nlevels == 1);				cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE;				*stat = 0;				return 0;			}			/*			 * Binary search the block.			 */			while (low <= high) {				xfs_extlen_t	blockcount;	/* key value */				xfs_agblock_t	startblock;	/* key value */				XFS_STATS_INC(xs_abt_compare);				/*				 * keyno is average of low and high.				 */				keyno = (low + high) >> 1;				/*				 * Get startblock & blockcount.				 */				if (level > 0) {					xfs_alloc_key_t	*kkp;					kkp = kkbase + keyno - 1;					startblock = be32_to_cpu(kkp->ar_startblock);					blockcount = be32_to_cpu(kkp->ar_blockcount);				} else {					xfs_alloc_rec_t	*krp;					krp = krbase + keyno - 1;					startblock = be32_to_cpu(krp->ar_startblock);					blockcount = be32_to_cpu(krp->ar_blockcount);				}				/*				 * Compute difference to get next direction.				 */				if (cur->bc_btnum == XFS_BTNUM_BNO)					diff = (int)startblock -					       (int)cur->bc_rec.a.ar_startblock;				else if (!(diff = (int)blockcount -					    (int)cur->bc_rec.a.ar_blockcount))					diff = (int)startblock -					    (int)cur->bc_rec.a.ar_startblock;				/*				 * Less than, move right.				 */				if (diff < 0)					low = keyno + 1;				/*				 * Greater than, move left.				 */				else if (diff > 0)					high = keyno - 1;				/*				 * Equal, we're done.				 */				else					break;			}		}		/*		 * If there are more levels, set up for the next level		 * by getting the block number and filling in the cursor.		 */		if (level > 0) {			/*			 * If we moved left, need the previous key number,			 * unless there isn't one.			 */			if (diff > 0 && --keyno < 1)				keyno = 1;			agbno = be32_to_cpu(*XFS_ALLOC_PTR_ADDR(block, keyno, cur));#ifdef DEBUG			if ((error = xfs_btree_check_sptr(cur, agbno, level)))				return error;#endif			cur->bc_ptrs[level] = keyno;		}	}	/*	 * Done with the search.	 * See if we need to adjust the results.	 */	if (dir != XFS_LOOKUP_LE && diff < 0) {		keyno++;		/*		 * If ge search and we went off the end of the block, but it's		 * not the last block, we're in the wrong block.		 */		if (dir == XFS_LOOKUP_GE &&		    keyno > be16_to_cpu(block->bb_numrecs) &&		    be32_to_cpu(block->bb_rightsib) != NULLAGBLOCK) {			int	i;			cur->bc_ptrs[0] = keyno;			if ((error = xfs_alloc_increment(cur, 0, &i)))				return error;			XFS_WANT_CORRUPTED_RETURN(i == 1);			*stat = 1;			return 0;		}	}	else if (dir == XFS_LOOKUP_LE && diff > 0)		keyno--;	cur->bc_ptrs[0] = keyno;	/*	 * Return if we succeeded or not.	 */	if (keyno == 0 || keyno > be16_to_cpu(block->bb_numrecs))		*stat = 0;	else		*stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0));	return 0;}/* * Move 1 record left from cur/level if possible. * Update cur to reflect the new path. */STATIC int				/* error */xfs_alloc_lshift(	xfs_btree_cur_t		*cur,	/* btree cursor */	int			level,	/* level to shift record on */	int			*stat)	/* success/failure */{	int			error;	/* error return value */#ifdef DEBUG	int			i;	/* loop index */#endif	xfs_alloc_key_t		key;	/* key value for leaf level upward */	xfs_buf_t		*lbp;	/* buffer for left neighbor block */	xfs_alloc_block_t	*left;	/* left neighbor btree block */	int			nrec;	/* new number of left block entries */	xfs_buf_t		*rbp;	/* buffer for right (current) block */	xfs_alloc_block_t	*right;	/* right (current) btree block */	xfs_alloc_key_t		*rkp=NULL;	/* key pointer for right block */	xfs_alloc_ptr_t		*rpp=NULL;	/* address pointer for right block */	xfs_alloc_rec_t		*rrp=NULL;	/* record pointer for right block */	/*	 * Set up variables for this block as "right".	 */	rbp = cur->bc_bufs[level];	right = XFS_BUF_TO_ALLOC_BLOCK(rbp);#ifdef DEBUG	if ((error = xfs_btree_check_sblock(cur, right, level, rbp)))		return error;#endif	/*	 * If we've got no left sibling then we can't shift an entry left.	 */	if (be32_to_cpu(right->bb_leftsib) == NULLAGBLOCK) {		*stat = 0;		return 0;	}	/*	 * If the cursor entry is the one that would be moved, don't	 * do it... it's too complicated.	 */	if (cur->bc_ptrs[level] <= 1) {		*stat = 0;		return 0;	}	/*	 * Set up the left neighbor as "left".	 */	if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp,			cur->bc_private.a.agno, be32_to_cpu(right->bb_leftsib),			0, &lbp, XFS_ALLOC_BTREE_REF)))		return error;	left = XFS_BUF_TO_ALLOC_BLOCK(lbp);	if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))		return error;	/*	 * If it's full, it can't take another entry.	 */	if (be16_to_cpu(left->bb_numrecs) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {		*stat = 0;		return 0;	}	nrec = be16_to_cpu(left->bb_numrecs) + 1;	/*	 * If non-leaf, copy a key and a ptr to the left block.	 */	if (level > 0) {		xfs_alloc_key_t	*lkp;	/* key pointer for left block */		xfs_alloc_ptr_t	*lpp;	/* address pointer for left block */		lkp = XFS_ALLOC_KEY_ADDR(left, nrec, cur);		rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur);		*lkp = *rkp;		xfs_alloc_log_keys(cur, lbp, nrec, nrec);		lpp = XFS_ALLOC_PTR_ADDR(left, nrec, cur);		rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur);#ifdef DEBUG		if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*rpp), level)))			return error;#endif		*lpp = *rpp;		xfs_alloc_log_ptrs(cur, lbp, nrec, nrec);		xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp);	}	/*	 * If leaf, copy a record to the left block.	 */	else {		xfs_alloc_rec_t	*lrp;	/* record pointer for left block */		lrp = XFS_ALLOC_REC_ADDR(left, nrec, cur);		rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);		*lrp = *rrp;		xfs_alloc_log_recs(cur, lbp, nrec, nrec);		xfs_btree_check_rec(cur->bc_btnum, lrp - 1, lrp);	}	/*	 * Bump and log left's numrecs, decrement and log right's numrecs.	 */	be16_add(&left->bb_numrecs, 1);	xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS);	be16_add(&right->bb_numrecs, -1);	xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS);	/*	 * Slide the contents of right down one entry.	 */	if (level > 0) {#ifdef DEBUG		for (i = 0; i < be16_to_cpu(right->bb_numrecs); i++) {			if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(rpp[i + 1]),					level)))				return error;		}#endif		memmove(rkp, rkp + 1, be16_to_cpu(right->bb_numrecs) * sizeof(*rkp));		memmove(rpp, rpp + 1, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp));		xfs_alloc_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));		xfs_alloc_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));	} else {		memmove(rrp, rrp + 1, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));		xfs_alloc_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));		key.ar_startblock = rrp->ar_startblock;		key.ar_blockcount = rrp->ar_blockcount;		rkp = &key;	}	/*	 * Update the parent key values of right.	 */	if ((error = xfs_alloc_updkey(cur, rkp, level + 1)))		return error;	/*	 * Slide the cursor value left one.	 */	cur->bc_ptrs[level]--;	*stat = 1;	return 0;}/* * Allocate a new root block, fill it in. */STATIC int				/* error */xfs_alloc_newroot(	xfs_btree_cur_t		*cur,	/* btree cursor */	int			*stat)	/* success/failure */{	int			error;	/* error return value */	xfs_agblock_t		lbno;	/* left block number */	xfs_buf_t		*lbp;	/* left btree buffer */	xfs_alloc_block_t	*left;	/* left btree block */	xfs_mount_t		*mp;	/* mount structure */	xfs_agblock_t		nbno;	/* new block number */	xfs_buf_t		*nbp;	/* new (root) buffer */	xfs_alloc_block_t	*new;	/* new (root) btree block */	int			nptr;	/* new value for key index, 1 or 2 */	xfs_agblock_t		rbno;	/* right block number */	xfs_buf_t		*rbp;	/* right btree buffer */	xfs_alloc_block_t	*right;	/* right btree block */	mp = cur->bc_mp;	ASSERT(cur->bc_nlevels < XFS_AG_MAXLEVELS(mp));	/*	 * Get a buffer from the freelist blocks, for the new root.	 */	error = xfs_alloc_get_freelist(cur->bc_tp,					cur->bc_private.a.agbp, &nbno, 1);

⌨️ 快捷键说明

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