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

📄 xfs_alloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	xfs_extlen_t	delta;	/* new blocks needed in freelist */	int		error;	/* error result code */	xfs_extlen_t	longest;/* longest extent in allocation group */	xfs_mount_t	*mp;	/* file system mount point structure */	xfs_extlen_t	need;	/* total blocks needed in freelist */	xfs_perag_t	*pag;	/* per-ag information structure */	xfs_alloc_arg_t	targs;	/* local allocation arguments */	xfs_trans_t	*tp;	/* transaction pointer */	mp = args->mp;	pag = args->pag;	tp = args->tp;	if (!pag->pagf_init) {		if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags,				&agbp)))			return error;		if (!pag->pagf_init) {			ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK);			ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));			args->agbp = NULL;			return 0;		}	} else		agbp = NULL;	/*	 * If this is a metadata preferred pag and we are user data	 * then try somewhere else if we are not being asked to	 * try harder at this point	 */	if (pag->pagf_metadata && args->userdata &&	    (flags & XFS_ALLOC_FLAG_TRYLOCK)) {		ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));		args->agbp = NULL;		return 0;	}	if (!(flags & XFS_ALLOC_FLAG_FREEING)) {		need = XFS_MIN_FREELIST_PAG(pag, mp);		delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0;		/*		 * If it looks like there isn't a long enough extent, or enough		 * total blocks, reject it.		 */		longest = (pag->pagf_longest > delta) ?			(pag->pagf_longest - delta) :			(pag->pagf_flcount > 0 || pag->pagf_longest > 0);		if ((args->minlen + args->alignment + args->minalignslop - 1) >				longest ||		    ((int)(pag->pagf_freeblks + pag->pagf_flcount -			   need - args->total) < (int)args->minleft)) {			if (agbp)				xfs_trans_brelse(tp, agbp);			args->agbp = NULL;			return 0;		}	}	/*	 * Get the a.g. freespace buffer.	 * Can fail if we're not blocking on locks, and it's held.	 */	if (agbp == NULL) {		if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags,				&agbp)))			return error;		if (agbp == NULL) {			ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK);			ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));			args->agbp = NULL;			return 0;		}	}	/*	 * Figure out how many blocks we should have in the freelist.	 */	agf = XFS_BUF_TO_AGF(agbp);	need = XFS_MIN_FREELIST(agf, mp);	/*	 * If there isn't enough total or single-extent, reject it.	 */	if (!(flags & XFS_ALLOC_FLAG_FREEING)) {		delta = need > be32_to_cpu(agf->agf_flcount) ?			(need - be32_to_cpu(agf->agf_flcount)) : 0;		longest = be32_to_cpu(agf->agf_longest);		longest = (longest > delta) ? (longest - delta) :			(be32_to_cpu(agf->agf_flcount) > 0 || longest > 0);		if ((args->minlen + args->alignment + args->minalignslop - 1) >				longest ||		    ((int)(be32_to_cpu(agf->agf_freeblks) +		     be32_to_cpu(agf->agf_flcount) - need - args->total) <				(int)args->minleft)) {			xfs_trans_brelse(tp, agbp);			args->agbp = NULL;			return 0;		}	}	/*	 * Make the freelist shorter if it's too long.	 */	while (be32_to_cpu(agf->agf_flcount) > need) {		xfs_buf_t	*bp;		error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);		if (error)			return error;		if ((error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1)))			return error;		bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0);		xfs_trans_binval(tp, bp);	}	/*	 * Initialize the args structure.	 */	targs.tp = tp;	targs.mp = mp;	targs.agbp = agbp;	targs.agno = args->agno;	targs.mod = targs.minleft = targs.wasdel = targs.userdata =		targs.minalignslop = 0;	targs.alignment = targs.minlen = targs.prod = targs.isfl = 1;	targs.type = XFS_ALLOCTYPE_THIS_AG;	targs.pag = pag;	if ((error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp)))		return error;	/*	 * Make the freelist longer if it's too short.	 */	while (be32_to_cpu(agf->agf_flcount) < need) {		targs.agbno = 0;		targs.maxlen = need - be32_to_cpu(agf->agf_flcount);		/*		 * Allocate as many blocks as possible at once.		 */		if ((error = xfs_alloc_ag_vextent(&targs))) {			xfs_trans_brelse(tp, agflbp);			return error;		}		/*		 * Stop if we run out.  Won't happen if callers are obeying		 * the restrictions correctly.  Can happen for free calls		 * on a completely full ag.		 */		if (targs.agbno == NULLAGBLOCK) {			if (flags & XFS_ALLOC_FLAG_FREEING)				break;			xfs_trans_brelse(tp, agflbp);			args->agbp = NULL;			return 0;		}		/*		 * Put each allocated block on the list.		 */		for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) {			error = xfs_alloc_put_freelist(tp, agbp,							agflbp, bno, 0);			if (error)				return error;		}	}	xfs_trans_brelse(tp, agflbp);	args->agbp = agbp;	return 0;}/* * Get a block from the freelist. * Returns with the buffer for the block gotten. */int				/* error */xfs_alloc_get_freelist(	xfs_trans_t	*tp,	/* transaction pointer */	xfs_buf_t	*agbp,	/* buffer containing the agf structure */	xfs_agblock_t	*bnop,	/* block address retrieved from freelist */	int		btreeblk) /* destination is a AGF btree */{	xfs_agf_t	*agf;	/* a.g. freespace structure */	xfs_agfl_t	*agfl;	/* a.g. freelist structure */	xfs_buf_t	*agflbp;/* buffer for a.g. freelist structure */	xfs_agblock_t	bno;	/* block number returned */	int		error;	int		logflags;	xfs_mount_t	*mp;	/* mount structure */	xfs_perag_t	*pag;	/* per allocation group data */	agf = XFS_BUF_TO_AGF(agbp);	/*	 * Freelist is empty, give up.	 */	if (!agf->agf_flcount) {		*bnop = NULLAGBLOCK;		return 0;	}	/*	 * Read the array of free blocks.	 */	mp = tp->t_mountp;	if ((error = xfs_alloc_read_agfl(mp, tp,			be32_to_cpu(agf->agf_seqno), &agflbp)))		return error;	agfl = XFS_BUF_TO_AGFL(agflbp);	/*	 * Get the block number and update the data structures.	 */	bno = be32_to_cpu(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)]);	be32_add(&agf->agf_flfirst, 1);	xfs_trans_brelse(tp, agflbp);	if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp))		agf->agf_flfirst = 0;	pag = &mp->m_perag[be32_to_cpu(agf->agf_seqno)];	be32_add(&agf->agf_flcount, -1);	xfs_trans_agflist_delta(tp, -1);	pag->pagf_flcount--;	logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT;	if (btreeblk) {		be32_add(&agf->agf_btreeblks, 1);		pag->pagf_btreeblks++;		logflags |= XFS_AGF_BTREEBLKS;	}	TRACE_MODAGF(NULL, agf, logflags);	xfs_alloc_log_agf(tp, agbp, logflags);	*bnop = bno;	/*	 * As blocks are freed, they are added to the per-ag busy list	 * and remain there until the freeing transaction is committed to	 * disk.  Now that we have allocated blocks, this list must be	 * searched to see if a block is being reused.  If one is, then	 * the freeing transaction must be pushed to disk NOW by forcing	 * to disk all iclogs up that transaction's LSN.	 */	xfs_alloc_search_busy(tp, be32_to_cpu(agf->agf_seqno), bno, 1);	return 0;}/* * Log the given fields from the agf structure. */voidxfs_alloc_log_agf(	xfs_trans_t	*tp,	/* transaction pointer */	xfs_buf_t	*bp,	/* buffer for a.g. freelist header */	int		fields)	/* mask of fields to be logged (XFS_AGF_...) */{	int	first;		/* first byte offset */	int	last;		/* last byte offset */	static const short	offsets[] = {		offsetof(xfs_agf_t, agf_magicnum),		offsetof(xfs_agf_t, agf_versionnum),		offsetof(xfs_agf_t, agf_seqno),		offsetof(xfs_agf_t, agf_length),		offsetof(xfs_agf_t, agf_roots[0]),		offsetof(xfs_agf_t, agf_levels[0]),		offsetof(xfs_agf_t, agf_flfirst),		offsetof(xfs_agf_t, agf_fllast),		offsetof(xfs_agf_t, agf_flcount),		offsetof(xfs_agf_t, agf_freeblks),		offsetof(xfs_agf_t, agf_longest),		offsetof(xfs_agf_t, agf_btreeblks),		sizeof(xfs_agf_t)	};	xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last);	xfs_trans_log_buf(tp, bp, (uint)first, (uint)last);}/* * Interface for inode allocation to force the pag data to be initialized. */int					/* error */xfs_alloc_pagf_init(	xfs_mount_t		*mp,	/* file system mount structure */	xfs_trans_t		*tp,	/* transaction pointer */	xfs_agnumber_t		agno,	/* allocation group number */	int			flags)	/* XFS_ALLOC_FLAGS_... */{	xfs_buf_t		*bp;	int			error;	if ((error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp)))		return error;	if (bp)		xfs_trans_brelse(tp, bp);	return 0;}/* * Put the block on the freelist for the allocation group. */int					/* error */xfs_alloc_put_freelist(	xfs_trans_t		*tp,	/* transaction pointer */	xfs_buf_t		*agbp,	/* buffer for a.g. freelist header */	xfs_buf_t		*agflbp,/* buffer for a.g. free block array */	xfs_agblock_t		bno,	/* block being freed */	int			btreeblk) /* block came from a AGF btree */{	xfs_agf_t		*agf;	/* a.g. freespace structure */	xfs_agfl_t		*agfl;	/* a.g. free block array */	__be32			*blockp;/* pointer to array entry */	int			error;	int			logflags;	xfs_mount_t		*mp;	/* mount structure */	xfs_perag_t		*pag;	/* per allocation group data */	agf = XFS_BUF_TO_AGF(agbp);	mp = tp->t_mountp;	if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp,			be32_to_cpu(agf->agf_seqno), &agflbp)))		return error;	agfl = XFS_BUF_TO_AGFL(agflbp);	be32_add(&agf->agf_fllast, 1);	if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp))		agf->agf_fllast = 0;	pag = &mp->m_perag[be32_to_cpu(agf->agf_seqno)];	be32_add(&agf->agf_flcount, 1);	xfs_trans_agflist_delta(tp, 1);	pag->pagf_flcount++;	logflags = XFS_AGF_FLLAST | XFS_AGF_FLCOUNT;	if (btreeblk) {		be32_add(&agf->agf_btreeblks, -1);		pag->pagf_btreeblks--;		logflags |= XFS_AGF_BTREEBLKS;	}	TRACE_MODAGF(NULL, agf, logflags);	xfs_alloc_log_agf(tp, agbp, logflags);	ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));	blockp = &agfl->agfl_bno[be32_to_cpu(agf->agf_fllast)];	*blockp = cpu_to_be32(bno);	TRACE_MODAGF(NULL, agf, logflags);	xfs_alloc_log_agf(tp, agbp, logflags);	xfs_trans_log_buf(tp, agflbp,		(int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl),		(int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl +			sizeof(xfs_agblock_t) - 1));	return 0;}/* * Read in the allocation group header (free/alloc section). */int					/* error */xfs_alloc_read_agf(	xfs_mount_t	*mp,		/* mount point structure */	xfs_trans_t	*tp,		/* transaction pointer */	xfs_agnumber_t	agno,		/* allocation group number */	int		flags,		/* XFS_ALLOC_FLAG_... */	xfs_buf_t	**bpp)		/* buffer for the ag freelist header */{	xfs_agf_t	*agf;		/* ag freelist header */	int		agf_ok;		/* set if agf is consistent */	xfs_buf_t	*bp;		/* return value */	xfs_perag_t	*pag;		/* per allocation group data */	int		error;	ASSERT(agno != NULLAGNUMBER);	error = xfs_trans_read_buf(			mp, tp, mp->m_ddev_targp,			XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),			XFS_FSS_TO_BB(mp, 1),			(flags & XFS_ALLOC_FLAG_TRYLOCK) ? XFS_BUF_TRYLOCK : 0U,			&bp);	if (error)		return error;	ASSERT(!bp || !XFS_BUF_GETERROR(bp));	if (!bp) {		*bpp = NULL;		return 0;	}	/*	 * Validate the magic number of the agf block.	 */	agf = XFS_BUF_TO_AGF(bp);	agf_ok =		be32_to_cpu(agf->agf_magicnum) == XFS_AGF_MAGIC &&		XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&		be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&		be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&		be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&		be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp);	if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,			XFS_RANDOM_ALLOC_READ_AGF))) {		XFS_CORRUPTION_ERROR("xfs_alloc_read_agf",				     XFS_ERRLEVEL_LOW, mp, agf);		xfs_trans_brelse(tp, bp);		return XFS_ERROR(EFSCORRUPTED);	}	pag = &mp->m_perag[agno];	if (!pag->pagf_init) {		pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks);		pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks);		pag->pagf_flcount = be32_to_cpu(agf->agf_flcount);		pag->pagf_longest = be32_to_cpu(agf->agf_longest);		pag->pagf_levels[XFS_BTNUM_BNOi] =			be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]);		pag->pagf_levels[XFS_BTNUM_CNTi] =			be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]);		spinlock_init(&pag->pagb_lock, "xfspagb");		pag->pagb_list = kmem_zalloc(XFS_PAGB_NUM_SLOTS *					sizeof(xfs_perag_busy_t), KM_SLEEP);		pag->pagf_init = 1;	}#ifdef DEBUG	else if (!XFS_FORCED_SHUTDOWN(mp)) {		ASSERT(pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks));		ASSERT(pag->pagf_flcount == be32_to_cpu(agf->agf_flcount));		ASSERT(pag->pagf_longest == be32_to_cpu(agf->agf_longest));		ASSERT(pag->pagf_levels[XFS_BTNUM_BNOi] ==		       be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]));		ASSERT(pag->pagf_levels[XFS_BTNUM_CNTi] ==		       be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]));	}#endif	XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGF, XFS_AGF_REF);	*bpp = bp;	return 0;}/* * Allocate an extent (variable-size). * Depending on the allocation type, we either look in a single allocation * group or loop over the allocation groups to find the result. */int				/* error */xfs_alloc_vextent(	xfs_alloc_arg_t	*args)	/* allocation argument structure */{	xfs_agblock_t	agsize;	/* allocation group size */	int		error;	int		flags;	/* XFS_ALLOC_FLAG_... locking flags */	xfs_extlen_t	minleft;/* minimum left value, temp copy */	xfs_mount_t	*mp;	/* mount structure pointer */	xfs_agnumber_t	sagno;	/* starting allocation group number */	xfs_alloctype_t	type;	/* input allocation type */	int		bump_rotor = 0;	int		no_min = 0;	xfs_agnumber_t	rotorstep = xfs_rotorstep; /* inode32 agf stepper */	mp = args->mp;	type = args->otype = args->type;	args-

⌨️ 快捷键说明

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