xfs_dir2_data.c

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

C
856
字号
	 */	error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, blkno), -1, &bp,		XFS_DATA_FORK);	if (error) {		return error;	}	ASSERT(bp != NULL);	/*	 * Initialize the header.	 */	d = bp->data;	INT_SET(d->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC);	INT_SET(d->hdr.bestfree[0].offset, ARCH_CONVERT, (xfs_dir2_data_off_t)sizeof(d->hdr));	for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {		INT_ZERO(d->hdr.bestfree[i].length, ARCH_CONVERT);		INT_ZERO(d->hdr.bestfree[i].offset, ARCH_CONVERT);	}	/*	 * Set up an unused entry for the block's body.	 */	dup = &d->u[0].unused;	INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);	t=mp->m_dirblksize - (uint)sizeof(d->hdr);	INT_SET(d->hdr.bestfree[0].length, ARCH_CONVERT, t);	INT_SET(dup->length, ARCH_CONVERT, t);	INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT,		(xfs_dir2_data_off_t)((char *)dup - (char *)d));	/*	 * Log it and return it.	 */	xfs_dir2_data_log_header(tp, bp);	xfs_dir2_data_log_unused(tp, bp, dup);	*bpp = bp;	return 0;}/* * Log an active data entry from the block. */voidxfs_dir2_data_log_entry(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp,		/* block buffer */	xfs_dir2_data_entry_t	*dep)		/* data entry pointer */{	xfs_dir2_data_t		*d;		/* data block pointer */	d = bp->data;	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);	xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)d),		(uint)((char *)(XFS_DIR2_DATA_ENTRY_TAG_P(dep) + 1) -		       (char *)d - 1));}/* * Log a data block header. */voidxfs_dir2_data_log_header(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp)		/* block buffer */{	xfs_dir2_data_t		*d;		/* data block pointer */	d = bp->data;	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);	xfs_da_log_buf(tp, bp, (uint)((char *)&d->hdr - (char *)d),		(uint)(sizeof(d->hdr) - 1));}/* * Log a data unused entry. */voidxfs_dir2_data_log_unused(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp,		/* block buffer */	xfs_dir2_data_unused_t	*dup)		/* data unused pointer */{	xfs_dir2_data_t		*d;		/* data block pointer */	d = bp->data;	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);	/*	 * Log the first part of the unused entry.	 */	xfs_da_log_buf(tp, bp, (uint)((char *)dup - (char *)d),		(uint)((char *)&dup->length + sizeof(dup->length) -		       1 - (char *)d));	/*	 * Log the end (tag) of the unused entry.	 */	xfs_da_log_buf(tp, bp,		(uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d),		(uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d +		       sizeof(xfs_dir2_data_off_t) - 1));}/* * Make a byte range in the data block unused. * Its current contents are unimportant. */voidxfs_dir2_data_make_free(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp,		/* block buffer */	xfs_dir2_data_aoff_t	offset,		/* starting byte offset */	xfs_dir2_data_aoff_t	len,		/* length in bytes */	int			*needlogp,	/* out: log header */	int			*needscanp)	/* out: regen bestfree */{	xfs_dir2_data_t		*d;		/* data block pointer */	xfs_dir2_data_free_t	*dfp;		/* bestfree pointer */	char			*endptr;	/* end of data area */	xfs_mount_t		*mp;		/* filesystem mount point */	int			needscan;	/* need to regen bestfree */	xfs_dir2_data_unused_t	*newdup;	/* new unused entry */	xfs_dir2_data_unused_t	*postdup;	/* unused entry after us */	xfs_dir2_data_unused_t	*prevdup;	/* unused entry before us */	mp = tp->t_mountp;	d = bp->data;	/*	 * Figure out where the end of the data area is.	 */	if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC)		endptr = (char *)d + mp->m_dirblksize;	else {		xfs_dir2_block_tail_t	*btp;	/* block tail */		ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);		btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);		endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);	}	/*	 * If this isn't the start of the block, then back up to	 * the previous entry and see if it's free.	 */	if (offset > sizeof(d->hdr)) {		xfs_dir2_data_off_t	*tagp;	/* tag just before us */		tagp = (xfs_dir2_data_off_t *)((char *)d + offset) - 1;		prevdup = (xfs_dir2_data_unused_t *)((char *)d + INT_GET(*tagp, ARCH_CONVERT));		if (INT_GET(prevdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG)			prevdup = NULL;	} else		prevdup = NULL;	/*	 * If this isn't the end of the block, see if the entry after	 * us is free.	 */	if ((char *)d + offset + len < endptr) {		postdup =			(xfs_dir2_data_unused_t *)((char *)d + offset + len);		if (INT_GET(postdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG)			postdup = NULL;	} else		postdup = NULL;	ASSERT(*needscanp == 0);	needscan = 0;	/*	 * Previous and following entries are both free,	 * merge everything into a single free entry.	 */	if (prevdup && postdup) {		xfs_dir2_data_free_t	*dfp2;	/* another bestfree pointer */		/*		 * See if prevdup and/or postdup are in bestfree table.		 */		dfp = xfs_dir2_data_freefind(d, prevdup);		dfp2 = xfs_dir2_data_freefind(d, postdup);		/*		 * We need a rescan unless there are exactly 2 free entries		 * namely our two.  Then we know what's happening, otherwise		 * since the third bestfree is there, there might be more		 * entries.		 */		needscan = !INT_ISZERO(d->hdr.bestfree[2].length, ARCH_CONVERT);		/*		 * Fix up the new big freespace.		 */		INT_MOD(prevdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT));		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT,			(xfs_dir2_data_off_t)((char *)prevdup - (char *)d));		xfs_dir2_data_log_unused(tp, bp, prevdup);		if (!needscan) {			/*			 * Has to be the case that entries 0 and 1 are			 * dfp and dfp2 (don't know which is which), and			 * entry 2 is empty.			 * Remove entry 1 first then entry 0.			 */			ASSERT(dfp && dfp2);			if (dfp == &d->hdr.bestfree[1]) {				dfp = &d->hdr.bestfree[0];				ASSERT(dfp2 == dfp);				dfp2 = &d->hdr.bestfree[1];			}			xfs_dir2_data_freeremove(d, dfp2, needlogp);			xfs_dir2_data_freeremove(d, dfp, needlogp);			/*			 * Now insert the new entry.			 */			dfp = xfs_dir2_data_freeinsert(d, prevdup, needlogp);			ASSERT(dfp == &d->hdr.bestfree[0]);			ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(prevdup->length, ARCH_CONVERT));			ASSERT(INT_ISZERO(dfp[1].length, ARCH_CONVERT));			ASSERT(INT_ISZERO(dfp[2].length, ARCH_CONVERT));		}	}	/*	 * The entry before us is free, merge with it.	 */	else if (prevdup) {		dfp = xfs_dir2_data_freefind(d, prevdup);		INT_MOD(prevdup->length, ARCH_CONVERT, len);		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT,			(xfs_dir2_data_off_t)((char *)prevdup - (char *)d));		xfs_dir2_data_log_unused(tp, bp, prevdup);		/*		 * If the previous entry was in the table, the new entry		 * is longer, so it will be in the table too.  Remove		 * the old one and add the new one.		 */		if (dfp) {			xfs_dir2_data_freeremove(d, dfp, needlogp);			(void)xfs_dir2_data_freeinsert(d, prevdup, needlogp);		}		/*		 * Otherwise we need a scan if the new entry is big enough.		 */		else			needscan = INT_GET(prevdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT);	}	/*	 * The following entry is free, merge with it.	 */	else if (postdup) {		dfp = xfs_dir2_data_freefind(d, postdup);		newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);		INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);		INT_SET(newdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT));		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));		xfs_dir2_data_log_unused(tp, bp, newdup);		/*		 * If the following entry was in the table, the new entry		 * is longer, so it will be in the table too.  Remove		 * the old one and add the new one.		 */		if (dfp) {			xfs_dir2_data_freeremove(d, dfp, needlogp);			(void)xfs_dir2_data_freeinsert(d, newdup, needlogp);		}		/*		 * Otherwise we need a scan if the new entry is big enough.		 */		else			needscan = INT_GET(newdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT);	}	/*	 * Neither neighbor is free.  Make a new entry.	 */	else {		newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);		INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);		INT_SET(newdup->length, ARCH_CONVERT, len);		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));		xfs_dir2_data_log_unused(tp, bp, newdup);		(void)xfs_dir2_data_freeinsert(d, newdup, needlogp);	}	*needscanp = needscan;}/* * Take a byte range out of an existing unused space and make it un-free. */voidxfs_dir2_data_use_free(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_dabuf_t		*bp,		/* data block buffer */	xfs_dir2_data_unused_t	*dup,		/* unused entry */	xfs_dir2_data_aoff_t	offset,		/* starting offset to use */	xfs_dir2_data_aoff_t	len,		/* length to use */	int			*needlogp,	/* out: need to log header */	int			*needscanp)	/* out: need regen bestfree */{	xfs_dir2_data_t		*d;		/* data block */	xfs_dir2_data_free_t	*dfp;		/* bestfree pointer */	int			matchback;	/* matches end of freespace */	int			matchfront;	/* matches start of freespace */	int			needscan;	/* need to regen bestfree */	xfs_dir2_data_unused_t	*newdup;	/* new unused entry */	xfs_dir2_data_unused_t	*newdup2;	/* another new unused entry */	int			oldlen;		/* old unused entry's length */	d = bp->data;	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);	ASSERT(INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG);	ASSERT(offset >= (char *)dup - (char *)d);	ASSERT(offset + len <= (char *)dup + INT_GET(dup->length, ARCH_CONVERT) - (char *)d);	ASSERT((char *)dup - (char *)d == INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT));	/*	 * Look up the entry in the bestfree table.	 */	dfp = xfs_dir2_data_freefind(d, dup);	oldlen = INT_GET(dup->length, ARCH_CONVERT);	ASSERT(dfp || oldlen <= INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT));	/*	 * Check for alignment with front and back of the entry.	 */	matchfront = (char *)dup - (char *)d == offset;	matchback = (char *)dup + oldlen - (char *)d == offset + len;	ASSERT(*needscanp == 0);	needscan = 0;	/*	 * If we matched it exactly we just need to get rid of it from	 * the bestfree table.	 */	if (matchfront && matchback) {		if (dfp) {			needscan = !INT_ISZERO(d->hdr.bestfree[2].offset, ARCH_CONVERT);			if (!needscan)				xfs_dir2_data_freeremove(d, dfp, needlogp);		}	}	/*	 * We match the first part of the entry.	 * Make a new entry with the remaining freespace.	 */	else if (matchfront) {		newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len);		INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);		INT_SET(newdup->length, ARCH_CONVERT, oldlen - len);		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));		xfs_dir2_data_log_unused(tp, bp, newdup);		/*		 * If it was in the table, remove it and add the new one.		 */		if (dfp) {			xfs_dir2_data_freeremove(d, dfp, needlogp);			dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp);			ASSERT(dfp != NULL);			ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT));			ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d);			/*			 * If we got inserted at the last slot,			 * that means we don't know if there was a better			 * choice for the last slot, or not.  Rescan.			 */			needscan = dfp == &d->hdr.bestfree[2];		}	}	/*	 * We match the last part of the entry.	 * Trim the allocated space off the tail of the entry.	 */	else if (matchback) {		newdup = dup;		INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t)			(((char *)d + offset) - (char *)newdup));		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));		xfs_dir2_data_log_unused(tp, bp, newdup);		/*		 * If it was in the table, remove it and add the new one.		 */		if (dfp) {			xfs_dir2_data_freeremove(d, dfp, needlogp);			dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp);			ASSERT(dfp != NULL);			ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT));			ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d);			/*			 * If we got inserted at the last slot,			 * that means we don't know if there was a better			 * choice for the last slot, or not.  Rescan.			 */			needscan = dfp == &d->hdr.bestfree[2];		}	}	/*	 * Poking out the middle of an entry.	 * Make two new entries.	 */	else {		newdup = dup;		INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t)			(((char *)d + offset) - (char *)newdup));		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT,			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));		xfs_dir2_data_log_unused(tp, bp, newdup);		newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len);		INT_SET(newdup2->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);		INT_SET(newdup2->length, ARCH_CONVERT, oldlen - len - INT_GET(newdup->length, ARCH_CONVERT));		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup2, ARCH_CONVERT), ARCH_CONVERT,			(xfs_dir2_data_off_t)((char *)newdup2 - (char *)d));		xfs_dir2_data_log_unused(tp, bp, newdup2);		/*		 * If the old entry was in the table, we need to scan		 * if the 3rd entry was valid, since these entries		 * are smaller than the old one.		 * If we don't need to scan that means there were 1 or 2		 * entries in the table, and removing the old and adding		 * the 2 new will work.		 */		if (dfp) {			needscan = !INT_ISZERO(d->hdr.bestfree[2].length, ARCH_CONVERT);			if (!needscan) {				xfs_dir2_data_freeremove(d, dfp, needlogp);				(void)xfs_dir2_data_freeinsert(d, newdup,					needlogp);				(void)xfs_dir2_data_freeinsert(d, newdup2,					needlogp);			}		}	}	*needscanp = needscan;}

⌨️ 快捷键说明

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