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 + -
显示快捷键?