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

📄 xfs_dir2_node.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			if (!free->hdr.nused) {				error = xfs_dir2_shrink_inode(args, fdb, fbp);				if (error == 0) {					fbp = NULL;					logfree = 0;				} else if (error != ENOSPC || args->total != 0)					return error;				/*				 * It's possible to get ENOSPC if there is no				 * space reservation.  In this case some one				 * else will eventually get rid of this block.				 */			}		}		/*		 * Data block is not empty, just set the free entry to		 * the new value.		 */		else {			free->bests[findex] = cpu_to_be16(longest);			logfree = 1;		}		/*		 * Log the free entry that changed, unless we got rid of it.		 */		if (logfree)			xfs_dir2_free_log_bests(tp, fbp, findex, findex);		/*		 * Drop the buffer if we still have it.		 */		if (fbp)			xfs_da_buf_done(fbp);	}	xfs_dir2_leafn_check(dp, bp);	/*	 * Return indication of whether this leaf block is emtpy enough	 * to justify trying to join it with a neighbor.	 */	*rval =		((uint)sizeof(leaf->hdr) +		 (uint)sizeof(leaf->ents[0]) *		 (be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale))) <		mp->m_dir_magicpct;	return 0;}/* * Split the leaf entries in the old block into old and new blocks. */int						/* error */xfs_dir2_leafn_split(	xfs_da_state_t		*state,		/* btree cursor */	xfs_da_state_blk_t	*oldblk,	/* original block */	xfs_da_state_blk_t	*newblk)	/* newly created block */{	xfs_da_args_t		*args;		/* operation arguments */	xfs_dablk_t		blkno;		/* new leaf block number */	int			error;		/* error return value */	xfs_mount_t		*mp;		/* filesystem mount point */	/*	 * Allocate space for a new leaf node.	 */	args = state->args;	mp = args->dp->i_mount;	ASSERT(args != NULL);	ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC);	error = xfs_da_grow_inode(args, &blkno);	if (error) {		return error;	}	/*	 * Initialize the new leaf block.	 */	error = xfs_dir2_leaf_init(args, xfs_dir2_da_to_db(mp, blkno),		&newblk->bp, XFS_DIR2_LEAFN_MAGIC);	if (error) {		return error;	}	newblk->blkno = blkno;	newblk->magic = XFS_DIR2_LEAFN_MAGIC;	/*	 * Rebalance the entries across the two leaves, link the new	 * block into the leaves.	 */	xfs_dir2_leafn_rebalance(state, oldblk, newblk);	error = xfs_da_blk_link(state, oldblk, newblk);	if (error) {		return error;	}	/*	 * Insert the new entry in the correct block.	 */	if (state->inleaf)		error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index);	else		error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index);	/*	 * Update last hashval in each block since we added the name.	 */	oldblk->hashval = xfs_dir2_leafn_lasthash(oldblk->bp, NULL);	newblk->hashval = xfs_dir2_leafn_lasthash(newblk->bp, NULL);	xfs_dir2_leafn_check(args->dp, oldblk->bp);	xfs_dir2_leafn_check(args->dp, newblk->bp);	return error;}/* * Check a leaf block and its neighbors to see if the block should be * collapsed into one or the other neighbor.  Always keep the block * with the smaller block number. * If the current block is over 50% full, don't try to join it, return 0. * If the block is empty, fill in the state structure and return 2. * If it can be collapsed, fill in the state structure and return 1. * If nothing can be done, return 0. */int						/* error */xfs_dir2_leafn_toosmall(	xfs_da_state_t		*state,		/* btree cursor */	int			*action)	/* resulting action to take */{	xfs_da_state_blk_t	*blk;		/* leaf block */	xfs_dablk_t		blkno;		/* leaf block number */	xfs_dabuf_t		*bp;		/* leaf buffer */	int			bytes;		/* bytes in use */	int			count;		/* leaf live entry count */	int			error;		/* error return value */	int			forward;	/* sibling block direction */	int			i;		/* sibling counter */	xfs_da_blkinfo_t	*info;		/* leaf block header */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	int			rval;		/* result from path_shift */	/*	 * Check for the degenerate case of the block being over 50% full.	 * If so, it's not worth even looking to see if we might be able	 * to coalesce with a sibling.	 */	blk = &state->path.blk[state->path.active - 1];	info = blk->bp->data;	ASSERT(be16_to_cpu(info->magic) == XFS_DIR2_LEAFN_MAGIC);	leaf = (xfs_dir2_leaf_t *)info;	count = be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);	bytes = (uint)sizeof(leaf->hdr) + count * (uint)sizeof(leaf->ents[0]);	if (bytes > (state->blocksize >> 1)) {		/*		 * Blk over 50%, don't try to join.		 */		*action = 0;		return 0;	}	/*	 * Check for the degenerate case of the block being empty.	 * If the block is empty, we'll simply delete it, no need to	 * coalesce it with a sibling block.  We choose (arbitrarily)	 * to merge with the forward block unless it is NULL.	 */	if (count == 0) {		/*		 * Make altpath point to the block we want to keep and		 * path point to the block we want to drop (this one).		 */		forward = (info->forw != 0);		memcpy(&state->altpath, &state->path, sizeof(state->path));		error = xfs_da_path_shift(state, &state->altpath, forward, 0,			&rval);		if (error)			return error;		*action = rval ? 2 : 0;		return 0;	}	/*	 * Examine each sibling block to see if we can coalesce with	 * at least 25% free space to spare.  We need to figure out	 * whether to merge with the forward or the backward block.	 * We prefer coalescing with the lower numbered sibling so as	 * to shrink a directory over time.	 */	forward = be32_to_cpu(info->forw) < be32_to_cpu(info->back);	for (i = 0, bp = NULL; i < 2; forward = !forward, i++) {		blkno = forward ? be32_to_cpu(info->forw) : be32_to_cpu(info->back);		if (blkno == 0)			continue;		/*		 * Read the sibling leaf block.		 */		if ((error =		    xfs_da_read_buf(state->args->trans, state->args->dp, blkno,			    -1, &bp, XFS_DATA_FORK))) {			return error;		}		ASSERT(bp != NULL);		/*		 * Count bytes in the two blocks combined.		 */		leaf = (xfs_dir2_leaf_t *)info;		count = be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);		bytes = state->blocksize - (state->blocksize >> 2);		leaf = bp->data;		ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);		count += be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);		bytes -= count * (uint)sizeof(leaf->ents[0]);		/*		 * Fits with at least 25% to spare.		 */		if (bytes >= 0)			break;		xfs_da_brelse(state->args->trans, bp);	}	/*	 * Didn't like either block, give up.	 */	if (i >= 2) {		*action = 0;		return 0;	}	/*	 * Done with the sibling leaf block here, drop the dabuf	 * so path_shift can get it.	 */	xfs_da_buf_done(bp);	/*	 * Make altpath point to the block we want to keep (the lower	 * numbered block) and path point to the block we want to drop.	 */	memcpy(&state->altpath, &state->path, sizeof(state->path));	if (blkno < blk->blkno)		error = xfs_da_path_shift(state, &state->altpath, forward, 0,			&rval);	else		error = xfs_da_path_shift(state, &state->path, forward, 0,			&rval);	if (error) {		return error;	}	*action = rval ? 0 : 1;	return 0;}/* * Move all the leaf entries from drop_blk to save_blk. * This is done as part of a join operation. */voidxfs_dir2_leafn_unbalance(	xfs_da_state_t		*state,		/* cursor */	xfs_da_state_blk_t	*drop_blk,	/* dead block */	xfs_da_state_blk_t	*save_blk)	/* surviving block */{	xfs_da_args_t		*args;		/* operation arguments */	xfs_dir2_leaf_t		*drop_leaf;	/* dead leaf structure */	xfs_dir2_leaf_t		*save_leaf;	/* surviving leaf structure */	args = state->args;	ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC);	ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC);	drop_leaf = drop_blk->bp->data;	save_leaf = save_blk->bp->data;	ASSERT(be16_to_cpu(drop_leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);	ASSERT(be16_to_cpu(save_leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);	/*	 * If there are any stale leaf entries, take this opportunity	 * to purge them.	 */	if (drop_leaf->hdr.stale)		xfs_dir2_leaf_compact(args, drop_blk->bp);	if (save_leaf->hdr.stale)		xfs_dir2_leaf_compact(args, save_blk->bp);	/*	 * Move the entries from drop to the appropriate end of save.	 */	drop_blk->hashval = be32_to_cpu(drop_leaf->ents[be16_to_cpu(drop_leaf->hdr.count) - 1].hashval);	if (xfs_dir2_leafn_order(save_blk->bp, drop_blk->bp))		xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, 0,			be16_to_cpu(drop_leaf->hdr.count));	else		xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp,			be16_to_cpu(save_leaf->hdr.count), be16_to_cpu(drop_leaf->hdr.count));	save_blk->hashval = be32_to_cpu(save_leaf->ents[be16_to_cpu(save_leaf->hdr.count) - 1].hashval);	xfs_dir2_leafn_check(args->dp, save_blk->bp);}/* * Top-level node form directory addname routine. */int						/* error */xfs_dir2_node_addname(	xfs_da_args_t		*args)		/* operation arguments */{	xfs_da_state_blk_t	*blk;		/* leaf block for insert */	int			error;		/* error return value */	int			rval;		/* sub-return value */	xfs_da_state_t		*state;		/* btree cursor */	xfs_dir2_trace_args("node_addname", args);	/*	 * Allocate and initialize the state (btree cursor).	 */	state = xfs_da_state_alloc();	state->args = args;	state->mp = args->dp->i_mount;	state->blocksize = state->mp->m_dirblksize;	state->node_ents = state->mp->m_dir_node_ents;	/*	 * Look up the name.  We're not supposed to find it, but	 * this gives us the insertion point.	 */	error = xfs_da_node_lookup_int(state, &rval);	if (error)		rval = error;	if (rval != ENOENT) {		goto done;	}	/*	 * Add the data entry to a data block.	 * Extravalid is set to a freeblock found by lookup.	 */	rval = xfs_dir2_node_addname_int(args,		state->extravalid ? &state->extrablk : NULL);	if (rval) {		goto done;	}	blk = &state->path.blk[state->path.active - 1];	ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC);	/*	 * Add the new leaf entry.	 */	rval = xfs_dir2_leafn_add(blk->bp, args, blk->index);	if (rval == 0) {		/*		 * It worked, fix the hash values up the btree.		 */		if (!args->justcheck)			xfs_da_fixhashpath(state, &state->path);	} else {		/*		 * It didn't work, we need to split the leaf block.		 */		if (args->total == 0) {			ASSERT(rval == ENOSPC);			goto done;		}		/*		 * Split the leaf block and insert the new entry.		 */		rval = xfs_da_split(state);	}done:	xfs_da_state_free(state);	return rval;}/* * Add the data entry for a node-format directory name addition. * The leaf entry is added in xfs_dir2_leafn_add. * We may enter with a freespace block that the lookup found. */static int					/* error */xfs_dir2_node_addname_int(	xfs_da_args_t		*args,		/* operation arguments */	xfs_da_state_blk_t	*fblk)		/* optional freespace block */{	xfs_dir2_data_t		*data;		/* data block structure */	xfs_dir2_db_t		dbno;		/* data block number */	xfs_dabuf_t		*dbp;		/* data block buffer */	xfs_dir2_data_entry_t	*dep;		/* data entry pointer */	xfs_inode_t		*dp;		/* incore directory inode */	xfs_dir2_data_unused_t	*dup;		/* data unused entry pointer */	int			error;		/* error return value */	xfs_dir2_db_t		fbno;		/* freespace block number */	xfs_dabuf_t		*fbp;		/* freespace buffer */	int			findex;		/* freespace entry index */	xfs_dir2_free_t		*free=NULL;	/* freespace block structure */	xfs_dir2_db_t		ifbno;		/* initial freespace block no */	xfs_dir2_db_t		lastfbno=0;	/* highest freespace block no */	int			length;		/* length of the new entry */	int			logfree;	/* need to log free entry */	xfs_mount_t		*mp;		/* filesystem mount point */	int			needlog;	/* need to log data header */	int			needscan;	/* need to rescan data frees */	__be16			*tagp;		/* data entry tag pointer */	xfs_trans_t		*tp;		/* transaction pointer */	dp = args->dp;	mp = dp->i_mount;	tp = args->trans;	length = xfs_dir2_data_entsize(args->namelen);	/*	 * If we came in with a freespace block that means that lookup	 * found an entry with our hash value.  This is the freespace	 * block for that data entry.	 */	if (fblk) {		fbp = fblk->bp;		/*		 * Remember initial freespace block number.		 */		ifbno = fblk->blkno;		free = fbp->data;		ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);		findex = fblk->index;		/*		 * This means the free entry showed that the data block had		 * space for our entry, so we remembered it.		 * Use that data block.		 */		if (findex >= 0) {			ASSERT(findex < be32_to_cpu(free->hdr.nvalid));			ASSERT(be16_to_cpu(free->bests[findex]) != NULLDATAOFF);			ASSERT(be16_to_cpu(free->bests[findex]) >= length);			dbno = be32_to_cpu(free->hdr.firstdb) + findex;		}		/*		 * The data block looked at didn't have enough room.		 * We'll start at the beginning of the freespace entries.		 */		else {			dbno = -1;			findex = 0;		}	}	/*	 * Didn't come in with a freespace block, so don't have a data block.	 */	else {		ifbno = dbno = -1;		fbp = NULL;		findex = 0;	}	/*	 * If we don't have a data block yet, we're going to scan the	 * freespace blocks looking for one.  Figure out what the	 * highest freespace block number is.	 */	if (dbno == -1) {		xfs_fileoff_t	fo;		/* freespace block number */		if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK)))			return error;		lastfbno = xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo);		fbno = ifbno;	}	/*	 * While we haven't identified a data block, search the freeblock	 * data for a good data block.  If we find a null freeblock entry,	 * indicating a hole in the data blocks, remember that.	 */	while (dbno == -1) {		/*		 * If we don't have a freeblock in hand, get the next one.		 */		if (fbp == NULL) {			/*			 * Happens the first time through unless lookup gave			 * us a freespace block to start with.			 */			if (++fbno == 0)				fbno = XFS_DIR2_FREE_FIRSTDB(mp);			/*			 * If it's ifbno we already looked at it.			 */			if (fbno == ifbno)				fbno++;			/*			 * If it's off the end we're done.			 */			if (fbno >= lastfbno)				break;			/*			 * Read the block.  There can be holes in the			 * freespace blocks, so this might not succeed.			 * This should be really rare, so there's no reason			 * to avoid it.			 */			if ((error = xfs_da_read_buf(tp, dp,					xfs_dir2_db_to_da(mp, fbno), -2, &fbp,					XFS_DATA_FORK))) {				return error;			}			if (unlikely(fbp == NULL)) {				continue;			}			free = fbp->data;			ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);			findex = 0;		}		/*		 * Look at the current free entry.  Is it good enough?		 */		if (be16_to_cpu(free->bests[findex]) != NULLDATAOFF &&		    be16_to_cpu(free->bests[findex]) >= length)			dbno = be32_to_cpu(free->hdr.firstdb) + findex;		else {			/*			 * Are we done with the freeblock?			 */			if (++findex == be32_to_cpu(free->hdr.nvalid)) {				/*				 * Drop the block.				 */				xfs_da_brelse(tp, fbp);

⌨️ 快捷键说明

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