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

📄 xfs_dir2_node.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				fbp = NULL;				if (fblk && fblk->bp)					fblk->bp = NULL;			}		}	}	/*	 * If we don't have a data block, we need to allocate one and make	 * the freespace entries refer to it.	 */	if (unlikely(dbno == -1)) {		/*		 * Not allowed to allocate, return failure.		 */		if (args->justcheck || args->total == 0) {			/*			 * Drop the freespace buffer unless it came from our			 * caller.			 */			if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)				xfs_da_buf_done(fbp);			return XFS_ERROR(ENOSPC);		}		/*		 * Allocate and initialize the new data block.		 */		if (unlikely((error = xfs_dir2_grow_inode(args,							 XFS_DIR2_DATA_SPACE,							 &dbno)) ||		    (error = xfs_dir2_data_init(args, dbno, &dbp)))) {			/*			 * Drop the freespace buffer unless it came from our			 * caller.			 */			if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)				xfs_da_buf_done(fbp);			return error;		}		/*		 * If (somehow) we have a freespace block, get rid of it.		 */		if (fbp)			xfs_da_brelse(tp, fbp);		if (fblk && fblk->bp)			fblk->bp = NULL;		/*		 * Get the freespace block corresponding to the data block		 * that was just allocated.		 */		fbno = xfs_dir2_db_to_fdb(mp, dbno);		if (unlikely(error = xfs_da_read_buf(tp, dp,				xfs_dir2_db_to_da(mp, fbno), -2, &fbp,				XFS_DATA_FORK))) {			xfs_da_buf_done(dbp);			return error;  		}		/*		 * If there wasn't a freespace block, the read will		 * return a NULL fbp.  Allocate and initialize a new one.		 */		if( fbp == NULL ) {			if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE,							&fbno))) {				return error;			}			if (unlikely(xfs_dir2_db_to_fdb(mp, dbno) != fbno)) {				cmn_err(CE_ALERT,					"xfs_dir2_node_addname_int: dir ino "					"%llu needed freesp block %lld for\n"					"  data block %lld, got %lld\n"					"  ifbno %llu lastfbno %d\n",					(unsigned long long)dp->i_ino,					(long long)xfs_dir2_db_to_fdb(mp, dbno),					(long long)dbno, (long long)fbno,					(unsigned long long)ifbno, lastfbno);				if (fblk) {					cmn_err(CE_ALERT,						" fblk 0x%p blkno %llu "						"index %d magic 0x%x\n",						fblk,						(unsigned long long)fblk->blkno,						fblk->index,						fblk->magic);				} else {					cmn_err(CE_ALERT,						" ... fblk is NULL\n");				}				XFS_ERROR_REPORT("xfs_dir2_node_addname_int",						 XFS_ERRLEVEL_LOW, mp);				return XFS_ERROR(EFSCORRUPTED);			}			/*			 * Get a buffer for the new block.			 */			if ((error = xfs_da_get_buf(tp, dp,						   xfs_dir2_db_to_da(mp, fbno),						   -1, &fbp, XFS_DATA_FORK))) {				return error;			}			ASSERT(fbp != NULL);			/*			 * Initialize the new block to be empty, and remember			 * its first slot as our empty slot.			 */			free = fbp->data;			free->hdr.magic = cpu_to_be32(XFS_DIR2_FREE_MAGIC);			free->hdr.firstdb = cpu_to_be32(				(fbno - XFS_DIR2_FREE_FIRSTDB(mp)) *				XFS_DIR2_MAX_FREE_BESTS(mp));			free->hdr.nvalid = 0;			free->hdr.nused = 0;		} else {			free = fbp->data;			ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);		}		/*		 * Set the freespace block index from the data block number.		 */		findex = xfs_dir2_db_to_fdindex(mp, dbno);		/*		 * If it's after the end of the current entries in the		 * freespace block, extend that table.		 */		if (findex >= be32_to_cpu(free->hdr.nvalid)) {			ASSERT(findex < XFS_DIR2_MAX_FREE_BESTS(mp));			free->hdr.nvalid = cpu_to_be32(findex + 1);			/*			 * Tag new entry so nused will go up.			 */			free->bests[findex] = cpu_to_be16(NULLDATAOFF);		}		/*		 * If this entry was for an empty data block		 * (this should always be true) then update the header.		 */		if (be16_to_cpu(free->bests[findex]) == NULLDATAOFF) {			be32_add(&free->hdr.nused, 1);			xfs_dir2_free_log_header(tp, fbp);		}		/*		 * Update the real value in the table.		 * We haven't allocated the data entry yet so this will		 * change again.		 */		data = dbp->data;		free->bests[findex] = data->hdr.bestfree[0].length;		logfree = 1;	}	/*	 * We had a data block so we don't have to make a new one.	 */	else {		/*		 * If just checking, we succeeded.		 */		if (args->justcheck) {			if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)				xfs_da_buf_done(fbp);			return 0;		}		/*		 * Read the data block in.		 */		if (unlikely(		    error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, dbno),				-1, &dbp, XFS_DATA_FORK))) {			if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)				xfs_da_buf_done(fbp);			return error;		}		data = dbp->data;		logfree = 0;	}	ASSERT(be16_to_cpu(data->hdr.bestfree[0].length) >= length);	/*	 * Point to the existing unused space.	 */	dup = (xfs_dir2_data_unused_t *)	      ((char *)data + be16_to_cpu(data->hdr.bestfree[0].offset));	needscan = needlog = 0;	/*	 * Mark the first part of the unused space, inuse for us.	 */	xfs_dir2_data_use_free(tp, dbp, dup,		(xfs_dir2_data_aoff_t)((char *)dup - (char *)data), length,		&needlog, &needscan);	/*	 * Fill in the new entry and log it.	 */	dep = (xfs_dir2_data_entry_t *)dup;	dep->inumber = cpu_to_be64(args->inumber);	dep->namelen = args->namelen;	memcpy(dep->name, args->name, dep->namelen);	tagp = xfs_dir2_data_entry_tag_p(dep);	*tagp = cpu_to_be16((char *)dep - (char *)data);	xfs_dir2_data_log_entry(tp, dbp, dep);	/*	 * Rescan the block for bestfree if needed.	 */	if (needscan)		xfs_dir2_data_freescan(mp, data, &needlog);	/*	 * Log the data block header if needed.	 */	if (needlog)		xfs_dir2_data_log_header(tp, dbp);	/*	 * If the freespace entry is now wrong, update it.	 */	if (be16_to_cpu(free->bests[findex]) != be16_to_cpu(data->hdr.bestfree[0].length)) {		free->bests[findex] = data->hdr.bestfree[0].length;		logfree = 1;	}	/*	 * Log the freespace entry if needed.	 */	if (logfree)		xfs_dir2_free_log_bests(tp, fbp, findex, findex);	/*	 * If the caller didn't hand us the freespace block, drop it.	 */	if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)		xfs_da_buf_done(fbp);	/*	 * Return the data block and offset in args, then drop the data block.	 */	args->blkno = (xfs_dablk_t)dbno;	args->index = be16_to_cpu(*tagp);	xfs_da_buf_done(dbp);	return 0;}/* * Lookup an entry in a node-format directory. * All the real work happens in xfs_da_node_lookup_int. * The only real output is the inode number of the entry. */int						/* error */xfs_dir2_node_lookup(	xfs_da_args_t	*args)			/* operation arguments */{	int		error;			/* error return value */	int		i;			/* btree level */	int		rval;			/* operation return value */	xfs_da_state_t	*state;			/* btree cursor */	xfs_dir2_trace_args("node_lookup", args);	/*	 * Allocate and initialize the 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;	/*	 * Fill in the path to the entry in the cursor.	 */	error = xfs_da_node_lookup_int(state, &rval);	if (error)		rval = error;	/*	 * Release the btree blocks and leaf block.	 */	for (i = 0; i < state->path.active; i++) {		xfs_da_brelse(args->trans, state->path.blk[i].bp);		state->path.blk[i].bp = NULL;	}	/*	 * Release the data block if we have it.	 */	if (state->extravalid && state->extrablk.bp) {		xfs_da_brelse(args->trans, state->extrablk.bp);		state->extrablk.bp = NULL;	}	xfs_da_state_free(state);	return rval;}/* * Remove an entry from a node-format directory. */int						/* error */xfs_dir2_node_removename(	xfs_da_args_t		*args)		/* operation arguments */{	xfs_da_state_blk_t	*blk;		/* leaf block */	int			error;		/* error return value */	int			rval;		/* operation return value */	xfs_da_state_t		*state;		/* btree cursor */	xfs_dir2_trace_args("node_removename", args);	/*	 * Allocate and initialize the 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 entry we're deleting, set up the cursor.	 */	error = xfs_da_node_lookup_int(state, &rval);	if (error) {		rval = error;	}	/*	 * Didn't find it, upper layer screwed up.	 */	if (rval != EEXIST) {		xfs_da_state_free(state);		return rval;	}	blk = &state->path.blk[state->path.active - 1];	ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC);	ASSERT(state->extravalid);	/*	 * Remove the leaf and data entries.	 * Extrablk refers to the data block.	 */	error = xfs_dir2_leafn_remove(args, blk->bp, blk->index,		&state->extrablk, &rval);	if (error) {		return error;	}	/*	 * Fix the hash values up the btree.	 */	xfs_da_fixhashpath(state, &state->path);	/*	 * If we need to join leaf blocks, do it.	 */	if (rval && state->path.active > 1)		error = xfs_da_join(state);	/*	 * If no errors so far, try conversion to leaf format.	 */	if (!error)		error = xfs_dir2_node_to_leaf(state);	xfs_da_state_free(state);	return error;}/* * Replace an entry's inode number in a node-format directory. */int						/* error */xfs_dir2_node_replace(	xfs_da_args_t		*args)		/* operation arguments */{	xfs_da_state_blk_t	*blk;		/* leaf block */	xfs_dir2_data_t		*data;		/* data block structure */	xfs_dir2_data_entry_t	*dep;		/* data entry changed */	int			error;		/* error return value */	int			i;		/* btree level */	xfs_ino_t		inum;		/* new inode number */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry being changed */	int			rval;		/* internal return value */	xfs_da_state_t		*state;		/* btree cursor */	xfs_dir2_trace_args("node_replace", args);	/*	 * Allocate and initialize the 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;	inum = args->inumber;	/*	 * Lookup the entry to change in the btree.	 */	error = xfs_da_node_lookup_int(state, &rval);	if (error) {		rval = error;	}	/*	 * It should be found, since the vnodeops layer has looked it up	 * and locked it.  But paranoia is good.	 */	if (rval == EEXIST) {		/*		 * Find the leaf entry.		 */		blk = &state->path.blk[state->path.active - 1];		ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC);		leaf = blk->bp->data;		lep = &leaf->ents[blk->index];		ASSERT(state->extravalid);		/*		 * Point to the data entry.		 */		data = state->extrablk.bp->data;		ASSERT(be32_to_cpu(data->hdr.magic) == XFS_DIR2_DATA_MAGIC);		dep = (xfs_dir2_data_entry_t *)		      ((char *)data +		       xfs_dir2_dataptr_to_off(state->mp, be32_to_cpu(lep->address)));		ASSERT(inum != be64_to_cpu(dep->inumber));		/*		 * Fill in the new inode number and log the entry.		 */		dep->inumber = cpu_to_be64(inum);		xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep);		rval = 0;	}	/*	 * Didn't find it, and we're holding a data block.  Drop it.	 */	else if (state->extravalid) {		xfs_da_brelse(args->trans, state->extrablk.bp);		state->extrablk.bp = NULL;	}	/*	 * Release all the buffers in the cursor.	 */	for (i = 0; i < state->path.active; i++) {		xfs_da_brelse(args->trans, state->path.blk[i].bp);		state->path.blk[i].bp = NULL;	}	xfs_da_state_free(state);	return rval;}/* * Trim off a trailing empty freespace block. * Return (in rvalp) 1 if we did it, 0 if not. */int						/* error */xfs_dir2_node_trim_free(	xfs_da_args_t		*args,		/* operation arguments */	xfs_fileoff_t		fo,		/* free block number */	int			*rvalp)		/* out: did something */{	xfs_dabuf_t		*bp;		/* freespace buffer */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return code */	xfs_dir2_free_t		*free;		/* freespace structure */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_trans_t		*tp;		/* transaction pointer */	dp = args->dp;	mp = dp->i_mount;	tp = args->trans;	/*	 * Read the freespace block.	 */	if (unlikely(error = xfs_da_read_buf(tp, dp, (xfs_dablk_t)fo, -2, &bp,			XFS_DATA_FORK))) {		return error;	}	/*	 * There can be holes in freespace.  If fo is a hole, there's	 * nothing to do.	 */	if (bp == NULL) {		return 0;	}	free = bp->data;	ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);	/*	 * If there are used entries, there's nothing to do.	 */	if (be32_to_cpu(free->hdr.nused) > 0) {		xfs_da_brelse(tp, bp);		*rvalp = 0;		return 0;	}	/*	 * Blow the block away.	 */	if ((error =	    xfs_dir2_shrink_inode(args, xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo),		    bp))) {		/*		 * Can't fail with ENOSPC since that only happens with no		 * space reservation, when breaking up an extent into two		 * pieces.  This is the last block of an extent.		 */		ASSERT(error != ENOSPC);		xfs_da_brelse(tp, bp);		return error;	}	/*	 * Return that we succeeded.	 */	*rvalp = 1;	return 0;}

⌨️ 快捷键说明

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