#if defined(XLOG_NOLOG) || defined(DEBUG) static xfs_lsn_t	trans_lsn = 1; #endif 
_xfs_trans_commit(	xfs_trans_t	*tp,	uint		flags,	xfs_lsn_t	*commit_lsn_p,	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];#if defined(XLOG_NOLOG) || defined(DEBUG)	static xfs_lsn_t	trans_lsn = 1;#endif	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);		}                PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);		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);		if (commit_lsn_p)			*commit_lsn_p = commit_lsn;		return (shutdown);	}#if defined(XLOG_NOLOG) || defined(DEBUG)	ASSERT(!xlog_debug || tp->t_ticket != NULL);#else	ASSERT(tp->t_ticket != NULL);#endif	/*	 * 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, XFS_LOG_IO_ERROR);		goto shut_us_down;	}	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);	/*	 * Ignore errors here. xfs_log_done would do the right thing.	 * We need to put the ticket, etc. away.	 */	error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket,			     &(tp->t_lsn));#if defined(XLOG_NOLOG) || defined(DEBUG)	if (xlog_debug) {		commit_lsn = xfs_log_done(mp, tp->t_ticket,					  &commit_iclog, log_flags);	} else {		commit_lsn = 0;		tp->t_lsn = trans_lsn++;	}#else	/*	 * This is the regular case.  At this point (after the call finishes),	 * the transaction is committed incore and could go out to disk at	 * any time.  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);#endif	tp->t_commit_lsn = commit_lsn;	if (nvec > XFS_TRANS_LOGVEC_COUNT) {		kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));	}	if (commit_lsn_p)		*commit_lsn_p = commit_lsn;	/*	 * 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) {                PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);		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;	/*	 * We need to pass the iclog buffer which was used for the	 * transaction commit record into this function, and attach	 * the callback to it. The callback must be attached before	 * the items are unlocked to avoid racing with other threads	 * waiting for an item to unlock.	 */	shutdown = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb));	/*	 * Mark this thread as no longer being in a transaction	 */	PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);	/*	 * Once all the items of the transaction have been copied	 * to the in core log and the callback is attached, the	 * items can be unlocked.	 *	 * This will free descriptors pointing to items which were	 * not logged since there is nothing more to do with them.	 * For items which were logged, we will keep pointers to them	 * so they can be unpinned after the transaction commits to disk.	 * This will also stamp each modified meta-data item with	 * the commit lsn of this transaction for dependency tracking	 * purposes.	 */	xfs_trans_unlock_items(tp, commit_lsn);	/*	 * If we detected a log error earlier, finish committing	 * the transaction now (unpin log items, etc).	 *	 * Order is critical here, to avoid using the transaction	 * pointer after its been freed (by xfs_trans_committed	 * either here now, or as a callback).  We cannot do this	 * step inside xfs_log_notify as was done earlier because	 * of this issue.	 */	if (shutdown)		xfs_trans_committed(tp, XFS_LI_ABORTED);	/*	 * Now that the xfs_trans_committed callback has been attached,	 * and the items are released we can finally allow the iclog to	 * go to disk.	 */	error = xfs_log_release_iclog(mp, commit_iclog);	/*	 * If the transaction needs to be synchronous, then force the	 * log out now and wait for it.	 */	if (sync) {		if (!error) {			error = _xfs_log_force(mp, commit_lsn,				      XFS_LOG_FORCE | XFS_LOG_SYNC,				      log_flushed);		}		XFS_STATS_INC(xs_trans_sync);	} else {		XFS_STATS_INC(xs_trans_async);	}	return (error);}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/cfcbbbd089eadcaa86abb2c0f352e1ab23e16f72/xfs_trans.c/clean/fs/xfs/xfs_trans.c