forked from mirrors/linux
		
	xfs: split out iclog writing from xfs_trans_commit()
Split the the part of xfs_trans_commit() that deals with writing the transaction into the iclog into a separate function. This isolates the physical commit process from the logical commit operation and makes it easier to insert different transaction commit paths without affecting the existing algorithm adversely. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
		
							parent
							
								
									713bf88bba
								
							
						
					
					
						commit
						0924378a68
					
				
					 1 changed files with 201 additions and 190 deletions
				
			
		| 
						 | 
				
			
			@ -47,8 +47,6 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
STATIC void	xfs_trans_apply_sb_deltas(xfs_trans_t *);
 | 
			
		||||
STATIC uint	xfs_trans_count_vecs(xfs_trans_t *);
 | 
			
		||||
STATIC void	xfs_trans_fill_vecs(xfs_trans_t *, xfs_log_iovec_t *);
 | 
			
		||||
STATIC void	xfs_trans_uncommit(xfs_trans_t *, uint);
 | 
			
		||||
STATIC void	xfs_trans_committed(xfs_trans_t *, int);
 | 
			
		||||
STATIC void	xfs_trans_chunk_committed(xfs_log_item_chunk_t *, xfs_lsn_t, int);
 | 
			
		||||
| 
						 | 
				
			
			@ -764,94 +762,126 @@ xfs_trans_unreserve_and_mod_sb(
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Total up the number of log iovecs needed to commit this
 | 
			
		||||
 * transaction.  The transaction itself needs one for the
 | 
			
		||||
 * transaction header.  Ask each dirty item in turn how many
 | 
			
		||||
 * it needs to get the total.
 | 
			
		||||
 */
 | 
			
		||||
static uint
 | 
			
		||||
xfs_trans_count_vecs(
 | 
			
		||||
	xfs_trans_t	*tp)
 | 
			
		||||
{
 | 
			
		||||
	int			nvecs;
 | 
			
		||||
	xfs_log_item_desc_t	*lidp;
 | 
			
		||||
 | 
			
		||||
	nvecs = 1;
 | 
			
		||||
	lidp = xfs_trans_first_item(tp);
 | 
			
		||||
	ASSERT(lidp != NULL);
 | 
			
		||||
 | 
			
		||||
	/* In the non-debug case we need to start bailing out if we
 | 
			
		||||
	 * didn't find a log_item here, return zero and let trans_commit
 | 
			
		||||
	 * deal with it.
 | 
			
		||||
	 */
 | 
			
		||||
	if (lidp == NULL)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	while (lidp != NULL) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Skip items which aren't dirty in this transaction.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
 | 
			
		||||
			lidp = xfs_trans_next_item(tp, lidp);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		lidp->lid_size = IOP_SIZE(lidp->lid_item);
 | 
			
		||||
		nvecs += lidp->lid_size;
 | 
			
		||||
		lidp = xfs_trans_next_item(tp, lidp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nvecs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * xfs_trans_commit
 | 
			
		||||
 * Fill in the vector with pointers to data to be logged
 | 
			
		||||
 * by this transaction.  The transaction header takes
 | 
			
		||||
 * the first vector, and then each dirty item takes the
 | 
			
		||||
 * number of vectors it indicated it needed in xfs_trans_count_vecs().
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 * As each item fills in the entries it needs, also pin the item
 | 
			
		||||
 * so that it cannot be flushed out until the log write completes.
 | 
			
		||||
 */
 | 
			
		||||
 /*ARGSUSED*/
 | 
			
		||||
int
 | 
			
		||||
_xfs_trans_commit(
 | 
			
		||||
	xfs_trans_t	*tp,
 | 
			
		||||
	uint		flags,
 | 
			
		||||
	int		*log_flushed)
 | 
			
		||||
static void
 | 
			
		||||
xfs_trans_fill_vecs(
 | 
			
		||||
	struct xfs_trans	*tp,
 | 
			
		||||
	struct xfs_log_iovec	*log_vector)
 | 
			
		||||
{
 | 
			
		||||
	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];
 | 
			
		||||
	struct xlog_in_core	*commit_iclog;
 | 
			
		||||
	int			shutdown;
 | 
			
		||||
 | 
			
		||||
	commit_lsn = -1;
 | 
			
		||||
	xfs_log_item_desc_t	*lidp;
 | 
			
		||||
	struct xfs_log_iovec	*vecp;
 | 
			
		||||
	uint			nitems;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Determine whether this commit is releasing a permanent
 | 
			
		||||
	 * log reservation or not.
 | 
			
		||||
	 * Skip over the entry for the transaction header, we'll
 | 
			
		||||
	 * fill that in at the end.
 | 
			
		||||
	 */
 | 
			
		||||
	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;
 | 
			
		||||
	vecp = log_vector + 1;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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(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);
 | 
			
		||||
	nitems = 0;
 | 
			
		||||
	lidp = xfs_trans_first_item(tp);
 | 
			
		||||
	ASSERT(lidp);
 | 
			
		||||
	while (lidp) {
 | 
			
		||||
		/* Skip items which aren't dirty in this transaction. */
 | 
			
		||||
		if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
 | 
			
		||||
			lidp = xfs_trans_next_item(tp, lidp);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		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);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * The item may be marked dirty but not log anything.  This can
 | 
			
		||||
		 * be used to get called when a transaction is committed.
 | 
			
		||||
		 */
 | 
			
		||||
		if (lidp->lid_size)
 | 
			
		||||
			nitems++;
 | 
			
		||||
		IOP_FORMAT(lidp->lid_item, vecp);
 | 
			
		||||
		vecp += lidp->lid_size;
 | 
			
		||||
		IOP_PIN(lidp->lid_item);
 | 
			
		||||
		lidp = xfs_trans_next_item(tp, lidp);
 | 
			
		||||
	}
 | 
			
		||||
	ASSERT(tp->t_ticket != NULL);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we need to update the superblock, then do it now.
 | 
			
		||||
	 * Now that we've counted the number of items in this transaction, fill
 | 
			
		||||
	 * in the transaction header. Note that the transaction header does not
 | 
			
		||||
	 * have a log item.
 | 
			
		||||
	 */
 | 
			
		||||
	if (tp->t_flags & XFS_TRANS_SB_DIRTY)
 | 
			
		||||
		xfs_trans_apply_sb_deltas(tp);
 | 
			
		||||
	xfs_trans_apply_dquot_deltas(tp);
 | 
			
		||||
	tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC;
 | 
			
		||||
	tp->t_header.th_type = tp->t_type;
 | 
			
		||||
	tp->t_header.th_num_items = nitems;
 | 
			
		||||
	log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
 | 
			
		||||
	log_vector->i_len = sizeof(xfs_trans_header_t);
 | 
			
		||||
	log_vector->i_type = XLOG_REG_TYPE_TRANSHDR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Format the transaction direct to the iclog. This isolates the physical
 | 
			
		||||
 * transaction commit operation from the logical operation and hence allows
 | 
			
		||||
 * other methods to be introduced without affecting the existing commit path.
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
xfs_trans_commit_iclog(
 | 
			
		||||
	struct xfs_mount	*mp,
 | 
			
		||||
	struct xfs_trans	*tp,
 | 
			
		||||
	xfs_lsn_t		*commit_lsn,
 | 
			
		||||
	int			flags)
 | 
			
		||||
{
 | 
			
		||||
	int			shutdown;
 | 
			
		||||
	int			error;
 | 
			
		||||
	int			log_flags = 0;
 | 
			
		||||
	struct xlog_in_core	*commit_iclog;
 | 
			
		||||
#define XFS_TRANS_LOGVEC_COUNT  16
 | 
			
		||||
	struct xfs_log_iovec	log_vector_fast[XFS_TRANS_LOGVEC_COUNT];
 | 
			
		||||
	struct xfs_log_iovec	*log_vector;
 | 
			
		||||
	uint			nvec;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Ask each log item how many log_vector entries it will
 | 
			
		||||
| 
						 | 
				
			
			@ -861,8 +891,7 @@ _xfs_trans_commit(
 | 
			
		|||
	 */
 | 
			
		||||
	nvec = xfs_trans_count_vecs(tp);
 | 
			
		||||
	if (nvec == 0) {
 | 
			
		||||
		xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
 | 
			
		||||
		goto shut_us_down;
 | 
			
		||||
		return ENOMEM;	/* triggers a shutdown! */
 | 
			
		||||
	} else if (nvec <= XFS_TRANS_LOGVEC_COUNT) {
 | 
			
		||||
		log_vector = log_vector_fast;
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -877,6 +906,9 @@ _xfs_trans_commit(
 | 
			
		|||
	 */
 | 
			
		||||
	xfs_trans_fill_vecs(tp, log_vector);
 | 
			
		||||
 | 
			
		||||
	if (flags & XFS_TRANS_RELEASE_LOG_RES)
 | 
			
		||||
		log_flags = XFS_LOG_REL_PERM_RESERV;
 | 
			
		||||
 | 
			
		||||
	error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, &(tp->t_lsn));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -884,18 +916,17 @@ _xfs_trans_commit(
 | 
			
		|||
	 * 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);
 | 
			
		||||
	*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) {
 | 
			
		||||
	tp->t_commit_lsn = *commit_lsn;
 | 
			
		||||
	if (nvec > XFS_TRANS_LOGVEC_COUNT)
 | 
			
		||||
		kmem_free(log_vector);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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) {
 | 
			
		||||
	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);
 | 
			
		||||
| 
						 | 
				
			
			@ -909,8 +940,6 @@ _xfs_trans_commit(
 | 
			
		|||
	 */
 | 
			
		||||
	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.
 | 
			
		||||
| 
						 | 
				
			
			@ -953,7 +982,7 @@ _xfs_trans_commit(
 | 
			
		|||
	 * the commit lsn of this transaction for dependency tracking
 | 
			
		||||
	 * purposes.
 | 
			
		||||
	 */
 | 
			
		||||
	xfs_trans_unlock_items(tp, commit_lsn);
 | 
			
		||||
	xfs_trans_unlock_items(tp, *commit_lsn);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we detected a log error earlier, finish committing
 | 
			
		||||
| 
						 | 
				
			
			@ -973,7 +1002,92 @@ _xfs_trans_commit(
 | 
			
		|||
	 * and the items are released we can finally allow the iclog to
 | 
			
		||||
	 * go to disk.
 | 
			
		||||
	 */
 | 
			
		||||
	error = xfs_log_release_iclog(mp, commit_iclog);
 | 
			
		||||
	return xfs_log_release_iclog(mp, commit_iclog);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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_mount_t		*mp = tp->t_mountp;
 | 
			
		||||
	xfs_lsn_t		commit_lsn = -1;
 | 
			
		||||
	int			error;
 | 
			
		||||
	int			log_flags = 0;
 | 
			
		||||
	int			sync = tp->t_flags & XFS_TRANS_SYNC;
 | 
			
		||||
	int			shutdown;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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(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(tp);
 | 
			
		||||
 | 
			
		||||
	error = xfs_trans_commit_iclog(mp, tp, &commit_lsn, flags);
 | 
			
		||||
	if (error == ENOMEM) {
 | 
			
		||||
		xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
 | 
			
		||||
		goto shut_us_down;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If the transaction needs to be synchronous, then force the
 | 
			
		||||
| 
						 | 
				
			
			@ -992,47 +1106,6 @@ _xfs_trans_commit(
 | 
			
		|||
	return (error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Total up the number of log iovecs needed to commit this
 | 
			
		||||
 * transaction.  The transaction itself needs one for the
 | 
			
		||||
 * transaction header.  Ask each dirty item in turn how many
 | 
			
		||||
 * it needs to get the total.
 | 
			
		||||
 */
 | 
			
		||||
STATIC uint
 | 
			
		||||
xfs_trans_count_vecs(
 | 
			
		||||
	xfs_trans_t	*tp)
 | 
			
		||||
{
 | 
			
		||||
	int			nvecs;
 | 
			
		||||
	xfs_log_item_desc_t	*lidp;
 | 
			
		||||
 | 
			
		||||
	nvecs = 1;
 | 
			
		||||
	lidp = xfs_trans_first_item(tp);
 | 
			
		||||
	ASSERT(lidp != NULL);
 | 
			
		||||
 | 
			
		||||
	/* In the non-debug case we need to start bailing out if we
 | 
			
		||||
	 * didn't find a log_item here, return zero and let trans_commit
 | 
			
		||||
	 * deal with it.
 | 
			
		||||
	 */
 | 
			
		||||
	if (lidp == NULL)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	while (lidp != NULL) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Skip items which aren't dirty in this transaction.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
 | 
			
		||||
			lidp = xfs_trans_next_item(tp, lidp);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		lidp->lid_size = IOP_SIZE(lidp->lid_item);
 | 
			
		||||
		nvecs += lidp->lid_size;
 | 
			
		||||
		lidp = xfs_trans_next_item(tp, lidp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nvecs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Called from the trans_commit code when we notice that
 | 
			
		||||
 * the filesystem is in the middle of a forced shutdown.
 | 
			
		||||
| 
						 | 
				
			
			@ -1062,68 +1135,6 @@ xfs_trans_uncommit(
 | 
			
		|||
	xfs_trans_free(tp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Fill in the vector with pointers to data to be logged
 | 
			
		||||
 * by this transaction.  The transaction header takes
 | 
			
		||||
 * the first vector, and then each dirty item takes the
 | 
			
		||||
 * number of vectors it indicated it needed in xfs_trans_count_vecs().
 | 
			
		||||
 *
 | 
			
		||||
 * As each item fills in the entries it needs, also pin the item
 | 
			
		||||
 * so that it cannot be flushed out until the log write completes.
 | 
			
		||||
 */
 | 
			
		||||
STATIC void
 | 
			
		||||
xfs_trans_fill_vecs(
 | 
			
		||||
	xfs_trans_t		*tp,
 | 
			
		||||
	xfs_log_iovec_t		*log_vector)
 | 
			
		||||
{
 | 
			
		||||
	xfs_log_item_desc_t	*lidp;
 | 
			
		||||
	xfs_log_iovec_t		*vecp;
 | 
			
		||||
	uint			nitems;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Skip over the entry for the transaction header, we'll
 | 
			
		||||
	 * fill that in at the end.
 | 
			
		||||
	 */
 | 
			
		||||
	vecp = log_vector + 1;		/* pointer arithmetic */
 | 
			
		||||
 | 
			
		||||
	nitems = 0;
 | 
			
		||||
	lidp = xfs_trans_first_item(tp);
 | 
			
		||||
	ASSERT(lidp != NULL);
 | 
			
		||||
	while (lidp != NULL) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Skip items which aren't dirty in this transaction.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
 | 
			
		||||
			lidp = xfs_trans_next_item(tp, lidp);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		/*
 | 
			
		||||
		 * The item may be marked dirty but not log anything.
 | 
			
		||||
		 * This can be used to get called when a transaction
 | 
			
		||||
		 * is committed.
 | 
			
		||||
		 */
 | 
			
		||||
		if (lidp->lid_size) {
 | 
			
		||||
			nitems++;
 | 
			
		||||
		}
 | 
			
		||||
		IOP_FORMAT(lidp->lid_item, vecp);
 | 
			
		||||
		vecp += lidp->lid_size;		/* pointer arithmetic */
 | 
			
		||||
		IOP_PIN(lidp->lid_item);
 | 
			
		||||
		lidp = xfs_trans_next_item(tp, lidp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Now that we've counted the number of items in this
 | 
			
		||||
	 * transaction, fill in the transaction header.
 | 
			
		||||
	 */
 | 
			
		||||
	tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC;
 | 
			
		||||
	tp->t_header.th_type = tp->t_type;
 | 
			
		||||
	tp->t_header.th_num_items = nitems;
 | 
			
		||||
	log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
 | 
			
		||||
	log_vector->i_len = sizeof(xfs_trans_header_t);
 | 
			
		||||
	log_vector->i_type = XLOG_REG_TYPE_TRANSHDR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Unlock all of the transaction's items and free the transaction.
 | 
			
		||||
 * The transaction must not have modified any of its items, because
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue