xfs_trans.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,316 行 · 第 1/3 页

C
1,316
字号
/* * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like.  Any license provided herein, whether implied or * otherwise, applies only to this software file.  Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA  94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */#include "xfs.h"#include "xfs_macros.h"#include "xfs_types.h"#include "xfs_inum.h"#include "xfs_log.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_error.h"#include "xfs_trans_priv.h"#include "xfs_alloc_btree.h"#include "xfs_bmap_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_alloc.h"#include "xfs_attr_sf.h"#include "xfs_dir_sf.h"#include "xfs_dir2_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_bmap.h"#include "xfs_da_btree.h"#include "xfs_quota.h"#include "xfs_trans_space.h"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);STATIC void	xfs_trans_free(xfs_trans_t *);kmem_zone_t		*xfs_trans_zone;/* * Initialize the precomputed transaction reservation values * in the mount structure. */voidxfs_trans_init(	xfs_mount_t	*mp){	xfs_trans_reservations_t	*resp;	resp = &(mp->m_reservations);	resp->tr_write =		(uint)(XFS_CALC_WRITE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_itruncate =		(uint)(XFS_CALC_ITRUNCATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_rename =		(uint)(XFS_CALC_RENAME_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_link = (uint)XFS_CALC_LINK_LOG_RES(mp);	resp->tr_remove =		(uint)(XFS_CALC_REMOVE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_symlink =		(uint)(XFS_CALC_SYMLINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_create =		(uint)(XFS_CALC_CREATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_mkdir =		(uint)(XFS_CALC_MKDIR_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_ifree =		(uint)(XFS_CALC_IFREE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_ichange =		(uint)(XFS_CALC_ICHANGE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_growdata = (uint)XFS_CALC_GROWDATA_LOG_RES(mp);	resp->tr_swrite = (uint)XFS_CALC_SWRITE_LOG_RES(mp);	resp->tr_writeid = (uint)XFS_CALC_WRITEID_LOG_RES(mp);	resp->tr_addafork =		(uint)(XFS_CALC_ADDAFORK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_attrinval = (uint)XFS_CALC_ATTRINVAL_LOG_RES(mp);	resp->tr_attrset =		(uint)(XFS_CALC_ATTRSET_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_attrrm =		(uint)(XFS_CALC_ATTRRM_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));	resp->tr_clearagi = (uint)XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp);	resp->tr_growrtalloc = (uint)XFS_CALC_GROWRTALLOC_LOG_RES(mp);	resp->tr_growrtzero = (uint)XFS_CALC_GROWRTZERO_LOG_RES(mp);	resp->tr_growrtfree = (uint)XFS_CALC_GROWRTFREE_LOG_RES(mp);}/* * This routine is called to allocate a transaction structure. * The type parameter indicates the type of the transaction.  These * are enumerated in xfs_trans.h. * * Dynamically allocate the transaction structure from the transaction * zone, initialize it, and return it to the caller. */xfs_trans_t *xfs_trans_alloc(	xfs_mount_t	*mp,	uint		type){	fs_check_frozen(XFS_MTOVFS(mp), SB_FREEZE_TRANS);	atomic_inc(&mp->m_active_trans);	return (_xfs_trans_alloc(mp, type));}xfs_trans_t *_xfs_trans_alloc(	xfs_mount_t	*mp,	uint		type){	xfs_trans_t	*tp;	ASSERT(xfs_trans_zone != NULL);	tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);	/*	 * Initialize the transaction structure.	 */	tp->t_magic = XFS_TRANS_MAGIC;	tp->t_type = type;	tp->t_mountp = mp;	tp->t_items_free = XFS_LIC_NUM_SLOTS;	tp->t_busy_free = XFS_LBC_NUM_SLOTS;	XFS_LIC_INIT(&(tp->t_items));	XFS_LBC_INIT(&(tp->t_busy));	return (tp);}/* * This is called to create a new transaction which will share the * permanent log reservation of the given transaction.  The remaining * unused block and rt extent reservations are also inherited.  This * implies that the original transaction is no longer allowed to allocate * blocks.  Locks and log items, however, are no inherited.  They must * be added to the new transaction explicitly. */xfs_trans_t *xfs_trans_dup(	xfs_trans_t	*tp){	xfs_trans_t	*ntp;	ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);	/*	 * Initialize the new transaction structure.	 */	ntp->t_magic = XFS_TRANS_MAGIC;	ntp->t_type = tp->t_type;	ntp->t_mountp = tp->t_mountp;	ntp->t_items_free = XFS_LIC_NUM_SLOTS;	ntp->t_busy_free = XFS_LBC_NUM_SLOTS;	XFS_LIC_INIT(&(ntp->t_items));	XFS_LBC_INIT(&(ntp->t_busy));	ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);#if defined(XLOG_NOLOG) || defined(DEBUG)	ASSERT(!xlog_debug || tp->t_ticket != NULL);#else	ASSERT(tp->t_ticket != NULL);#endif	ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE);	ntp->t_ticket = tp->t_ticket;	ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used;	tp->t_blk_res = tp->t_blk_res_used;	ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;	tp->t_rtx_res = tp->t_rtx_res_used;	PFLAGS_DUP(&tp->t_pflags, &ntp->t_pflags);	XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp);	atomic_inc(&tp->t_mountp->m_active_trans);	return ntp;}/* * This is called to reserve free disk blocks and log space for the * given transaction.  This must be done before allocating any resources * within the transaction. * * This will return ENOSPC if there are not enough blocks available. * It will sleep waiting for available log space. * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which * is used by long running transactions.  If any one of the reservations * fails then they will all be backed out. * * This does not do quota reservations. That typically is done by the * caller afterwards. */intxfs_trans_reserve(	xfs_trans_t	*tp,	uint		blocks,	uint		logspace,	uint		rtextents,	uint		flags,	uint		logcount){	int		log_flags;	int		error;	int	rsvd;	error = 0;	rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;	/* Mark this thread as being in a transaction */        PFLAGS_SET_FSTRANS(&tp->t_pflags);	/*	 * Attempt to reserve the needed disk blocks by decrementing	 * the number needed from the number available.  This will	 * fail if the count would go below zero.	 */	if (blocks > 0) {		error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,					  -blocks, rsvd);		if (error != 0) {                        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);			return (XFS_ERROR(ENOSPC));		}		tp->t_blk_res += blocks;	}	/*	 * Reserve the log space needed for this transaction.	 */	if (logspace > 0) {		ASSERT((tp->t_log_res == 0) || (tp->t_log_res == logspace));		ASSERT((tp->t_log_count == 0) ||			(tp->t_log_count == logcount));		if (flags & XFS_TRANS_PERM_LOG_RES) {			log_flags = XFS_LOG_PERM_RESERV;			tp->t_flags |= XFS_TRANS_PERM_LOG_RES;		} else {			ASSERT(tp->t_ticket == NULL);			ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES));			log_flags = 0;		}		error = xfs_log_reserve(tp->t_mountp, logspace, logcount,					&tp->t_ticket,					XFS_TRANSACTION, log_flags);		if (error) {			goto undo_blocks;		}		tp->t_log_res = logspace;		tp->t_log_count = logcount;	}	/*	 * Attempt to reserve the needed realtime extents by decrementing	 * the number needed from the number available.  This will	 * fail if the count would go below zero.	 */	if (rtextents > 0) {		error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FREXTENTS,					  -rtextents, rsvd);		if (error) {			error = XFS_ERROR(ENOSPC);			goto undo_log;		}		tp->t_rtx_res += rtextents;	}	return 0;	/*	 * Error cases jump to one of these labels to undo any	 * reservations which have already been performed.	 */undo_log:	if (logspace > 0) {		if (flags & XFS_TRANS_PERM_LOG_RES) {			log_flags = XFS_LOG_REL_PERM_RESERV;		} else {			log_flags = 0;		}		xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, log_flags);		tp->t_ticket = NULL;		tp->t_log_res = 0;		tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES;	}undo_blocks:	if (blocks > 0) {		(void) xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,					 blocks, rsvd);		tp->t_blk_res = 0;	}        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);	return (error);}/* * This is called to set the a callback to be called when the given * transaction is committed to disk.  The transaction pointer and the * argument pointer will be passed to the callback routine. * * Only one callback can be associated with any single transaction. */voidxfs_trans_callback(	xfs_trans_t		*tp,	xfs_trans_callback_t	callback,	void			*arg){	ASSERT(tp->t_callback == NULL);	tp->t_callback = callback;	tp->t_callarg = arg;}/* * Record the indicated change to the given field for application * to the file system's superblock when the transaction commits. * For now, just store the change in the transaction structure. * * Mark the transaction structure to indicate that the superblock * needs to be updated before committing. */voidxfs_trans_mod_sb(	xfs_trans_t	*tp,	uint		field,	long		delta){	switch (field) {	case XFS_TRANS_SB_ICOUNT:		tp->t_icount_delta += delta;		break;	case XFS_TRANS_SB_IFREE:		tp->t_ifree_delta += delta;		break;	case XFS_TRANS_SB_FDBLOCKS:		/*		 * Track the number of blocks allocated in the		 * transaction.  Make sure it does not exceed the		 * number reserved.		 */		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;		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;		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 superblocks'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;

⌨️ 快捷键说明

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