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

📄 xfs_trans.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (delta < 0) {			tp->t_blk_res_used += (uint)-delta;			ASSERT(tp->t_blk_res_used <= tp->t_blk_res);		}		tp->t_fdblocks_delta += delta;		if (xfs_sb_version_haslazysbcount(&mp->m_sb))			flags &= ~XFS_TRANS_SB_DIRTY;		break;	case XFS_TRANS_SB_RES_FDBLOCKS:		/*		 * The allocation has already been applied to the		 * in-core superblock's counter.  This should only		 * be applied to the on-disk superblock.		 */		ASSERT(delta < 0);		tp->t_res_fdblocks_delta += delta;		if (xfs_sb_version_haslazysbcount(&mp->m_sb))			flags &= ~XFS_TRANS_SB_DIRTY;		break;	case XFS_TRANS_SB_FREXTENTS:		/*		 * Track the number of blocks allocated in the		 * transaction.  Make sure it does not exceed the		 * number reserved.		 */		if (delta < 0) {			tp->t_rtx_res_used += (uint)-delta;			ASSERT(tp->t_rtx_res_used <= tp->t_rtx_res);		}		tp->t_frextents_delta += delta;		break;	case XFS_TRANS_SB_RES_FREXTENTS:		/*		 * The allocation has already been applied to the		 * in-core superblock's counter.  This should only		 * be applied to the on-disk superblock.		 */		ASSERT(delta < 0);		tp->t_res_frextents_delta += delta;		break;	case XFS_TRANS_SB_DBLOCKS:		ASSERT(delta > 0);		tp->t_dblocks_delta += delta;		break;	case XFS_TRANS_SB_AGCOUNT:		ASSERT(delta > 0);		tp->t_agcount_delta += delta;		break;	case XFS_TRANS_SB_IMAXPCT:		tp->t_imaxpct_delta += delta;		break;	case XFS_TRANS_SB_REXTSIZE:		tp->t_rextsize_delta += delta;		break;	case XFS_TRANS_SB_RBMBLOCKS:		tp->t_rbmblocks_delta += delta;		break;	case XFS_TRANS_SB_RBLOCKS:		tp->t_rblocks_delta += delta;		break;	case XFS_TRANS_SB_REXTENTS:		tp->t_rextents_delta += delta;		break;	case XFS_TRANS_SB_REXTSLOG:		tp->t_rextslog_delta += delta;		break;	default:		ASSERT(0);		return;	}	tp->t_flags |= flags;}/* * xfs_trans_apply_sb_deltas() is called from the commit code * to bring the superblock buffer into the current transaction * and modify it as requested by earlier calls to xfs_trans_mod_sb(). * * For now we just look at each field allowed to change and change * it if necessary. */STATIC voidxfs_trans_apply_sb_deltas(	xfs_trans_t	*tp){	xfs_dsb_t	*sbp;	xfs_buf_t	*bp;	int		whole = 0;	bp = xfs_trans_getsb(tp, tp->t_mountp, 0);	sbp = XFS_BUF_TO_SBP(bp);	/*	 * Check that superblock mods match the mods made to AGF counters.	 */	ASSERT((tp->t_fdblocks_delta + tp->t_res_fdblocks_delta) ==	       (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta +		tp->t_ag_btree_delta));	/*	 * Only update the superblock counters if we are logging them	 */	if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) {		if (tp->t_icount_delta)			be64_add(&sbp->sb_icount, tp->t_icount_delta);		if (tp->t_ifree_delta)			be64_add(&sbp->sb_ifree, tp->t_ifree_delta);		if (tp->t_fdblocks_delta)			be64_add(&sbp->sb_fdblocks, tp->t_fdblocks_delta);		if (tp->t_res_fdblocks_delta)			be64_add(&sbp->sb_fdblocks, tp->t_res_fdblocks_delta);	}	if (tp->t_frextents_delta)		be64_add(&sbp->sb_frextents, tp->t_frextents_delta);	if (tp->t_res_frextents_delta)		be64_add(&sbp->sb_frextents, tp->t_res_frextents_delta);	if (tp->t_dblocks_delta) {		be64_add(&sbp->sb_dblocks, tp->t_dblocks_delta);		whole = 1;	}	if (tp->t_agcount_delta) {		be32_add(&sbp->sb_agcount, tp->t_agcount_delta);		whole = 1;	}	if (tp->t_imaxpct_delta) {		sbp->sb_imax_pct += tp->t_imaxpct_delta;		whole = 1;	}	if (tp->t_rextsize_delta) {		be32_add(&sbp->sb_rextsize, tp->t_rextsize_delta);		whole = 1;	}	if (tp->t_rbmblocks_delta) {		be32_add(&sbp->sb_rbmblocks, tp->t_rbmblocks_delta);		whole = 1;	}	if (tp->t_rblocks_delta) {		be64_add(&sbp->sb_rblocks, tp->t_rblocks_delta);		whole = 1;	}	if (tp->t_rextents_delta) {		be64_add(&sbp->sb_rextents, tp->t_rextents_delta);		whole = 1;	}	if (tp->t_rextslog_delta) {		sbp->sb_rextslog += tp->t_rextslog_delta;		whole = 1;	}	if (whole)		/*		 * Log the whole thing, the fields are noncontiguous.		 */		xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_dsb_t) - 1);	else		/*		 * Since all the modifiable fields are contiguous, we		 * can get away with this.		 */		xfs_trans_log_buf(tp, bp, offsetof(xfs_dsb_t, sb_icount),				  offsetof(xfs_dsb_t, sb_frextents) +				  sizeof(sbp->sb_frextents) - 1);	tp->t_mountp->m_super->s_dirt = 1;}/* * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations * and apply superblock counter changes to the in-core superblock.  The * t_res_fdblocks_delta and t_res_frextents_delta fields are explicitly NOT * applied to the in-core superblock.  The idea is that that has already been * done. * * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). * However, we have to ensure that we only modify each superblock field only * once because the application of the delta values may not be atomic. That can * lead to ENOSPC races occurring if we have two separate modifcations of the * free space counter to put back the entire reservation and then take away * what we used. * * If we are not logging superblock counters, then the inode allocated/free and * used block counts are not updated in the on disk superblock. In this case, * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we * still need to update the incore superblock with the changes. */STATIC voidxfs_trans_unreserve_and_mod_sb(	xfs_trans_t	*tp){	xfs_mod_sb_t	msb[14];	/* If you add cases, add entries */	xfs_mod_sb_t	*msbp;	xfs_mount_t	*mp = tp->t_mountp;	/* REFERENCED */	int		error;	int		rsvd;	int64_t		blkdelta = 0;	int64_t		rtxdelta = 0;	msbp = msb;	rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;	/* calculate free blocks delta */	if (tp->t_blk_res > 0)		blkdelta = tp->t_blk_res;	if ((tp->t_fdblocks_delta != 0) &&	    (xfs_sb_version_haslazysbcount(&mp->m_sb) ||	     (tp->t_flags & XFS_TRANS_SB_DIRTY)))	        blkdelta += tp->t_fdblocks_delta;	if (blkdelta != 0) {		msbp->msb_field = XFS_SBS_FDBLOCKS;		msbp->msb_delta = blkdelta;		msbp++;	}	/* calculate free realtime extents delta */	if (tp->t_rtx_res > 0)		rtxdelta = tp->t_rtx_res;	if ((tp->t_frextents_delta != 0) &&	    (tp->t_flags & XFS_TRANS_SB_DIRTY))		rtxdelta += tp->t_frextents_delta;	if (rtxdelta != 0) {		msbp->msb_field = XFS_SBS_FREXTENTS;		msbp->msb_delta = rtxdelta;		msbp++;	}	/* apply remaining deltas */	if (xfs_sb_version_haslazysbcount(&mp->m_sb) ||	     (tp->t_flags & XFS_TRANS_SB_DIRTY)) {		if (tp->t_icount_delta != 0) {			msbp->msb_field = XFS_SBS_ICOUNT;			msbp->msb_delta = tp->t_icount_delta;			msbp++;		}		if (tp->t_ifree_delta != 0) {			msbp->msb_field = XFS_SBS_IFREE;			msbp->msb_delta = tp->t_ifree_delta;			msbp++;		}	}	if (tp->t_flags & XFS_TRANS_SB_DIRTY) {		if (tp->t_dblocks_delta != 0) {			msbp->msb_field = XFS_SBS_DBLOCKS;			msbp->msb_delta = tp->t_dblocks_delta;			msbp++;		}		if (tp->t_agcount_delta != 0) {			msbp->msb_field = XFS_SBS_AGCOUNT;			msbp->msb_delta = tp->t_agcount_delta;			msbp++;		}		if (tp->t_imaxpct_delta != 0) {			msbp->msb_field = XFS_SBS_IMAX_PCT;			msbp->msb_delta = tp->t_imaxpct_delta;			msbp++;		}		if (tp->t_rextsize_delta != 0) {			msbp->msb_field = XFS_SBS_REXTSIZE;			msbp->msb_delta = tp->t_rextsize_delta;			msbp++;		}		if (tp->t_rbmblocks_delta != 0) {			msbp->msb_field = XFS_SBS_RBMBLOCKS;			msbp->msb_delta = tp->t_rbmblocks_delta;			msbp++;		}		if (tp->t_rblocks_delta != 0) {			msbp->msb_field = XFS_SBS_RBLOCKS;			msbp->msb_delta = tp->t_rblocks_delta;			msbp++;		}		if (tp->t_rextents_delta != 0) {			msbp->msb_field = XFS_SBS_REXTENTS;			msbp->msb_delta = tp->t_rextents_delta;			msbp++;		}		if (tp->t_rextslog_delta != 0) {			msbp->msb_field = XFS_SBS_REXTSLOG;			msbp->msb_delta = tp->t_rextslog_delta;			msbp++;		}	}	/*	 * If we need to change anything, do it.	 */	if (msbp > msb) {		error = xfs_mod_incore_sb_batch(tp->t_mountp, msb,			(uint)(msbp - msb), rsvd);		ASSERT(error == 0);	}}/* * xfs_trans_commit * * Commit the given transaction to the log a/synchronously. * * XFS disk error handling mechanism is not based on a typical * transaction abort mechanism. Logically after the filesystem * gets marked 'SHUTDOWN', we can't let any new transactions * be durable - ie. committed to disk - because some metadata might * be inconsistent. In such cases, this returns an error, and the * caller may assume that all locked objects joined to the transaction * have already been unlocked as if the commit had succeeded. * Do not reference the transaction structure after this call. */ /*ARGSUSED*/int_xfs_trans_commit(	xfs_trans_t	*tp,	uint		flags,	int		*log_flushed){	xfs_log_iovec_t		*log_vector;	int			nvec;	xfs_mount_t		*mp;	xfs_lsn_t		commit_lsn;	/* REFERENCED */	int			error;	int			log_flags;	int			sync;#define	XFS_TRANS_LOGVEC_COUNT	16	xfs_log_iovec_t		log_vector_fast[XFS_TRANS_LOGVEC_COUNT];	void			*commit_iclog;	int			shutdown;	commit_lsn = -1;	/*	 * Determine whether this commit is releasing a permanent	 * log reservation or not.	 */	if (flags & XFS_TRANS_RELEASE_LOG_RES) {		ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);		log_flags = XFS_LOG_REL_PERM_RESERV;	} else {		log_flags = 0;	}	mp = tp->t_mountp;	/*	 * If there is nothing to be logged by the transaction,	 * then unlock all of the items associated with the	 * transaction and free the transaction structure.	 * Also make sure to return any reserved blocks to	 * the free pool.	 */shut_us_down:	shutdown = XFS_FORCED_SHUTDOWN(mp) ? EIO : 0;	if (!(tp->t_flags & XFS_TRANS_DIRTY) || shutdown) {		xfs_trans_unreserve_and_mod_sb(tp);		/*		 * It is indeed possible for the transaction to be		 * not dirty but the dqinfo portion to be. All that		 * means is that we have some (non-persistent) quota		 * reservations that need to be unreserved.		 */		XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);		if (tp->t_ticket) {			commit_lsn = xfs_log_done(mp, tp->t_ticket,							NULL, log_flags);			if (commit_lsn == -1 && !shutdown)				shutdown = XFS_ERROR(EIO);		}		current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);		xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);		xfs_trans_free_busy(tp);		xfs_trans_free(tp);		XFS_STATS_INC(xs_trans_empty);		return (shutdown);	}	ASSERT(tp->t_ticket != NULL);	/*	 * If we need to update the superblock, then do it now.	 */	if (tp->t_flags & XFS_TRANS_SB_DIRTY) {		xfs_trans_apply_sb_deltas(tp);	}	XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp);	/*	 * Ask each log item how many log_vector entries it will	 * need so we can figure out how many to allocate.	 * Try to avoid the kmem_alloc() call in the common case	 * by using a vector from the stack when it fits.	 */	nvec = xfs_trans_count_vecs(tp);	if (nvec == 0) {		xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);		goto shut_us_down;	} else if (nvec <= XFS_TRANS_LOGVEC_COUNT) {		log_vector = log_vector_fast;	} else {		log_vector = (xfs_log_iovec_t *)kmem_alloc(nvec *						   sizeof(xfs_log_iovec_t),						   KM_SLEEP);	}	/*	 * Fill in the log_vector and pin the logged items, and	 * then write the transaction to the log.	 */	xfs_trans_fill_vecs(tp, log_vector);	error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, &(tp->t_lsn));	/*	 * The transaction is committed incore here, and can go out to disk	 * at any time after this call.  However, all the items associated	 * with the transaction are still locked and pinned in memory.	 */	commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags);	tp->t_commit_lsn = commit_lsn;	if (nvec > XFS_TRANS_LOGVEC_COUNT) {		kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));	}	/*	 * If we got a log write error. Unpin the logitems that we	 * had pinned, clean up, free trans structure, and return error.	 */	if (error || commit_lsn == -1) {		current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);		xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);		return XFS_ERROR(EIO);	}	/*	 * Once the transaction has committed, unused	 * reservations need to be released and changes to	 * the superblock need to be reflected in the in-core	 * version.  Do that now.	 */	xfs_trans_unreserve_and_mod_sb(tp);	sync = tp->t_flags & XFS_TRANS_SYNC;	/*	 * Tell the LM to call the transaction completion routine	 * when the log write with LSN commit_lsn completes (e.g.	 * when the transaction commit really hits the on-disk log).	 * After this call we cannot reference tp, because the call	 * can happen at any time and the call will free the transaction	 * structure pointed to by tp.  The only case where we call	 * the completion routine (xfs_trans_committed) directly is	 * if the log is turned off on a debug kernel or we're	 * running in simulation mode (the log is explicitly turned	 * off).	 */	tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed;	tp->t_logcb.cb_arg = tp;

⌨️ 快捷键说明

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