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

📄 xfs_rtalloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	xfs_sb_t	*sbp;		/* old superblock */	xfs_fsblock_t	sumbno;		/* summary block number */	xfs_trans_t	*tp;		/* transaction pointer */	sbp = &mp->m_sb;	/*	 * Initial error checking.	 */	if (mp->m_rtdev_targp == NULL || mp->m_rbmip == NULL ||	    (nrblocks = in->newblocks) <= sbp->sb_rblocks ||	    (sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize)))		return XFS_ERROR(EINVAL);	if ((error = xfs_sb_validate_fsb_count(sbp, nrblocks)))		return error;	/*	 * Read in the last block of the device, make sure it exists.	 */	error = xfs_read_buf(mp, mp->m_rtdev_targp,			XFS_FSB_TO_BB(mp, nrblocks - 1),			XFS_FSB_TO_BB(mp, 1), 0, &bp);	if (error)		return error;	ASSERT(bp);	xfs_buf_relse(bp);	/*	 * Calculate new parameters.  These are the final values to be reached.	 */	nrextents = nrblocks;	do_div(nrextents, in->extsize);	nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize);	nrextslog = xfs_highbit32(nrextents);	nrsumlevels = nrextslog + 1;	nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks;	nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);	nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);	/*	 * New summary size can't be more than half the size of	 * the log.  This prevents us from getting a log overflow,	 * since we'll log basically the whole summary file at once.	 */	if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1))		return XFS_ERROR(EINVAL);	/*	 * Get the old block counts for bitmap and summary inodes.	 * These can't change since other growfs callers are locked out.	 */	rbmblocks = XFS_B_TO_FSB(mp, mp->m_rbmip->i_d.di_size);	rsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumip->i_d.di_size);	/*	 * Allocate space to the bitmap and summary files, as necessary.	 */	if ((error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks,			mp->m_sb.sb_rbmino)))		return error;	if ((error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks,			mp->m_sb.sb_rsumino)))		return error;	/*	 * Allocate a new (fake) mount/sb.	 */	nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP);	/*	 * Loop over the bitmap blocks.	 * We will do everything one bitmap block at a time.	 * Skip the current block if it is exactly full.	 * This also deals with the case where there were no rtextents before.	 */	for (bmbno = sbp->sb_rbmblocks -		     ((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);	     bmbno < nrbmblocks;	     bmbno++) {		*nmp = *mp;		nsbp = &nmp->m_sb;		/*		 * Calculate new sb and mount fields for this round.		 */		nsbp->sb_rextsize = in->extsize;		nsbp->sb_rbmblocks = bmbno + 1;		nsbp->sb_rblocks =			XFS_RTMIN(nrblocks,				  nsbp->sb_rbmblocks * NBBY *				  nsbp->sb_blocksize * nsbp->sb_rextsize);		nsbp->sb_rextents = nsbp->sb_rblocks;		do_div(nsbp->sb_rextents, nsbp->sb_rextsize);		nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents);		nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1;		nrsumsize =			(uint)sizeof(xfs_suminfo_t) * nrsumlevels *			nsbp->sb_rbmblocks;		nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);		nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);		/*		 * Start a transaction, get the log reservation.		 */		tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_FREE);		cancelflags = 0;		if ((error = xfs_trans_reserve(tp, 0,				XFS_GROWRTFREE_LOG_RES(nmp), 0, 0, 0)))			break;		/*		 * Lock out other callers by grabbing the bitmap inode lock.		 */		if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,						XFS_ILOCK_EXCL, &ip)))			break;		ASSERT(ip == mp->m_rbmip);		/*		 * Update the bitmap inode's size.		 */		mp->m_rbmip->i_d.di_size =			nsbp->sb_rbmblocks * nsbp->sb_blocksize;		xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);		cancelflags |= XFS_TRANS_ABORT;		/*		 * Get the summary inode into the transaction.		 */		if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0,						XFS_ILOCK_EXCL, &ip)))			break;		ASSERT(ip == mp->m_rsumip);		/*		 * Update the summary inode's size.		 */		mp->m_rsumip->i_d.di_size = nmp->m_rsumsize;		xfs_trans_log_inode(tp, mp->m_rsumip, XFS_ILOG_CORE);		/*		 * Copy summary data from old to new sizes.		 * Do this when the real size (not block-aligned) changes.		 */		if (sbp->sb_rbmblocks != nsbp->sb_rbmblocks ||		    mp->m_rsumlevels != nmp->m_rsumlevels) {			error = xfs_rtcopy_summary(mp, nmp, tp);			if (error)				break;		}		/*		 * Update superblock fields.		 */		if (nsbp->sb_rextsize != sbp->sb_rextsize)			xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSIZE,				nsbp->sb_rextsize - sbp->sb_rextsize);		if (nsbp->sb_rbmblocks != sbp->sb_rbmblocks)			xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBMBLOCKS,				nsbp->sb_rbmblocks - sbp->sb_rbmblocks);		if (nsbp->sb_rblocks != sbp->sb_rblocks)			xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBLOCKS,				nsbp->sb_rblocks - sbp->sb_rblocks);		if (nsbp->sb_rextents != sbp->sb_rextents)			xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTENTS,				nsbp->sb_rextents - sbp->sb_rextents);		if (nsbp->sb_rextslog != sbp->sb_rextslog)			xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG,				nsbp->sb_rextslog - sbp->sb_rextslog);		/*		 * Free new extent.		 */		bp = NULL;		error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,			nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);		if (error)			break;		/*		 * Mark more blocks free in the superblock.		 */		xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS,			nsbp->sb_rextents - sbp->sb_rextents);		/*		 * Update mp values into the real mp structure.		 */		mp->m_rsumlevels = nrsumlevels;		mp->m_rsumsize = nrsumsize;		/*		 * Commit the transaction.		 */		xfs_trans_commit(tp, 0);	}	if (error)		xfs_trans_cancel(tp, cancelflags);	/*	 * Free the fake mp structure.	 */	kmem_free(nmp, sizeof(*nmp));	return error;}/* * Allocate an extent in the realtime subvolume, with the usual allocation * parameters.  The length units are all in realtime extents, as is the * result block number. */int					/* error */xfs_rtallocate_extent(	xfs_trans_t	*tp,		/* transaction pointer */	xfs_rtblock_t	bno,		/* starting block number to allocate */	xfs_extlen_t	minlen,		/* minimum length to allocate */	xfs_extlen_t	maxlen,		/* maximum length to allocate */	xfs_extlen_t	*len,		/* out: actual length allocated */	xfs_alloctype_t	type,		/* allocation type XFS_ALLOCTYPE... */	int		wasdel,		/* was a delayed allocation extent */	xfs_extlen_t	prod,		/* extent product factor */	xfs_rtblock_t	*rtblock)	/* out: start block allocated */{	int		error;		/* error value */	xfs_inode_t	*ip;		/* inode for bitmap file */	xfs_mount_t	*mp;		/* file system mount structure */	xfs_rtblock_t	r;		/* result allocated block */	xfs_fsblock_t	sb;		/* summary file block number */	xfs_buf_t	*sumbp;		/* summary file block buffer */	ASSERT(minlen > 0 && minlen <= maxlen);	mp = tp->t_mountp;	/*	 * If prod is set then figure out what to do to minlen and maxlen.	 */	if (prod > 1) {		xfs_extlen_t	i;		if ((i = maxlen % prod))			maxlen -= i;		if ((i = minlen % prod))			minlen += prod - i;		if (maxlen < minlen) {			*rtblock = NULLRTBLOCK;			return 0;		}	}	/*	 * Lock out other callers by grabbing the bitmap inode lock.	 */	if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,					XFS_ILOCK_EXCL, &ip)))		return error;	sumbp = NULL;	/*	 * Allocate by size, or near another block, or exactly at some block.	 */	switch (type) {	case XFS_ALLOCTYPE_ANY_AG:		error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len,				&sumbp,	&sb, prod, &r);		break;	case XFS_ALLOCTYPE_NEAR_BNO:		error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen,				len, &sumbp, &sb, prod, &r);		break;	case XFS_ALLOCTYPE_THIS_BNO:		error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen,				len, &sumbp, &sb, prod, &r);		break;	default:		ASSERT(0);	}	if (error) {		return error;	}	/*	 * If it worked, update the superblock.	 */	if (r != NULLRTBLOCK) {		long	slen = (long)*len;		ASSERT(*len >= minlen && *len <= maxlen);		if (wasdel)			xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FREXTENTS, -slen);		else			xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, -slen);	}	*rtblock = r;	return 0;}/* * Free an extent in the realtime subvolume.  Length is expressed in * realtime extents, as is the block number. */int					/* error */xfs_rtfree_extent(	xfs_trans_t	*tp,		/* transaction pointer */	xfs_rtblock_t	bno,		/* starting block number to free */	xfs_extlen_t	len)		/* length of extent freed */{	int		error;		/* error value */	xfs_inode_t	*ip;		/* bitmap file inode */	xfs_mount_t	*mp;		/* file system mount structure */	xfs_fsblock_t	sb;		/* summary file block number */	xfs_buf_t	*sumbp;		/* summary file block buffer */	mp = tp->t_mountp;	/*	 * Synchronize by locking the bitmap inode.	 */	if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,					XFS_ILOCK_EXCL, &ip)))		return error;#if defined(__KERNEL__) && defined(DEBUG)	/*	 * Check to see that this whole range is currently allocated.	 */	{		int	stat;		/* result from checking range */		error = xfs_rtcheck_alloc_range(mp, tp, bno, len, &stat);		if (error) {			return error;		}		ASSERT(stat);	}#endif	sumbp = NULL;	/*	 * Free the range of realtime blocks.	 */	error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb);	if (error) {		return error;	}	/*	 * Mark more blocks free in the superblock.	 */	xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len);	/*	 * If we've now freed all the blocks, reset the file sequence	 * number to 0.	 */	if (tp->t_frextents_delta + mp->m_sb.sb_frextents ==	    mp->m_sb.sb_rextents) {		if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM))			ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;		*(__uint64_t *)&ip->i_d.di_atime = 0;		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);	}	return 0;}/* * Initialize realtime fields in the mount structure. */int				/* error */xfs_rtmount_init(	xfs_mount_t	*mp)	/* file system mount structure */{	xfs_buf_t	*bp;	/* buffer for last block of subvolume */	xfs_daddr_t	d;	/* address of last block of subvolume */	int		error;	/* error return value */	xfs_sb_t	*sbp;	/* filesystem superblock copy in mount */	sbp = &mp->m_sb;	if (sbp->sb_rblocks == 0)		return 0;	if (mp->m_rtdev_targp == NULL) {		cmn_err(CE_WARN,	"XFS: This filesystem has a realtime volume, use rtdev=device option");		return XFS_ERROR(ENODEV);	}	mp->m_rsumlevels = sbp->sb_rextslog + 1;	mp->m_rsumsize =		(uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels *		sbp->sb_rbmblocks;	mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize);	mp->m_rbmip = mp->m_rsumip = NULL;	/*	 * Check that the realtime section is an ok size.	 */	d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);	if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) {		cmn_err(CE_WARN, "XFS: realtime mount -- %llu != %llu",			(unsigned long long) XFS_BB_TO_FSB(mp, d),			(unsigned long long) mp->m_sb.sb_rblocks);		return XFS_ERROR(E2BIG);	}	error = xfs_read_buf(mp, mp->m_rtdev_targp,				d - XFS_FSB_TO_BB(mp, 1),				XFS_FSB_TO_BB(mp, 1), 0, &bp);	if (error) {		cmn_err(CE_WARN,	"XFS: realtime mount -- xfs_read_buf failed, returned %d", error);		if (error == ENOSPC)			return XFS_ERROR(E2BIG);		return error;	}	xfs_buf_relse(bp);	return 0;}/* * Get the bitmap and summary inodes into the mount structure * at mount time. */int					/* error */xfs_rtmount_inodes(	xfs_mount_t	*mp)		/* file system mount structure */{	int		error;		/* error return value */	xfs_sb_t	*sbp;	sbp = &mp->m_sb;	if (sbp->sb_rbmino == NULLFSINO)		return 0;	error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip, 0);	if (error)		return error;	ASSERT(mp->m_rbmip != NULL);	ASSERT(sbp->sb_rsumino != NULLFSINO);	error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip, 0);	if (error) {		VN_RELE(XFS_ITOV(mp->m_rbmip));		return error;	}	ASSERT(mp->m_rsumip != NULL);	return 0;}/* * Pick an extent for allocation at the start of a new realtime file. * Use the sequence number stored in the atime field of the bitmap inode. * Translate this to a fraction of the rtextents, and return the product * of rtextents and the fraction. * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ... */int					/* error */xfs_rtpick_extent(	xfs_mount_t	*mp,		/* file system mount point */	xfs_trans_t	*tp,		/* transaction pointer */	xfs_extlen_t	len,		/* allocation length (rtextents) */	xfs_rtblock_t	*pick)		/* result rt extent */{	xfs_rtblock_t	b;		/* result block */	int		error;		/* error return value */	xfs_inode_t	*ip;		/* bitmap incore inode */	int		log2;		/* log of sequence number */	__uint64_t	resid;		/* residual after log removed */	__uint64_t	seq;		/* sequence number of file creation */	__uint64_t	*seqp;		/* pointer to seqno in inode */	if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,					XFS_ILOCK_EXCL, &ip)))		return error;	ASSERT(ip == mp->m_rbmip);	seqp = (__uint64_t *)&ip->i_d.di_atime;	if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) {		ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;		*seqp = 0;	}	seq = *seqp;	if ((log2 = xfs_highbit64(seq)) == -1)		b = 0;	else {		resid = seq - (1ULL << log2);		b = (mp->m_sb.sb_rextents * ((resid << 1) + 1ULL)) >>		    (log2 + 1);		if (b >= mp->m_sb.sb_rextents)			b = do_mod(b, mp->m_sb.sb_rextents);		if (b + len > mp->m_sb.sb_rextents)			b = mp->m_sb.sb_rextents - len;	}	*seqp = seq + 1;	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);	*pick = b;	return 0;}

⌨️ 快捷键说明

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