xref: /linux/fs/xfs/xfs_trans.c (revision 2bdf7cd0baa67608ada1517a281af359faf4c58c)
11da177e4SLinus Torvalds /*
27b718769SNathan Scott  * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
37b718769SNathan Scott  * All Rights Reserved.
41da177e4SLinus Torvalds  *
57b718769SNathan Scott  * This program is free software; you can redistribute it and/or
67b718769SNathan Scott  * modify it under the terms of the GNU General Public License as
71da177e4SLinus Torvalds  * published by the Free Software Foundation.
81da177e4SLinus Torvalds  *
97b718769SNathan Scott  * This program is distributed in the hope that it would be useful,
107b718769SNathan Scott  * but WITHOUT ANY WARRANTY; without even the implied warranty of
117b718769SNathan Scott  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
127b718769SNathan Scott  * GNU General Public License for more details.
131da177e4SLinus Torvalds  *
147b718769SNathan Scott  * You should have received a copy of the GNU General Public License
157b718769SNathan Scott  * along with this program; if not, write the Free Software Foundation,
167b718769SNathan Scott  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
171da177e4SLinus Torvalds  */
181da177e4SLinus Torvalds #include "xfs.h"
19a844f451SNathan Scott #include "xfs_fs.h"
201da177e4SLinus Torvalds #include "xfs_types.h"
21a844f451SNathan Scott #include "xfs_bit.h"
221da177e4SLinus Torvalds #include "xfs_log.h"
23a844f451SNathan Scott #include "xfs_inum.h"
241da177e4SLinus Torvalds #include "xfs_trans.h"
251da177e4SLinus Torvalds #include "xfs_sb.h"
261da177e4SLinus Torvalds #include "xfs_ag.h"
271da177e4SLinus Torvalds #include "xfs_dir2.h"
281da177e4SLinus Torvalds #include "xfs_dmapi.h"
291da177e4SLinus Torvalds #include "xfs_mount.h"
301da177e4SLinus Torvalds #include "xfs_error.h"
31a844f451SNathan Scott #include "xfs_da_btree.h"
321da177e4SLinus Torvalds #include "xfs_bmap_btree.h"
33a844f451SNathan Scott #include "xfs_alloc_btree.h"
341da177e4SLinus Torvalds #include "xfs_ialloc_btree.h"
35a844f451SNathan Scott #include "xfs_dir2_sf.h"
36a844f451SNathan Scott #include "xfs_attr_sf.h"
37a844f451SNathan Scott #include "xfs_dinode.h"
38a844f451SNathan Scott #include "xfs_inode.h"
391da177e4SLinus Torvalds #include "xfs_btree.h"
401da177e4SLinus Torvalds #include "xfs_ialloc.h"
411da177e4SLinus Torvalds #include "xfs_alloc.h"
421da177e4SLinus Torvalds #include "xfs_bmap.h"
431da177e4SLinus Torvalds #include "xfs_quota.h"
44a844f451SNathan Scott #include "xfs_trans_priv.h"
451da177e4SLinus Torvalds #include "xfs_trans_space.h"
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds STATIC void	xfs_trans_apply_sb_deltas(xfs_trans_t *);
491da177e4SLinus Torvalds STATIC uint	xfs_trans_count_vecs(xfs_trans_t *);
501da177e4SLinus Torvalds STATIC void	xfs_trans_fill_vecs(xfs_trans_t *, xfs_log_iovec_t *);
511da177e4SLinus Torvalds STATIC void	xfs_trans_uncommit(xfs_trans_t *, uint);
521da177e4SLinus Torvalds STATIC void	xfs_trans_committed(xfs_trans_t *, int);
531da177e4SLinus Torvalds STATIC void	xfs_trans_chunk_committed(xfs_log_item_chunk_t *, xfs_lsn_t, int);
541da177e4SLinus Torvalds STATIC void	xfs_trans_free(xfs_trans_t *);
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds kmem_zone_t	*xfs_trans_zone;
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds /*
608f794055SNathan Scott  * Reservation functions here avoid a huge stack in xfs_trans_init
618f794055SNathan Scott  * due to register overflow from temporaries in the calculations.
628f794055SNathan Scott  */
638f794055SNathan Scott 
648f794055SNathan Scott STATIC uint
658f794055SNathan Scott xfs_calc_write_reservation(xfs_mount_t *mp)
668f794055SNathan Scott {
678f794055SNathan Scott 	return XFS_CALC_WRITE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
688f794055SNathan Scott }
698f794055SNathan Scott 
708f794055SNathan Scott STATIC uint
718f794055SNathan Scott xfs_calc_itruncate_reservation(xfs_mount_t *mp)
728f794055SNathan Scott {
738f794055SNathan Scott 	return XFS_CALC_ITRUNCATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
748f794055SNathan Scott }
758f794055SNathan Scott 
768f794055SNathan Scott STATIC uint
778f794055SNathan Scott xfs_calc_rename_reservation(xfs_mount_t *mp)
788f794055SNathan Scott {
798f794055SNathan Scott 	return XFS_CALC_RENAME_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
808f794055SNathan Scott }
818f794055SNathan Scott 
828f794055SNathan Scott STATIC uint
838f794055SNathan Scott xfs_calc_link_reservation(xfs_mount_t *mp)
848f794055SNathan Scott {
852ddd5928SNathan Scott 	return XFS_CALC_LINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
868f794055SNathan Scott }
878f794055SNathan Scott 
888f794055SNathan Scott STATIC uint
898f794055SNathan Scott xfs_calc_remove_reservation(xfs_mount_t *mp)
908f794055SNathan Scott {
918f794055SNathan Scott 	return XFS_CALC_REMOVE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
928f794055SNathan Scott }
938f794055SNathan Scott 
948f794055SNathan Scott STATIC uint
958f794055SNathan Scott xfs_calc_symlink_reservation(xfs_mount_t *mp)
968f794055SNathan Scott {
978f794055SNathan Scott 	return XFS_CALC_SYMLINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
988f794055SNathan Scott }
998f794055SNathan Scott 
1008f794055SNathan Scott STATIC uint
1018f794055SNathan Scott xfs_calc_create_reservation(xfs_mount_t *mp)
1028f794055SNathan Scott {
1038f794055SNathan Scott 	return XFS_CALC_CREATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
1048f794055SNathan Scott }
1058f794055SNathan Scott 
1068f794055SNathan Scott STATIC uint
1078f794055SNathan Scott xfs_calc_mkdir_reservation(xfs_mount_t *mp)
1088f794055SNathan Scott {
1098f794055SNathan Scott 	return XFS_CALC_MKDIR_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
1108f794055SNathan Scott }
1118f794055SNathan Scott 
1128f794055SNathan Scott STATIC uint
1138f794055SNathan Scott xfs_calc_ifree_reservation(xfs_mount_t *mp)
1148f794055SNathan Scott {
1158f794055SNathan Scott 	return XFS_CALC_IFREE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
1168f794055SNathan Scott }
1178f794055SNathan Scott 
1188f794055SNathan Scott STATIC uint
1198f794055SNathan Scott xfs_calc_ichange_reservation(xfs_mount_t *mp)
1208f794055SNathan Scott {
1218f794055SNathan Scott 	return XFS_CALC_ICHANGE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
1228f794055SNathan Scott }
1238f794055SNathan Scott 
1248f794055SNathan Scott STATIC uint
1258f794055SNathan Scott xfs_calc_growdata_reservation(xfs_mount_t *mp)
1268f794055SNathan Scott {
1278f794055SNathan Scott 	return XFS_CALC_GROWDATA_LOG_RES(mp);
1288f794055SNathan Scott }
1298f794055SNathan Scott 
1308f794055SNathan Scott STATIC uint
1318f794055SNathan Scott xfs_calc_growrtalloc_reservation(xfs_mount_t *mp)
1328f794055SNathan Scott {
1338f794055SNathan Scott 	return XFS_CALC_GROWRTALLOC_LOG_RES(mp);
1348f794055SNathan Scott }
1358f794055SNathan Scott 
1368f794055SNathan Scott STATIC uint
1378f794055SNathan Scott xfs_calc_growrtzero_reservation(xfs_mount_t *mp)
1388f794055SNathan Scott {
1398f794055SNathan Scott 	return XFS_CALC_GROWRTZERO_LOG_RES(mp);
1408f794055SNathan Scott }
1418f794055SNathan Scott 
1428f794055SNathan Scott STATIC uint
1438f794055SNathan Scott xfs_calc_growrtfree_reservation(xfs_mount_t *mp)
1448f794055SNathan Scott {
1458f794055SNathan Scott 	return XFS_CALC_GROWRTFREE_LOG_RES(mp);
1468f794055SNathan Scott }
1478f794055SNathan Scott 
1488f794055SNathan Scott STATIC uint
1498f794055SNathan Scott xfs_calc_swrite_reservation(xfs_mount_t *mp)
1508f794055SNathan Scott {
1518f794055SNathan Scott 	return XFS_CALC_SWRITE_LOG_RES(mp);
1528f794055SNathan Scott }
1538f794055SNathan Scott 
1548f794055SNathan Scott STATIC uint
1558f794055SNathan Scott xfs_calc_writeid_reservation(xfs_mount_t *mp)
1568f794055SNathan Scott {
1578f794055SNathan Scott 	return XFS_CALC_WRITEID_LOG_RES(mp);
1588f794055SNathan Scott }
1598f794055SNathan Scott 
1608f794055SNathan Scott STATIC uint
1618f794055SNathan Scott xfs_calc_addafork_reservation(xfs_mount_t *mp)
1628f794055SNathan Scott {
1638f794055SNathan Scott 	return XFS_CALC_ADDAFORK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
1648f794055SNathan Scott }
1658f794055SNathan Scott 
1668f794055SNathan Scott STATIC uint
1678f794055SNathan Scott xfs_calc_attrinval_reservation(xfs_mount_t *mp)
1688f794055SNathan Scott {
1698f794055SNathan Scott 	return XFS_CALC_ATTRINVAL_LOG_RES(mp);
1708f794055SNathan Scott }
1718f794055SNathan Scott 
1728f794055SNathan Scott STATIC uint
1738f794055SNathan Scott xfs_calc_attrset_reservation(xfs_mount_t *mp)
1748f794055SNathan Scott {
1758f794055SNathan Scott 	return XFS_CALC_ATTRSET_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
1768f794055SNathan Scott }
1778f794055SNathan Scott 
1788f794055SNathan Scott STATIC uint
1798f794055SNathan Scott xfs_calc_attrrm_reservation(xfs_mount_t *mp)
1808f794055SNathan Scott {
1818f794055SNathan Scott 	return XFS_CALC_ATTRRM_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
1828f794055SNathan Scott }
1838f794055SNathan Scott 
1848f794055SNathan Scott STATIC uint
1858f794055SNathan Scott xfs_calc_clear_agi_bucket_reservation(xfs_mount_t *mp)
1868f794055SNathan Scott {
1878f794055SNathan Scott 	return XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp);
1888f794055SNathan Scott }
1898f794055SNathan Scott 
1908f794055SNathan Scott /*
1911da177e4SLinus Torvalds  * Initialize the precomputed transaction reservation values
1921da177e4SLinus Torvalds  * in the mount structure.
1931da177e4SLinus Torvalds  */
1941da177e4SLinus Torvalds void
1951da177e4SLinus Torvalds xfs_trans_init(
1961da177e4SLinus Torvalds 	xfs_mount_t	*mp)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds 	xfs_trans_reservations_t	*resp;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	resp = &(mp->m_reservations);
2018f794055SNathan Scott 	resp->tr_write = xfs_calc_write_reservation(mp);
2028f794055SNathan Scott 	resp->tr_itruncate = xfs_calc_itruncate_reservation(mp);
2038f794055SNathan Scott 	resp->tr_rename = xfs_calc_rename_reservation(mp);
2048f794055SNathan Scott 	resp->tr_link = xfs_calc_link_reservation(mp);
2058f794055SNathan Scott 	resp->tr_remove = xfs_calc_remove_reservation(mp);
2068f794055SNathan Scott 	resp->tr_symlink = xfs_calc_symlink_reservation(mp);
2078f794055SNathan Scott 	resp->tr_create = xfs_calc_create_reservation(mp);
2088f794055SNathan Scott 	resp->tr_mkdir = xfs_calc_mkdir_reservation(mp);
2098f794055SNathan Scott 	resp->tr_ifree = xfs_calc_ifree_reservation(mp);
2108f794055SNathan Scott 	resp->tr_ichange = xfs_calc_ichange_reservation(mp);
2118f794055SNathan Scott 	resp->tr_growdata = xfs_calc_growdata_reservation(mp);
2128f794055SNathan Scott 	resp->tr_swrite = xfs_calc_swrite_reservation(mp);
2138f794055SNathan Scott 	resp->tr_writeid = xfs_calc_writeid_reservation(mp);
2148f794055SNathan Scott 	resp->tr_addafork = xfs_calc_addafork_reservation(mp);
2158f794055SNathan Scott 	resp->tr_attrinval = xfs_calc_attrinval_reservation(mp);
2168f794055SNathan Scott 	resp->tr_attrset = xfs_calc_attrset_reservation(mp);
2178f794055SNathan Scott 	resp->tr_attrrm = xfs_calc_attrrm_reservation(mp);
2188f794055SNathan Scott 	resp->tr_clearagi = xfs_calc_clear_agi_bucket_reservation(mp);
2198f794055SNathan Scott 	resp->tr_growrtalloc = xfs_calc_growrtalloc_reservation(mp);
2208f794055SNathan Scott 	resp->tr_growrtzero = xfs_calc_growrtzero_reservation(mp);
2218f794055SNathan Scott 	resp->tr_growrtfree = xfs_calc_growrtfree_reservation(mp);
2221da177e4SLinus Torvalds }
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds /*
2251da177e4SLinus Torvalds  * This routine is called to allocate a transaction structure.
2261da177e4SLinus Torvalds  * The type parameter indicates the type of the transaction.  These
2271da177e4SLinus Torvalds  * are enumerated in xfs_trans.h.
2281da177e4SLinus Torvalds  *
2291da177e4SLinus Torvalds  * Dynamically allocate the transaction structure from the transaction
2301da177e4SLinus Torvalds  * zone, initialize it, and return it to the caller.
2311da177e4SLinus Torvalds  */
2321da177e4SLinus Torvalds xfs_trans_t *
2331da177e4SLinus Torvalds xfs_trans_alloc(
2341da177e4SLinus Torvalds 	xfs_mount_t	*mp,
2351da177e4SLinus Torvalds 	uint		type)
2361da177e4SLinus Torvalds {
23734327e13SNathan Scott 	vfs_wait_for_freeze(XFS_MTOVFS(mp), SB_FREEZE_TRANS);
23834327e13SNathan Scott 	return _xfs_trans_alloc(mp, type);
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds xfs_trans_t *
2421da177e4SLinus Torvalds _xfs_trans_alloc(
2431da177e4SLinus Torvalds 	xfs_mount_t	*mp,
2441da177e4SLinus Torvalds 	uint		type)
2451da177e4SLinus Torvalds {
2461da177e4SLinus Torvalds 	xfs_trans_t	*tp;
2471da177e4SLinus Torvalds 
24834327e13SNathan Scott 	atomic_inc(&mp->m_active_trans);
2491da177e4SLinus Torvalds 
25034327e13SNathan Scott 	tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);
2511da177e4SLinus Torvalds 	tp->t_magic = XFS_TRANS_MAGIC;
2521da177e4SLinus Torvalds 	tp->t_type = type;
2531da177e4SLinus Torvalds 	tp->t_mountp = mp;
2541da177e4SLinus Torvalds 	tp->t_items_free = XFS_LIC_NUM_SLOTS;
2551da177e4SLinus Torvalds 	tp->t_busy_free = XFS_LBC_NUM_SLOTS;
2561da177e4SLinus Torvalds 	XFS_LIC_INIT(&(tp->t_items));
2571da177e4SLinus Torvalds 	XFS_LBC_INIT(&(tp->t_busy));
25834327e13SNathan Scott 	return tp;
2591da177e4SLinus Torvalds }
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds /*
2621da177e4SLinus Torvalds  * This is called to create a new transaction which will share the
2631da177e4SLinus Torvalds  * permanent log reservation of the given transaction.  The remaining
2641da177e4SLinus Torvalds  * unused block and rt extent reservations are also inherited.  This
2651da177e4SLinus Torvalds  * implies that the original transaction is no longer allowed to allocate
2661da177e4SLinus Torvalds  * blocks.  Locks and log items, however, are no inherited.  They must
2671da177e4SLinus Torvalds  * be added to the new transaction explicitly.
2681da177e4SLinus Torvalds  */
2691da177e4SLinus Torvalds xfs_trans_t *
2701da177e4SLinus Torvalds xfs_trans_dup(
2711da177e4SLinus Torvalds 	xfs_trans_t	*tp)
2721da177e4SLinus Torvalds {
2731da177e4SLinus Torvalds 	xfs_trans_t	*ntp;
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds 	ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 	/*
2781da177e4SLinus Torvalds 	 * Initialize the new transaction structure.
2791da177e4SLinus Torvalds 	 */
2801da177e4SLinus Torvalds 	ntp->t_magic = XFS_TRANS_MAGIC;
2811da177e4SLinus Torvalds 	ntp->t_type = tp->t_type;
2821da177e4SLinus Torvalds 	ntp->t_mountp = tp->t_mountp;
2831da177e4SLinus Torvalds 	ntp->t_items_free = XFS_LIC_NUM_SLOTS;
2841da177e4SLinus Torvalds 	ntp->t_busy_free = XFS_LBC_NUM_SLOTS;
2851da177e4SLinus Torvalds 	XFS_LIC_INIT(&(ntp->t_items));
2861da177e4SLinus Torvalds 	XFS_LBC_INIT(&(ntp->t_busy));
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
2891da177e4SLinus Torvalds 	ASSERT(tp->t_ticket != NULL);
290cfcbbbd0SNathan Scott 
2911da177e4SLinus Torvalds 	ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE);
2921da177e4SLinus Torvalds 	ntp->t_ticket = tp->t_ticket;
2931da177e4SLinus Torvalds 	ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used;
2941da177e4SLinus Torvalds 	tp->t_blk_res = tp->t_blk_res_used;
2951da177e4SLinus Torvalds 	ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
2961da177e4SLinus Torvalds 	tp->t_rtx_res = tp->t_rtx_res_used;
29759c1b082SNathan Scott 	ntp->t_pflags = tp->t_pflags;
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds 	XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp);
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 	atomic_inc(&tp->t_mountp->m_active_trans);
3021da177e4SLinus Torvalds 	return ntp;
3031da177e4SLinus Torvalds }
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds /*
3061da177e4SLinus Torvalds  * This is called to reserve free disk blocks and log space for the
3071da177e4SLinus Torvalds  * given transaction.  This must be done before allocating any resources
3081da177e4SLinus Torvalds  * within the transaction.
3091da177e4SLinus Torvalds  *
3101da177e4SLinus Torvalds  * This will return ENOSPC if there are not enough blocks available.
3111da177e4SLinus Torvalds  * It will sleep waiting for available log space.
3121da177e4SLinus Torvalds  * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which
3131da177e4SLinus Torvalds  * is used by long running transactions.  If any one of the reservations
3141da177e4SLinus Torvalds  * fails then they will all be backed out.
3151da177e4SLinus Torvalds  *
3161da177e4SLinus Torvalds  * This does not do quota reservations. That typically is done by the
3171da177e4SLinus Torvalds  * caller afterwards.
3181da177e4SLinus Torvalds  */
3191da177e4SLinus Torvalds int
3201da177e4SLinus Torvalds xfs_trans_reserve(
3211da177e4SLinus Torvalds 	xfs_trans_t	*tp,
3221da177e4SLinus Torvalds 	uint		blocks,
3231da177e4SLinus Torvalds 	uint		logspace,
3241da177e4SLinus Torvalds 	uint		rtextents,
3251da177e4SLinus Torvalds 	uint		flags,
3261da177e4SLinus Torvalds 	uint		logcount)
3271da177e4SLinus Torvalds {
3281da177e4SLinus Torvalds 	int		log_flags;
32959c1b082SNathan Scott 	int		error = 0;
33059c1b082SNathan Scott 	int		rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
3311da177e4SLinus Torvalds 
3321da177e4SLinus Torvalds 	/* Mark this thread as being in a transaction */
33359c1b082SNathan Scott 	current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	/*
3361da177e4SLinus Torvalds 	 * Attempt to reserve the needed disk blocks by decrementing
3371da177e4SLinus Torvalds 	 * the number needed from the number available.  This will
3381da177e4SLinus Torvalds 	 * fail if the count would go below zero.
3391da177e4SLinus Torvalds 	 */
3401da177e4SLinus Torvalds 	if (blocks > 0) {
3411da177e4SLinus Torvalds 		error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
34220f4ebf2SDavid Chinner 					  -((int64_t)blocks), rsvd);
3431da177e4SLinus Torvalds 		if (error != 0) {
34459c1b082SNathan Scott 			current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
3451da177e4SLinus Torvalds 			return (XFS_ERROR(ENOSPC));
3461da177e4SLinus Torvalds 		}
3471da177e4SLinus Torvalds 		tp->t_blk_res += blocks;
3481da177e4SLinus Torvalds 	}
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	/*
3511da177e4SLinus Torvalds 	 * Reserve the log space needed for this transaction.
3521da177e4SLinus Torvalds 	 */
3531da177e4SLinus Torvalds 	if (logspace > 0) {
3541da177e4SLinus Torvalds 		ASSERT((tp->t_log_res == 0) || (tp->t_log_res == logspace));
3551da177e4SLinus Torvalds 		ASSERT((tp->t_log_count == 0) ||
3561da177e4SLinus Torvalds 			(tp->t_log_count == logcount));
3571da177e4SLinus Torvalds 		if (flags & XFS_TRANS_PERM_LOG_RES) {
3581da177e4SLinus Torvalds 			log_flags = XFS_LOG_PERM_RESERV;
3591da177e4SLinus Torvalds 			tp->t_flags |= XFS_TRANS_PERM_LOG_RES;
3601da177e4SLinus Torvalds 		} else {
3611da177e4SLinus Torvalds 			ASSERT(tp->t_ticket == NULL);
3621da177e4SLinus Torvalds 			ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES));
3631da177e4SLinus Torvalds 			log_flags = 0;
3641da177e4SLinus Torvalds 		}
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds 		error = xfs_log_reserve(tp->t_mountp, logspace, logcount,
3671da177e4SLinus Torvalds 					&tp->t_ticket,
3687e9c6396STim Shimmin 					XFS_TRANSACTION, log_flags, tp->t_type);
3691da177e4SLinus Torvalds 		if (error) {
3701da177e4SLinus Torvalds 			goto undo_blocks;
3711da177e4SLinus Torvalds 		}
3721da177e4SLinus Torvalds 		tp->t_log_res = logspace;
3731da177e4SLinus Torvalds 		tp->t_log_count = logcount;
3741da177e4SLinus Torvalds 	}
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 	/*
3771da177e4SLinus Torvalds 	 * Attempt to reserve the needed realtime extents by decrementing
3781da177e4SLinus Torvalds 	 * the number needed from the number available.  This will
3791da177e4SLinus Torvalds 	 * fail if the count would go below zero.
3801da177e4SLinus Torvalds 	 */
3811da177e4SLinus Torvalds 	if (rtextents > 0) {
3821da177e4SLinus Torvalds 		error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FREXTENTS,
38320f4ebf2SDavid Chinner 					  -((int64_t)rtextents), rsvd);
3841da177e4SLinus Torvalds 		if (error) {
3851da177e4SLinus Torvalds 			error = XFS_ERROR(ENOSPC);
3861da177e4SLinus Torvalds 			goto undo_log;
3871da177e4SLinus Torvalds 		}
3881da177e4SLinus Torvalds 		tp->t_rtx_res += rtextents;
3891da177e4SLinus Torvalds 	}
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 	return 0;
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	/*
3941da177e4SLinus Torvalds 	 * Error cases jump to one of these labels to undo any
3951da177e4SLinus Torvalds 	 * reservations which have already been performed.
3961da177e4SLinus Torvalds 	 */
3971da177e4SLinus Torvalds undo_log:
3981da177e4SLinus Torvalds 	if (logspace > 0) {
3991da177e4SLinus Torvalds 		if (flags & XFS_TRANS_PERM_LOG_RES) {
4001da177e4SLinus Torvalds 			log_flags = XFS_LOG_REL_PERM_RESERV;
4011da177e4SLinus Torvalds 		} else {
4021da177e4SLinus Torvalds 			log_flags = 0;
4031da177e4SLinus Torvalds 		}
4041da177e4SLinus Torvalds 		xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, log_flags);
4051da177e4SLinus Torvalds 		tp->t_ticket = NULL;
4061da177e4SLinus Torvalds 		tp->t_log_res = 0;
4071da177e4SLinus Torvalds 		tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES;
4081da177e4SLinus Torvalds 	}
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds undo_blocks:
4111da177e4SLinus Torvalds 	if (blocks > 0) {
4121da177e4SLinus Torvalds 		(void) xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
41320f4ebf2SDavid Chinner 					 (int64_t)blocks, rsvd);
4141da177e4SLinus Torvalds 		tp->t_blk_res = 0;
4151da177e4SLinus Torvalds 	}
4161da177e4SLinus Torvalds 
41759c1b082SNathan Scott 	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
4181da177e4SLinus Torvalds 
41959c1b082SNathan Scott 	return error;
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds /*
4241da177e4SLinus Torvalds  * Record the indicated change to the given field for application
4251da177e4SLinus Torvalds  * to the file system's superblock when the transaction commits.
4261da177e4SLinus Torvalds  * For now, just store the change in the transaction structure.
4271da177e4SLinus Torvalds  *
4281da177e4SLinus Torvalds  * Mark the transaction structure to indicate that the superblock
4291da177e4SLinus Torvalds  * needs to be updated before committing.
43092821e2bSDavid Chinner  *
43192821e2bSDavid Chinner  * Because we may not be keeping track of allocated/free inodes and
43292821e2bSDavid Chinner  * used filesystem blocks in the superblock, we do not mark the
43392821e2bSDavid Chinner  * superblock dirty in this transaction if we modify these fields.
43492821e2bSDavid Chinner  * We still need to update the transaction deltas so that they get
43592821e2bSDavid Chinner  * applied to the incore superblock, but we don't want them to
43692821e2bSDavid Chinner  * cause the superblock to get locked and logged if these are the
43792821e2bSDavid Chinner  * only fields in the superblock that the transaction modifies.
4381da177e4SLinus Torvalds  */
4391da177e4SLinus Torvalds void
4401da177e4SLinus Torvalds xfs_trans_mod_sb(
4411da177e4SLinus Torvalds 	xfs_trans_t	*tp,
4421da177e4SLinus Torvalds 	uint		field,
44320f4ebf2SDavid Chinner 	int64_t		delta)
4441da177e4SLinus Torvalds {
44592821e2bSDavid Chinner 	uint32_t	flags = (XFS_TRANS_DIRTY|XFS_TRANS_SB_DIRTY);
44692821e2bSDavid Chinner 	xfs_mount_t	*mp = tp->t_mountp;
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 	switch (field) {
4491da177e4SLinus Torvalds 	case XFS_TRANS_SB_ICOUNT:
4501da177e4SLinus Torvalds 		tp->t_icount_delta += delta;
45192821e2bSDavid Chinner 		if (xfs_sb_version_haslazysbcount(&mp->m_sb))
45292821e2bSDavid Chinner 			flags &= ~XFS_TRANS_SB_DIRTY;
4531da177e4SLinus Torvalds 		break;
4541da177e4SLinus Torvalds 	case XFS_TRANS_SB_IFREE:
4551da177e4SLinus Torvalds 		tp->t_ifree_delta += delta;
45692821e2bSDavid Chinner 		if (xfs_sb_version_haslazysbcount(&mp->m_sb))
45792821e2bSDavid Chinner 			flags &= ~XFS_TRANS_SB_DIRTY;
4581da177e4SLinus Torvalds 		break;
4591da177e4SLinus Torvalds 	case XFS_TRANS_SB_FDBLOCKS:
4601da177e4SLinus Torvalds 		/*
4611da177e4SLinus Torvalds 		 * Track the number of blocks allocated in the
4621da177e4SLinus Torvalds 		 * transaction.  Make sure it does not exceed the
4631da177e4SLinus Torvalds 		 * number reserved.
4641da177e4SLinus Torvalds 		 */
4651da177e4SLinus Torvalds 		if (delta < 0) {
4661da177e4SLinus Torvalds 			tp->t_blk_res_used += (uint)-delta;
4671da177e4SLinus Torvalds 			ASSERT(tp->t_blk_res_used <= tp->t_blk_res);
4681da177e4SLinus Torvalds 		}
4691da177e4SLinus Torvalds 		tp->t_fdblocks_delta += delta;
47092821e2bSDavid Chinner 		if (xfs_sb_version_haslazysbcount(&mp->m_sb))
47192821e2bSDavid Chinner 			flags &= ~XFS_TRANS_SB_DIRTY;
4721da177e4SLinus Torvalds 		break;
4731da177e4SLinus Torvalds 	case XFS_TRANS_SB_RES_FDBLOCKS:
4741da177e4SLinus Torvalds 		/*
4751da177e4SLinus Torvalds 		 * The allocation has already been applied to the
4761da177e4SLinus Torvalds 		 * in-core superblock's counter.  This should only
4771da177e4SLinus Torvalds 		 * be applied to the on-disk superblock.
4781da177e4SLinus Torvalds 		 */
4791da177e4SLinus Torvalds 		ASSERT(delta < 0);
4801da177e4SLinus Torvalds 		tp->t_res_fdblocks_delta += delta;
48192821e2bSDavid Chinner 		if (xfs_sb_version_haslazysbcount(&mp->m_sb))
48292821e2bSDavid Chinner 			flags &= ~XFS_TRANS_SB_DIRTY;
4831da177e4SLinus Torvalds 		break;
4841da177e4SLinus Torvalds 	case XFS_TRANS_SB_FREXTENTS:
4851da177e4SLinus Torvalds 		/*
4861da177e4SLinus Torvalds 		 * Track the number of blocks allocated in the
4871da177e4SLinus Torvalds 		 * transaction.  Make sure it does not exceed the
4881da177e4SLinus Torvalds 		 * number reserved.
4891da177e4SLinus Torvalds 		 */
4901da177e4SLinus Torvalds 		if (delta < 0) {
4911da177e4SLinus Torvalds 			tp->t_rtx_res_used += (uint)-delta;
4921da177e4SLinus Torvalds 			ASSERT(tp->t_rtx_res_used <= tp->t_rtx_res);
4931da177e4SLinus Torvalds 		}
4941da177e4SLinus Torvalds 		tp->t_frextents_delta += delta;
4951da177e4SLinus Torvalds 		break;
4961da177e4SLinus Torvalds 	case XFS_TRANS_SB_RES_FREXTENTS:
4971da177e4SLinus Torvalds 		/*
4981da177e4SLinus Torvalds 		 * The allocation has already been applied to the
499c41564b5SNathan Scott 		 * in-core superblock's counter.  This should only
5001da177e4SLinus Torvalds 		 * be applied to the on-disk superblock.
5011da177e4SLinus Torvalds 		 */
5021da177e4SLinus Torvalds 		ASSERT(delta < 0);
5031da177e4SLinus Torvalds 		tp->t_res_frextents_delta += delta;
5041da177e4SLinus Torvalds 		break;
5051da177e4SLinus Torvalds 	case XFS_TRANS_SB_DBLOCKS:
5061da177e4SLinus Torvalds 		ASSERT(delta > 0);
5071da177e4SLinus Torvalds 		tp->t_dblocks_delta += delta;
5081da177e4SLinus Torvalds 		break;
5091da177e4SLinus Torvalds 	case XFS_TRANS_SB_AGCOUNT:
5101da177e4SLinus Torvalds 		ASSERT(delta > 0);
5111da177e4SLinus Torvalds 		tp->t_agcount_delta += delta;
5121da177e4SLinus Torvalds 		break;
5131da177e4SLinus Torvalds 	case XFS_TRANS_SB_IMAXPCT:
5141da177e4SLinus Torvalds 		tp->t_imaxpct_delta += delta;
5151da177e4SLinus Torvalds 		break;
5161da177e4SLinus Torvalds 	case XFS_TRANS_SB_REXTSIZE:
5171da177e4SLinus Torvalds 		tp->t_rextsize_delta += delta;
5181da177e4SLinus Torvalds 		break;
5191da177e4SLinus Torvalds 	case XFS_TRANS_SB_RBMBLOCKS:
5201da177e4SLinus Torvalds 		tp->t_rbmblocks_delta += delta;
5211da177e4SLinus Torvalds 		break;
5221da177e4SLinus Torvalds 	case XFS_TRANS_SB_RBLOCKS:
5231da177e4SLinus Torvalds 		tp->t_rblocks_delta += delta;
5241da177e4SLinus Torvalds 		break;
5251da177e4SLinus Torvalds 	case XFS_TRANS_SB_REXTENTS:
5261da177e4SLinus Torvalds 		tp->t_rextents_delta += delta;
5271da177e4SLinus Torvalds 		break;
5281da177e4SLinus Torvalds 	case XFS_TRANS_SB_REXTSLOG:
5291da177e4SLinus Torvalds 		tp->t_rextslog_delta += delta;
5301da177e4SLinus Torvalds 		break;
5311da177e4SLinus Torvalds 	default:
5321da177e4SLinus Torvalds 		ASSERT(0);
5331da177e4SLinus Torvalds 		return;
5341da177e4SLinus Torvalds 	}
5351da177e4SLinus Torvalds 
536210c6f1cSDavid Chinner 	tp->t_flags |= flags;
5371da177e4SLinus Torvalds }
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds /*
5401da177e4SLinus Torvalds  * xfs_trans_apply_sb_deltas() is called from the commit code
5411da177e4SLinus Torvalds  * to bring the superblock buffer into the current transaction
5421da177e4SLinus Torvalds  * and modify it as requested by earlier calls to xfs_trans_mod_sb().
5431da177e4SLinus Torvalds  *
5441da177e4SLinus Torvalds  * For now we just look at each field allowed to change and change
5451da177e4SLinus Torvalds  * it if necessary.
5461da177e4SLinus Torvalds  */
5471da177e4SLinus Torvalds STATIC void
5481da177e4SLinus Torvalds xfs_trans_apply_sb_deltas(
5491da177e4SLinus Torvalds 	xfs_trans_t	*tp)
5501da177e4SLinus Torvalds {
551*2bdf7cd0SChristoph Hellwig 	xfs_dsb_t	*sbp;
5521da177e4SLinus Torvalds 	xfs_buf_t	*bp;
5531da177e4SLinus Torvalds 	int		whole = 0;
5541da177e4SLinus Torvalds 
5551da177e4SLinus Torvalds 	bp = xfs_trans_getsb(tp, tp->t_mountp, 0);
5561da177e4SLinus Torvalds 	sbp = XFS_BUF_TO_SBP(bp);
5571da177e4SLinus Torvalds 
5581da177e4SLinus Torvalds 	/*
5591da177e4SLinus Torvalds 	 * Check that superblock mods match the mods made to AGF counters.
5601da177e4SLinus Torvalds 	 */
5611da177e4SLinus Torvalds 	ASSERT((tp->t_fdblocks_delta + tp->t_res_fdblocks_delta) ==
5621da177e4SLinus Torvalds 	       (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta +
5631da177e4SLinus Torvalds 		tp->t_ag_btree_delta));
5641da177e4SLinus Torvalds 
56592821e2bSDavid Chinner 	/*
56692821e2bSDavid Chinner 	 * Only update the superblock counters if we are logging them
56792821e2bSDavid Chinner 	 */
56892821e2bSDavid Chinner 	if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) {
569*2bdf7cd0SChristoph Hellwig 		if (tp->t_icount_delta)
570*2bdf7cd0SChristoph Hellwig 			be64_add(&sbp->sb_icount, tp->t_icount_delta);
571*2bdf7cd0SChristoph Hellwig 		if (tp->t_ifree_delta)
572*2bdf7cd0SChristoph Hellwig 			be64_add(&sbp->sb_ifree, tp->t_ifree_delta);
573*2bdf7cd0SChristoph Hellwig 		if (tp->t_fdblocks_delta)
574*2bdf7cd0SChristoph Hellwig 			be64_add(&sbp->sb_fdblocks, tp->t_fdblocks_delta);
575*2bdf7cd0SChristoph Hellwig 		if (tp->t_res_fdblocks_delta)
576*2bdf7cd0SChristoph Hellwig 			be64_add(&sbp->sb_fdblocks, tp->t_res_fdblocks_delta);
5771da177e4SLinus Torvalds 	}
5781da177e4SLinus Torvalds 
579*2bdf7cd0SChristoph Hellwig 	if (tp->t_frextents_delta)
580*2bdf7cd0SChristoph Hellwig 		be64_add(&sbp->sb_frextents, tp->t_frextents_delta);
581*2bdf7cd0SChristoph Hellwig 	if (tp->t_res_frextents_delta)
582*2bdf7cd0SChristoph Hellwig 		be64_add(&sbp->sb_frextents, tp->t_res_frextents_delta);
5831da177e4SLinus Torvalds 
584*2bdf7cd0SChristoph Hellwig 	if (tp->t_dblocks_delta) {
585*2bdf7cd0SChristoph Hellwig 		be64_add(&sbp->sb_dblocks, tp->t_dblocks_delta);
5861da177e4SLinus Torvalds 		whole = 1;
5871da177e4SLinus Torvalds 	}
588*2bdf7cd0SChristoph Hellwig 	if (tp->t_agcount_delta) {
589*2bdf7cd0SChristoph Hellwig 		be32_add(&sbp->sb_agcount, tp->t_agcount_delta);
5901da177e4SLinus Torvalds 		whole = 1;
5911da177e4SLinus Torvalds 	}
592*2bdf7cd0SChristoph Hellwig 	if (tp->t_imaxpct_delta) {
593*2bdf7cd0SChristoph Hellwig 		sbp->sb_imax_pct += tp->t_imaxpct_delta;
5941da177e4SLinus Torvalds 		whole = 1;
5951da177e4SLinus Torvalds 	}
596*2bdf7cd0SChristoph Hellwig 	if (tp->t_rextsize_delta) {
597*2bdf7cd0SChristoph Hellwig 		be32_add(&sbp->sb_rextsize, tp->t_rextsize_delta);
5981da177e4SLinus Torvalds 		whole = 1;
5991da177e4SLinus Torvalds 	}
600*2bdf7cd0SChristoph Hellwig 	if (tp->t_rbmblocks_delta) {
601*2bdf7cd0SChristoph Hellwig 		be32_add(&sbp->sb_rbmblocks, tp->t_rbmblocks_delta);
6021da177e4SLinus Torvalds 		whole = 1;
6031da177e4SLinus Torvalds 	}
604*2bdf7cd0SChristoph Hellwig 	if (tp->t_rblocks_delta) {
605*2bdf7cd0SChristoph Hellwig 		be64_add(&sbp->sb_rblocks, tp->t_rblocks_delta);
6061da177e4SLinus Torvalds 		whole = 1;
6071da177e4SLinus Torvalds 	}
608*2bdf7cd0SChristoph Hellwig 	if (tp->t_rextents_delta) {
609*2bdf7cd0SChristoph Hellwig 		be64_add(&sbp->sb_rextents, tp->t_rextents_delta);
6101da177e4SLinus Torvalds 		whole = 1;
6111da177e4SLinus Torvalds 	}
612*2bdf7cd0SChristoph Hellwig 	if (tp->t_rextslog_delta) {
613*2bdf7cd0SChristoph Hellwig 		sbp->sb_rextslog += tp->t_rextslog_delta;
6141da177e4SLinus Torvalds 		whole = 1;
6151da177e4SLinus Torvalds 	}
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds 	if (whole)
6181da177e4SLinus Torvalds 		/*
619c41564b5SNathan Scott 		 * Log the whole thing, the fields are noncontiguous.
6201da177e4SLinus Torvalds 		 */
621*2bdf7cd0SChristoph Hellwig 		xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_dsb_t) - 1);
6221da177e4SLinus Torvalds 	else
6231da177e4SLinus Torvalds 		/*
6241da177e4SLinus Torvalds 		 * Since all the modifiable fields are contiguous, we
6251da177e4SLinus Torvalds 		 * can get away with this.
6261da177e4SLinus Torvalds 		 */
627*2bdf7cd0SChristoph Hellwig 		xfs_trans_log_buf(tp, bp, offsetof(xfs_dsb_t, sb_icount),
628*2bdf7cd0SChristoph Hellwig 				  offsetof(xfs_dsb_t, sb_frextents) +
6291da177e4SLinus Torvalds 				  sizeof(sbp->sb_frextents) - 1);
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	XFS_MTOVFS(tp->t_mountp)->vfs_super->s_dirt = 1;
6321da177e4SLinus Torvalds }
6331da177e4SLinus Torvalds 
6341da177e4SLinus Torvalds /*
63545c34141SDavid Chinner  * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations
63645c34141SDavid Chinner  * and apply superblock counter changes to the in-core superblock.  The
63745c34141SDavid Chinner  * t_res_fdblocks_delta and t_res_frextents_delta fields are explicitly NOT
63845c34141SDavid Chinner  * applied to the in-core superblock.  The idea is that that has already been
63945c34141SDavid Chinner  * done.
6401da177e4SLinus Torvalds  *
6411da177e4SLinus Torvalds  * This is done efficiently with a single call to xfs_mod_incore_sb_batch().
64245c34141SDavid Chinner  * However, we have to ensure that we only modify each superblock field only
64345c34141SDavid Chinner  * once because the application of the delta values may not be atomic. That can
64445c34141SDavid Chinner  * lead to ENOSPC races occurring if we have two separate modifcations of the
64545c34141SDavid Chinner  * free space counter to put back the entire reservation and then take away
64645c34141SDavid Chinner  * what we used.
64745c34141SDavid Chinner  *
64845c34141SDavid Chinner  * If we are not logging superblock counters, then the inode allocated/free and
64945c34141SDavid Chinner  * used block counts are not updated in the on disk superblock. In this case,
65045c34141SDavid Chinner  * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we
65145c34141SDavid Chinner  * still need to update the incore superblock with the changes.
6521da177e4SLinus Torvalds  */
653ba0f32d4SChristoph Hellwig STATIC void
6541da177e4SLinus Torvalds xfs_trans_unreserve_and_mod_sb(
6551da177e4SLinus Torvalds 	xfs_trans_t	*tp)
6561da177e4SLinus Torvalds {
6571da177e4SLinus Torvalds 	xfs_mod_sb_t	msb[14];	/* If you add cases, add entries */
6581da177e4SLinus Torvalds 	xfs_mod_sb_t	*msbp;
65992821e2bSDavid Chinner 	xfs_mount_t	*mp = tp->t_mountp;
6601da177e4SLinus Torvalds 	/* REFERENCED */
6611da177e4SLinus Torvalds 	int		error;
6621da177e4SLinus Torvalds 	int		rsvd;
66345c34141SDavid Chinner 	int64_t		blkdelta = 0;
66445c34141SDavid Chinner 	int64_t		rtxdelta = 0;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	msbp = msb;
6671da177e4SLinus Torvalds 	rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
6681da177e4SLinus Torvalds 
66945c34141SDavid Chinner 	/* calculate free blocks delta */
67045c34141SDavid Chinner 	if (tp->t_blk_res > 0)
67145c34141SDavid Chinner 		blkdelta = tp->t_blk_res;
67245c34141SDavid Chinner 
67345c34141SDavid Chinner 	if ((tp->t_fdblocks_delta != 0) &&
67445c34141SDavid Chinner 	    (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
67545c34141SDavid Chinner 	     (tp->t_flags & XFS_TRANS_SB_DIRTY)))
67645c34141SDavid Chinner 	        blkdelta += tp->t_fdblocks_delta;
67745c34141SDavid Chinner 
67845c34141SDavid Chinner 	if (blkdelta != 0) {
6791da177e4SLinus Torvalds 		msbp->msb_field = XFS_SBS_FDBLOCKS;
68045c34141SDavid Chinner 		msbp->msb_delta = blkdelta;
6811da177e4SLinus Torvalds 		msbp++;
6821da177e4SLinus Torvalds 	}
6831da177e4SLinus Torvalds 
68445c34141SDavid Chinner 	/* calculate free realtime extents delta */
68545c34141SDavid Chinner 	if (tp->t_rtx_res > 0)
68645c34141SDavid Chinner 		rtxdelta = tp->t_rtx_res;
68745c34141SDavid Chinner 
68845c34141SDavid Chinner 	if ((tp->t_frextents_delta != 0) &&
68945c34141SDavid Chinner 	    (tp->t_flags & XFS_TRANS_SB_DIRTY))
69045c34141SDavid Chinner 		rtxdelta += tp->t_frextents_delta;
69145c34141SDavid Chinner 
69245c34141SDavid Chinner 	if (rtxdelta != 0) {
6931da177e4SLinus Torvalds 		msbp->msb_field = XFS_SBS_FREXTENTS;
69445c34141SDavid Chinner 		msbp->msb_delta = rtxdelta;
6951da177e4SLinus Torvalds 		msbp++;
6961da177e4SLinus Torvalds 	}
6971da177e4SLinus Torvalds 
69845c34141SDavid Chinner 	/* apply remaining deltas */
69945c34141SDavid Chinner 
70092821e2bSDavid Chinner 	if (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
70192821e2bSDavid Chinner 	     (tp->t_flags & XFS_TRANS_SB_DIRTY)) {
7021da177e4SLinus Torvalds 		if (tp->t_icount_delta != 0) {
7031da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_ICOUNT;
70420f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_icount_delta;
7051da177e4SLinus Torvalds 			msbp++;
7061da177e4SLinus Torvalds 		}
7071da177e4SLinus Torvalds 		if (tp->t_ifree_delta != 0) {
7081da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_IFREE;
70920f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_ifree_delta;
7101da177e4SLinus Torvalds 			msbp++;
7111da177e4SLinus Torvalds 		}
71292821e2bSDavid Chinner 	}
71392821e2bSDavid Chinner 
71492821e2bSDavid Chinner 	if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
7151da177e4SLinus Torvalds 		if (tp->t_dblocks_delta != 0) {
7161da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_DBLOCKS;
71720f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_dblocks_delta;
7181da177e4SLinus Torvalds 			msbp++;
7191da177e4SLinus Torvalds 		}
7201da177e4SLinus Torvalds 		if (tp->t_agcount_delta != 0) {
7211da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_AGCOUNT;
72220f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_agcount_delta;
7231da177e4SLinus Torvalds 			msbp++;
7241da177e4SLinus Torvalds 		}
7251da177e4SLinus Torvalds 		if (tp->t_imaxpct_delta != 0) {
7261da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_IMAX_PCT;
72720f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_imaxpct_delta;
7281da177e4SLinus Torvalds 			msbp++;
7291da177e4SLinus Torvalds 		}
7301da177e4SLinus Torvalds 		if (tp->t_rextsize_delta != 0) {
7311da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_REXTSIZE;
73220f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_rextsize_delta;
7331da177e4SLinus Torvalds 			msbp++;
7341da177e4SLinus Torvalds 		}
7351da177e4SLinus Torvalds 		if (tp->t_rbmblocks_delta != 0) {
7361da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_RBMBLOCKS;
73720f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_rbmblocks_delta;
7381da177e4SLinus Torvalds 			msbp++;
7391da177e4SLinus Torvalds 		}
7401da177e4SLinus Torvalds 		if (tp->t_rblocks_delta != 0) {
7411da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_RBLOCKS;
74220f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_rblocks_delta;
7431da177e4SLinus Torvalds 			msbp++;
7441da177e4SLinus Torvalds 		}
7451da177e4SLinus Torvalds 		if (tp->t_rextents_delta != 0) {
7461da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_REXTENTS;
74720f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_rextents_delta;
7481da177e4SLinus Torvalds 			msbp++;
7491da177e4SLinus Torvalds 		}
7501da177e4SLinus Torvalds 		if (tp->t_rextslog_delta != 0) {
7511da177e4SLinus Torvalds 			msbp->msb_field = XFS_SBS_REXTSLOG;
75220f4ebf2SDavid Chinner 			msbp->msb_delta = tp->t_rextslog_delta;
7531da177e4SLinus Torvalds 			msbp++;
7541da177e4SLinus Torvalds 		}
7551da177e4SLinus Torvalds 	}
7561da177e4SLinus Torvalds 
7571da177e4SLinus Torvalds 	/*
7581da177e4SLinus Torvalds 	 * If we need to change anything, do it.
7591da177e4SLinus Torvalds 	 */
7601da177e4SLinus Torvalds 	if (msbp > msb) {
7611da177e4SLinus Torvalds 		error = xfs_mod_incore_sb_batch(tp->t_mountp, msb,
7621da177e4SLinus Torvalds 			(uint)(msbp - msb), rsvd);
7631da177e4SLinus Torvalds 		ASSERT(error == 0);
7641da177e4SLinus Torvalds 	}
7651da177e4SLinus Torvalds }
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds /*
7691da177e4SLinus Torvalds  * xfs_trans_commit
7701da177e4SLinus Torvalds  *
7711da177e4SLinus Torvalds  * Commit the given transaction to the log a/synchronously.
7721da177e4SLinus Torvalds  *
7731da177e4SLinus Torvalds  * XFS disk error handling mechanism is not based on a typical
7741da177e4SLinus Torvalds  * transaction abort mechanism. Logically after the filesystem
7751da177e4SLinus Torvalds  * gets marked 'SHUTDOWN', we can't let any new transactions
7761da177e4SLinus Torvalds  * be durable - ie. committed to disk - because some metadata might
7771da177e4SLinus Torvalds  * be inconsistent. In such cases, this returns an error, and the
7781da177e4SLinus Torvalds  * caller may assume that all locked objects joined to the transaction
7791da177e4SLinus Torvalds  * have already been unlocked as if the commit had succeeded.
7801da177e4SLinus Torvalds  * Do not reference the transaction structure after this call.
7811da177e4SLinus Torvalds  */
7821da177e4SLinus Torvalds  /*ARGSUSED*/
7831da177e4SLinus Torvalds int
784f538d4daSChristoph Hellwig _xfs_trans_commit(
7851da177e4SLinus Torvalds 	xfs_trans_t	*tp,
7861da177e4SLinus Torvalds 	uint		flags,
787f538d4daSChristoph Hellwig 	int		*log_flushed)
7881da177e4SLinus Torvalds {
7891da177e4SLinus Torvalds 	xfs_log_iovec_t		*log_vector;
7901da177e4SLinus Torvalds 	int			nvec;
7911da177e4SLinus Torvalds 	xfs_mount_t		*mp;
7921da177e4SLinus Torvalds 	xfs_lsn_t		commit_lsn;
7931da177e4SLinus Torvalds 	/* REFERENCED */
7941da177e4SLinus Torvalds 	int			error;
7951da177e4SLinus Torvalds 	int			log_flags;
7961da177e4SLinus Torvalds 	int			sync;
7971da177e4SLinus Torvalds #define	XFS_TRANS_LOGVEC_COUNT	16
7981da177e4SLinus Torvalds 	xfs_log_iovec_t		log_vector_fast[XFS_TRANS_LOGVEC_COUNT];
7991da177e4SLinus Torvalds 	void			*commit_iclog;
8001da177e4SLinus Torvalds 	int			shutdown;
8011da177e4SLinus Torvalds 
8021da177e4SLinus Torvalds 	commit_lsn = -1;
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds 	/*
8051da177e4SLinus Torvalds 	 * Determine whether this commit is releasing a permanent
8061da177e4SLinus Torvalds 	 * log reservation or not.
8071da177e4SLinus Torvalds 	 */
8081da177e4SLinus Torvalds 	if (flags & XFS_TRANS_RELEASE_LOG_RES) {
8091da177e4SLinus Torvalds 		ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
8101da177e4SLinus Torvalds 		log_flags = XFS_LOG_REL_PERM_RESERV;
8111da177e4SLinus Torvalds 	} else {
8121da177e4SLinus Torvalds 		log_flags = 0;
8131da177e4SLinus Torvalds 	}
8141da177e4SLinus Torvalds 	mp = tp->t_mountp;
8151da177e4SLinus Torvalds 
8161da177e4SLinus Torvalds 	/*
8171da177e4SLinus Torvalds 	 * If there is nothing to be logged by the transaction,
8181da177e4SLinus Torvalds 	 * then unlock all of the items associated with the
8191da177e4SLinus Torvalds 	 * transaction and free the transaction structure.
8201da177e4SLinus Torvalds 	 * Also make sure to return any reserved blocks to
8211da177e4SLinus Torvalds 	 * the free pool.
8221da177e4SLinus Torvalds 	 */
8231da177e4SLinus Torvalds shut_us_down:
8241da177e4SLinus Torvalds 	shutdown = XFS_FORCED_SHUTDOWN(mp) ? EIO : 0;
8251da177e4SLinus Torvalds 	if (!(tp->t_flags & XFS_TRANS_DIRTY) || shutdown) {
8261da177e4SLinus Torvalds 		xfs_trans_unreserve_and_mod_sb(tp);
8271da177e4SLinus Torvalds 		/*
8281da177e4SLinus Torvalds 		 * It is indeed possible for the transaction to be
8291da177e4SLinus Torvalds 		 * not dirty but the dqinfo portion to be. All that
8301da177e4SLinus Torvalds 		 * means is that we have some (non-persistent) quota
8311da177e4SLinus Torvalds 		 * reservations that need to be unreserved.
8321da177e4SLinus Torvalds 		 */
8331da177e4SLinus Torvalds 		XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
8341da177e4SLinus Torvalds 		if (tp->t_ticket) {
8351da177e4SLinus Torvalds 			commit_lsn = xfs_log_done(mp, tp->t_ticket,
8361da177e4SLinus Torvalds 							NULL, log_flags);
8371da177e4SLinus Torvalds 			if (commit_lsn == -1 && !shutdown)
8381da177e4SLinus Torvalds 				shutdown = XFS_ERROR(EIO);
8391da177e4SLinus Torvalds 		}
84059c1b082SNathan Scott 		current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
8411da177e4SLinus Torvalds 		xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);
8421da177e4SLinus Torvalds 		xfs_trans_free_busy(tp);
8431da177e4SLinus Torvalds 		xfs_trans_free(tp);
8441da177e4SLinus Torvalds 		XFS_STATS_INC(xs_trans_empty);
8451da177e4SLinus Torvalds 		return (shutdown);
8461da177e4SLinus Torvalds 	}
8471da177e4SLinus Torvalds 	ASSERT(tp->t_ticket != NULL);
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds 	/*
8501da177e4SLinus Torvalds 	 * If we need to update the superblock, then do it now.
8511da177e4SLinus Torvalds 	 */
8521da177e4SLinus Torvalds 	if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
8531da177e4SLinus Torvalds 		xfs_trans_apply_sb_deltas(tp);
8541da177e4SLinus Torvalds 	}
8551da177e4SLinus Torvalds 	XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp);
8561da177e4SLinus Torvalds 
8571da177e4SLinus Torvalds 	/*
8581da177e4SLinus Torvalds 	 * Ask each log item how many log_vector entries it will
8591da177e4SLinus Torvalds 	 * need so we can figure out how many to allocate.
8601da177e4SLinus Torvalds 	 * Try to avoid the kmem_alloc() call in the common case
8611da177e4SLinus Torvalds 	 * by using a vector from the stack when it fits.
8621da177e4SLinus Torvalds 	 */
8631da177e4SLinus Torvalds 	nvec = xfs_trans_count_vecs(tp);
8641da177e4SLinus Torvalds 	if (nvec == 0) {
8657d04a335SNathan Scott 		xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
8661da177e4SLinus Torvalds 		goto shut_us_down;
867cfcbbbd0SNathan Scott 	} else if (nvec <= XFS_TRANS_LOGVEC_COUNT) {
8681da177e4SLinus Torvalds 		log_vector = log_vector_fast;
8691da177e4SLinus Torvalds 	} else {
8701da177e4SLinus Torvalds 		log_vector = (xfs_log_iovec_t *)kmem_alloc(nvec *
8711da177e4SLinus Torvalds 						   sizeof(xfs_log_iovec_t),
8721da177e4SLinus Torvalds 						   KM_SLEEP);
8731da177e4SLinus Torvalds 	}
8741da177e4SLinus Torvalds 
8751da177e4SLinus Torvalds 	/*
8761da177e4SLinus Torvalds 	 * Fill in the log_vector and pin the logged items, and
8771da177e4SLinus Torvalds 	 * then write the transaction to the log.
8781da177e4SLinus Torvalds 	 */
8791da177e4SLinus Torvalds 	xfs_trans_fill_vecs(tp, log_vector);
8801da177e4SLinus Torvalds 
881cfcbbbd0SNathan Scott 	error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, &(tp->t_lsn));
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds 	/*
884cfcbbbd0SNathan Scott 	 * The transaction is committed incore here, and can go out to disk
885cfcbbbd0SNathan Scott 	 * at any time after this call.  However, all the items associated
886cfcbbbd0SNathan Scott 	 * with the transaction are still locked and pinned in memory.
8871da177e4SLinus Torvalds 	 */
8881da177e4SLinus Torvalds 	commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags);
8891da177e4SLinus Torvalds 
8901da177e4SLinus Torvalds 	tp->t_commit_lsn = commit_lsn;
8911da177e4SLinus Torvalds 	if (nvec > XFS_TRANS_LOGVEC_COUNT) {
8921da177e4SLinus Torvalds 		kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));
8931da177e4SLinus Torvalds 	}
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds 	/*
8961da177e4SLinus Torvalds 	 * If we got a log write error. Unpin the logitems that we
8971da177e4SLinus Torvalds 	 * had pinned, clean up, free trans structure, and return error.
8981da177e4SLinus Torvalds 	 */
8991da177e4SLinus Torvalds 	if (error || commit_lsn == -1) {
90059c1b082SNathan Scott 		current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
9011da177e4SLinus Torvalds 		xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
9021da177e4SLinus Torvalds 		return XFS_ERROR(EIO);
9031da177e4SLinus Torvalds 	}
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds 	/*
9061da177e4SLinus Torvalds 	 * Once the transaction has committed, unused
9071da177e4SLinus Torvalds 	 * reservations need to be released and changes to
9081da177e4SLinus Torvalds 	 * the superblock need to be reflected in the in-core
9091da177e4SLinus Torvalds 	 * version.  Do that now.
9101da177e4SLinus Torvalds 	 */
9111da177e4SLinus Torvalds 	xfs_trans_unreserve_and_mod_sb(tp);
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds 	sync = tp->t_flags & XFS_TRANS_SYNC;
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds 	/*
9161da177e4SLinus Torvalds 	 * Tell the LM to call the transaction completion routine
9171da177e4SLinus Torvalds 	 * when the log write with LSN commit_lsn completes (e.g.
9181da177e4SLinus Torvalds 	 * when the transaction commit really hits the on-disk log).
9191da177e4SLinus Torvalds 	 * After this call we cannot reference tp, because the call
9201da177e4SLinus Torvalds 	 * can happen at any time and the call will free the transaction
9211da177e4SLinus Torvalds 	 * structure pointed to by tp.  The only case where we call
9221da177e4SLinus Torvalds 	 * the completion routine (xfs_trans_committed) directly is
9231da177e4SLinus Torvalds 	 * if the log is turned off on a debug kernel or we're
9241da177e4SLinus Torvalds 	 * running in simulation mode (the log is explicitly turned
9251da177e4SLinus Torvalds 	 * off).
9261da177e4SLinus Torvalds 	 */
9271da177e4SLinus Torvalds 	tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed;
9281da177e4SLinus Torvalds 	tp->t_logcb.cb_arg = tp;
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 	/*
9311da177e4SLinus Torvalds 	 * We need to pass the iclog buffer which was used for the
9321da177e4SLinus Torvalds 	 * transaction commit record into this function, and attach
9331da177e4SLinus Torvalds 	 * the callback to it. The callback must be attached before
9341da177e4SLinus Torvalds 	 * the items are unlocked to avoid racing with other threads
9351da177e4SLinus Torvalds 	 * waiting for an item to unlock.
9361da177e4SLinus Torvalds 	 */
9371da177e4SLinus Torvalds 	shutdown = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb));
9381da177e4SLinus Torvalds 
9391da177e4SLinus Torvalds 	/*
9401da177e4SLinus Torvalds 	 * Mark this thread as no longer being in a transaction
9411da177e4SLinus Torvalds 	 */
94259c1b082SNathan Scott 	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 	/*
9451da177e4SLinus Torvalds 	 * Once all the items of the transaction have been copied
9461da177e4SLinus Torvalds 	 * to the in core log and the callback is attached, the
9471da177e4SLinus Torvalds 	 * items can be unlocked.
9481da177e4SLinus Torvalds 	 *
9491da177e4SLinus Torvalds 	 * This will free descriptors pointing to items which were
9501da177e4SLinus Torvalds 	 * not logged since there is nothing more to do with them.
9511da177e4SLinus Torvalds 	 * For items which were logged, we will keep pointers to them
9521da177e4SLinus Torvalds 	 * so they can be unpinned after the transaction commits to disk.
9531da177e4SLinus Torvalds 	 * This will also stamp each modified meta-data item with
9541da177e4SLinus Torvalds 	 * the commit lsn of this transaction for dependency tracking
9551da177e4SLinus Torvalds 	 * purposes.
9561da177e4SLinus Torvalds 	 */
9571da177e4SLinus Torvalds 	xfs_trans_unlock_items(tp, commit_lsn);
9581da177e4SLinus Torvalds 
9591da177e4SLinus Torvalds 	/*
9601da177e4SLinus Torvalds 	 * If we detected a log error earlier, finish committing
9611da177e4SLinus Torvalds 	 * the transaction now (unpin log items, etc).
9621da177e4SLinus Torvalds 	 *
9631da177e4SLinus Torvalds 	 * Order is critical here, to avoid using the transaction
9641da177e4SLinus Torvalds 	 * pointer after its been freed (by xfs_trans_committed
9651da177e4SLinus Torvalds 	 * either here now, or as a callback).  We cannot do this
9661da177e4SLinus Torvalds 	 * step inside xfs_log_notify as was done earlier because
9671da177e4SLinus Torvalds 	 * of this issue.
9681da177e4SLinus Torvalds 	 */
9691da177e4SLinus Torvalds 	if (shutdown)
9701da177e4SLinus Torvalds 		xfs_trans_committed(tp, XFS_LI_ABORTED);
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 	/*
9731da177e4SLinus Torvalds 	 * Now that the xfs_trans_committed callback has been attached,
9741da177e4SLinus Torvalds 	 * and the items are released we can finally allow the iclog to
9751da177e4SLinus Torvalds 	 * go to disk.
9761da177e4SLinus Torvalds 	 */
9771da177e4SLinus Torvalds 	error = xfs_log_release_iclog(mp, commit_iclog);
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds 	/*
9801da177e4SLinus Torvalds 	 * If the transaction needs to be synchronous, then force the
9811da177e4SLinus Torvalds 	 * log out now and wait for it.
9821da177e4SLinus Torvalds 	 */
9831da177e4SLinus Torvalds 	if (sync) {
984f538d4daSChristoph Hellwig 		if (!error) {
985f538d4daSChristoph Hellwig 			error = _xfs_log_force(mp, commit_lsn,
986f538d4daSChristoph Hellwig 				      XFS_LOG_FORCE | XFS_LOG_SYNC,
987f538d4daSChristoph Hellwig 				      log_flushed);
988f538d4daSChristoph Hellwig 		}
9891da177e4SLinus Torvalds 		XFS_STATS_INC(xs_trans_sync);
9901da177e4SLinus Torvalds 	} else {
9911da177e4SLinus Torvalds 		XFS_STATS_INC(xs_trans_async);
9921da177e4SLinus Torvalds 	}
9931da177e4SLinus Torvalds 
9941da177e4SLinus Torvalds 	return (error);
9951da177e4SLinus Torvalds }
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds /*
9991da177e4SLinus Torvalds  * Total up the number of log iovecs needed to commit this
10001da177e4SLinus Torvalds  * transaction.  The transaction itself needs one for the
10011da177e4SLinus Torvalds  * transaction header.  Ask each dirty item in turn how many
10021da177e4SLinus Torvalds  * it needs to get the total.
10031da177e4SLinus Torvalds  */
10041da177e4SLinus Torvalds STATIC uint
10051da177e4SLinus Torvalds xfs_trans_count_vecs(
10061da177e4SLinus Torvalds 	xfs_trans_t	*tp)
10071da177e4SLinus Torvalds {
10081da177e4SLinus Torvalds 	int			nvecs;
10091da177e4SLinus Torvalds 	xfs_log_item_desc_t	*lidp;
10101da177e4SLinus Torvalds 
10111da177e4SLinus Torvalds 	nvecs = 1;
10121da177e4SLinus Torvalds 	lidp = xfs_trans_first_item(tp);
10131da177e4SLinus Torvalds 	ASSERT(lidp != NULL);
10141da177e4SLinus Torvalds 
10151da177e4SLinus Torvalds 	/* In the non-debug case we need to start bailing out if we
10161da177e4SLinus Torvalds 	 * didn't find a log_item here, return zero and let trans_commit
10171da177e4SLinus Torvalds 	 * deal with it.
10181da177e4SLinus Torvalds 	 */
10191da177e4SLinus Torvalds 	if (lidp == NULL)
10201da177e4SLinus Torvalds 		return 0;
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds 	while (lidp != NULL) {
10231da177e4SLinus Torvalds 		/*
10241da177e4SLinus Torvalds 		 * Skip items which aren't dirty in this transaction.
10251da177e4SLinus Torvalds 		 */
10261da177e4SLinus Torvalds 		if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
10271da177e4SLinus Torvalds 			lidp = xfs_trans_next_item(tp, lidp);
10281da177e4SLinus Torvalds 			continue;
10291da177e4SLinus Torvalds 		}
10301da177e4SLinus Torvalds 		lidp->lid_size = IOP_SIZE(lidp->lid_item);
10311da177e4SLinus Torvalds 		nvecs += lidp->lid_size;
10321da177e4SLinus Torvalds 		lidp = xfs_trans_next_item(tp, lidp);
10331da177e4SLinus Torvalds 	}
10341da177e4SLinus Torvalds 
10351da177e4SLinus Torvalds 	return nvecs;
10361da177e4SLinus Torvalds }
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds /*
10391da177e4SLinus Torvalds  * Called from the trans_commit code when we notice that
10401da177e4SLinus Torvalds  * the filesystem is in the middle of a forced shutdown.
10411da177e4SLinus Torvalds  */
10421da177e4SLinus Torvalds STATIC void
10431da177e4SLinus Torvalds xfs_trans_uncommit(
10441da177e4SLinus Torvalds 	xfs_trans_t	*tp,
10451da177e4SLinus Torvalds 	uint		flags)
10461da177e4SLinus Torvalds {
10471da177e4SLinus Torvalds 	xfs_log_item_desc_t	*lidp;
10481da177e4SLinus Torvalds 
10491da177e4SLinus Torvalds 	for (lidp = xfs_trans_first_item(tp);
10501da177e4SLinus Torvalds 	     lidp != NULL;
10511da177e4SLinus Torvalds 	     lidp = xfs_trans_next_item(tp, lidp)) {
10521da177e4SLinus Torvalds 		/*
10531da177e4SLinus Torvalds 		 * Unpin all but those that aren't dirty.
10541da177e4SLinus Torvalds 		 */
10551da177e4SLinus Torvalds 		if (lidp->lid_flags & XFS_LID_DIRTY)
10561da177e4SLinus Torvalds 			IOP_UNPIN_REMOVE(lidp->lid_item, tp);
10571da177e4SLinus Torvalds 	}
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 	xfs_trans_unreserve_and_mod_sb(tp);
10601da177e4SLinus Torvalds 	XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds 	xfs_trans_free_items(tp, flags);
10631da177e4SLinus Torvalds 	xfs_trans_free_busy(tp);
10641da177e4SLinus Torvalds 	xfs_trans_free(tp);
10651da177e4SLinus Torvalds }
10661da177e4SLinus Torvalds 
10671da177e4SLinus Torvalds /*
10681da177e4SLinus Torvalds  * Fill in the vector with pointers to data to be logged
10691da177e4SLinus Torvalds  * by this transaction.  The transaction header takes
10701da177e4SLinus Torvalds  * the first vector, and then each dirty item takes the
10711da177e4SLinus Torvalds  * number of vectors it indicated it needed in xfs_trans_count_vecs().
10721da177e4SLinus Torvalds  *
10731da177e4SLinus Torvalds  * As each item fills in the entries it needs, also pin the item
10741da177e4SLinus Torvalds  * so that it cannot be flushed out until the log write completes.
10751da177e4SLinus Torvalds  */
10761da177e4SLinus Torvalds STATIC void
10771da177e4SLinus Torvalds xfs_trans_fill_vecs(
10781da177e4SLinus Torvalds 	xfs_trans_t		*tp,
10791da177e4SLinus Torvalds 	xfs_log_iovec_t		*log_vector)
10801da177e4SLinus Torvalds {
10811da177e4SLinus Torvalds 	xfs_log_item_desc_t	*lidp;
10821da177e4SLinus Torvalds 	xfs_log_iovec_t		*vecp;
10831da177e4SLinus Torvalds 	uint			nitems;
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds 	/*
10861da177e4SLinus Torvalds 	 * Skip over the entry for the transaction header, we'll
10871da177e4SLinus Torvalds 	 * fill that in at the end.
10881da177e4SLinus Torvalds 	 */
10891da177e4SLinus Torvalds 	vecp = log_vector + 1;		/* pointer arithmetic */
10901da177e4SLinus Torvalds 
10911da177e4SLinus Torvalds 	nitems = 0;
10921da177e4SLinus Torvalds 	lidp = xfs_trans_first_item(tp);
10931da177e4SLinus Torvalds 	ASSERT(lidp != NULL);
10941da177e4SLinus Torvalds 	while (lidp != NULL) {
10951da177e4SLinus Torvalds 		/*
10961da177e4SLinus Torvalds 		 * Skip items which aren't dirty in this transaction.
10971da177e4SLinus Torvalds 		 */
10981da177e4SLinus Torvalds 		if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
10991da177e4SLinus Torvalds 			lidp = xfs_trans_next_item(tp, lidp);
11001da177e4SLinus Torvalds 			continue;
11011da177e4SLinus Torvalds 		}
11021da177e4SLinus Torvalds 		/*
11031da177e4SLinus Torvalds 		 * The item may be marked dirty but not log anything.
11041da177e4SLinus Torvalds 		 * This can be used to get called when a transaction
11051da177e4SLinus Torvalds 		 * is committed.
11061da177e4SLinus Torvalds 		 */
11071da177e4SLinus Torvalds 		if (lidp->lid_size) {
11081da177e4SLinus Torvalds 			nitems++;
11091da177e4SLinus Torvalds 		}
11101da177e4SLinus Torvalds 		IOP_FORMAT(lidp->lid_item, vecp);
11111da177e4SLinus Torvalds 		vecp += lidp->lid_size;		/* pointer arithmetic */
11121da177e4SLinus Torvalds 		IOP_PIN(lidp->lid_item);
11131da177e4SLinus Torvalds 		lidp = xfs_trans_next_item(tp, lidp);
11141da177e4SLinus Torvalds 	}
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds 	/*
11171da177e4SLinus Torvalds 	 * Now that we've counted the number of items in this
11181da177e4SLinus Torvalds 	 * transaction, fill in the transaction header.
11191da177e4SLinus Torvalds 	 */
11201da177e4SLinus Torvalds 	tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC;
11211da177e4SLinus Torvalds 	tp->t_header.th_type = tp->t_type;
11221da177e4SLinus Torvalds 	tp->t_header.th_num_items = nitems;
11231da177e4SLinus Torvalds 	log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
11241da177e4SLinus Torvalds 	log_vector->i_len = sizeof(xfs_trans_header_t);
11257e9c6396STim Shimmin 	XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_TRANSHDR);
11261da177e4SLinus Torvalds }
11271da177e4SLinus Torvalds 
11281da177e4SLinus Torvalds 
11291da177e4SLinus Torvalds /*
11301da177e4SLinus Torvalds  * Unlock all of the transaction's items and free the transaction.
11311da177e4SLinus Torvalds  * The transaction must not have modified any of its items, because
11321da177e4SLinus Torvalds  * there is no way to restore them to their previous state.
11331da177e4SLinus Torvalds  *
11341da177e4SLinus Torvalds  * If the transaction has made a log reservation, make sure to release
11351da177e4SLinus Torvalds  * it as well.
11361da177e4SLinus Torvalds  */
11371da177e4SLinus Torvalds void
11381da177e4SLinus Torvalds xfs_trans_cancel(
11391da177e4SLinus Torvalds 	xfs_trans_t		*tp,
11401da177e4SLinus Torvalds 	int			flags)
11411da177e4SLinus Torvalds {
11421da177e4SLinus Torvalds 	int			log_flags;
11431da177e4SLinus Torvalds #ifdef DEBUG
11441da177e4SLinus Torvalds 	xfs_log_item_chunk_t	*licp;
11451da177e4SLinus Torvalds 	xfs_log_item_desc_t	*lidp;
11461da177e4SLinus Torvalds 	xfs_log_item_t		*lip;
11471da177e4SLinus Torvalds 	int			i;
11481da177e4SLinus Torvalds #endif
11490733af21SRyan Hankins 	xfs_mount_t		*mp = tp->t_mountp;
11501da177e4SLinus Torvalds 
11511da177e4SLinus Torvalds 	/*
11521da177e4SLinus Torvalds 	 * See if the caller is being too lazy to figure out if
11531da177e4SLinus Torvalds 	 * the transaction really needs an abort.
11541da177e4SLinus Torvalds 	 */
11551da177e4SLinus Torvalds 	if ((flags & XFS_TRANS_ABORT) && !(tp->t_flags & XFS_TRANS_DIRTY))
11561da177e4SLinus Torvalds 		flags &= ~XFS_TRANS_ABORT;
11571da177e4SLinus Torvalds 	/*
11581da177e4SLinus Torvalds 	 * See if the caller is relying on us to shut down the
11591da177e4SLinus Torvalds 	 * filesystem.  This happens in paths where we detect
11601da177e4SLinus Torvalds 	 * corruption and decide to give up.
11611da177e4SLinus Torvalds 	 */
116260a204f0SNathan Scott 	if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) {
11630733af21SRyan Hankins 		XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp);
11647d04a335SNathan Scott 		xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
116560a204f0SNathan Scott 	}
11661da177e4SLinus Torvalds #ifdef DEBUG
11671da177e4SLinus Torvalds 	if (!(flags & XFS_TRANS_ABORT)) {
11681da177e4SLinus Torvalds 		licp = &(tp->t_items);
11691da177e4SLinus Torvalds 		while (licp != NULL) {
11701da177e4SLinus Torvalds 			lidp = licp->lic_descs;
11711da177e4SLinus Torvalds 			for (i = 0; i < licp->lic_unused; i++, lidp++) {
11721da177e4SLinus Torvalds 				if (XFS_LIC_ISFREE(licp, i)) {
11731da177e4SLinus Torvalds 					continue;
11741da177e4SLinus Torvalds 				}
11751da177e4SLinus Torvalds 
11761da177e4SLinus Torvalds 				lip = lidp->lid_item;
11770733af21SRyan Hankins 				if (!XFS_FORCED_SHUTDOWN(mp))
11781da177e4SLinus Torvalds 					ASSERT(!(lip->li_type == XFS_LI_EFD));
11791da177e4SLinus Torvalds 			}
11801da177e4SLinus Torvalds 			licp = licp->lic_next;
11811da177e4SLinus Torvalds 		}
11821da177e4SLinus Torvalds 	}
11831da177e4SLinus Torvalds #endif
11841da177e4SLinus Torvalds 	xfs_trans_unreserve_and_mod_sb(tp);
11850733af21SRyan Hankins 	XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
11861da177e4SLinus Torvalds 
11871da177e4SLinus Torvalds 	if (tp->t_ticket) {
11881da177e4SLinus Torvalds 		if (flags & XFS_TRANS_RELEASE_LOG_RES) {
11891da177e4SLinus Torvalds 			ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
11901da177e4SLinus Torvalds 			log_flags = XFS_LOG_REL_PERM_RESERV;
11911da177e4SLinus Torvalds 		} else {
11921da177e4SLinus Torvalds 			log_flags = 0;
11931da177e4SLinus Torvalds 		}
11940733af21SRyan Hankins 		xfs_log_done(mp, tp->t_ticket, NULL, log_flags);
11951da177e4SLinus Torvalds 	}
11961da177e4SLinus Torvalds 
11971da177e4SLinus Torvalds 	/* mark this thread as no longer being in a transaction */
119859c1b082SNathan Scott 	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
11991da177e4SLinus Torvalds 
12001da177e4SLinus Torvalds 	xfs_trans_free_items(tp, flags);
12011da177e4SLinus Torvalds 	xfs_trans_free_busy(tp);
12021da177e4SLinus Torvalds 	xfs_trans_free(tp);
12031da177e4SLinus Torvalds }
12041da177e4SLinus Torvalds 
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds /*
12071da177e4SLinus Torvalds  * Free the transaction structure.  If there is more clean up
12081da177e4SLinus Torvalds  * to do when the structure is freed, add it here.
12091da177e4SLinus Torvalds  */
12101da177e4SLinus Torvalds STATIC void
12111da177e4SLinus Torvalds xfs_trans_free(
12121da177e4SLinus Torvalds 	xfs_trans_t	*tp)
12131da177e4SLinus Torvalds {
12141da177e4SLinus Torvalds 	atomic_dec(&tp->t_mountp->m_active_trans);
12151da177e4SLinus Torvalds 	XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
12161da177e4SLinus Torvalds 	kmem_zone_free(xfs_trans_zone, tp);
12171da177e4SLinus Torvalds }
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds /*
12211da177e4SLinus Torvalds  * THIS SHOULD BE REWRITTEN TO USE xfs_trans_next_item().
12221da177e4SLinus Torvalds  *
12231da177e4SLinus Torvalds  * This is typically called by the LM when a transaction has been fully
12241da177e4SLinus Torvalds  * committed to disk.  It needs to unpin the items which have
12251da177e4SLinus Torvalds  * been logged by the transaction and update their positions
12261da177e4SLinus Torvalds  * in the AIL if necessary.
12271da177e4SLinus Torvalds  * This also gets called when the transactions didn't get written out
12281da177e4SLinus Torvalds  * because of an I/O error. Abortflag & XFS_LI_ABORTED is set then.
12291da177e4SLinus Torvalds  *
12301da177e4SLinus Torvalds  * Call xfs_trans_chunk_committed() to process the items in
12311da177e4SLinus Torvalds  * each chunk.
12321da177e4SLinus Torvalds  */
12331da177e4SLinus Torvalds STATIC void
12341da177e4SLinus Torvalds xfs_trans_committed(
12351da177e4SLinus Torvalds 	xfs_trans_t	*tp,
12361da177e4SLinus Torvalds 	int		abortflag)
12371da177e4SLinus Torvalds {
12381da177e4SLinus Torvalds 	xfs_log_item_chunk_t	*licp;
12391da177e4SLinus Torvalds 	xfs_log_item_chunk_t	*next_licp;
12401da177e4SLinus Torvalds 	xfs_log_busy_chunk_t	*lbcp;
12411da177e4SLinus Torvalds 	xfs_log_busy_slot_t	*lbsp;
12421da177e4SLinus Torvalds 	int			i;
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 	/*
12451da177e4SLinus Torvalds 	 * Call the transaction's completion callback if there
12461da177e4SLinus Torvalds 	 * is one.
12471da177e4SLinus Torvalds 	 */
12481da177e4SLinus Torvalds 	if (tp->t_callback != NULL) {
12491da177e4SLinus Torvalds 		tp->t_callback(tp, tp->t_callarg);
12501da177e4SLinus Torvalds 	}
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds 	/*
12531da177e4SLinus Torvalds 	 * Special case the chunk embedded in the transaction.
12541da177e4SLinus Torvalds 	 */
12551da177e4SLinus Torvalds 	licp = &(tp->t_items);
12561da177e4SLinus Torvalds 	if (!(XFS_LIC_ARE_ALL_FREE(licp))) {
12571da177e4SLinus Torvalds 		xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag);
12581da177e4SLinus Torvalds 	}
12591da177e4SLinus Torvalds 
12601da177e4SLinus Torvalds 	/*
12611da177e4SLinus Torvalds 	 * Process the items in each chunk in turn.
12621da177e4SLinus Torvalds 	 */
12631da177e4SLinus Torvalds 	licp = licp->lic_next;
12641da177e4SLinus Torvalds 	while (licp != NULL) {
12651da177e4SLinus Torvalds 		ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
12661da177e4SLinus Torvalds 		xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag);
12671da177e4SLinus Torvalds 		next_licp = licp->lic_next;
12681da177e4SLinus Torvalds 		kmem_free(licp, sizeof(xfs_log_item_chunk_t));
12691da177e4SLinus Torvalds 		licp = next_licp;
12701da177e4SLinus Torvalds 	}
12711da177e4SLinus Torvalds 
12721da177e4SLinus Torvalds 	/*
12731da177e4SLinus Torvalds 	 * Clear all the per-AG busy list items listed in this transaction
12741da177e4SLinus Torvalds 	 */
12751da177e4SLinus Torvalds 	lbcp = &tp->t_busy;
12761da177e4SLinus Torvalds 	while (lbcp != NULL) {
12771da177e4SLinus Torvalds 		for (i = 0, lbsp = lbcp->lbc_busy; i < lbcp->lbc_unused; i++, lbsp++) {
12781da177e4SLinus Torvalds 			if (!XFS_LBC_ISFREE(lbcp, i)) {
12791da177e4SLinus Torvalds 				xfs_alloc_clear_busy(tp, lbsp->lbc_ag,
12801da177e4SLinus Torvalds 						     lbsp->lbc_idx);
12811da177e4SLinus Torvalds 			}
12821da177e4SLinus Torvalds 		}
12831da177e4SLinus Torvalds 		lbcp = lbcp->lbc_next;
12841da177e4SLinus Torvalds 	}
12851da177e4SLinus Torvalds 	xfs_trans_free_busy(tp);
12861da177e4SLinus Torvalds 
12871da177e4SLinus Torvalds 	/*
12881da177e4SLinus Torvalds 	 * That's it for the transaction structure.  Free it.
12891da177e4SLinus Torvalds 	 */
12901da177e4SLinus Torvalds 	xfs_trans_free(tp);
12911da177e4SLinus Torvalds }
12921da177e4SLinus Torvalds 
12931da177e4SLinus Torvalds /*
12941da177e4SLinus Torvalds  * This is called to perform the commit processing for each
12951da177e4SLinus Torvalds  * item described by the given chunk.
12961da177e4SLinus Torvalds  *
12971da177e4SLinus Torvalds  * The commit processing consists of unlocking items which were
12981da177e4SLinus Torvalds  * held locked with the SYNC_UNLOCK attribute, calling the committed
12991da177e4SLinus Torvalds  * routine of each logged item, updating the item's position in the AIL
13001da177e4SLinus Torvalds  * if necessary, and unpinning each item.  If the committed routine
13011da177e4SLinus Torvalds  * returns -1, then do nothing further with the item because it
13021da177e4SLinus Torvalds  * may have been freed.
13031da177e4SLinus Torvalds  *
13041da177e4SLinus Torvalds  * Since items are unlocked when they are copied to the incore
13051da177e4SLinus Torvalds  * log, it is possible for two transactions to be completing
13061da177e4SLinus Torvalds  * and manipulating the same item simultaneously.  The AIL lock
13071da177e4SLinus Torvalds  * will protect the lsn field of each item.  The value of this
13081da177e4SLinus Torvalds  * field can never go backwards.
13091da177e4SLinus Torvalds  *
13101da177e4SLinus Torvalds  * We unpin the items after repositioning them in the AIL, because
13111da177e4SLinus Torvalds  * otherwise they could be immediately flushed and we'd have to race
13121da177e4SLinus Torvalds  * with the flusher trying to pull the item from the AIL as we add it.
13131da177e4SLinus Torvalds  */
13141da177e4SLinus Torvalds STATIC void
13151da177e4SLinus Torvalds xfs_trans_chunk_committed(
13161da177e4SLinus Torvalds 	xfs_log_item_chunk_t	*licp,
13171da177e4SLinus Torvalds 	xfs_lsn_t		lsn,
13181da177e4SLinus Torvalds 	int			aborted)
13191da177e4SLinus Torvalds {
13201da177e4SLinus Torvalds 	xfs_log_item_desc_t	*lidp;
13211da177e4SLinus Torvalds 	xfs_log_item_t		*lip;
13221da177e4SLinus Torvalds 	xfs_lsn_t		item_lsn;
13231da177e4SLinus Torvalds 	struct xfs_mount	*mp;
13241da177e4SLinus Torvalds 	int			i;
13251da177e4SLinus Torvalds 	SPLDECL(s);
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds 	lidp = licp->lic_descs;
13281da177e4SLinus Torvalds 	for (i = 0; i < licp->lic_unused; i++, lidp++) {
13291da177e4SLinus Torvalds 		if (XFS_LIC_ISFREE(licp, i)) {
13301da177e4SLinus Torvalds 			continue;
13311da177e4SLinus Torvalds 		}
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 		lip = lidp->lid_item;
13341da177e4SLinus Torvalds 		if (aborted)
13351da177e4SLinus Torvalds 			lip->li_flags |= XFS_LI_ABORTED;
13361da177e4SLinus Torvalds 
13371da177e4SLinus Torvalds 		/*
13381da177e4SLinus Torvalds 		 * Send in the ABORTED flag to the COMMITTED routine
13391da177e4SLinus Torvalds 		 * so that it knows whether the transaction was aborted
13401da177e4SLinus Torvalds 		 * or not.
13411da177e4SLinus Torvalds 		 */
13421da177e4SLinus Torvalds 		item_lsn = IOP_COMMITTED(lip, lsn);
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds 		/*
13451da177e4SLinus Torvalds 		 * If the committed routine returns -1, make
13461da177e4SLinus Torvalds 		 * no more references to the item.
13471da177e4SLinus Torvalds 		 */
13481da177e4SLinus Torvalds 		if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) {
13491da177e4SLinus Torvalds 			continue;
13501da177e4SLinus Torvalds 		}
13511da177e4SLinus Torvalds 
13521da177e4SLinus Torvalds 		/*
13531da177e4SLinus Torvalds 		 * If the returned lsn is greater than what it
13541da177e4SLinus Torvalds 		 * contained before, update the location of the
13551da177e4SLinus Torvalds 		 * item in the AIL.  If it is not, then do nothing.
13561da177e4SLinus Torvalds 		 * Items can never move backwards in the AIL.
13571da177e4SLinus Torvalds 		 *
13581da177e4SLinus Torvalds 		 * While the new lsn should usually be greater, it
13591da177e4SLinus Torvalds 		 * is possible that a later transaction completing
13601da177e4SLinus Torvalds 		 * simultaneously with an earlier one using the
13611da177e4SLinus Torvalds 		 * same item could complete first with a higher lsn.
13621da177e4SLinus Torvalds 		 * This would cause the earlier transaction to fail
13631da177e4SLinus Torvalds 		 * the test below.
13641da177e4SLinus Torvalds 		 */
13651da177e4SLinus Torvalds 		mp = lip->li_mountp;
13661da177e4SLinus Torvalds 		AIL_LOCK(mp,s);
13671da177e4SLinus Torvalds 		if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) {
13681da177e4SLinus Torvalds 			/*
13691da177e4SLinus Torvalds 			 * This will set the item's lsn to item_lsn
13701da177e4SLinus Torvalds 			 * and update the position of the item in
13711da177e4SLinus Torvalds 			 * the AIL.
13721da177e4SLinus Torvalds 			 *
13731da177e4SLinus Torvalds 			 * xfs_trans_update_ail() drops the AIL lock.
13741da177e4SLinus Torvalds 			 */
13751da177e4SLinus Torvalds 			xfs_trans_update_ail(mp, lip, item_lsn, s);
13761da177e4SLinus Torvalds 		} else {
13771da177e4SLinus Torvalds 			AIL_UNLOCK(mp, s);
13781da177e4SLinus Torvalds 		}
13791da177e4SLinus Torvalds 
13801da177e4SLinus Torvalds 		/*
13811da177e4SLinus Torvalds 		 * Now that we've repositioned the item in the AIL,
13821da177e4SLinus Torvalds 		 * unpin it so it can be flushed. Pass information
13831da177e4SLinus Torvalds 		 * about buffer stale state down from the log item
13841da177e4SLinus Torvalds 		 * flags, if anyone else stales the buffer we do not
13851da177e4SLinus Torvalds 		 * want to pay any attention to it.
13861da177e4SLinus Torvalds 		 */
13871da177e4SLinus Torvalds 		IOP_UNPIN(lip, lidp->lid_flags & XFS_LID_BUF_STALE);
13881da177e4SLinus Torvalds 	}
13891da177e4SLinus Torvalds }
1390