xfs_alloc.c

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

C
2,225
字号
			break;		/*		 * Point at the best entry, and retrieve it again.		 */		cnt_cur->bc_ptrs[0] = besti;		if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno, &ltlen, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		ltend = ltbno + ltlen;		ASSERT(ltend <= INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length,				ARCH_CONVERT));		args->len = blen;		if (!xfs_alloc_fix_minleft(args)) {			xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);			TRACE_ALLOC("nominleft", args);			return 0;		}		blen = args->len;		/*		 * We are allocating starting at bnew for blen blocks.		 */		args->agbno = bnew;		ASSERT(bnew >= ltbno);		ASSERT(bnew + blen <= ltend);		/*		 * Set up a cursor for the by-bno tree.		 */		bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp,			args->agbp, args->agno, XFS_BTNUM_BNO, NULL, 0);		/*		 * Fix up the btree entries.		 */		if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno,				ltlen, bnew, blen, XFSA_FIXUP_CNT_OK)))			goto error0;		xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);		xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR);		TRACE_ALLOC("first", args);		return 0;	}	/*	 * Second algorithm.	 * Search in the by-bno tree to the left and to the right	 * simultaneously, until in each case we find a space big enough,	 * or run into the edge of the tree.  When we run into the edge,	 * we deallocate that cursor.	 * If both searches succeed, we compare the two spaces and pick	 * the better one.	 * With alignment, it's possible for both to fail; the upper	 * level algorithm that picks allocation groups for allocations	 * is not supposed to do this.	 */	/*	 * Allocate and initialize the cursor for the leftward search.	 */	bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,		args->agno, XFS_BTNUM_BNO, NULL, 0);	/*	 * Lookup <= bno to find the leftward search's starting point.	 */	if ((error = xfs_alloc_lookup_le(bno_cur_lt, args->agbno, args->maxlen, &i)))		goto error0;	if (!i) {		/*		 * Didn't find anything; use this cursor for the rightward		 * search.		 */		bno_cur_gt = bno_cur_lt;		bno_cur_lt = NULL;	}	/*	 * Found something.  Duplicate the cursor for the rightward search.	 */	else if ((error = xfs_btree_dup_cursor(bno_cur_lt, &bno_cur_gt)))		goto error0;	/*	 * Increment the cursor, so we will point at the entry just right	 * of the leftward entry if any, or to the leftmost entry.	 */	if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i)))		goto error0;	if (!i) {		/*		 * It failed, there are no rightward entries.		 */		xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR);		bno_cur_gt = NULL;	}	/*	 * Loop going left with the leftward cursor, right with the	 * rightward cursor, until either both directions give up or	 * we find an entry at least as big as minlen.	 */	do {		if (bno_cur_lt) {			if ((error = xfs_alloc_get_rec(bno_cur_lt, &ltbno, &ltlen, &i)))				goto error0;			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);			if (xfs_alloc_compute_aligned(ltbno, ltlen,					args->alignment, args->minlen,					&ltbnoa, &ltlena))				break;			if ((error = xfs_alloc_decrement(bno_cur_lt, 0, &i)))				goto error0;			if (!i) {				xfs_btree_del_cursor(bno_cur_lt,						     XFS_BTREE_NOERROR);				bno_cur_lt = NULL;			}		}		if (bno_cur_gt) {			if ((error = xfs_alloc_get_rec(bno_cur_gt, &gtbno, &gtlen, &i)))				goto error0;			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);			if (xfs_alloc_compute_aligned(gtbno, gtlen,					args->alignment, args->minlen,					&gtbnoa, &gtlena))				break;			if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i)))				goto error0;			if (!i) {				xfs_btree_del_cursor(bno_cur_gt,						     XFS_BTREE_NOERROR);				bno_cur_gt = NULL;			}		}	} while (bno_cur_lt || bno_cur_gt);	/*	 * Got both cursors still active, need to find better entry.	 */	if (bno_cur_lt && bno_cur_gt) {		/*		 * Left side is long enough, look for a right side entry.		 */		if (ltlena >= args->minlen) {			/*			 * Fix up the length.			 */			args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);			xfs_alloc_fix_len(args);			rlen = args->len;			ltdiff = xfs_alloc_compute_diff(args->agbno, rlen,				args->alignment, ltbno, ltlen, &ltnew);			/*			 * Not perfect.			 */			if (ltdiff) {				/*				 * Look until we find a better one, run out of				 * space, or run off the end.				 */				while (bno_cur_lt && bno_cur_gt) {					if ((error = xfs_alloc_get_rec(							bno_cur_gt, &gtbno,							&gtlen, &i)))						goto error0;					XFS_WANT_CORRUPTED_GOTO(i == 1, error0);					xfs_alloc_compute_aligned(gtbno, gtlen,						args->alignment, args->minlen,						&gtbnoa, &gtlena);					/*					 * The left one is clearly better.					 */					if (gtbnoa >= args->agbno + ltdiff) {						xfs_btree_del_cursor(							bno_cur_gt,							XFS_BTREE_NOERROR);						bno_cur_gt = NULL;						break;					}					/*					 * If we reach a big enough entry,					 * compare the two and pick the best.					 */					if (gtlena >= args->minlen) {						args->len =							XFS_EXTLEN_MIN(gtlena,								args->maxlen);						xfs_alloc_fix_len(args);						rlen = args->len;						gtdiff = xfs_alloc_compute_diff(							args->agbno, rlen,							args->alignment,							gtbno, gtlen, &gtnew);						/*						 * Right side is better.						 */						if (gtdiff < ltdiff) {							xfs_btree_del_cursor(								bno_cur_lt,								XFS_BTREE_NOERROR);							bno_cur_lt = NULL;						}						/*						 * Left side is better.						 */						else {							xfs_btree_del_cursor(								bno_cur_gt,								XFS_BTREE_NOERROR);							bno_cur_gt = NULL;						}						break;					}					/*					 * Fell off the right end.					 */					if ((error = xfs_alloc_increment(							bno_cur_gt, 0, &i)))						goto error0;					if (!i) {						xfs_btree_del_cursor(							bno_cur_gt,							XFS_BTREE_NOERROR);						bno_cur_gt = NULL;						break;					}				}			}			/*			 * The left side is perfect, trash the right side.			 */			else {				xfs_btree_del_cursor(bno_cur_gt,						     XFS_BTREE_NOERROR);				bno_cur_gt = NULL;			}		}		/*		 * It's the right side that was found first, look left.		 */		else {			/*			 * Fix up the length.			 */			args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen);			xfs_alloc_fix_len(args);			rlen = args->len;			gtdiff = xfs_alloc_compute_diff(args->agbno, rlen,				args->alignment, gtbno, gtlen, &gtnew);			/*			 * Right side entry isn't perfect.			 */			if (gtdiff) {				/*				 * Look until we find a better one, run out of				 * space, or run off the end.				 */				while (bno_cur_lt && bno_cur_gt) {					if ((error = xfs_alloc_get_rec(							bno_cur_lt, &ltbno,							&ltlen, &i)))						goto error0;					XFS_WANT_CORRUPTED_GOTO(i == 1, error0);					xfs_alloc_compute_aligned(ltbno, ltlen,						args->alignment, args->minlen,						&ltbnoa, &ltlena);					/*					 * The right one is clearly better.					 */					if (ltbnoa <= args->agbno - gtdiff) {						xfs_btree_del_cursor(							bno_cur_lt,							XFS_BTREE_NOERROR);						bno_cur_lt = NULL;						break;					}					/*					 * If we reach a big enough entry,					 * compare the two and pick the best.					 */					if (ltlena >= args->minlen) {						args->len = XFS_EXTLEN_MIN(							ltlena, args->maxlen);						xfs_alloc_fix_len(args);						rlen = args->len;						ltdiff = xfs_alloc_compute_diff(							args->agbno, rlen,							args->alignment,							ltbno, ltlen, &ltnew);						/*						 * Left side is better.						 */						if (ltdiff < gtdiff) {							xfs_btree_del_cursor(								bno_cur_gt,								XFS_BTREE_NOERROR);							bno_cur_gt = NULL;						}						/*						 * Right side is better.						 */						else {							xfs_btree_del_cursor(								bno_cur_lt,								XFS_BTREE_NOERROR);							bno_cur_lt = NULL;						}						break;					}					/*					 * Fell off the left end.					 */					if ((error = xfs_alloc_decrement(							bno_cur_lt, 0, &i)))						goto error0;					if (!i) {						xfs_btree_del_cursor(bno_cur_lt,							XFS_BTREE_NOERROR);						bno_cur_lt = NULL;						break;					}				}			}			/*			 * The right side is perfect, trash the left side.			 */			else {				xfs_btree_del_cursor(bno_cur_lt,					XFS_BTREE_NOERROR);				bno_cur_lt = NULL;			}		}	}	/*	 * If we couldn't get anything, give up.	 */	if (bno_cur_lt == NULL && bno_cur_gt == NULL) {		TRACE_ALLOC("neither", args);		args->agbno = NULLAGBLOCK;		return 0;	}	/*	 * At this point we have selected a freespace entry, either to the	 * left or to the right.  If it's on the right, copy all the	 * useful variables to the "left" set so we only have one	 * copy of this code.	 */	if (bno_cur_gt) {		bno_cur_lt = bno_cur_gt;		bno_cur_gt = NULL;		ltbno = gtbno;		ltbnoa = gtbnoa;		ltlen = gtlen;		ltlena = gtlena;		j = 1;	} else		j = 0;	/*	 * Fix up the length and compute the useful address.	 */	ltend = ltbno + ltlen;	args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);	xfs_alloc_fix_len(args);	if (!xfs_alloc_fix_minleft(args)) {		TRACE_ALLOC("nominleft", args);		xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR);		xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);		return 0;	}	rlen = args->len;	(void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, ltbno,		ltlen, &ltnew);	ASSERT(ltnew >= ltbno);	ASSERT(ltnew + rlen <= ltend);	ASSERT(ltnew + rlen <= INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length,		ARCH_CONVERT));	args->agbno = ltnew;	if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen,			ltnew, rlen, XFSA_FIXUP_BNO_OK)))		goto error0;	TRACE_ALLOC(j ? "gt" : "lt", args);	xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);	xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR);	return 0; error0:	TRACE_ALLOC("error", args);	if (cnt_cur != NULL)		xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR);	if (bno_cur_lt != NULL)		xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_ERROR);	if (bno_cur_gt != NULL)		xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_ERROR);	return error;}/* * Allocate a variable extent anywhere in the allocation group agno. * Extent's length (returned in len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. */STATIC int				/* error */xfs_alloc_ag_vextent_size(	xfs_alloc_arg_t	*args)		/* allocation argument structure */{	xfs_btree_cur_t	*bno_cur;	/* cursor for bno btree */	xfs_btree_cur_t	*cnt_cur;	/* cursor for cnt btree */	int		error;		/* error result */	xfs_agblock_t	fbno;		/* start of found freespace */	xfs_extlen_t	flen;		/* length of found freespace */#ifdef XFS_ALLOC_TRACE	static char	fname[] = "xfs_alloc_ag_vextent_size";#endif	int		i;		/* temp status variable */	xfs_agblock_t	rbno;		/* returned block number */	xfs_extlen_t	rlen;		/* length of returned extent */	/*	 * Allocate and initialize a cursor for the by-size btree.	 */	cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,		args->agno, XFS_BTNUM_CNT, NULL, 0);	bno_cur = NULL;	/*	 * Look for an entry >= maxlen+alignment-1 blocks.	 */	if ((error = xfs_alloc_lookup_ge(cnt_cur, 0,			args->maxlen + args->alignment - 1, &i)))		goto error0;	/*	 * If none, then pick up the last entry in the tree unless the	 * tree is empty.	 */	if (!i) {		if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, &fbno,				&flen, &i)))			goto error0;		if (i == 0 || flen == 0) {			xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);			TRACE_ALLOC("noentry", args);			return 0;		}		ASSERT(i == 1);	}	/*	 * There's a freespace as big as maxlen+alignment-1, get it.	 */	else {		if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);	}	/*

⌨️ 快捷键说明

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