⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfs_alloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 <=			be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length),		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;	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 &&		 (be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_flcount)		  > args->minleft)) {		error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0);		if (error)			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 <=				be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length),				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 {		fbno = NULLAGBLOCK;		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 */	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];		be32_add(&agf->agf_freeblks, len);		xfs_trans_agblocks_delta(tp, len);		pag->pagf_freeblks += len;		XFS_WANT_CORRUPTED_GOTO(			be32_to_cpu(agf->agf_freeblks) <=			be32_to_cpu(agf->agf_length),			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	 * used in xfs_bmap_finish, we can't allow block to be available	 * for reallocation and non-transaction writing (user data)	 * until we know that the transaction that moved it to the free	 * list is permanently on disk.  We track the blocks by declaring	 * these blocks as "busy"; the busy list is maintained on a per-ag	 * basis and each transaction records which entries should be removed	 * when the iclog commits to disk.  If a busy block is allocated,	 * the iclog is pushed up to the LSN that freed the block.	 */	xfs_alloc_mark_busy(tp, agno, bno, len);	return 0; error0:	TRACE_FREE("error", agno, bno, len, isfl);	if (bno_cur)		xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR);	if (cnt_cur)		xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR);	return error;}/* * Visible (exported) allocation/free functions. * Some of these are used just by xfs_alloc_btree.c and this file. *//* * Compute and fill in value of m_ag_maxlevels. */voidxfs_alloc_compute_maxlevels(	xfs_mount_t	*mp)	/* file system mount structure */{	int		level;	uint		maxblocks;	uint		maxleafents;	int		minleafrecs;	int		minnoderecs;	maxleafents = (mp->m_sb.sb_agblocks + 1) / 2;	minleafrecs = mp->m_alloc_mnr[0];	minnoderecs = mp->m_alloc_mnr[1];	maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;	for (level = 1; maxblocks > 1; level++)		maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs;	mp->m_ag_maxlevels = level;}/* * Decide whether to use this allocation group for this allocation. * If so, fix up the btree freelist's size. */STATIC int			/* error */xfs_alloc_fix_freelist(	xfs_alloc_arg_t	*args,	/* allocation argument structure */	int		flags)	/* XFS_ALLOC_FLAG_... */{	xfs_buf_t	*agbp;	/* agf buffer pointer */	xfs_agf_t	*agf;	/* a.g. freespace structure pointer */	xfs_buf_t	*agflbp;/* agfl buffer pointer */	xfs_agblock_t	bno;	/* freelist block */

⌨️ 快捷键说明

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