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

📄 xfs_dir2_node.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_da_btree.h"#include "xfs_bmap_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_bmap.h"#include "xfs_dir2_data.h"#include "xfs_dir2_leaf.h"#include "xfs_dir2_block.h"#include "xfs_dir2_node.h"#include "xfs_dir2_trace.h"#include "xfs_error.h"/* * Function declarations. */static void xfs_dir2_free_log_header(xfs_trans_t *tp, xfs_dabuf_t *bp);static int xfs_dir2_leafn_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index);#ifdef DEBUGstatic void xfs_dir2_leafn_check(xfs_inode_t *dp, xfs_dabuf_t *bp);#else#define	xfs_dir2_leafn_check(dp, bp)#endifstatic void xfs_dir2_leafn_moveents(xfs_da_args_t *args, xfs_dabuf_t *bp_s,				    int start_s, xfs_dabuf_t *bp_d, int start_d,				    int count);static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state,				     xfs_da_state_blk_t *blk1,				     xfs_da_state_blk_t *blk2);static int xfs_dir2_leafn_remove(xfs_da_args_t *args, xfs_dabuf_t *bp,				 int index, xfs_da_state_blk_t *dblk,				 int *rval);static int xfs_dir2_node_addname_int(xfs_da_args_t *args,				     xfs_da_state_blk_t *fblk);/* * Log entries from a freespace block. */voidxfs_dir2_free_log_bests(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp,		/* freespace buffer */	int			first,		/* first entry to log */	int			last)		/* last entry to log */{	xfs_dir2_free_t		*free;		/* freespace structure */	free = bp->data;	ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);	xfs_da_log_buf(tp, bp,		(uint)((char *)&free->bests[first] - (char *)free),		(uint)((char *)&free->bests[last] - (char *)free +		       sizeof(free->bests[0]) - 1));}/* * Log header from a freespace block. */static voidxfs_dir2_free_log_header(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp)		/* freespace buffer */{	xfs_dir2_free_t		*free;		/* freespace structure */	free = bp->data;	ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);	xfs_da_log_buf(tp, bp, (uint)((char *)&free->hdr - (char *)free),		(uint)(sizeof(xfs_dir2_free_hdr_t) - 1));}/* * Convert a leaf-format directory to a node-format directory. * We need to change the magic number of the leaf block, and copy * the freespace table out of the leaf block into its own block. */int						/* error */xfs_dir2_leaf_to_node(	xfs_da_args_t		*args,		/* operation arguments */	xfs_dabuf_t		*lbp)		/* leaf buffer */{	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return value */	xfs_dabuf_t		*fbp;		/* freespace buffer */	xfs_dir2_db_t		fdb;		/* freespace block number */	xfs_dir2_free_t		*free;		/* freespace structure */	__be16			*from;		/* pointer to freespace entry */	int			i;		/* leaf freespace index */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */	xfs_mount_t		*mp;		/* filesystem mount point */	int			n;		/* count of live freespc ents */	xfs_dir2_data_off_t	off;		/* freespace entry value */	__be16			*to;		/* pointer to freespace entry */	xfs_trans_t		*tp;		/* transaction pointer */	xfs_dir2_trace_args_b("leaf_to_node", args, lbp);	dp = args->dp;	mp = dp->i_mount;	tp = args->trans;	/*	 * Add a freespace block to the directory.	 */	if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) {		return error;	}	ASSERT(fdb == XFS_DIR2_FREE_FIRSTDB(mp));	/*	 * Get the buffer for the new freespace block.	 */	if ((error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, fdb), -1, &fbp,			XFS_DATA_FORK))) {		return error;	}	ASSERT(fbp != NULL);	free = fbp->data;	leaf = lbp->data;	ltp = xfs_dir2_leaf_tail_p(mp, leaf);	/*	 * Initialize the freespace block header.	 */	free->hdr.magic = cpu_to_be32(XFS_DIR2_FREE_MAGIC);	free->hdr.firstdb = 0;	ASSERT(be32_to_cpu(ltp->bestcount) <= (uint)dp->i_d.di_size / mp->m_dirblksize);	free->hdr.nvalid = ltp->bestcount;	/*	 * Copy freespace entries from the leaf block to the new block.	 * Count active entries.	 */	for (i = n = 0, from = xfs_dir2_leaf_bests_p(ltp), to = free->bests;	     i < be32_to_cpu(ltp->bestcount); i++, from++, to++) {		if ((off = be16_to_cpu(*from)) != NULLDATAOFF)			n++;		*to = cpu_to_be16(off);	}	free->hdr.nused = cpu_to_be32(n);	leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC);	/*	 * Log everything.	 */	xfs_dir2_leaf_log_header(tp, lbp);	xfs_dir2_free_log_header(tp, fbp);	xfs_dir2_free_log_bests(tp, fbp, 0, be32_to_cpu(free->hdr.nvalid) - 1);	xfs_da_buf_done(fbp);	xfs_dir2_leafn_check(dp, lbp);	return 0;}/* * Add a leaf entry to a leaf block in a node-form directory. * The other work necessary is done from the caller. */static int					/* error */xfs_dir2_leafn_add(	xfs_dabuf_t		*bp,		/* leaf buffer */	xfs_da_args_t		*args,		/* operation arguments */	int			index)		/* insertion pt for new entry */{	int			compact;	/* compacting stale leaves */	xfs_inode_t		*dp;		/* incore directory inode */	int			highstale;	/* next stale entry */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */	int			lfloghigh;	/* high leaf entry logging */	int			lfloglow;	/* low leaf entry logging */	int			lowstale;	/* previous stale entry */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_trans_t		*tp;		/* transaction pointer */	xfs_dir2_trace_args_sb("leafn_add", args, index, bp);	dp = args->dp;	mp = dp->i_mount;	tp = args->trans;	leaf = bp->data;	/*	 * Quick check just to make sure we are not going to index	 * into other peoples memory	 */	if (index < 0)		return XFS_ERROR(EFSCORRUPTED);	/*	 * If there are already the maximum number of leaf entries in	 * the block, if there are no stale entries it won't fit.	 * Caller will do a split.  If there are stale entries we'll do	 * a compact.	 */	if (be16_to_cpu(leaf->hdr.count) == xfs_dir2_max_leaf_ents(mp)) {		if (!leaf->hdr.stale)			return XFS_ERROR(ENOSPC);		compact = be16_to_cpu(leaf->hdr.stale) > 1;	} else		compact = 0;	ASSERT(index == 0 || be32_to_cpu(leaf->ents[index - 1].hashval) <= args->hashval);	ASSERT(index == be16_to_cpu(leaf->hdr.count) ||	       be32_to_cpu(leaf->ents[index].hashval) >= args->hashval);	if (args->justcheck)		return 0;	/*	 * Compact out all but one stale leaf entry.  Leaves behind	 * the entry closest to index.	 */	if (compact) {		xfs_dir2_leaf_compact_x1(bp, &index, &lowstale, &highstale,			&lfloglow, &lfloghigh);	}	/*	 * Set impossible logging indices for this case.	 */	else if (leaf->hdr.stale) {		lfloglow = be16_to_cpu(leaf->hdr.count);		lfloghigh = -1;	}	/*	 * No stale entries, just insert a space for the new entry.	 */	if (!leaf->hdr.stale) {		lep = &leaf->ents[index];		if (index < be16_to_cpu(leaf->hdr.count))			memmove(lep + 1, lep,				(be16_to_cpu(leaf->hdr.count) - index) * sizeof(*lep));		lfloglow = index;		lfloghigh = be16_to_cpu(leaf->hdr.count);		be16_add(&leaf->hdr.count, 1);	}	/*	 * There are stale entries.  We'll use one for the new entry.	 */	else {		/*		 * If we didn't do a compact then we need to figure out		 * which stale entry will be used.		 */		if (compact == 0) {			/*			 * Find first stale entry before our insertion point.			 */			for (lowstale = index - 1;			     lowstale >= 0 &&				be32_to_cpu(leaf->ents[lowstale].address) !=				XFS_DIR2_NULL_DATAPTR;			     lowstale--)				continue;			/*			 * Find next stale entry after insertion point.			 * Stop looking if the answer would be worse than			 * lowstale already found.			 */			for (highstale = index;			     highstale < be16_to_cpu(leaf->hdr.count) &&				be32_to_cpu(leaf->ents[highstale].address) !=				XFS_DIR2_NULL_DATAPTR &&				(lowstale < 0 ||				 index - lowstale - 1 >= highstale - index);			     highstale++)				continue;		}		/*		 * Using the low stale entry.		 * Shift entries up toward the stale slot.		 */		if (lowstale >= 0 &&		    (highstale == be16_to_cpu(leaf->hdr.count) ||		     index - lowstale - 1 < highstale - index)) {			ASSERT(be32_to_cpu(leaf->ents[lowstale].address) ==			       XFS_DIR2_NULL_DATAPTR);			ASSERT(index - lowstale - 1 >= 0);			if (index - lowstale - 1 > 0)				memmove(&leaf->ents[lowstale],					&leaf->ents[lowstale + 1],					(index - lowstale - 1) * sizeof(*lep));			lep = &leaf->ents[index - 1];			lfloglow = MIN(lowstale, lfloglow);			lfloghigh = MAX(index - 1, lfloghigh);		}		/*		 * Using the high stale entry.		 * Shift entries down toward the stale slot.		 */		else {			ASSERT(be32_to_cpu(leaf->ents[highstale].address) ==			       XFS_DIR2_NULL_DATAPTR);			ASSERT(highstale - index >= 0);			if (highstale - index > 0)				memmove(&leaf->ents[index + 1],					&leaf->ents[index],					(highstale - index) * sizeof(*lep));			lep = &leaf->ents[index];			lfloglow = MIN(index, lfloglow);			lfloghigh = MAX(highstale, lfloghigh);		}		be16_add(&leaf->hdr.stale, -1);	}	/*	 * Insert the new entry, log everything.	 */	lep->hashval = cpu_to_be32(args->hashval);	lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp,				args->blkno, args->index));	xfs_dir2_leaf_log_header(tp, bp);	xfs_dir2_leaf_log_ents(tp, bp, lfloglow, lfloghigh);	xfs_dir2_leafn_check(dp, bp);	return 0;}#ifdef DEBUG/* * Check internal consistency of a leafn block. */voidxfs_dir2_leafn_check(	xfs_inode_t	*dp,			/* incore directory inode */	xfs_dabuf_t	*bp)			/* leaf buffer */{	int		i;			/* leaf index */	xfs_dir2_leaf_t	*leaf;			/* leaf structure */	xfs_mount_t	*mp;			/* filesystem mount point */	int		stale;			/* count of stale leaves */	leaf = bp->data;	mp = dp->i_mount;	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);	ASSERT(be16_to_cpu(leaf->hdr.count) <= xfs_dir2_max_leaf_ents(mp));	for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) {		if (i + 1 < be16_to_cpu(leaf->hdr.count)) {			ASSERT(be32_to_cpu(leaf->ents[i].hashval) <=			       be32_to_cpu(leaf->ents[i + 1].hashval));		}		if (be32_to_cpu(leaf->ents[i].address) == XFS_DIR2_NULL_DATAPTR)			stale++;	}	ASSERT(be16_to_cpu(leaf->hdr.stale) == stale);}#endif	/* DEBUG *//* * Return the last hash value in the leaf. * Stale entries are ok. */xfs_dahash_t					/* hash value */xfs_dir2_leafn_lasthash(	xfs_dabuf_t	*bp,			/* leaf buffer */	int		*count)			/* count of entries in leaf */{	xfs_dir2_leaf_t	*leaf;			/* leaf structure */	leaf = bp->data;	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);	if (count)		*count = be16_to_cpu(leaf->hdr.count);	if (!leaf->hdr.count)		return 0;	return be32_to_cpu(leaf->ents[be16_to_cpu(leaf->hdr.count) - 1].hashval);}/* * Look up a leaf entry in a node-format leaf block. * If this is an addname then the extrablk in state is a freespace block, * otherwise it's a data block. */intxfs_dir2_leafn_lookup_int(	xfs_dabuf_t		*bp,		/* leaf buffer */	xfs_da_args_t		*args,		/* operation arguments */	int			*indexp,	/* out: leaf entry index */	xfs_da_state_t		*state)		/* state to fill in */{	xfs_dabuf_t		*curbp;		/* current data/free buffer */	xfs_dir2_db_t		curdb;		/* current data block number */	xfs_dir2_db_t		curfdb;		/* current free block number */	xfs_dir2_data_entry_t	*dep;		/* data block entry */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return value */	int			fi;		/* free entry index */	xfs_dir2_free_t		*free=NULL;	/* free block structure */	int			index;		/* leaf entry index */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	int			length=0;	/* length of new data entry */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_dir2_db_t		newdb;		/* new data block number */	xfs_dir2_db_t		newfdb;		/* new free block number */	xfs_trans_t		*tp;		/* transaction pointer */	dp = args->dp;	tp = args->trans;	mp = dp->i_mount;	leaf = bp->data;	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);#ifdef __KERNEL__	ASSERT(be16_to_cpu(leaf->hdr.count) > 0);#endif	xfs_dir2_leafn_check(dp, bp);	/*	 * Look up the hash value in the leaf entries.	 */	index = xfs_dir2_leaf_search_hash(args, bp);	/*	 * Do we have a buffer coming in?	 */	if (state->extravalid)		curbp = state->extrablk.bp;	else		curbp = NULL;	/*	 * For addname, it's a free block buffer, get the block number.	 */	if (args->addname) {		curfdb = curbp ? state->extrablk.blkno : -1;		curdb = -1;		length = xfs_dir2_data_entsize(args->namelen);		if ((free = (curbp ? curbp->data : NULL)))			ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);	}	/*	 * For others, it's a data block buffer, get the block number.	 */	else {		curfdb = -1;		curdb = curbp ? state->extrablk.blkno : -1;	}	/*	 * Loop over leaf entries with the right hash value.	 */	for (lep = &leaf->ents[index];	     index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval;	     lep++, index++) {		/*		 * Skip stale leaf entries.		 */		if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)			continue;		/*		 * Pull the data block number from the entry.		 */		newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));		/*		 * For addname, we're looking for a place to put the new entry.		 * We want to use a data block with an entry of equal		 * hash value to ours if there is one with room.		 */		if (args->addname) {			/*			 * If this block isn't the data block we already have			 * in hand, take a look at it.			 */			if (newdb != curdb) {				curdb = newdb;				/*				 * Convert the data block to the free block				 * holding its freespace information.				 */				newfdb = xfs_dir2_db_to_fdb(mp, newdb);				/*				 * If it's not the one we have in hand,				 * read it in.				 */				if (newfdb != curfdb) {					/*					 * If we had one before, drop it.					 */					if (curbp)						xfs_da_brelse(tp, curbp);					/*					 * Read the free block.					 */					if ((error = xfs_da_read_buf(tp, dp,							xfs_dir2_db_to_da(mp,

⌨️ 快捷键说明

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