xfs_dir2_leaf.c

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

C
1,897
字号
	 * 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.			 */			for (lowstale = index - 1;			     lowstale >= 0 &&				INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) !=				XFS_DIR2_NULL_DATAPTR;			     lowstale--)				continue;			/*			 * Find the next stale entry at or after the insertion			 * point, if any.   Stop if we go so far that the			 * lowstale entry would be better.			 */			for (highstale = index;			     highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) &&				INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) !=				XFS_DIR2_NULL_DATAPTR &&				(lowstale < 0 ||				 index - lowstale - 1 >= highstale - index);			     highstale++)				continue;		}		/*		 * If the low one is better, use it.		 */		if (lowstale >= 0 &&		    (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) ||		     index - lowstale - 1 < highstale - index)) {			ASSERT(index - lowstale - 1 >= 0);			ASSERT(INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) ==			       XFS_DIR2_NULL_DATAPTR);			/*			 * Copy entries up to cover the stale entry			 * and make room for the new entry.			 */			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);		}		/*		 * The high one is better, so use that one.		 */		else {			ASSERT(highstale - index >= 0);			ASSERT(INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) ==			       XFS_DIR2_NULL_DATAPTR);			/*			 * Copy entries down to copver the stale entry			 * and make room for the new entry.			 */			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);		}		INT_MOD(leaf->hdr.stale, ARCH_CONVERT, -1);	}	/*	 * Fill in the new leaf entry.	 */	INT_SET(lep->hashval, ARCH_CONVERT, args->hashval);	INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_DB_OFF_TO_DATAPTR(mp, use_block, INT_GET(*tagp, ARCH_CONVERT)));	/*	 * Log the leaf fields and give up the buffers.	 */	xfs_dir2_leaf_log_header(tp, lbp);	xfs_dir2_leaf_log_ents(tp, lbp, lfloglow, lfloghigh);	xfs_dir2_leaf_check(dp, lbp);	xfs_da_buf_done(lbp);	xfs_dir2_data_check(dp, dbp);	xfs_da_buf_done(dbp);	return 0;}#ifdef DEBUG/* * Check the internal consistency of a leaf1 block. * Pop an assert if something is wrong. */voidxfs_dir2_leaf_check(	xfs_inode_t		*dp,		/* incore directory inode */	xfs_dabuf_t		*bp)		/* leaf's buffer */{	int			i;		/* leaf index */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail pointer */	xfs_mount_t		*mp;		/* filesystem mount point */	int			stale;		/* count of stale leaves */	leaf = bp->data;	mp = dp->i_mount;	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);	/*	 * This value is not restrictive enough.	 * Should factor in the size of the bests table as well.	 * We can deduce a value for that from di_size.	 */	ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) <= XFS_DIR2_MAX_LEAF_ENTS(mp));	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);	/*	 * Leaves and bests don't overlap.	 */	ASSERT((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] <=	       (char *)XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT));	/*	 * Check hash value order, count stale entries.	 */	for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) {		if (i + 1 < INT_GET(leaf->hdr.count, ARCH_CONVERT))			ASSERT(INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <=			       INT_GET(leaf->ents[i + 1].hashval, ARCH_CONVERT));		if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)			stale++;	}	ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == stale);}#endif	/* DEBUG *//* * Compact out any stale entries in the leaf. * Log the header and changed leaf entries, if any. */voidxfs_dir2_leaf_compact(	xfs_da_args_t	*args,		/* operation arguments */	xfs_dabuf_t	*bp)		/* leaf buffer */{	int		from;		/* source leaf index */	xfs_dir2_leaf_t	*leaf;		/* leaf structure */	int		loglow;		/* first leaf entry to log */	int		to;		/* target leaf index */	leaf = bp->data;	if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) {		return;	}	/*	 * Compress out the stale entries in place.	 */	for (from = to = 0, loglow = -1; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) {		if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)			continue;		/*		 * Only actually copy the entries that are different.		 */		if (from > to) {			if (loglow == -1)				loglow = to;			leaf->ents[to] = leaf->ents[from];		}		to++;	}	/*	 * Update and log the header, log the leaf entries.	 */	ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == from - to);	INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(INT_GET(leaf->hdr.stale, ARCH_CONVERT)));	INT_ZERO(leaf->hdr.stale, ARCH_CONVERT);	xfs_dir2_leaf_log_header(args->trans, bp);	if (loglow != -1)		xfs_dir2_leaf_log_ents(args->trans, bp, loglow, to - 1);}/* * Compact the leaf entries, removing stale ones. * Leave one stale entry behind - the one closest to our * insertion index - and the caller will shift that one to our insertion * point later. * Return new insertion index, where the remaining stale entry is, * and leaf logging indices. */voidxfs_dir2_leaf_compact_x1(	xfs_dabuf_t	*bp,		/* leaf buffer */	int		*indexp,	/* insertion index */	int		*lowstalep,	/* out: stale entry before us */	int		*highstalep,	/* out: stale entry after us */	int		*lowlogp,	/* out: low log index */	int		*highlogp)	/* out: high log index */{	int		from;		/* source copy index */	int		highstale;	/* stale entry at/after index */	int		index;		/* insertion index */	int		keepstale;	/* source index of kept stale */	xfs_dir2_leaf_t	*leaf;		/* leaf structure */	int		lowstale;	/* stale entry before index */	int		newindex=0;	/* new insertion index */	int		to;		/* destination copy index */	leaf = bp->data;	ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1);	index = *indexp;	/*	 * Find the first stale entry before our index, if any.	 */	for (lowstale = index - 1;	     lowstale >= 0 &&		INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR;	     lowstale--)		continue;	/*	 * Find the first stale entry at or after our index, if any.	 * Stop if the answer would be worse than lowstale.	 */	for (highstale = index;	     highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) &&		INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR &&		(lowstale < 0 || index - lowstale > highstale - index);	     highstale++)		continue;	/*	 * Pick the better of lowstale and highstale.	 */	if (lowstale >= 0 &&	    (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) ||	     index - lowstale <= highstale - index))		keepstale = lowstale;	else		keepstale = highstale;	/*	 * Copy the entries in place, removing all the stale entries	 * except keepstale.	 */	for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) {		/*		 * Notice the new value of index.		 */		if (index == from)			newindex = to;		if (from != keepstale &&		    INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) {			if (from == to)				*lowlogp = to;			continue;		}		/*		 * Record the new keepstale value for the insertion.		 */		if (from == keepstale)			lowstale = highstale = to;		/*		 * Copy only the entries that have moved.		 */		if (from > to)			leaf->ents[to] = leaf->ents[from];		to++;	}	ASSERT(from > to);	/*	 * If the insertion point was past the last entry,	 * set the new insertion point accordingly.	 */	if (index == from)		newindex = to;	*indexp = newindex;	/*	 * Adjust the leaf header values.	 */	INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(from - to));	INT_SET(leaf->hdr.stale, ARCH_CONVERT, 1);	/*	 * Remember the low/high stale value only in the "right"	 * direction.	 */	if (lowstale >= newindex)		lowstale = -1;	else		highstale = INT_GET(leaf->hdr.count, ARCH_CONVERT);	*highlogp = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1;	*lowstalep = lowstale;	*highstalep = highstale;}/* * Getdents (readdir) for leaf and node directories. * This reads the data blocks only, so is the same for both forms. */int						/* error */xfs_dir2_leaf_getdents(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_inode_t		*dp,		/* incore directory inode */	uio_t			*uio,		/* I/O control & vectors */	int			*eofp,		/* out: reached end of dir */	xfs_dirent_t		*dbp,		/* caller's buffer */	xfs_dir2_put_t		put)		/* ABI formatting routine */{	xfs_dabuf_t		*bp;		/* data block buffer */	int			byteoff;	/* offset in current block */	xfs_dir2_db_t		curdb;		/* db for current block */	xfs_dir2_off_t		curoff;		/* current overall offset */	xfs_dir2_data_t		*data;		/* data block structure */	xfs_dir2_data_entry_t	*dep;		/* data entry */	xfs_dir2_data_unused_t	*dup;		/* unused entry */	int			eof;		/* reached end of directory */	int			error=0;		/* error return value */	int			i;		/* temporary loop index */	int			j;		/* temporary loop index */	int			length;		/* temporary length value */	xfs_bmbt_irec_t		*map;		/* map vector for blocks */	xfs_extlen_t		map_blocks;	/* number of fsbs in map */	xfs_dablk_t		map_off;	/* last mapped file offset */	int			map_size;	/* total entries in *map */	int			map_valid;	/* valid entries in *map */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_dir2_off_t		newoff;		/* new curoff after new blk */	int			nmap;		/* mappings to ask xfs_bmapi */	xfs_dir2_put_args_t	p;		/* formatting arg bundle */	char			*ptr=NULL;		/* pointer to current data */	int			ra_current;	/* number of read-ahead blks */	int			ra_index;	/* *map index for read-ahead */	int			ra_offset;	/* map entry offset for ra */	int			ra_want;	/* readahead count wanted */	/*	 * If the offset is at or past the largest allowed value,	 * give up right away, return eof.	 */	if (uio->uio_offset >= XFS_DIR2_MAX_DATAPTR) {		*eofp = 1;		return 0;	}	mp = dp->i_mount;	/*	 * Setup formatting arguments.	 */	p.dbp = dbp;	p.put = put;	p.uio = uio;	/*	 * Set up to bmap a number of blocks based on the caller's	 * buffer size, the directory block size, and the filesystem	 * block size.	 */	map_size =		howmany(uio->uio_resid + mp->m_dirblksize,			mp->m_sb.sb_blocksize);	map = kmem_alloc(map_size * sizeof(*map), KM_SLEEP);	map_valid = ra_index = ra_offset = ra_current = map_blocks = 0;	bp = NULL;	eof = 1;	/*	 * Inside the loop we keep the main offset value as a byte offset	 * in the directory file.	 */	curoff = XFS_DIR2_DATAPTR_TO_BYTE(mp, uio->uio_offset);	/*	 * Force this conversion through db so we truncate the offset	 * down to get the start of the data block.	 */	map_off = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, curoff));	/*	 * Loop over directory entries until we reach the end offset.	 * Get more blocks and readahead as necessary.	 */	while (curoff < XFS_DIR2_LEAF_OFFSET) {		/*		 * If we have no buffer, or we're off the end of the		 * current buffer, need to get another one.		 */		if (!bp || ptr >= (char *)bp->data + mp->m_dirblksize) {			/*			 * If we have a buffer, we need to release it and			 * take it out of the mapping.			 */			if (bp) {				xfs_da_brelse(tp, bp);				bp = NULL;				map_blocks -= mp->m_dirblkfsbs;				/*				 * Loop to get rid of the extents for the				 * directory block.				 */				for (i = mp->m_dirblkfsbs; i > 0; ) {					j = MIN((int)map->br_blockcount, i);					map->br_blockcount -= j;					map->br_startblock += j;					map->br_startoff += j;					/*					 * If mapping is done, pitch it from					 * the table.					 */					if (!map->br_blockcount && --map_valid)						memmove(&map[0], &map[1],							sizeof(map[0]) *							map_valid);					i -= j;				}			}			/*			 * Recalculate the readahead blocks wanted.			 */			ra_want = howmany(uio->uio_resid + mp->m_dirblksize,					  mp->m_sb.sb_blocksize) - 1;			/*			 * If we don't have as many as we want, and we haven't			 * run out of data blocks, get some more mappings.			 */			if (1 + ra_want > map_blocks &&			    map_off <			    XFS_DIR2_BYTE_TO_DA(mp, XFS_DIR2_LEAF_OFFSET)) {				/*				 * Get more bmaps, fill in after the ones				 * we already have in the table.				 */				nmap = map_size - map_valid;				error = xfs_bmapi(tp, dp,					map_off,					XFS_DIR2_BYTE_TO_DA(mp,						XFS_DIR2_LEAF_OFFSET) - map_off,					XFS_BMAPI_METADATA, NULL, 0,					&map[map_valid], &nmap, NULL);				/*				 * Don't know if we should ignore this or				 * try to return an error.				 * The trouble with returning errors				 * is that readdir will just stop without				 * actually passing the error through.				 */				if (error)					break;	/* XXX */				/*				 * If we got all the mappings we asked for,				 * set the final map offset based on the				 * last bmap value received.				 * Otherwise, we've reached the end.				 */				if (nmap == map_size - map_valid)					map_off =					map[map_valid + nmap - 1].br_startoff +					map[map_valid + nmap - 1].br_blockcount;				else					map_off =						XFS_DIR2_BYTE_TO_DA(mp,							XFS_DIR2_LEAF_OFFSET);				/*				 * Look for holes in the mapping, and				 * eliminate them.  Count up the valid blocks.				 */				for (i = map_valid; i < map_valid + nmap; ) {					if (map[i].br_startblock ==					    HOLESTARTBLOCK) {						nmap--;						length = map_valid + nmap - i;						if (length)							memmove(&map[i],								&map[i + 1],								sizeof(map[i]) *								length);					} else {						map_blocks +=							map[i].br_blockcount;						i++;					}				}				map_valid += nmap;			}

⌨️ 快捷键说明

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