xfs_alloc.c

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

C
2,225
字号
	 * In the first case above, we got the last entry in the	 * by-size btree.  Now we check to see if the space hits maxlen	 * once aligned; if not, we search left for something better.	 * This can't happen in the second case above.	 */	xfs_alloc_compute_aligned(fbno, flen, args->alignment, args->minlen,		&rbno, &rlen);	rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);	XFS_WANT_CORRUPTED_GOTO(rlen == 0 ||			(rlen <= flen && rbno + rlen <= fbno + flen), error0);	if (rlen < args->maxlen) {		xfs_agblock_t	bestfbno;		xfs_extlen_t	bestflen;		xfs_agblock_t	bestrbno;		xfs_extlen_t	bestrlen;		bestrlen = rlen;		bestrbno = rbno;		bestflen = flen;		bestfbno = fbno;		for (;;) {			if ((error = xfs_alloc_decrement(cnt_cur, 0, &i)))				goto error0;			if (i == 0)				break;			if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen,					&i)))				goto error0;			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);			if (flen < bestrlen)				break;			xfs_alloc_compute_aligned(fbno, flen, args->alignment,				args->minlen, &rbno, &rlen);			rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);			XFS_WANT_CORRUPTED_GOTO(rlen == 0 ||				(rlen <= flen && rbno + rlen <= fbno + flen),				error0);			if (rlen > bestrlen) {				bestrlen = rlen;				bestrbno = rbno;				bestflen = flen;				bestfbno = fbno;				if (rlen == args->maxlen)					break;			}		}		if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen,				&i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		rlen = bestrlen;		rbno = bestrbno;		flen = bestflen;		fbno = bestfbno;	}	args->wasfromfl = 0;	/*	 * Fix up the length.	 */	args->len = rlen;	xfs_alloc_fix_len(args);	if (rlen < args->minlen || !xfs_alloc_fix_minleft(args)) {		xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);		TRACE_ALLOC("nominleft", args);		args->agbno = NULLAGBLOCK;		return 0;	}	rlen = args->len;	XFS_WANT_CORRUPTED_GOTO(rlen <= flen, error0);	/*	 * Allocate and initialize a cursor for the by-block tree.	 */	bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,		args->agno, XFS_BTNUM_BNO, NULL, 0);	if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,			rbno, rlen, XFSA_FIXUP_CNT_OK)))		goto error0;	xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);	xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR);	cnt_cur = bno_cur = NULL;	args->len = rlen;	args->agbno = rbno;	XFS_WANT_CORRUPTED_GOTO(		args->agbno + args->len <=			INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length,			ARCH_CONVERT),		error0);	TRACE_ALLOC("normal", args);	return 0;error0:	TRACE_ALLOC("error", args);	if (cnt_cur)		xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR);	if (bno_cur)		xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR);	return error;}/* * Deal with the case where only small freespaces remain. * Either return the contents of the last freespace record, * or allocate space from the freelist if there is nothing in the tree. */STATIC int			/* error */xfs_alloc_ag_vextent_small(	xfs_alloc_arg_t	*args,	/* allocation argument structure */	xfs_btree_cur_t	*ccur,	/* by-size cursor */	xfs_agblock_t	*fbnop,	/* result block number */	xfs_extlen_t	*flenp,	/* result length */	int		*stat)	/* status: 0-freelist, 1-normal/none */{	int		error;	xfs_agblock_t	fbno;	xfs_extlen_t	flen;#ifdef XFS_ALLOC_TRACE	static char	fname[] = "xfs_alloc_ag_vextent_small";#endif	int		i;	if ((error = xfs_alloc_decrement(ccur, 0, &i)))		goto error0;	if (i) {		if ((error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);	}	/*	 * Nothing in the btree, try the freelist.  Make sure	 * to respect minleft even when pulling from the	 * freelist.	 */	else if (args->minlen == 1 && args->alignment == 1 && !args->isfl &&		 (INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_flcount,			ARCH_CONVERT) > args->minleft)) {		if ((error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno)))			goto error0;		if (fbno != NULLAGBLOCK) {			if (args->userdata) {				xfs_buf_t	*bp;				bp = xfs_btree_get_bufs(args->mp, args->tp,					args->agno, fbno, 0);				xfs_trans_binval(args->tp, bp);			}			args->len = 1;			args->agbno = fbno;			XFS_WANT_CORRUPTED_GOTO(				args->agbno + args->len <=				INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length,					ARCH_CONVERT),				error0);			args->wasfromfl = 1;			TRACE_ALLOC("freelist", args);			*stat = 0;			return 0;		}		/*		 * Nothing in the freelist.		 */		else			flen = 0;	}	/*	 * Can't allocate from the freelist for some reason.	 */	else		flen = 0;	/*	 * Can't do the allocation, give up.	 */	if (flen < args->minlen) {		args->agbno = NULLAGBLOCK;		TRACE_ALLOC("notenough", args);		flen = 0;	}	*fbnop = fbno;	*flenp = flen;	*stat = 1;	TRACE_ALLOC("normal", args);	return 0;error0:	TRACE_ALLOC("error", args);	return error;}/* * Free the extent starting at agno/bno for length. */STATIC int			/* error */xfs_free_ag_extent(	xfs_trans_t	*tp,	/* transaction pointer */	xfs_buf_t	*agbp,	/* buffer for a.g. freelist header */	xfs_agnumber_t	agno,	/* allocation group number */	xfs_agblock_t	bno,	/* starting block number */	xfs_extlen_t	len,	/* length of extent */	int		isfl)	/* set if is freelist blocks - no sb acctg */{	xfs_btree_cur_t	*bno_cur;	/* cursor for by-block btree */	xfs_btree_cur_t	*cnt_cur;	/* cursor for by-size btree */	int		error;		/* error return value */#ifdef XFS_ALLOC_TRACE	static char	fname[] = "xfs_free_ag_extent";#endif	xfs_agblock_t	gtbno;		/* start of right neighbor block */	xfs_extlen_t	gtlen;		/* length of right neighbor block */	int		haveleft;	/* have a left neighbor block */	int		haveright;	/* have a right neighbor block */	int		i;		/* temp, result code */	xfs_agblock_t	ltbno;		/* start of left neighbor block */	xfs_extlen_t	ltlen;		/* length of left neighbor block */	xfs_mount_t	*mp;		/* mount point struct for filesystem */	xfs_agblock_t	nbno;		/* new starting block of freespace */	xfs_extlen_t	nlen;		/* new length of freespace */	mp = tp->t_mountp;	/*	 * Allocate and initialize a cursor for the by-block btree.	 */	bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, NULL,		0);	cnt_cur = NULL;	/*	 * Look for a neighboring block on the left (lower block numbers)	 * that is contiguous with this space.	 */	if ((error = xfs_alloc_lookup_le(bno_cur, bno, len, &haveleft)))		goto error0;	if (haveleft) {		/*		 * There is a block to our left.		 */		if ((error = xfs_alloc_get_rec(bno_cur, &ltbno, &ltlen, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		/*		 * It's not contiguous, though.		 */		if (ltbno + ltlen < bno)			haveleft = 0;		else {			/*			 * If this failure happens the request to free this			 * space was invalid, it's (partly) already free.			 * Very bad.			 */			XFS_WANT_CORRUPTED_GOTO(ltbno + ltlen <= bno, error0);		}	}	/*	 * Look for a neighboring block on the right (higher block numbers)	 * that is contiguous with this space.	 */	if ((error = xfs_alloc_increment(bno_cur, 0, &haveright)))		goto error0;	if (haveright) {		/*		 * There is a block to our right.		 */		if ((error = xfs_alloc_get_rec(bno_cur, &gtbno, &gtlen, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		/*		 * It's not contiguous, though.		 */		if (bno + len < gtbno)			haveright = 0;		else {			/*			 * If this failure happens the request to free this			 * space was invalid, it's (partly) already free.			 * Very bad.			 */			XFS_WANT_CORRUPTED_GOTO(gtbno >= bno + len, error0);		}	}	/*	 * Now allocate and initialize a cursor for the by-size tree.	 */	cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, NULL,		0);	/*	 * Have both left and right contiguous neighbors.	 * Merge all three into a single free block.	 */	if (haveleft && haveright) {		/*		 * Delete the old by-size entry on the left.		 */		if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		if ((error = xfs_alloc_delete(cnt_cur, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		/*		 * Delete the old by-size entry on the right.		 */		if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		if ((error = xfs_alloc_delete(cnt_cur, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		/*		 * Delete the old by-block entry for the right block.		 */		if ((error = xfs_alloc_delete(bno_cur, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		/*		 * Move the by-block cursor back to the left neighbor.		 */		if ((error = xfs_alloc_decrement(bno_cur, 0, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);#ifdef DEBUG		/*		 * Check that this is the right record: delete didn't		 * mangle the cursor.		 */		{			xfs_agblock_t	xxbno;			xfs_extlen_t	xxlen;			if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen,					&i)))				goto error0;			XFS_WANT_CORRUPTED_GOTO(				i == 1 && xxbno == ltbno && xxlen == ltlen,				error0);		}#endif		/*		 * Update remaining by-block entry to the new, joined block.		 */		nbno = ltbno;		nlen = len + ltlen + gtlen;		if ((error = xfs_alloc_update(bno_cur, nbno, nlen)))			goto error0;	}	/*	 * Have only a left contiguous neighbor.	 * Merge it together with the new freespace.	 */	else if (haveleft) {		/*		 * Delete the old by-size entry on the left.		 */		if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		if ((error = xfs_alloc_delete(cnt_cur, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		/*		 * Back up the by-block cursor to the left neighbor, and		 * update its length.		 */		if ((error = xfs_alloc_decrement(bno_cur, 0, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		nbno = ltbno;		nlen = len + ltlen;		if ((error = xfs_alloc_update(bno_cur, nbno, nlen)))			goto error0;	}	/*	 * Have only a right contiguous neighbor.	 * Merge it together with the new freespace.	 */	else if (haveright) {		/*		 * Delete the old by-size entry on the right.		 */		if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		if ((error = xfs_alloc_delete(cnt_cur, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		/*		 * Update the starting block and length of the right		 * neighbor in the by-block tree.		 */		nbno = bno;		nlen = len + gtlen;		if ((error = xfs_alloc_update(bno_cur, nbno, nlen)))			goto error0;	}	/*	 * No contiguous neighbors.	 * Insert the new freespace into the by-block tree.	 */	else {		nbno = bno;		nlen = len;		if ((error = xfs_alloc_insert(bno_cur, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);	}	xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR);	bno_cur = NULL;	/*	 * In all cases we need to insert the new freespace in the by-size tree.	 */	if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i)))		goto error0;	XFS_WANT_CORRUPTED_GOTO(i == 0, error0);	if ((error = xfs_alloc_insert(cnt_cur, &i)))		goto error0;	XFS_WANT_CORRUPTED_GOTO(i == 1, error0);	xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);	cnt_cur = NULL;	/*	 * Update the freespace totals in the ag and superblock.	 */	{		xfs_agf_t	*agf;		xfs_perag_t	*pag;		/* per allocation group data */		agf = XFS_BUF_TO_AGF(agbp);		pag = &mp->m_perag[agno];		INT_MOD(agf->agf_freeblks, ARCH_CONVERT, len);		xfs_trans_agblocks_delta(tp, len);		pag->pagf_freeblks += len;		XFS_WANT_CORRUPTED_GOTO(			INT_GET(agf->agf_freeblks, ARCH_CONVERT)				<= INT_GET(agf->agf_length, ARCH_CONVERT),			error0);		TRACE_MODAGF(NULL, agf, XFS_AGF_FREEBLKS);		xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS);		if (!isfl)			xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len);		XFS_STATS_INC(xs_freex);		XFS_STATS_ADD(xs_freeb, len);	}	TRACE_FREE(haveleft ?			(haveright ? "both" : "left") :			(haveright ? "right" : "none"),		agno, bno, len, isfl);	/*	 * Since blocks move to the free list without the coordination

⌨️ 快捷键说明

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