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

📄 xfs_trans.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/*	 * 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	 */	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);	/*	 * 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);}/* * 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 uintxfs_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. */STATIC voidxfs_trans_uncommit(	xfs_trans_t	*tp,	uint		flags){	xfs_log_item_desc_t	*lidp;	for (lidp = xfs_trans_first_item(tp);	     lidp != NULL;	     lidp = xfs_trans_next_item(tp, lidp)) {		/*		 * Unpin all but those that aren't dirty.		 */		if (lidp->lid_flags & XFS_LID_DIRTY)			IOP_UNPIN_REMOVE(lidp->lid_item, tp);	}	xfs_trans_unreserve_and_mod_sb(tp);	XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);	xfs_trans_free_items(tp, flags);	xfs_trans_free_busy(tp);	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 voidxfs_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);	XLOG_VEC_SET_TYPE(log_vector, 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 * there is no way to restore them to their previous state. * * If the transaction has made a log reservation, make sure to release * it as well. */voidxfs_trans_cancel(	xfs_trans_t		*tp,	int			flags){	int			log_flags;#ifdef DEBUG	xfs_log_item_chunk_t	*licp;	xfs_log_item_desc_t	*lidp;	xfs_log_item_t		*lip;	int			i;#endif	xfs_mount_t		*mp = tp->t_mountp;	/*	 * See if the caller is being too lazy to figure out if	 * the transaction really needs an abort.	 */	if ((flags & XFS_TRANS_ABORT) && !(tp->t_flags & XFS_TRANS_DIRTY))		flags &= ~XFS_TRANS_ABORT;	/*	 * See if the caller is relying on us to shut down the	 * filesystem.  This happens in paths where we detect	 * corruption and decide to give up.	 */	if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) {		XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp);		xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);	}#ifdef DEBUG	if (!(flags & XFS_TRANS_ABORT)) {		licp = &(tp->t_items);		while (licp != NULL) {			lidp = licp->lic_descs;			for (i = 0; i < licp->lic_unused; i++, lidp++) {				if (XFS_LIC_ISFREE(licp, i)) {					continue;				}				lip = lidp->lid_item;				if (!XFS_FORCED_SHUTDOWN(mp))					ASSERT(!(lip->li_type == XFS_LI_EFD));			}			licp = licp->lic_next;		}	}#endif	xfs_trans_unreserve_and_mod_sb(tp);	XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);	if (tp->t_ticket) {		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;		}		xfs_log_done(mp, tp->t_ticket, NULL, log_flags);	}	/* mark this thread as no longer being in a transaction */	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);	xfs_trans_free_items(tp, flags);	xfs_trans_free_busy(tp);	xfs_trans_free(tp);}/* * Free the transaction structure.  If there is more clean up * to do when the structure is freed, add it here. */STATIC voidxfs_trans_free(	xfs_trans_t	*tp){	atomic_dec(&tp->t_mountp->m_active_trans);	XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);	kmem_zone_free(xfs_trans_zone, tp);}/* * THIS SHOULD BE REWRITTEN TO USE xfs_trans_next_item(). * * This is typically called by the LM when a transaction has been fully * committed to disk.  It needs to unpin the items which have * been logged by the transaction and update their positions * in the AIL if necessary. * This also gets called when the transactions didn't get written out * because of an I/O error. Abortflag & XFS_LI_ABORTED is set then. * * Call xfs_trans_chunk_committed() to process the items in * each chunk. */STATIC voidxfs_trans_committed(	xfs_trans_t	*tp,	int		abortflag){	xfs_log_item_chunk_t	*licp;	xfs_log_item_chunk_t	*next_licp;	xfs_log_busy_chunk_t	*lbcp;	xfs_log_busy_slot_t	*lbsp;	int			i;	/*	 * Call the transaction's completion callback if there	 * is one.	 */	if (tp->t_callback != NULL) {		tp->t_callback(tp, tp->t_callarg);	}	/*	 * Special case the chunk embedded in the transaction.	 */	licp = &(tp->t_items);	if (!(XFS_LIC_ARE_ALL_FREE(licp))) {		xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag);	}	/*	 * Process the items in each chunk in turn.	 */	licp = licp->lic_next;	while (licp != NULL) {		ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));		xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag);		next_licp = licp->lic_next;		kmem_free(licp, sizeof(xfs_log_item_chunk_t));		licp = next_licp;	}	/*	 * Clear all the per-AG busy list items listed in this transaction	 */	lbcp = &tp->t_busy;	while (lbcp != NULL) {		for (i = 0, lbsp = lbcp->lbc_busy; i < lbcp->lbc_unused; i++, lbsp++) {			if (!XFS_LBC_ISFREE(lbcp, i)) {				xfs_alloc_clear_busy(tp, lbsp->lbc_ag,						     lbsp->lbc_idx);			}		}		lbcp = lbcp->lbc_next;	}	xfs_trans_free_busy(tp);	/*	 * That's it for the transaction structure.  Free it.	 */	xfs_trans_free(tp);}/* * This is called to perform the commit processing for each * item described by the given chunk. * * The commit processing consists of unlocking items which were * held locked with the SYNC_UNLOCK attribute, calling the committed * routine of each logged item, updating the item's position in the AIL * if necessary, and unpinning each item.  If the committed routine * returns -1, then do nothing further with the item because it * may have been freed. * * Since items are unlocked when they are copied to the incore * log, it is possible for two transactions to be completing * and manipulating the same item simultaneously.  The AIL lock * will protect the lsn field of each item.  The value of this * field can never go backwards. * * We unpin the items after repositioning them in the AIL, because * otherwise they could be immediately flushed and we'd have to race * with the flusher trying to pull the item from the AIL as we add it. */STATIC voidxfs_trans_chunk_committed(	xfs_log_item_chunk_t	*licp,	xfs_lsn_t		lsn,	int			aborted){	xfs_log_item_desc_t	*lidp;	xfs_log_item_t		*lip;	xfs_lsn_t		item_lsn;	struct xfs_mount	*mp;	int			i;	SPLDECL(s);	lidp = licp->lic_descs;	for (i = 0; i < licp->lic_unused; i++, lidp++) {		if (XFS_LIC_ISFREE(licp, i)) {			continue;		}		lip = lidp->lid_item;		if (aborted)			lip->li_flags |= XFS_LI_ABORTED;		/*		 * Send in the ABORTED flag to the COMMITTED routine		 * so that it knows whether the transaction was aborted		 * or not.		 */		item_lsn = IOP_COMMITTED(lip, lsn);		/*		 * If the committed routine returns -1, make		 * no more references to the item.		 */		if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) {			continue;		}		/*		 * If the returned lsn is greater than what it		 * contained before, update the location of the		 * item in the AIL.  If it is not, then do nothing.		 * Items can never move backwards in the AIL.		 *		 * While the new lsn should usually be greater, it		 * is possible that a later transaction completing		 * simultaneously with an earlier one using the		 * same item could complete first with a higher lsn.		 * This would cause the earlier transaction to fail		 * the test below.		 */		mp = lip->li_mountp;		AIL_LOCK(mp,s);		if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) {			/*			 * This will set the item's lsn to item_lsn			 * and update the position of the item in			 * the AIL.			 *			 * xfs_trans_update_ail() drops the AIL lock.			 */			xfs_trans_update_ail(mp, lip, item_lsn, s);		} else {			AIL_UNLOCK(mp, s);		}		/*		 * Now that we've repositioned the item in the AIL,		 * unpin it so it can be flushed. Pass information		 * about buffer stale state down from the log item		 * flags, if anyone else stales the buffer we do not		 * want to pay any attention to it.		 */		IOP_UNPIN(lip, lidp->lid_flags & XFS_LID_BUF_STALE);	}}

⌨️ 快捷键说明

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