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

📄 xfs_da_btree.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	btree = &node->btree[drop_blk->index];	if (drop_blk->index < (be16_to_cpu(node->hdr.count)-1)) {		tmp  = be16_to_cpu(node->hdr.count) - drop_blk->index - 1;		tmp *= (uint)sizeof(xfs_da_node_entry_t);		memmove(btree, btree + 1, tmp);		xfs_da_log_buf(state->args->trans, drop_blk->bp,		    XFS_DA_LOGRANGE(node, btree, tmp));		btree = &node->btree[be16_to_cpu(node->hdr.count)-1];	}	memset((char *)btree, 0, sizeof(xfs_da_node_entry_t));	xfs_da_log_buf(state->args->trans, drop_blk->bp,	    XFS_DA_LOGRANGE(node, btree, sizeof(*btree)));	be16_add(&node->hdr.count, -1);	xfs_da_log_buf(state->args->trans, drop_blk->bp,	    XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr)));	/*	 * Copy the last hash value from the block to propagate upwards.	 */	btree--;	drop_blk->hashval = be32_to_cpu(btree->hashval);}/* * Unbalance the btree elements between two intermediate nodes, * move all Btree elements from one node into another. */STATIC voidxfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,				     xfs_da_state_blk_t *save_blk){	xfs_da_intnode_t *drop_node, *save_node;	xfs_da_node_entry_t *btree;	int tmp;	xfs_trans_t *tp;	drop_node = drop_blk->bp->data;	save_node = save_blk->bp->data;	ASSERT(be16_to_cpu(drop_node->hdr.info.magic) == XFS_DA_NODE_MAGIC);	ASSERT(be16_to_cpu(save_node->hdr.info.magic) == XFS_DA_NODE_MAGIC);	tp = state->args->trans;	/*	 * If the dying block has lower hashvals, then move all the	 * elements in the remaining block up to make a hole.	 */	if ((be32_to_cpu(drop_node->btree[0].hashval) < be32_to_cpu(save_node->btree[ 0 ].hashval)) ||	    (be32_to_cpu(drop_node->btree[be16_to_cpu(drop_node->hdr.count)-1].hashval) <	     be32_to_cpu(save_node->btree[be16_to_cpu(save_node->hdr.count)-1].hashval)))	{		btree = &save_node->btree[be16_to_cpu(drop_node->hdr.count)];		tmp = be16_to_cpu(save_node->hdr.count) * (uint)sizeof(xfs_da_node_entry_t);		memmove(btree, &save_node->btree[0], tmp);		btree = &save_node->btree[0];		xfs_da_log_buf(tp, save_blk->bp,			XFS_DA_LOGRANGE(save_node, btree,				(be16_to_cpu(save_node->hdr.count) + be16_to_cpu(drop_node->hdr.count)) *				sizeof(xfs_da_node_entry_t)));	} else {		btree = &save_node->btree[be16_to_cpu(save_node->hdr.count)];		xfs_da_log_buf(tp, save_blk->bp,			XFS_DA_LOGRANGE(save_node, btree,				be16_to_cpu(drop_node->hdr.count) *				sizeof(xfs_da_node_entry_t)));	}	/*	 * Move all the B-tree elements from drop_blk to save_blk.	 */	tmp = be16_to_cpu(drop_node->hdr.count) * (uint)sizeof(xfs_da_node_entry_t);	memcpy(btree, &drop_node->btree[0], tmp);	be16_add(&save_node->hdr.count, be16_to_cpu(drop_node->hdr.count));	xfs_da_log_buf(tp, save_blk->bp,		XFS_DA_LOGRANGE(save_node, &save_node->hdr,			sizeof(save_node->hdr)));	/*	 * Save the last hashval in the remaining block for upward propagation.	 */	save_blk->hashval = be32_to_cpu(save_node->btree[be16_to_cpu(save_node->hdr.count)-1].hashval);}/*======================================================================== * Routines used for finding things in the Btree. *========================================================================*//* * Walk down the Btree looking for a particular filename, filling * in the state structure as we go. * * We will set the state structure to point to each of the elements * in each of the nodes where either the hashval is or should be. * * We support duplicate hashval's so for each entry in the current * node that could contain the desired hashval, descend.  This is a * pruned depth-first tree search. */int							/* error */xfs_da_node_lookup_int(xfs_da_state_t *state, int *result){	xfs_da_state_blk_t *blk;	xfs_da_blkinfo_t *curr;	xfs_da_intnode_t *node;	xfs_da_node_entry_t *btree;	xfs_dablk_t blkno;	int probe, span, max, error, retval;	xfs_dahash_t hashval, btreehashval;	xfs_da_args_t *args;	args = state->args;	/*	 * Descend thru the B-tree searching each level for the right	 * node to use, until the right hashval is found.	 */	blkno = (args->whichfork == XFS_DATA_FORK)? state->mp->m_dirleafblk : 0;	for (blk = &state->path.blk[0], state->path.active = 1;			 state->path.active <= XFS_DA_NODE_MAXDEPTH;			 blk++, state->path.active++) {		/*		 * Read the next node down in the tree.		 */		blk->blkno = blkno;		error = xfs_da_read_buf(args->trans, args->dp, blkno,					-1, &blk->bp, args->whichfork);		if (error) {			blk->blkno = 0;			state->path.active--;			return(error);		}		curr = blk->bp->data;		blk->magic = be16_to_cpu(curr->magic);		ASSERT(blk->magic == XFS_DA_NODE_MAGIC ||		       blk->magic == XFS_DIR2_LEAFN_MAGIC ||		       blk->magic == XFS_ATTR_LEAF_MAGIC);		/*		 * Search an intermediate node for a match.		 */		if (blk->magic == XFS_DA_NODE_MAGIC) {			node = blk->bp->data;			max = be16_to_cpu(node->hdr.count);			blk->hashval = be32_to_cpu(node->btree[max-1].hashval);			/*			 * Binary search.  (note: small blocks will skip loop)			 */			probe = span = max / 2;			hashval = args->hashval;			for (btree = &node->btree[probe]; span > 4;				   btree = &node->btree[probe]) {				span /= 2;				btreehashval = be32_to_cpu(btree->hashval);				if (btreehashval < hashval)					probe += span;				else if (btreehashval > hashval)					probe -= span;				else					break;			}			ASSERT((probe >= 0) && (probe < max));			ASSERT((span <= 4) || (be32_to_cpu(btree->hashval) == hashval));			/*			 * Since we may have duplicate hashval's, find the first			 * matching hashval in the node.			 */			while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashval)) {				btree--;				probe--;			}			while ((probe < max) && (be32_to_cpu(btree->hashval) < hashval)) {				btree++;				probe++;			}			/*			 * Pick the right block to descend on.			 */			if (probe == max) {				blk->index = max-1;				blkno = be32_to_cpu(node->btree[max-1].before);			} else {				blk->index = probe;				blkno = be32_to_cpu(btree->before);			}		} else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {			blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);			break;		} else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {			blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL);			break;		}	}	/*	 * A leaf block that ends in the hashval that we are interested in	 * (final hashval == search hashval) means that the next block may	 * contain more entries with the same hashval, shift upward to the	 * next leaf and keep searching.	 */	for (;;) {		if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {			retval = xfs_dir2_leafn_lookup_int(blk->bp, args,							&blk->index, state);		} else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {			retval = xfs_attr_leaf_lookup_int(blk->bp, args);			blk->index = args->index;			args->blkno = blk->blkno;		} else {			ASSERT(0);			return XFS_ERROR(EFSCORRUPTED);		}		if (((retval == ENOENT) || (retval == ENOATTR)) &&		    (blk->hashval == args->hashval)) {			error = xfs_da_path_shift(state, &state->path, 1, 1,							 &retval);			if (error)				return(error);			if (retval == 0) {				continue;			} else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {				/* path_shift() gives ENOENT */				retval = XFS_ERROR(ENOATTR);			}		}		break;	}	*result = retval;	return(0);}/*======================================================================== * Utility routines. *========================================================================*//* * Link a new block into a doubly linked list of blocks (of whatever type). */int							/* error */xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,			       xfs_da_state_blk_t *new_blk){	xfs_da_blkinfo_t *old_info, *new_info, *tmp_info;	xfs_da_args_t *args;	int before=0, error;	xfs_dabuf_t *bp;	/*	 * Set up environment.	 */	args = state->args;	ASSERT(args != NULL);	old_info = old_blk->bp->data;	new_info = new_blk->bp->data;	ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC ||	       old_blk->magic == XFS_DIR2_LEAFN_MAGIC ||	       old_blk->magic == XFS_ATTR_LEAF_MAGIC);	ASSERT(old_blk->magic == be16_to_cpu(old_info->magic));	ASSERT(new_blk->magic == be16_to_cpu(new_info->magic));	ASSERT(old_blk->magic == new_blk->magic);	switch (old_blk->magic) {	case XFS_ATTR_LEAF_MAGIC:		before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp);		break;	case XFS_DIR2_LEAFN_MAGIC:		before = xfs_dir2_leafn_order(old_blk->bp, new_blk->bp);		break;	case XFS_DA_NODE_MAGIC:		before = xfs_da_node_order(old_blk->bp, new_blk->bp);		break;	}	/*	 * Link blocks in appropriate order.	 */	if (before) {		/*		 * Link new block in before existing block.		 */		new_info->forw = cpu_to_be32(old_blk->blkno);		new_info->back = old_info->back;		if (old_info->back) {			error = xfs_da_read_buf(args->trans, args->dp,						be32_to_cpu(old_info->back),						-1, &bp, args->whichfork);			if (error)				return(error);			ASSERT(bp != NULL);			tmp_info = bp->data;			ASSERT(be16_to_cpu(tmp_info->magic) == be16_to_cpu(old_info->magic));			ASSERT(be32_to_cpu(tmp_info->forw) == old_blk->blkno);			tmp_info->forw = cpu_to_be32(new_blk->blkno);			xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);			xfs_da_buf_done(bp);		}		old_info->back = cpu_to_be32(new_blk->blkno);	} else {		/*		 * Link new block in after existing block.		 */		new_info->forw = old_info->forw;		new_info->back = cpu_to_be32(old_blk->blkno);		if (old_info->forw) {			error = xfs_da_read_buf(args->trans, args->dp,						be32_to_cpu(old_info->forw),						-1, &bp, args->whichfork);			if (error)				return(error);			ASSERT(bp != NULL);			tmp_info = bp->data;			ASSERT(tmp_info->magic == old_info->magic);			ASSERT(be32_to_cpu(tmp_info->back) == old_blk->blkno);			tmp_info->back = cpu_to_be32(new_blk->blkno);			xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);			xfs_da_buf_done(bp);		}		old_info->forw = cpu_to_be32(new_blk->blkno);	}	xfs_da_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1);	xfs_da_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1);	return(0);}/* * Compare two intermediate nodes for "order". */STATIC intxfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp){	xfs_da_intnode_t *node1, *node2;	node1 = node1_bp->data;	node2 = node2_bp->data;	ASSERT((be16_to_cpu(node1->hdr.info.magic) == XFS_DA_NODE_MAGIC) &&	       (be16_to_cpu(node2->hdr.info.magic) == XFS_DA_NODE_MAGIC));	if ((be16_to_cpu(node1->hdr.count) > 0) && (be16_to_cpu(node2->hdr.count) > 0) &&	    ((be32_to_cpu(node2->btree[0].hashval) <	      be32_to_cpu(node1->btree[0].hashval)) ||	     (be32_to_cpu(node2->btree[be16_to_cpu(node2->hdr.count)-1].hashval) <	      be32_to_cpu(node1->btree[be16_to_cpu(node1->hdr.count)-1].hashval)))) {		return(1);	}	return(0);}/* * Pick up the last hashvalue from an intermediate node. */STATIC uintxfs_da_node_lasthash(xfs_dabuf_t *bp, int *count){	xfs_da_intnode_t *node;	node = bp->data;	ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);	if (count)		*count = be16_to_cpu(node->hdr.count);	if (!node->hdr.count)		return(0);	return be32_to_cpu(node->btree[be16_to_cpu(node->hdr.count)-1].hashval);}/* * Unlink a block from a doubly linked list of blocks. */STATIC int						/* error */xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,				 xfs_da_state_blk_t *save_blk){	xfs_da_blkinfo_t *drop_info, *save_info, *tmp_info;	xfs_da_args_t *args;	xfs_dabuf_t *bp;	int error;	/*	 * Set up environment.	 */	args = state->args;	ASSERT(args != NULL);	save_info = save_blk->bp->data;	drop_info = drop_blk->bp->data;	ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC ||	       save_blk->magic == XFS_DIR2_LEAFN_MAGIC ||	       save_blk->magic == XFS_ATTR_LEAF_MAGIC);	ASSERT(save_blk->magic == be16_to_cpu(save_info->magic));	ASSERT(drop_blk->magic == be16_to_cpu(drop_info->magic));	ASSERT(save_blk->magic == drop_blk->magic);	ASSERT((be32_to_cpu(save_info->forw) == drop_blk->blkno) ||	       (be32_to_cpu(save_info->back) == drop_blk->blkno));	ASSERT((be32_to_cpu(drop_info->forw) == save_blk->blkno) ||	       (be32_to_cpu(drop_info->back) == save_blk->blkno));	/*	 * Unlink the leaf block from the doubly linked chain of leaves.	 */	if (be32_to_cpu(save_info->back) == drop_blk->blkno) {		save_info->back = drop_info->back;		if (drop_info->back) {			error = xfs_da_read_buf(args->trans, args->dp,						be32_to_cpu(drop_info->back),						-1, &bp, args->whichfork);			if (error)				return(error);			ASSERT(bp != NULL);			tmp_info = bp->data;			ASSERT(tmp_info->magic == save_info->magic);			ASSERT(be32_to_cpu(tmp_info->forw) == drop_blk->blkno);			tmp_info->forw = cpu_to_be32(save_blk->blkno);			xfs_da_log_buf(args->trans, bp, 0,						    sizeof(*tmp_info) - 1);			xfs_da_buf_done(bp);		}	} else {		save_info->forw = drop_info->forw;		if (drop_info->forw) {			error = xfs_da_read_buf(args->trans, args->dp,						be32_to_cpu(drop_info->forw),						-1, &bp, args->whichfork);			if (error)				return(error);			ASSERT(bp != NULL);			tmp_info = bp->data;			ASSERT(tmp_info->magic == save_info->magic);			ASSERT(be32_to_cpu(tmp_info->back) == drop_blk->blkno);			tmp_info->back = cpu_to_be32(save_blk->blkno);			xfs_da_log_buf(args->trans, bp, 0,						    sizeof(*tmp_info) - 1);			xfs_da_buf_done(bp);		}	}	xfs_da_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1);	return(0);}/* * Move a path "forward" or "!forward" one block at the current level. * * This routine will adjust a "path" to point to the next block * "forward" (higher hashvalues) or "!forward" (lower hashvals) in the * Btree, including updating pointers to the intermediate nodes between * the new bottom and the root. */int							/* error */xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,				 int forward, int release, int *result){	xfs_da_state_blk_t *blk;	xfs_da_blkinfo_t *info;	xfs_da_intnode_t *node;	xfs_da_args_t *args;	xfs_dablk_t blkno=0;	int level, error;	/*	 * Roll up the Btree looking for the first block where our	 * current index is not at the edge of the block.  Note that	 * we skip the bottom layer because we want the sibling block.	 */	args = state->args;	ASSERT(args != NULL);	ASSERT(path != NULL);	ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH));	level = (path->active-1) - 1;	/* skip bottom layer in path */	for (blk = &path->blk[level]; level >= 0; blk--, level--) {		ASSERT(blk->bp != NULL);		node = blk->bp->data;		ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);		if (forward && (blk->index < be16_to_cpu(node->hdr.count)-1)) {

⌨️ 快捷键说明

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