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

📄 xfs_dir2_leaf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Copyright (c) 2000-2003,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_bit.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_attr_sf.h"#include "xfs_dir2_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"/* * Local function declarations. */#ifdef DEBUGstatic void xfs_dir2_leaf_check(xfs_inode_t *dp, xfs_dabuf_t *bp);#else#define	xfs_dir2_leaf_check(dp, bp)#endifstatic int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **lbpp,				    int *indexp, xfs_dabuf_t **dbpp);static void xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp,				    int first, int last);static void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp);/* * Convert a block form directory to a leaf form directory. */int						/* error */xfs_dir2_block_to_leaf(	xfs_da_args_t		*args,		/* operation arguments */	xfs_dabuf_t		*dbp)		/* input block's buffer */{	__be16			*bestsp;	/* leaf's bestsp entries */	xfs_dablk_t		blkno;		/* leaf block's bno */	xfs_dir2_block_t	*block;		/* block structure */	xfs_dir2_leaf_entry_t	*blp;		/* block's leaf entries */	xfs_dir2_block_tail_t	*btp;		/* block's tail */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return code */	xfs_dabuf_t		*lbp;		/* leaf block's buffer */	xfs_dir2_db_t		ldb;		/* leaf block's bno */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf's tail */	xfs_mount_t		*mp;		/* filesystem mount point */	int			needlog;	/* need to log block header */	int			needscan;	/* need to rescan bestfree */	xfs_trans_t		*tp;		/* transaction pointer */	xfs_dir2_trace_args_b("block_to_leaf", args, dbp);	dp = args->dp;	mp = dp->i_mount;	tp = args->trans;	/*	 * Add the leaf block to the inode.	 * This interface will only put blocks in the leaf/node range.	 * Since that's empty now, we'll get the root (block 0 in range).	 */	if ((error = xfs_da_grow_inode(args, &blkno))) {		return error;	}	ldb = xfs_dir2_da_to_db(mp, blkno);	ASSERT(ldb == XFS_DIR2_LEAF_FIRSTDB(mp));	/*	 * Initialize the leaf block, get a buffer for it.	 */	if ((error = xfs_dir2_leaf_init(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC))) {		return error;	}	ASSERT(lbp != NULL);	leaf = lbp->data;	block = dbp->data;	xfs_dir2_data_check(dp, dbp);	btp = xfs_dir2_block_tail_p(mp, block);	blp = xfs_dir2_block_leaf_p(btp);	/*	 * Set the counts in the leaf header.	 */	leaf->hdr.count = cpu_to_be16(be32_to_cpu(btp->count));	leaf->hdr.stale = cpu_to_be16(be32_to_cpu(btp->stale));	/*	 * Could compact these but I think we always do the conversion	 * after squeezing out stale entries.	 */	memcpy(leaf->ents, blp, be32_to_cpu(btp->count) * sizeof(xfs_dir2_leaf_entry_t));	xfs_dir2_leaf_log_ents(tp, lbp, 0, be16_to_cpu(leaf->hdr.count) - 1);	needscan = 0;	needlog = 1;	/*	 * Make the space formerly occupied by the leaf entries and block	 * tail be free.	 */	xfs_dir2_data_make_free(tp, dbp,		(xfs_dir2_data_aoff_t)((char *)blp - (char *)block),		(xfs_dir2_data_aoff_t)((char *)block + mp->m_dirblksize -				       (char *)blp),		&needlog, &needscan);	/*	 * Fix up the block header, make it a data block.	 */	block->hdr.magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);	if (needscan)		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);	/*	 * Set up leaf tail and bests table.	 */	ltp = xfs_dir2_leaf_tail_p(mp, leaf);	ltp->bestcount = cpu_to_be32(1);	bestsp = xfs_dir2_leaf_bests_p(ltp);	bestsp[0] =  block->hdr.bestfree[0].length;	/*	 * Log the data header and leaf bests table.	 */	if (needlog)		xfs_dir2_data_log_header(tp, dbp);	xfs_dir2_leaf_check(dp, lbp);	xfs_dir2_data_check(dp, dbp);	xfs_dir2_leaf_log_bests(tp, lbp, 0, 0);	xfs_da_buf_done(lbp);	return 0;}/* * Add an entry to a leaf form directory. */int						/* error */xfs_dir2_leaf_addname(	xfs_da_args_t		*args)		/* operation arguments */{	__be16			*bestsp;	/* freespace table in leaf */	int			compact;	/* need to compact leaves */	xfs_dir2_data_t		*data;		/* data block structure */	xfs_dabuf_t		*dbp;		/* data block buffer */	xfs_dir2_data_entry_t	*dep;		/* data block entry */	xfs_inode_t		*dp;		/* incore directory inode */	xfs_dir2_data_unused_t	*dup;		/* data unused entry */	int			error;		/* error return value */	int			grown;		/* allocated new data block */	int			highstale;	/* index of next stale leaf */	int			i;		/* temporary, index */	int			index;		/* leaf table position */	xfs_dabuf_t		*lbp;		/* leaf's buffer */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	int			length;		/* length of new entry */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry table pointer */	int			lfloglow;	/* low leaf logging index */	int			lfloghigh;	/* high leaf logging index */	int			lowstale;	/* index of prev stale leaf */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail pointer */	xfs_mount_t		*mp;		/* filesystem mount point */	int			needbytes;	/* leaf block bytes needed */	int			needlog;	/* need to log data header */	int			needscan;	/* need to rescan data free */	__be16			*tagp;		/* end of data entry */	xfs_trans_t		*tp;		/* transaction pointer */	xfs_dir2_db_t		use_block;	/* data block number */	xfs_dir2_trace_args("leaf_addname", args);	dp = args->dp;	tp = args->trans;	mp = dp->i_mount;	/*	 * Read the leaf block.	 */	error = xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp,		XFS_DATA_FORK);	if (error) {		return error;	}	ASSERT(lbp != NULL);	/*	 * Look up the entry by hash value and name.	 * We know it's not there, our caller has already done a lookup.	 * So the index is of the entry to insert in front of.	 * But if there are dup hash values the index is of the first of those.	 */	index = xfs_dir2_leaf_search_hash(args, lbp);	leaf = lbp->data;	ltp = xfs_dir2_leaf_tail_p(mp, leaf);	bestsp = xfs_dir2_leaf_bests_p(ltp);	length = xfs_dir2_data_entsize(args->namelen);	/*	 * See if there are any entries with the same hash value	 * and space in their block for the new entry.	 * This is good because it puts multiple same-hash value entries	 * in a data block, improving the lookup of those entries.	 */	for (use_block = -1, lep = &leaf->ents[index];	     index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval;	     index++, lep++) {		if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)			continue;		i = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));		ASSERT(i < be32_to_cpu(ltp->bestcount));		ASSERT(be16_to_cpu(bestsp[i]) != NULLDATAOFF);		if (be16_to_cpu(bestsp[i]) >= length) {			use_block = i;			break;		}	}	/*	 * Didn't find a block yet, linear search all the data blocks.	 */	if (use_block == -1) {		for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) {			/*			 * Remember a block we see that's missing.			 */			if (be16_to_cpu(bestsp[i]) == NULLDATAOFF && use_block == -1)				use_block = i;			else if (be16_to_cpu(bestsp[i]) >= length) {				use_block = i;				break;			}		}	}	/*	 * How many bytes do we need in the leaf block?	 */	needbytes =		(leaf->hdr.stale ? 0 : (uint)sizeof(leaf->ents[0])) +		(use_block != -1 ? 0 : (uint)sizeof(leaf->bests[0]));	/*	 * Now kill use_block if it refers to a missing block, so we	 * can use it as an indication of allocation needed.	 */	if (use_block != -1 && be16_to_cpu(bestsp[use_block]) == NULLDATAOFF)		use_block = -1;	/*	 * If we don't have enough free bytes but we can make enough	 * by compacting out stale entries, we'll do that.	 */	if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] < needbytes &&	    be16_to_cpu(leaf->hdr.stale) > 1) {		compact = 1;	}	/*	 * Otherwise if we don't have enough free bytes we need to	 * convert to node form.	 */	else if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <		 needbytes) {		/*		 * Just checking or no space reservation, give up.		 */		if (args->justcheck || args->total == 0) {			xfs_da_brelse(tp, lbp);			return XFS_ERROR(ENOSPC);		}		/*		 * Convert to node form.		 */		error = xfs_dir2_leaf_to_node(args, lbp);		xfs_da_buf_done(lbp);		if (error)			return error;		/*		 * Then add the new entry.		 */		return xfs_dir2_node_addname(args);	}	/*	 * Otherwise it will fit without compaction.	 */	else		compact = 0;	/*	 * If just checking, then it will fit unless we needed to allocate	 * a new data block.	 */	if (args->justcheck) {		xfs_da_brelse(tp, lbp);		return use_block == -1 ? XFS_ERROR(ENOSPC) : 0;	}	/*	 * If no allocations are allowed, return now before we've	 * changed anything.	 */	if (args->total == 0 && use_block == -1) {		xfs_da_brelse(tp, lbp);		return XFS_ERROR(ENOSPC);	}	/*	 * Need to compact the leaf entries, removing stale ones.	 * Leave one stale entry behind - the one closest to our	 * insertion index - and we'll shift that one to our insertion	 * point later.	 */	if (compact) {		xfs_dir2_leaf_compact_x1(lbp, &index, &lowstale, &highstale,			&lfloglow, &lfloghigh);	}	/*	 * There are stale entries, so we'll need log-low and log-high	 * impossibly bad values later.	 */	else if (be16_to_cpu(leaf->hdr.stale)) {		lfloglow = be16_to_cpu(leaf->hdr.count);		lfloghigh = -1;	}	/*	 * If there was no data block space found, we need to allocate	 * a new one.	 */	if (use_block == -1) {		/*		 * Add the new data block.		 */		if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE,				&use_block))) {			xfs_da_brelse(tp, lbp);			return error;		}		/*		 * Initialize the block.		 */		if ((error = xfs_dir2_data_init(args, use_block, &dbp))) {			xfs_da_brelse(tp, lbp);			return error;		}		/*		 * If we're adding a new data block on the end we need to		 * extend the bests table.  Copy it up one entry.		 */		if (use_block >= be32_to_cpu(ltp->bestcount)) {			bestsp--;			memmove(&bestsp[0], &bestsp[1],				be32_to_cpu(ltp->bestcount) * sizeof(bestsp[0]));			be32_add(&ltp->bestcount, 1);			xfs_dir2_leaf_log_tail(tp, lbp);			xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);		}		/*		 * If we're filling in a previously empty block just log it.		 */		else			xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block);		data = dbp->data;		bestsp[use_block] = data->hdr.bestfree[0].length;		grown = 1;	}	/*	 * Already had space in some data block.	 * Just read that one in.	 */	else {		if ((error =		    xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, use_block),			    -1, &dbp, XFS_DATA_FORK))) {			xfs_da_brelse(tp, lbp);			return error;		}		data = dbp->data;		grown = 0;	}	xfs_dir2_data_check(dp, dbp);	/*	 * Point to the biggest freespace in our data block.	 */	dup = (xfs_dir2_data_unused_t *)	      ((char *)data + be16_to_cpu(data->hdr.bestfree[0].offset));	ASSERT(be16_to_cpu(dup->length) >= length);	needscan = needlog = 0;	/*	 * Mark the initial part of our freespace in use for the new entry.	 */	xfs_dir2_data_use_free(tp, dbp, dup,		(xfs_dir2_data_aoff_t)((char *)dup - (char *)data), length,		&needlog, &needscan);	/*	 * Initialize our new entry (at last).	 */	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);	/*	 * Need to scan fix up the bestfree table.	 */	if (needscan)		xfs_dir2_data_freescan(mp, data, &needlog);	/*	 * Need to log the data block's header.	 */	if (needlog)		xfs_dir2_data_log_header(tp, dbp);	xfs_dir2_data_log_entry(tp, dbp, dep);	/*	 * If the bests table needs to be changed, do it.	 * Log the change unless we've already done that.	 */	if (be16_to_cpu(bestsp[use_block]) != be16_to_cpu(data->hdr.bestfree[0].length)) {		bestsp[use_block] = data->hdr.bestfree[0].length;		if (!grown)			xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block);	}	/*	 * Now we need to make room to insert the leaf entry.	 * If there are no stale entries, we just insert a hole at index.	 */	if (!leaf->hdr.stale) {		/*		 * lep is still good as the index leaf entry.		 */		if (index < be16_to_cpu(leaf->hdr.count))			memmove(lep + 1, lep,				(be16_to_cpu(leaf->hdr.count) - index) * sizeof(*lep));		/*		 * Record low and high logging indices for the leaf.		 */		lfloglow = index;		lfloghigh = be16_to_cpu(leaf->hdr.count);		be16_add(&leaf->hdr.count, 1);	}	/*	 * There are stale entries.	 * We will use one of them for the new entry.	 * It's probably not at the right location, so we'll have to	 * shift some up or down first.	 */	else {		/*		 * If we didn't compact before, we need to find the nearest		 * stale entries before and after our insertion point.		 */		if (compact == 0) {			/*			 * Find the first stale entry before the insertion			 * point, if any.			 */

⌨️ 快捷键说明

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