xfs_dir2_leaf.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,897 行 · 第 1/4 页

C
1,897
字号
			/*			 * No valid mappings, so no more data blocks.			 */			if (!map_valid) {				curoff = XFS_DIR2_DA_TO_BYTE(mp, map_off);				break;			}			/*			 * Read the directory block starting at the first			 * mapping.			 */			curdb = XFS_DIR2_DA_TO_DB(mp, map->br_startoff);			error = xfs_da_read_buf(tp, dp, map->br_startoff,				map->br_blockcount >= mp->m_dirblkfsbs ?				    XFS_FSB_TO_DADDR(mp, map->br_startblock) :				    -1,				&bp, XFS_DATA_FORK);			/*			 * Should just skip over the data block instead			 * of giving up.			 */			if (error)				break;	/* XXX */			/*			 * Adjust the current amount of read-ahead: we just			 * read a block that was previously ra.			 */			if (ra_current)				ra_current -= mp->m_dirblkfsbs;			/*			 * Do we need more readahead?			 */			for (ra_index = ra_offset = i = 0;			     ra_want > ra_current && i < map_blocks;			     i += mp->m_dirblkfsbs) {				ASSERT(ra_index < map_valid);				/*				 * Read-ahead a contiguous directory block.				 */				if (i > ra_current &&				    map[ra_index].br_blockcount >=				    mp->m_dirblkfsbs) {					xfs_baread(mp->m_ddev_targp,						XFS_FSB_TO_DADDR(mp,						   map[ra_index].br_startblock +						   ra_offset),						(int)BTOBB(mp->m_dirblksize));					ra_current = i;				}				/*				 * Read-ahead a non-contiguous directory block.				 * This doesn't use our mapping, but this				 * is a very rare case.				 */				else if (i > ra_current) {					(void)xfs_da_reada_buf(tp, dp,						map[ra_index].br_startoff +						ra_offset, XFS_DATA_FORK);					ra_current = i;				}				/*				 * Advance offset through the mapping table.				 */				for (j = 0; j < mp->m_dirblkfsbs; j++) {					/*					 * The rest of this extent but not					 * more than a dir block.					 */					length = MIN(mp->m_dirblkfsbs,						(int)(map[ra_index].br_blockcount -						ra_offset));					j += length;					ra_offset += length;					/*					 * Advance to the next mapping if					 * this one is used up.					 */					if (ra_offset ==					    map[ra_index].br_blockcount) {						ra_offset = 0;						ra_index++;					}				}			}			/*			 * Having done a read, we need to set a new offset.			 */			newoff = XFS_DIR2_DB_OFF_TO_BYTE(mp, curdb, 0);			/*			 * Start of the current block.			 */			if (curoff < newoff)				curoff = newoff;			/*			 * Make sure we're in the right block.			 */			else if (curoff > newoff)				ASSERT(XFS_DIR2_BYTE_TO_DB(mp, curoff) ==				       curdb);			data = bp->data;			xfs_dir2_data_check(dp, bp);			/*			 * Find our position in the block.			 */			ptr = (char *)&data->u;			byteoff = XFS_DIR2_BYTE_TO_OFF(mp, curoff);			/*			 * Skip past the header.			 */			if (byteoff == 0)				curoff += (uint)sizeof(data->hdr);			/*			 * Skip past entries until we reach our offset.			 */			else {				while ((char *)ptr - (char *)data < byteoff) {					dup = (xfs_dir2_data_unused_t *)ptr;					if (INT_GET(dup->freetag, ARCH_CONVERT)						  == XFS_DIR2_DATA_FREE_TAG) {						length = INT_GET(dup->length,								 ARCH_CONVERT);						ptr += length;						continue;					}					dep = (xfs_dir2_data_entry_t *)ptr;					length =					   XFS_DIR2_DATA_ENTSIZE(dep->namelen);					ptr += length;				}				/*				 * Now set our real offset.				 */				curoff =					XFS_DIR2_DB_OFF_TO_BYTE(mp,					    XFS_DIR2_BYTE_TO_DB(mp, curoff),					    (char *)ptr - (char *)data);				if (ptr >= (char *)data + mp->m_dirblksize) {					continue;				}			}		}		/*		 * We have a pointer to an entry.		 * Is it a live one?		 */		dup = (xfs_dir2_data_unused_t *)ptr;		/*		 * No, it's unused, skip over it.		 */		if (INT_GET(dup->freetag, ARCH_CONVERT)						== XFS_DIR2_DATA_FREE_TAG) {			length = INT_GET(dup->length, ARCH_CONVERT);			ptr += length;			curoff += length;			continue;		}		/*		 * Copy the entry into the putargs, and try formatting it.		 */		dep = (xfs_dir2_data_entry_t *)ptr;		p.namelen = dep->namelen;		length = XFS_DIR2_DATA_ENTSIZE(p.namelen);		p.cook = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff + length);		p.ino = INT_GET(dep->inumber, ARCH_CONVERT);#if XFS_BIG_INUMS		p.ino += mp->m_inoadd;#endif		p.name = (char *)dep->name;		error = p.put(&p);		/*		 * Won't fit.  Return to caller.		 */		if (!p.done) {			eof = 0;			break;		}		/*		 * Advance to next entry in the block.		 */		ptr += length;		curoff += length;	}	/*	 * All done.  Set output offset value to current offset.	 */	*eofp = eof;	if (curoff > XFS_DIR2_DATAPTR_TO_BYTE(mp, XFS_DIR2_MAX_DATAPTR))		uio->uio_offset = XFS_DIR2_MAX_DATAPTR;	else		uio->uio_offset = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff);	kmem_free(map, map_size * sizeof(*map));	if (bp)		xfs_da_brelse(tp, bp);	return error;}/* * Initialize a new leaf block, leaf1 or leafn magic accepted. */intxfs_dir2_leaf_init(	xfs_da_args_t		*args,		/* operation arguments */	xfs_dir2_db_t		bno,		/* directory block number */	xfs_dabuf_t		**bpp,		/* out: leaf buffer */	int			magic)		/* magic number for block */{	xfs_dabuf_t		*bp;		/* leaf buffer */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return code */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_trans_t		*tp;		/* transaction pointer */	dp = args->dp;	ASSERT(dp != NULL);	tp = args->trans;	mp = dp->i_mount;	ASSERT(bno >= XFS_DIR2_LEAF_FIRSTDB(mp) &&	       bno < XFS_DIR2_FREE_FIRSTDB(mp));	/*	 * Get the buffer for the block.	 */	error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, bno), -1, &bp,		XFS_DATA_FORK);	if (error) {		return error;	}	ASSERT(bp != NULL);	leaf = bp->data;	/*	 * Initialize the header.	 */	INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, magic);	INT_ZERO(leaf->hdr.info.forw, ARCH_CONVERT);	INT_ZERO(leaf->hdr.info.back, ARCH_CONVERT);	INT_ZERO(leaf->hdr.count, ARCH_CONVERT);	INT_ZERO(leaf->hdr.stale, ARCH_CONVERT);	xfs_dir2_leaf_log_header(tp, bp);	/*	 * If it's a leaf-format directory initialize the tail.	 * In this case our caller has the real bests table to copy into	 * the block.	 */	if (magic == XFS_DIR2_LEAF1_MAGIC) {		ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);		INT_ZERO(ltp->bestcount, ARCH_CONVERT);		xfs_dir2_leaf_log_tail(tp, bp);	}	*bpp = bp;	return 0;}/* * Log the bests entries indicated from a leaf1 block. */voidxfs_dir2_leaf_log_bests(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp,		/* leaf buffer */	int			first,		/* first entry to log */	int			last)		/* last entry to log */{	xfs_dir2_data_off_t	*firstb;	/* pointer to first entry */	xfs_dir2_data_off_t	*lastb;		/* pointer to last entry */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */	leaf = bp->data;	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);	ltp = XFS_DIR2_LEAF_TAIL_P(tp->t_mountp, leaf);	firstb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + first;	lastb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + last;	xfs_da_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf),		(uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1));}/* * Log the leaf entries indicated from a leaf1 or leafn block. */voidxfs_dir2_leaf_log_ents(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp,		/* leaf buffer */	int			first,		/* first entry to log */	int			last)		/* last entry to log */{	xfs_dir2_leaf_entry_t	*firstlep;	/* pointer to first entry */	xfs_dir2_leaf_entry_t	*lastlep;	/* pointer to last entry */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	leaf = bp->data;	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC ||	       INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);	firstlep = &leaf->ents[first];	lastlep = &leaf->ents[last];	xfs_da_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf),		(uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1));}/* * Log the header of the leaf1 or leafn block. */voidxfs_dir2_leaf_log_header(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp)		/* leaf buffer */{	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	leaf = bp->data;	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC ||	       INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);	xfs_da_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf),		(uint)(sizeof(leaf->hdr) - 1));}/* * Log the tail of the leaf1 block. */voidxfs_dir2_leaf_log_tail(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp)		/* leaf buffer */{	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */	xfs_mount_t		*mp;		/* filesystem mount point */	mp = tp->t_mountp;	leaf = bp->data;	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);	xfs_da_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf),		(uint)(mp->m_dirblksize - 1));}/* * Look up the entry referred to by args in the leaf format directory. * Most of the work is done by the xfs_dir2_leaf_lookup_int routine which * is also used by the node-format code. */intxfs_dir2_leaf_lookup(	xfs_da_args_t		*args)		/* operation arguments */{	xfs_dabuf_t		*dbp;		/* data block buffer */	xfs_dir2_data_entry_t	*dep;		/* data block entry */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return code */	int			index;		/* found entry index */	xfs_dabuf_t		*lbp;		/* leaf buffer */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */	xfs_trans_t		*tp;		/* transaction pointer */	xfs_dir2_trace_args("leaf_lookup", args);	/*	 * Look up name in the leaf block, returning both buffers and index.	 */	if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) {		return error;	}	tp = args->trans;	dp = args->dp;	xfs_dir2_leaf_check(dp, lbp);	leaf = lbp->data;	/*	 * Get to the leaf entry and contained data entry address.	 */	lep = &leaf->ents[index];	/*	 * Point to the data entry.	 */	dep = (xfs_dir2_data_entry_t *)	      ((char *)dbp->data +	       XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT)));	/*	 * Return the found inode number.	 */	args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);	xfs_da_brelse(tp, dbp);	xfs_da_brelse(tp, lbp);	return XFS_ERROR(EEXIST);}/* * Look up name/hash in the leaf block. * Fill in indexp with the found index, and dbpp with the data buffer. * If not found dbpp will be NULL, and ENOENT comes back. * lbpp will always be filled in with the leaf buffer unless there's an error. */static int					/* error */xfs_dir2_leaf_lookup_int(	xfs_da_args_t		*args,		/* operation arguments */	xfs_dabuf_t		**lbpp,		/* out: leaf buffer */	int			*indexp,	/* out: index in leaf block */	xfs_dabuf_t		**dbpp)		/* out: data buffer */{	xfs_dir2_db_t		curdb;		/* current data block number */	xfs_dabuf_t		*dbp;		/* data buffer */	xfs_dir2_data_entry_t	*dep;		/* data entry */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return code */	int			index;		/* index in leaf block */	xfs_dabuf_t		*lbp;		/* leaf buffer */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_dir2_db_t		newdb;		/* new data block number */	xfs_trans_t		*tp;		/* transaction pointer */	dp = args->dp;	tp = args->trans;	mp = dp->i_mount;	/*	 * Read the leaf block into the buffer.	 */	if ((error =	    xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp,		    XFS_DATA_FORK))) {		return error;	}	*lbpp = lbp;	leaf = lbp->data;	xfs_dir2_leaf_check(dp, lbp);	/*	 * Look for the first leaf entry with our hash value.	 */	index = xfs_dir2_leaf_search_hash(args, lbp);	/*	 * Loop over all the entries with the right hash value	 * looking to match the name.	 */	for (lep = &leaf->ents[index], dbp = NULL, curdb = -1;	     index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval;	     lep++, index++) {		/*		 * Skip over stale leaf entries.		 */		if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)			continue;		/*		 * Get the new data block number.		 */		newdb = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT));		/*		 * If it's not the same as the old data block number,		 * need to pitch the old one and read the new one.		 */		if (newdb != curdb) {			if (dbp)				xfs_da_brelse(tp, dbp);			if ((error =			    xfs_da_read_buf(tp, dp,				    XFS_DIR2_DB_TO_DA(mp, newdb), -1, &dbp,				    XFS_DATA_FORK))) {				xfs_da_brelse(tp, lbp);				return error;			}			xfs_dir2_data_check(dp, dbp);			curdb = newdb;		}		/*		 * Point to the data entry.

⌨️ 快捷键说明

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