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

📄 xfs_alloc_btree.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	/*	 * If that won't work, see if we can join with the right neighbor block.	 */	else if (rbno != NULLAGBLOCK &&		 rrecs + numrecs <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {		/*		 * Set "left" to be the starting block,		 * "right" to be the right neighbor.		 */		lbno = bno;		left = block;		lrecs = be16_to_cpu(left->bb_numrecs);		lbp = bp;		if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,				cur->bc_private.a.agno, rbno, 0, &rbp,				XFS_ALLOC_BTREE_REF)))			return error;		right = XFS_BUF_TO_ALLOC_BLOCK(rbp);		rrecs = be16_to_cpu(right->bb_numrecs);		if ((error = xfs_btree_check_sblock(cur, right, level, rbp)))			return error;	}	/*	 * Otherwise, we can't fix the imbalance.	 * Just return.  This is probably a logic error, but it's not fatal.	 */	else {		if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i)))			return error;		*stat = 1;		return 0;	}	/*	 * We're now going to join "left" and "right" by moving all the stuff	 * in "right" to "left" and deleting "right".	 */	if (level > 0) {		/*		 * It's a non-leaf.  Move keys and pointers.		 */		lkp = XFS_ALLOC_KEY_ADDR(left, lrecs + 1, cur);		lpp = XFS_ALLOC_PTR_ADDR(left, lrecs + 1, cur);		rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur);		rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur);#ifdef DEBUG		for (i = 0; i < rrecs; i++) {			if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(rpp[i]), level)))				return error;		}#endif		memcpy(lkp, rkp, rrecs * sizeof(*lkp));		memcpy(lpp, rpp, rrecs * sizeof(*lpp));		xfs_alloc_log_keys(cur, lbp, lrecs + 1, lrecs + rrecs);		xfs_alloc_log_ptrs(cur, lbp, lrecs + 1, lrecs + rrecs);	} else {		/*		 * It's a leaf.  Move records.		 */		lrp = XFS_ALLOC_REC_ADDR(left, lrecs + 1, cur);		rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);		memcpy(lrp, rrp, rrecs * sizeof(*lrp));		xfs_alloc_log_recs(cur, lbp, lrecs + 1, lrecs + rrecs);	}	/*	 * If we joined with the left neighbor, set the buffer in the	 * cursor to the left block, and fix up the index.	 */	if (bp != lbp) {		xfs_btree_setbuf(cur, level, lbp);		cur->bc_ptrs[level] += lrecs;	}	/*	 * If we joined with the right neighbor and there's a level above	 * us, increment the cursor at that level.	 */	else if (level + 1 < cur->bc_nlevels &&		 (error = xfs_alloc_increment(cur, level + 1, &i)))		return error;	/*	 * Fix up the number of records in the surviving block.	 */	lrecs += rrecs;	left->bb_numrecs = cpu_to_be16(lrecs);	/*	 * Fix up the right block pointer in the surviving block, and log it.	 */	left->bb_rightsib = right->bb_rightsib;	xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB);	/*	 * If there is a right sibling now, make it point to the	 * remaining block.	 */	if (be32_to_cpu(left->bb_rightsib) != NULLAGBLOCK) {		xfs_alloc_block_t	*rrblock;		xfs_buf_t		*rrbp;		if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,				cur->bc_private.a.agno, be32_to_cpu(left->bb_rightsib), 0,				&rrbp, XFS_ALLOC_BTREE_REF)))			return error;		rrblock = XFS_BUF_TO_ALLOC_BLOCK(rrbp);		if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp)))			return error;		rrblock->bb_leftsib = cpu_to_be32(lbno);		xfs_alloc_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB);	}	/*	 * Free the deleting block by putting it on the freelist.	 */	error = xfs_alloc_put_freelist(cur->bc_tp,					 cur->bc_private.a.agbp, NULL, rbno, 1);	if (error)		return error;	/*	 * Since blocks move to the free list without the coordination	 * used in xfs_bmap_finish, we can't allow block to be available	 * for reallocation and non-transaction writing (user data)	 * until we know that the transaction that moved it to the free	 * list is permanently on disk. We track the blocks by declaring	 * these blocks as "busy"; the busy list is maintained on a	 * per-ag basis and each transaction records which entries	 * should be removed when the iclog commits to disk. If a	 * busy block is allocated, the iclog is pushed up to the	 * LSN that freed the block.	 */	xfs_alloc_mark_busy(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1);	xfs_trans_agbtree_delta(cur->bc_tp, -1);	/*	 * Adjust the current level's cursor so that we're left referring	 * to the right node, after we're done.	 * If this leaves the ptr value 0 our caller will fix it up.	 */	if (level > 0)		cur->bc_ptrs[level]--;	/*	 * Return value means the next level up has something to do.	 */	*stat = 2;	return 0;error0:	xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);	return error;}/* * Insert one record/level.  Return information to the caller * allowing the next level up to proceed if necessary. */STATIC int				/* error */xfs_alloc_insrec(	xfs_btree_cur_t		*cur,	/* btree cursor */	int			level,	/* level to insert record at */	xfs_agblock_t		*bnop,	/* i/o: block number inserted */	xfs_alloc_rec_t		*recp,	/* i/o: record data inserted */	xfs_btree_cur_t		**curp,	/* output: new cursor replacing cur */	int			*stat)	/* output: success/failure */{	xfs_agf_t		*agf;	/* allocation group freelist header */	xfs_alloc_block_t	*block;	/* btree block record/key lives in */	xfs_buf_t		*bp;	/* buffer for block */	int			error;	/* error return value */	int			i;	/* loop index */	xfs_alloc_key_t		key;	/* key value being inserted */	xfs_alloc_key_t		*kp;	/* pointer to btree keys */	xfs_agblock_t		nbno;	/* block number of allocated block */	xfs_btree_cur_t		*ncur;	/* new cursor to be used at next lvl */	xfs_alloc_key_t		nkey;	/* new key value, from split */	xfs_alloc_rec_t		nrec;	/* new record value, for caller */	int			numrecs;	int			optr;	/* old ptr value */	xfs_alloc_ptr_t		*pp;	/* pointer to btree addresses */	int			ptr;	/* index in btree block for this rec */	xfs_alloc_rec_t		*rp;	/* pointer to btree records */	ASSERT(be32_to_cpu(recp->ar_blockcount) > 0);	/*	 * GCC doesn't understand the (arguably complex) control flow in	 * this function and complains about uninitialized structure fields	 * without this.	 */	memset(&nrec, 0, sizeof(nrec));	/*	 * If we made it to the root level, allocate a new root block	 * and we're done.	 */	if (level >= cur->bc_nlevels) {		XFS_STATS_INC(xs_abt_insrec);		if ((error = xfs_alloc_newroot(cur, &i)))			return error;		*bnop = NULLAGBLOCK;		*stat = i;		return 0;	}	/*	 * Make a key out of the record data to be inserted, and save it.	 */	key.ar_startblock = recp->ar_startblock;	key.ar_blockcount = recp->ar_blockcount;	optr = ptr = cur->bc_ptrs[level];	/*	 * If we're off the left edge, return failure.	 */	if (ptr == 0) {		*stat = 0;		return 0;	}	XFS_STATS_INC(xs_abt_insrec);	/*	 * Get pointers to the btree buffer and block.	 */	bp = cur->bc_bufs[level];	block = XFS_BUF_TO_ALLOC_BLOCK(bp);	numrecs = be16_to_cpu(block->bb_numrecs);#ifdef DEBUG	if ((error = xfs_btree_check_sblock(cur, block, level, bp)))		return error;	/*	 * Check that the new entry is being inserted in the right place.	 */	if (ptr <= numrecs) {		if (level == 0) {			rp = XFS_ALLOC_REC_ADDR(block, ptr, cur);			xfs_btree_check_rec(cur->bc_btnum, recp, rp);		} else {			kp = XFS_ALLOC_KEY_ADDR(block, ptr, cur);			xfs_btree_check_key(cur->bc_btnum, &key, kp);		}	}#endif	nbno = NULLAGBLOCK;	ncur = NULL;	/*	 * If the block is full, we can't insert the new entry until we	 * make the block un-full.	 */	if (numrecs == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {		/*		 * First, try shifting an entry to the right neighbor.		 */		if ((error = xfs_alloc_rshift(cur, level, &i)))			return error;		if (i) {			/* nothing */		}		/*		 * Next, try shifting an entry to the left neighbor.		 */		else {			if ((error = xfs_alloc_lshift(cur, level, &i)))				return error;			if (i)				optr = ptr = cur->bc_ptrs[level];			else {				/*				 * Next, try splitting the current block in				 * half. If this works we have to re-set our				 * variables because we could be in a				 * different block now.				 */				if ((error = xfs_alloc_split(cur, level, &nbno,						&nkey, &ncur, &i)))					return error;				if (i) {					bp = cur->bc_bufs[level];					block = XFS_BUF_TO_ALLOC_BLOCK(bp);#ifdef DEBUG					if ((error =						xfs_btree_check_sblock(cur,							block, level, bp)))						return error;#endif					ptr = cur->bc_ptrs[level];					nrec.ar_startblock = nkey.ar_startblock;					nrec.ar_blockcount = nkey.ar_blockcount;				}				/*				 * Otherwise the insert fails.				 */				else {					*stat = 0;					return 0;				}			}		}	}	/*	 * At this point we know there's room for our new entry in the block	 * we're pointing at.	 */	numrecs = be16_to_cpu(block->bb_numrecs);	if (level > 0) {		/*		 * It's a non-leaf entry.  Make a hole for the new data		 * in the key and ptr regions of the block.		 */		kp = XFS_ALLOC_KEY_ADDR(block, 1, cur);		pp = XFS_ALLOC_PTR_ADDR(block, 1, cur);#ifdef DEBUG		for (i = numrecs; i >= ptr; i--) {			if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(pp[i - 1]), level)))				return error;		}#endif		memmove(&kp[ptr], &kp[ptr - 1],			(numrecs - ptr + 1) * sizeof(*kp));		memmove(&pp[ptr], &pp[ptr - 1],			(numrecs - ptr + 1) * sizeof(*pp));#ifdef DEBUG		if ((error = xfs_btree_check_sptr(cur, *bnop, level)))			return error;#endif		/*		 * Now stuff the new data in, bump numrecs and log the new data.		 */		kp[ptr - 1] = key;		pp[ptr - 1] = cpu_to_be32(*bnop);		numrecs++;		block->bb_numrecs = cpu_to_be16(numrecs);		xfs_alloc_log_keys(cur, bp, ptr, numrecs);		xfs_alloc_log_ptrs(cur, bp, ptr, numrecs);#ifdef DEBUG		if (ptr < numrecs)			xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1,				kp + ptr);#endif	} else {		/*		 * It's a leaf entry.  Make a hole for the new record.		 */		rp = XFS_ALLOC_REC_ADDR(block, 1, cur);		memmove(&rp[ptr], &rp[ptr - 1],			(numrecs - ptr + 1) * sizeof(*rp));		/*		 * Now stuff the new record in, bump numrecs		 * and log the new data.		 */		rp[ptr - 1] = *recp;		numrecs++;		block->bb_numrecs = cpu_to_be16(numrecs);		xfs_alloc_log_recs(cur, bp, ptr, numrecs);#ifdef DEBUG		if (ptr < numrecs)			xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1,				rp + ptr);#endif	}	/*	 * Log the new number of records in the btree header.	 */	xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS);	/*	 * If we inserted at the start of a block, update the parents' keys.	 */	if (optr == 1 && (error = xfs_alloc_updkey(cur, &key, level + 1)))		return error;	/*	 * Look to see if the longest extent in the allocation group	 * needs to be updated.	 */	agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);	if (level == 0 &&	    cur->bc_btnum == XFS_BTNUM_CNT &&	    be32_to_cpu(block->bb_rightsib) == NULLAGBLOCK &&	    be32_to_cpu(recp->ar_blockcount) > be32_to_cpu(agf->agf_longest)) {		/*		 * If this is a leaf in the by-size btree and there		 * is no right sibling block and this block is bigger		 * than the previous longest block, update it.		 */		agf->agf_longest = recp->ar_blockcount;		cur->bc_mp->m_perag[be32_to_cpu(agf->agf_seqno)].pagf_longest			= be32_to_cpu(recp->ar_blockcount);		xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp,			XFS_AGF_LONGEST);	}	/*	 * Return the new block number, if any.	 * If there is one, give back a record value and a cursor too.	 */	*bnop = nbno;	if (nbno != NULLAGBLOCK) {		*recp = nrec;		*curp = ncur;	}	*stat = 1;	return 0;}/* * Log header fields from a btree block. */STATIC voidxfs_alloc_log_block(	xfs_trans_t		*tp,	/* transaction pointer */	xfs_buf_t		*bp,	/* buffer containing btree block */	int			fields)	/* mask of fields: XFS_BB_... */{	int			first;	/* first byte offset logged */	int			last;	/* last byte offset logged */	static const short	offsets[] = {	/* table of offsets */		offsetof(xfs_alloc_block_t, bb_magic),		offsetof(xfs_alloc_block_t, bb_level),		offsetof(xfs_alloc_block_t, bb_numrecs),		offsetof(xfs_alloc_block_t, bb_leftsib),		offsetof(xfs_alloc_block_t, bb_rightsib),		sizeof(xfs_alloc_block_t)	};	xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, &last);	xfs_trans_log_buf(tp, bp, first, last);}/* * Log keys from a btree block (nonleaf). */STATIC voidxfs_alloc_log_keys(	xfs_btree_cur_t		*cur,	/* btree cursor */	xfs_buf_t		*bp,	/* buffer containing btree block */	int			kfirst,	/* index of first key to log */	int			klast)	/* index of last key to log */{	xfs_alloc_block_t	*block;	/* btree block to log from */	int			first;	/* first byte offset logged */	xfs_alloc_key_t		*kp;	/* key pointer in btree block */	int			last;	/* last byte offset logged */	block = XFS_BUF_TO_ALLOC_BLOCK(bp);	kp = XFS_ALLOC_KEY_ADDR(block, 1, cur);	first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block);	last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block);	xfs_trans_log_buf(cur->bc_tp, bp, first, last);}/* * Log block pointer fields from a btree block (nonleaf).

⌨️ 快捷键说明

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