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

📄 xfs_ialloc_btree.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Insert one record/level.  Return information to the caller * allowing the next level up to proceed if necessary. */STATIC int				/* error */xfs_inobt_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_inobt_rec_t		*recp,	/* i/o: record data inserted */	xfs_btree_cur_t		**curp,	/* output: new cursor replacing cur */	int			*stat)	/* success/failure */{	xfs_inobt_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_inobt_key_t		key;	/* key value being inserted */	xfs_inobt_key_t		*kp=NULL;	/* 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_inobt_key_t		nkey;	/* new key value, from split */	xfs_inobt_rec_t		nrec;	/* new record value, for caller */	int			numrecs;	int			optr;	/* old ptr value */	xfs_inobt_ptr_t		*pp;	/* pointer to btree addresses */	int			ptr;	/* index in btree block for this rec */	xfs_inobt_rec_t		*rp=NULL;	/* pointer to btree records */	/*	 * 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) {		error = xfs_inobt_newroot(cur, &i);		*bnop = NULLAGBLOCK;		*stat = i;		return error;	}	/*	 * Make a key out of the record data to be inserted, and save it.	 */	key.ir_startino = recp->ir_startino;	optr = ptr = cur->bc_ptrs[level];	/*	 * If we're off the left edge, return failure.	 */	if (ptr == 0) {		*stat = 0;		return 0;	}	/*	 * Get pointers to the btree buffer and block.	 */	bp = cur->bc_bufs[level];	block = XFS_BUF_TO_INOBT_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_INOBT_REC_ADDR(block, ptr, cur);			xfs_btree_check_rec(cur->bc_btnum, recp, rp);		} else {			kp = XFS_INOBT_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_INOBT_BLOCK_MAXRECS(level, cur)) {		/*		 * First, try shifting an entry to the right neighbor.		 */		if ((error = xfs_inobt_rshift(cur, level, &i)))			return error;		if (i) {			/* nothing */		}		/*		 * Next, try shifting an entry to the left neighbor.		 */		else {			if ((error = xfs_inobt_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_inobt_split(cur, level, &nbno,						&nkey, &ncur, &i)))					return error;				if (i) {					bp = cur->bc_bufs[level];					block = XFS_BUF_TO_INOBT_BLOCK(bp);#ifdef DEBUG					if ((error = xfs_btree_check_sblock(cur,							block, level, bp)))						return error;#endif					ptr = cur->bc_ptrs[level];					nrec.ir_startino = nkey.ir_startino;				} else {					/*					 * Otherwise the insert fails.					 */					*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_INOBT_KEY_ADDR(block, 1, cur);		pp = XFS_INOBT_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));		/*		 * Now stuff the new data in, bump numrecs and log the new data.		 */#ifdef DEBUG		if ((error = xfs_btree_check_sptr(cur, *bnop, level)))			return error;#endif		kp[ptr - 1] = key;		pp[ptr - 1] = cpu_to_be32(*bnop);		numrecs++;		block->bb_numrecs = cpu_to_be16(numrecs);		xfs_inobt_log_keys(cur, bp, ptr, numrecs);		xfs_inobt_log_ptrs(cur, bp, ptr, numrecs);	} else {		/*		 * It's a leaf entry.  Make a hole for the new record.		 */		rp = XFS_INOBT_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_inobt_log_recs(cur, bp, ptr, numrecs);	}	/*	 * Log the new number of records in the btree header.	 */	xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS);#ifdef DEBUG	/*	 * Check that the key/record is in the right place, now.	 */	if (ptr < numrecs) {		if (level == 0)			xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1,				rp + ptr);		else			xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1,				kp + ptr);	}#endif	/*	 * If we inserted at the start of a block, update the parents' keys.	 */	if (optr == 1 && (error = xfs_inobt_updkey(cur, &key, level + 1)))		return error;	/*	 * 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_inobt_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_inobt_block_t, bb_magic),		offsetof(xfs_inobt_block_t, bb_level),		offsetof(xfs_inobt_block_t, bb_numrecs),		offsetof(xfs_inobt_block_t, bb_leftsib),		offsetof(xfs_inobt_block_t, bb_rightsib),		sizeof(xfs_inobt_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_inobt_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_inobt_block_t	*block;	/* btree block to log from */	int			first;	/* first byte offset logged */	xfs_inobt_key_t		*kp;	/* key pointer in btree block */	int			last;	/* last byte offset logged */	block = XFS_BUF_TO_INOBT_BLOCK(bp);	kp = XFS_INOBT_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). */STATIC voidxfs_inobt_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_inobt_block_t	*block;	/* btree block to log from */	int			first;	/* first byte offset logged */	int			last;	/* last byte offset logged */	xfs_inobt_ptr_t		*pp;	/* block-pointer pointer in btree blk */	block = XFS_BUF_TO_INOBT_BLOCK(bp);	pp = XFS_INOBT_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_inobt_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_inobt_block_t	*block;	/* btree block to log from */	int			first;	/* first byte offset logged */	int			last;	/* last byte offset logged */	xfs_inobt_rec_t		*rp;	/* record pointer for btree block */	block = XFS_BUF_TO_INOBT_BLOCK(bp);	rp = XFS_INOBT_REC_ADDR(block, 1, cur);	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_inobt_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_inobt_block_t	*block=NULL;	/* current btree block */	__int64_t		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 */	/*	 * Get the allocation group header, and the root block number.	 */	mp = cur->bc_mp;	{		xfs_agi_t	*agi;	/* a.g. inode header */		agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp);		agno = be32_to_cpu(agi->agi_seqno);		agbno = be32_to_cpu(agi->agi_root);	}	/*	 * 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_INO_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_INOBT_BLOCK(bp);			if ((error = xfs_btree_check_sblock(cur, block, level,					bp)))				return error;		} else			block = XFS_BUF_TO_INOBT_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_inobt_key_t	*kkbase=NULL;/* base of keys in block */			xfs_inobt_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_INOBT_KEY_ADDR(block, 1, cur);			else				krbase = XFS_INOBT_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_agino_t	startino;	/* key value */				/*				 * keyno is average of low and high.				 */				keyno = (low + high) >> 1;				/*				 * Get startino.				 */				if (level > 0) {					xfs_inobt_key_t	*kkp;					kkp = kkbase + keyno - 1;					startino = be32_to_cpu(kkp->ir_startino);				} else {					xfs_inobt_rec_t	*krp;					krp = krbase + keyno - 1;					startino = be32_to_cpu(krp->ir_startino);				}				/*				 * Compute difference to get next direction.				 */				diff = (__int64_t)					startino - cur->bc_rec.i.ir_startino;				/*				 * 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_INOBT_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_inobt_increment(cur, 0, &i)))				return error;			ASSERT(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. */

⌨️ 快捷键说明

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