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" 46322ff6b8SNiv Sardi #include "xfs_inode_item.h" 47ed3b4d6cSDave Chinner #include "xfs_trace.h" 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds kmem_zone_t *xfs_trans_zone; 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds /* 528f794055SNathan Scott * Reservation functions here avoid a huge stack in xfs_trans_init 538f794055SNathan Scott * due to register overflow from temporaries in the calculations. 548f794055SNathan Scott */ 558f794055SNathan Scott STATIC uint 568f794055SNathan Scott xfs_calc_write_reservation(xfs_mount_t *mp) 578f794055SNathan Scott { 588f794055SNathan Scott return XFS_CALC_WRITE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 598f794055SNathan Scott } 608f794055SNathan Scott 618f794055SNathan Scott STATIC uint 628f794055SNathan Scott xfs_calc_itruncate_reservation(xfs_mount_t *mp) 638f794055SNathan Scott { 648f794055SNathan Scott return XFS_CALC_ITRUNCATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 658f794055SNathan Scott } 668f794055SNathan Scott 678f794055SNathan Scott STATIC uint 688f794055SNathan Scott xfs_calc_rename_reservation(xfs_mount_t *mp) 698f794055SNathan Scott { 708f794055SNathan Scott return XFS_CALC_RENAME_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 718f794055SNathan Scott } 728f794055SNathan Scott 738f794055SNathan Scott STATIC uint 748f794055SNathan Scott xfs_calc_link_reservation(xfs_mount_t *mp) 758f794055SNathan Scott { 762ddd5928SNathan Scott return XFS_CALC_LINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 778f794055SNathan Scott } 788f794055SNathan Scott 798f794055SNathan Scott STATIC uint 808f794055SNathan Scott xfs_calc_remove_reservation(xfs_mount_t *mp) 818f794055SNathan Scott { 828f794055SNathan Scott return XFS_CALC_REMOVE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 838f794055SNathan Scott } 848f794055SNathan Scott 858f794055SNathan Scott STATIC uint 868f794055SNathan Scott xfs_calc_symlink_reservation(xfs_mount_t *mp) 878f794055SNathan Scott { 888f794055SNathan Scott return XFS_CALC_SYMLINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 898f794055SNathan Scott } 908f794055SNathan Scott 918f794055SNathan Scott STATIC uint 928f794055SNathan Scott xfs_calc_create_reservation(xfs_mount_t *mp) 938f794055SNathan Scott { 948f794055SNathan Scott return XFS_CALC_CREATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 958f794055SNathan Scott } 968f794055SNathan Scott 978f794055SNathan Scott STATIC uint 988f794055SNathan Scott xfs_calc_mkdir_reservation(xfs_mount_t *mp) 998f794055SNathan Scott { 1008f794055SNathan Scott return XFS_CALC_MKDIR_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 1018f794055SNathan Scott } 1028f794055SNathan Scott 1038f794055SNathan Scott STATIC uint 1048f794055SNathan Scott xfs_calc_ifree_reservation(xfs_mount_t *mp) 1058f794055SNathan Scott { 1068f794055SNathan Scott return XFS_CALC_IFREE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 1078f794055SNathan Scott } 1088f794055SNathan Scott 1098f794055SNathan Scott STATIC uint 1108f794055SNathan Scott xfs_calc_ichange_reservation(xfs_mount_t *mp) 1118f794055SNathan Scott { 1128f794055SNathan Scott return XFS_CALC_ICHANGE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 1138f794055SNathan Scott } 1148f794055SNathan Scott 1158f794055SNathan Scott STATIC uint 1168f794055SNathan Scott xfs_calc_growdata_reservation(xfs_mount_t *mp) 1178f794055SNathan Scott { 1188f794055SNathan Scott return XFS_CALC_GROWDATA_LOG_RES(mp); 1198f794055SNathan Scott } 1208f794055SNathan Scott 1218f794055SNathan Scott STATIC uint 1228f794055SNathan Scott xfs_calc_growrtalloc_reservation(xfs_mount_t *mp) 1238f794055SNathan Scott { 1248f794055SNathan Scott return XFS_CALC_GROWRTALLOC_LOG_RES(mp); 1258f794055SNathan Scott } 1268f794055SNathan Scott 1278f794055SNathan Scott STATIC uint 1288f794055SNathan Scott xfs_calc_growrtzero_reservation(xfs_mount_t *mp) 1298f794055SNathan Scott { 1308f794055SNathan Scott return XFS_CALC_GROWRTZERO_LOG_RES(mp); 1318f794055SNathan Scott } 1328f794055SNathan Scott 1338f794055SNathan Scott STATIC uint 1348f794055SNathan Scott xfs_calc_growrtfree_reservation(xfs_mount_t *mp) 1358f794055SNathan Scott { 1368f794055SNathan Scott return XFS_CALC_GROWRTFREE_LOG_RES(mp); 1378f794055SNathan Scott } 1388f794055SNathan Scott 1398f794055SNathan Scott STATIC uint 1408f794055SNathan Scott xfs_calc_swrite_reservation(xfs_mount_t *mp) 1418f794055SNathan Scott { 1428f794055SNathan Scott return XFS_CALC_SWRITE_LOG_RES(mp); 1438f794055SNathan Scott } 1448f794055SNathan Scott 1458f794055SNathan Scott STATIC uint 1468f794055SNathan Scott xfs_calc_writeid_reservation(xfs_mount_t *mp) 1478f794055SNathan Scott { 1488f794055SNathan Scott return XFS_CALC_WRITEID_LOG_RES(mp); 1498f794055SNathan Scott } 1508f794055SNathan Scott 1518f794055SNathan Scott STATIC uint 1528f794055SNathan Scott xfs_calc_addafork_reservation(xfs_mount_t *mp) 1538f794055SNathan Scott { 1548f794055SNathan Scott return XFS_CALC_ADDAFORK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 1558f794055SNathan Scott } 1568f794055SNathan Scott 1578f794055SNathan Scott STATIC uint 1588f794055SNathan Scott xfs_calc_attrinval_reservation(xfs_mount_t *mp) 1598f794055SNathan Scott { 1608f794055SNathan Scott return XFS_CALC_ATTRINVAL_LOG_RES(mp); 1618f794055SNathan Scott } 1628f794055SNathan Scott 1638f794055SNathan Scott STATIC uint 1648f794055SNathan Scott xfs_calc_attrset_reservation(xfs_mount_t *mp) 1658f794055SNathan Scott { 1668f794055SNathan Scott return XFS_CALC_ATTRSET_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 1678f794055SNathan Scott } 1688f794055SNathan Scott 1698f794055SNathan Scott STATIC uint 1708f794055SNathan Scott xfs_calc_attrrm_reservation(xfs_mount_t *mp) 1718f794055SNathan Scott { 1728f794055SNathan Scott return XFS_CALC_ATTRRM_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); 1738f794055SNathan Scott } 1748f794055SNathan Scott 1758f794055SNathan Scott STATIC uint 1768f794055SNathan Scott xfs_calc_clear_agi_bucket_reservation(xfs_mount_t *mp) 1778f794055SNathan Scott { 1788f794055SNathan Scott return XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp); 1798f794055SNathan Scott } 1808f794055SNathan Scott 1818f794055SNathan Scott /* 1821da177e4SLinus Torvalds * Initialize the precomputed transaction reservation values 1831da177e4SLinus Torvalds * in the mount structure. 1841da177e4SLinus Torvalds */ 1851da177e4SLinus Torvalds void 1861da177e4SLinus Torvalds xfs_trans_init( 1871da177e4SLinus Torvalds xfs_mount_t *mp) 1881da177e4SLinus Torvalds { 1891da177e4SLinus Torvalds xfs_trans_reservations_t *resp; 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds resp = &(mp->m_reservations); 1928f794055SNathan Scott resp->tr_write = xfs_calc_write_reservation(mp); 1938f794055SNathan Scott resp->tr_itruncate = xfs_calc_itruncate_reservation(mp); 1948f794055SNathan Scott resp->tr_rename = xfs_calc_rename_reservation(mp); 1958f794055SNathan Scott resp->tr_link = xfs_calc_link_reservation(mp); 1968f794055SNathan Scott resp->tr_remove = xfs_calc_remove_reservation(mp); 1978f794055SNathan Scott resp->tr_symlink = xfs_calc_symlink_reservation(mp); 1988f794055SNathan Scott resp->tr_create = xfs_calc_create_reservation(mp); 1998f794055SNathan Scott resp->tr_mkdir = xfs_calc_mkdir_reservation(mp); 2008f794055SNathan Scott resp->tr_ifree = xfs_calc_ifree_reservation(mp); 2018f794055SNathan Scott resp->tr_ichange = xfs_calc_ichange_reservation(mp); 2028f794055SNathan Scott resp->tr_growdata = xfs_calc_growdata_reservation(mp); 2038f794055SNathan Scott resp->tr_swrite = xfs_calc_swrite_reservation(mp); 2048f794055SNathan Scott resp->tr_writeid = xfs_calc_writeid_reservation(mp); 2058f794055SNathan Scott resp->tr_addafork = xfs_calc_addafork_reservation(mp); 2068f794055SNathan Scott resp->tr_attrinval = xfs_calc_attrinval_reservation(mp); 2078f794055SNathan Scott resp->tr_attrset = xfs_calc_attrset_reservation(mp); 2088f794055SNathan Scott resp->tr_attrrm = xfs_calc_attrrm_reservation(mp); 2098f794055SNathan Scott resp->tr_clearagi = xfs_calc_clear_agi_bucket_reservation(mp); 2108f794055SNathan Scott resp->tr_growrtalloc = xfs_calc_growrtalloc_reservation(mp); 2118f794055SNathan Scott resp->tr_growrtzero = xfs_calc_growrtzero_reservation(mp); 2128f794055SNathan Scott resp->tr_growrtfree = xfs_calc_growrtfree_reservation(mp); 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds /* 2161da177e4SLinus Torvalds * This routine is called to allocate a transaction structure. 2171da177e4SLinus Torvalds * The type parameter indicates the type of the transaction. These 2181da177e4SLinus Torvalds * are enumerated in xfs_trans.h. 2191da177e4SLinus Torvalds * 2201da177e4SLinus Torvalds * Dynamically allocate the transaction structure from the transaction 2211da177e4SLinus Torvalds * zone, initialize it, and return it to the caller. 2221da177e4SLinus Torvalds */ 2231da177e4SLinus Torvalds xfs_trans_t * 2241da177e4SLinus Torvalds xfs_trans_alloc( 2251da177e4SLinus Torvalds xfs_mount_t *mp, 2261da177e4SLinus Torvalds uint type) 2271da177e4SLinus Torvalds { 228b267ce99SChristoph Hellwig xfs_wait_for_freeze(mp, SB_FREEZE_TRANS); 22980641dc6SChristoph Hellwig return _xfs_trans_alloc(mp, type, KM_SLEEP); 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds xfs_trans_t * 2331da177e4SLinus Torvalds _xfs_trans_alloc( 2341da177e4SLinus Torvalds xfs_mount_t *mp, 23580641dc6SChristoph Hellwig uint type, 23680641dc6SChristoph Hellwig uint memflags) 2371da177e4SLinus Torvalds { 2381da177e4SLinus Torvalds xfs_trans_t *tp; 2391da177e4SLinus Torvalds 24034327e13SNathan Scott atomic_inc(&mp->m_active_trans); 2411da177e4SLinus Torvalds 24280641dc6SChristoph Hellwig tp = kmem_zone_zalloc(xfs_trans_zone, memflags); 2431da177e4SLinus Torvalds tp->t_magic = XFS_TRANS_MAGIC; 2441da177e4SLinus Torvalds tp->t_type = type; 2451da177e4SLinus Torvalds tp->t_mountp = mp; 2461da177e4SLinus Torvalds tp->t_items_free = XFS_LIC_NUM_SLOTS; 24739dab9d7SEric Sandeen xfs_lic_init(&(tp->t_items)); 248ed3b4d6cSDave Chinner INIT_LIST_HEAD(&tp->t_busy); 24934327e13SNathan Scott return tp; 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds /* 253b1c1b5b6SDave Chinner * Free the transaction structure. If there is more clean up 254b1c1b5b6SDave Chinner * to do when the structure is freed, add it here. 255b1c1b5b6SDave Chinner */ 256b1c1b5b6SDave Chinner STATIC void 257b1c1b5b6SDave Chinner xfs_trans_free( 258ed3b4d6cSDave Chinner struct xfs_trans *tp) 259b1c1b5b6SDave Chinner { 260ed3b4d6cSDave Chinner struct xfs_busy_extent *busyp, *n; 261ed3b4d6cSDave Chinner 262ed3b4d6cSDave Chinner list_for_each_entry_safe(busyp, n, &tp->t_busy, list) 263ed3b4d6cSDave Chinner xfs_alloc_busy_clear(tp->t_mountp, busyp); 264ed3b4d6cSDave Chinner 265b1c1b5b6SDave Chinner atomic_dec(&tp->t_mountp->m_active_trans); 266b1c1b5b6SDave Chinner xfs_trans_free_dqinfo(tp); 267b1c1b5b6SDave Chinner kmem_zone_free(xfs_trans_zone, tp); 268b1c1b5b6SDave Chinner } 269b1c1b5b6SDave Chinner 270b1c1b5b6SDave Chinner /* 2711da177e4SLinus Torvalds * This is called to create a new transaction which will share the 2721da177e4SLinus Torvalds * permanent log reservation of the given transaction. The remaining 2731da177e4SLinus Torvalds * unused block and rt extent reservations are also inherited. This 2741da177e4SLinus Torvalds * implies that the original transaction is no longer allowed to allocate 2751da177e4SLinus Torvalds * blocks. Locks and log items, however, are no inherited. They must 2761da177e4SLinus Torvalds * be added to the new transaction explicitly. 2771da177e4SLinus Torvalds */ 2781da177e4SLinus Torvalds xfs_trans_t * 2791da177e4SLinus Torvalds xfs_trans_dup( 2801da177e4SLinus Torvalds xfs_trans_t *tp) 2811da177e4SLinus Torvalds { 2821da177e4SLinus Torvalds xfs_trans_t *ntp; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds /* 2871da177e4SLinus Torvalds * Initialize the new transaction structure. 2881da177e4SLinus Torvalds */ 2891da177e4SLinus Torvalds ntp->t_magic = XFS_TRANS_MAGIC; 2901da177e4SLinus Torvalds ntp->t_type = tp->t_type; 2911da177e4SLinus Torvalds ntp->t_mountp = tp->t_mountp; 2921da177e4SLinus Torvalds ntp->t_items_free = XFS_LIC_NUM_SLOTS; 29339dab9d7SEric Sandeen xfs_lic_init(&(ntp->t_items)); 294ed3b4d6cSDave Chinner INIT_LIST_HEAD(&ntp->t_busy); 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); 2971da177e4SLinus Torvalds ASSERT(tp->t_ticket != NULL); 298cfcbbbd0SNathan Scott 2991da177e4SLinus Torvalds ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE); 300cc09c0dcSDave Chinner ntp->t_ticket = xfs_log_ticket_get(tp->t_ticket); 3011da177e4SLinus Torvalds ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used; 3021da177e4SLinus Torvalds tp->t_blk_res = tp->t_blk_res_used; 3031da177e4SLinus Torvalds ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; 3041da177e4SLinus Torvalds tp->t_rtx_res = tp->t_rtx_res_used; 30559c1b082SNathan Scott ntp->t_pflags = tp->t_pflags; 3061da177e4SLinus Torvalds 3077d095257SChristoph Hellwig xfs_trans_dup_dqinfo(tp, ntp); 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds atomic_inc(&tp->t_mountp->m_active_trans); 3101da177e4SLinus Torvalds return ntp; 3111da177e4SLinus Torvalds } 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds /* 3141da177e4SLinus Torvalds * This is called to reserve free disk blocks and log space for the 3151da177e4SLinus Torvalds * given transaction. This must be done before allocating any resources 3161da177e4SLinus Torvalds * within the transaction. 3171da177e4SLinus Torvalds * 3181da177e4SLinus Torvalds * This will return ENOSPC if there are not enough blocks available. 3191da177e4SLinus Torvalds * It will sleep waiting for available log space. 3201da177e4SLinus Torvalds * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which 3211da177e4SLinus Torvalds * is used by long running transactions. If any one of the reservations 3221da177e4SLinus Torvalds * fails then they will all be backed out. 3231da177e4SLinus Torvalds * 3241da177e4SLinus Torvalds * This does not do quota reservations. That typically is done by the 3251da177e4SLinus Torvalds * caller afterwards. 3261da177e4SLinus Torvalds */ 3271da177e4SLinus Torvalds int 3281da177e4SLinus Torvalds xfs_trans_reserve( 3291da177e4SLinus Torvalds xfs_trans_t *tp, 3301da177e4SLinus Torvalds uint blocks, 3311da177e4SLinus Torvalds uint logspace, 3321da177e4SLinus Torvalds uint rtextents, 3331da177e4SLinus Torvalds uint flags, 3341da177e4SLinus Torvalds uint logcount) 3351da177e4SLinus Torvalds { 3361da177e4SLinus Torvalds int log_flags; 33759c1b082SNathan Scott int error = 0; 33859c1b082SNathan Scott int rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds /* Mark this thread as being in a transaction */ 34159c1b082SNathan Scott current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds /* 3441da177e4SLinus Torvalds * Attempt to reserve the needed disk blocks by decrementing 3451da177e4SLinus Torvalds * the number needed from the number available. This will 3461da177e4SLinus Torvalds * fail if the count would go below zero. 3471da177e4SLinus Torvalds */ 3481da177e4SLinus Torvalds if (blocks > 0) { 3491da177e4SLinus Torvalds error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, 35020f4ebf2SDavid Chinner -((int64_t)blocks), rsvd); 3511da177e4SLinus Torvalds if (error != 0) { 35259c1b082SNathan Scott current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 3531da177e4SLinus Torvalds return (XFS_ERROR(ENOSPC)); 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds tp->t_blk_res += blocks; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds /* 3591da177e4SLinus Torvalds * Reserve the log space needed for this transaction. 3601da177e4SLinus Torvalds */ 3611da177e4SLinus Torvalds if (logspace > 0) { 3621da177e4SLinus Torvalds ASSERT((tp->t_log_res == 0) || (tp->t_log_res == logspace)); 3631da177e4SLinus Torvalds ASSERT((tp->t_log_count == 0) || 3641da177e4SLinus Torvalds (tp->t_log_count == logcount)); 3651da177e4SLinus Torvalds if (flags & XFS_TRANS_PERM_LOG_RES) { 3661da177e4SLinus Torvalds log_flags = XFS_LOG_PERM_RESERV; 3671da177e4SLinus Torvalds tp->t_flags |= XFS_TRANS_PERM_LOG_RES; 3681da177e4SLinus Torvalds } else { 3691da177e4SLinus Torvalds ASSERT(tp->t_ticket == NULL); 3701da177e4SLinus Torvalds ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); 3711da177e4SLinus Torvalds log_flags = 0; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds error = xfs_log_reserve(tp->t_mountp, logspace, logcount, 3751da177e4SLinus Torvalds &tp->t_ticket, 3767e9c6396STim Shimmin XFS_TRANSACTION, log_flags, tp->t_type); 3771da177e4SLinus Torvalds if (error) { 3781da177e4SLinus Torvalds goto undo_blocks; 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds tp->t_log_res = logspace; 3811da177e4SLinus Torvalds tp->t_log_count = logcount; 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds /* 3851da177e4SLinus Torvalds * Attempt to reserve the needed realtime extents by decrementing 3861da177e4SLinus Torvalds * the number needed from the number available. This will 3871da177e4SLinus Torvalds * fail if the count would go below zero. 3881da177e4SLinus Torvalds */ 3891da177e4SLinus Torvalds if (rtextents > 0) { 3901da177e4SLinus Torvalds error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FREXTENTS, 39120f4ebf2SDavid Chinner -((int64_t)rtextents), rsvd); 3921da177e4SLinus Torvalds if (error) { 3931da177e4SLinus Torvalds error = XFS_ERROR(ENOSPC); 3941da177e4SLinus Torvalds goto undo_log; 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds tp->t_rtx_res += rtextents; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds return 0; 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* 4021da177e4SLinus Torvalds * Error cases jump to one of these labels to undo any 4031da177e4SLinus Torvalds * reservations which have already been performed. 4041da177e4SLinus Torvalds */ 4051da177e4SLinus Torvalds undo_log: 4061da177e4SLinus Torvalds if (logspace > 0) { 4071da177e4SLinus Torvalds if (flags & XFS_TRANS_PERM_LOG_RES) { 4081da177e4SLinus Torvalds log_flags = XFS_LOG_REL_PERM_RESERV; 4091da177e4SLinus Torvalds } else { 4101da177e4SLinus Torvalds log_flags = 0; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, log_flags); 4131da177e4SLinus Torvalds tp->t_ticket = NULL; 4141da177e4SLinus Torvalds tp->t_log_res = 0; 4151da177e4SLinus Torvalds tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds undo_blocks: 4191da177e4SLinus Torvalds if (blocks > 0) { 4201da177e4SLinus Torvalds (void) xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, 42120f4ebf2SDavid Chinner (int64_t)blocks, rsvd); 4221da177e4SLinus Torvalds tp->t_blk_res = 0; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 42559c1b082SNathan Scott current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 4261da177e4SLinus Torvalds 42759c1b082SNathan Scott return error; 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds /* 4311da177e4SLinus Torvalds * Record the indicated change to the given field for application 4321da177e4SLinus Torvalds * to the file system's superblock when the transaction commits. 4331da177e4SLinus Torvalds * For now, just store the change in the transaction structure. 4341da177e4SLinus Torvalds * 4351da177e4SLinus Torvalds * Mark the transaction structure to indicate that the superblock 4361da177e4SLinus Torvalds * needs to be updated before committing. 43792821e2bSDavid Chinner * 43892821e2bSDavid Chinner * Because we may not be keeping track of allocated/free inodes and 43992821e2bSDavid Chinner * used filesystem blocks in the superblock, we do not mark the 44092821e2bSDavid Chinner * superblock dirty in this transaction if we modify these fields. 44192821e2bSDavid Chinner * We still need to update the transaction deltas so that they get 44292821e2bSDavid Chinner * applied to the incore superblock, but we don't want them to 44392821e2bSDavid Chinner * cause the superblock to get locked and logged if these are the 44492821e2bSDavid Chinner * only fields in the superblock that the transaction modifies. 4451da177e4SLinus Torvalds */ 4461da177e4SLinus Torvalds void 4471da177e4SLinus Torvalds xfs_trans_mod_sb( 4481da177e4SLinus Torvalds xfs_trans_t *tp, 4491da177e4SLinus Torvalds uint field, 45020f4ebf2SDavid Chinner int64_t delta) 4511da177e4SLinus Torvalds { 45292821e2bSDavid Chinner uint32_t flags = (XFS_TRANS_DIRTY|XFS_TRANS_SB_DIRTY); 45392821e2bSDavid Chinner xfs_mount_t *mp = tp->t_mountp; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds switch (field) { 4561da177e4SLinus Torvalds case XFS_TRANS_SB_ICOUNT: 4571da177e4SLinus Torvalds tp->t_icount_delta += delta; 45892821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb)) 45992821e2bSDavid Chinner flags &= ~XFS_TRANS_SB_DIRTY; 4601da177e4SLinus Torvalds break; 4611da177e4SLinus Torvalds case XFS_TRANS_SB_IFREE: 4621da177e4SLinus Torvalds tp->t_ifree_delta += delta; 46392821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb)) 46492821e2bSDavid Chinner flags &= ~XFS_TRANS_SB_DIRTY; 4651da177e4SLinus Torvalds break; 4661da177e4SLinus Torvalds case XFS_TRANS_SB_FDBLOCKS: 4671da177e4SLinus Torvalds /* 4681da177e4SLinus Torvalds * Track the number of blocks allocated in the 4691da177e4SLinus Torvalds * transaction. Make sure it does not exceed the 4701da177e4SLinus Torvalds * number reserved. 4711da177e4SLinus Torvalds */ 4721da177e4SLinus Torvalds if (delta < 0) { 4731da177e4SLinus Torvalds tp->t_blk_res_used += (uint)-delta; 4741da177e4SLinus Torvalds ASSERT(tp->t_blk_res_used <= tp->t_blk_res); 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds tp->t_fdblocks_delta += delta; 47792821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb)) 47892821e2bSDavid Chinner flags &= ~XFS_TRANS_SB_DIRTY; 4791da177e4SLinus Torvalds break; 4801da177e4SLinus Torvalds case XFS_TRANS_SB_RES_FDBLOCKS: 4811da177e4SLinus Torvalds /* 4821da177e4SLinus Torvalds * The allocation has already been applied to the 4831da177e4SLinus Torvalds * in-core superblock's counter. This should only 4841da177e4SLinus Torvalds * be applied to the on-disk superblock. 4851da177e4SLinus Torvalds */ 4861da177e4SLinus Torvalds ASSERT(delta < 0); 4871da177e4SLinus Torvalds tp->t_res_fdblocks_delta += delta; 48892821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb)) 48992821e2bSDavid Chinner flags &= ~XFS_TRANS_SB_DIRTY; 4901da177e4SLinus Torvalds break; 4911da177e4SLinus Torvalds case XFS_TRANS_SB_FREXTENTS: 4921da177e4SLinus Torvalds /* 4931da177e4SLinus Torvalds * Track the number of blocks allocated in the 4941da177e4SLinus Torvalds * transaction. Make sure it does not exceed the 4951da177e4SLinus Torvalds * number reserved. 4961da177e4SLinus Torvalds */ 4971da177e4SLinus Torvalds if (delta < 0) { 4981da177e4SLinus Torvalds tp->t_rtx_res_used += (uint)-delta; 4991da177e4SLinus Torvalds ASSERT(tp->t_rtx_res_used <= tp->t_rtx_res); 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds tp->t_frextents_delta += delta; 5021da177e4SLinus Torvalds break; 5031da177e4SLinus Torvalds case XFS_TRANS_SB_RES_FREXTENTS: 5041da177e4SLinus Torvalds /* 5051da177e4SLinus Torvalds * The allocation has already been applied to the 506c41564b5SNathan Scott * in-core superblock's counter. This should only 5071da177e4SLinus Torvalds * be applied to the on-disk superblock. 5081da177e4SLinus Torvalds */ 5091da177e4SLinus Torvalds ASSERT(delta < 0); 5101da177e4SLinus Torvalds tp->t_res_frextents_delta += delta; 5111da177e4SLinus Torvalds break; 5121da177e4SLinus Torvalds case XFS_TRANS_SB_DBLOCKS: 5131da177e4SLinus Torvalds ASSERT(delta > 0); 5141da177e4SLinus Torvalds tp->t_dblocks_delta += delta; 5151da177e4SLinus Torvalds break; 5161da177e4SLinus Torvalds case XFS_TRANS_SB_AGCOUNT: 5171da177e4SLinus Torvalds ASSERT(delta > 0); 5181da177e4SLinus Torvalds tp->t_agcount_delta += delta; 5191da177e4SLinus Torvalds break; 5201da177e4SLinus Torvalds case XFS_TRANS_SB_IMAXPCT: 5211da177e4SLinus Torvalds tp->t_imaxpct_delta += delta; 5221da177e4SLinus Torvalds break; 5231da177e4SLinus Torvalds case XFS_TRANS_SB_REXTSIZE: 5241da177e4SLinus Torvalds tp->t_rextsize_delta += delta; 5251da177e4SLinus Torvalds break; 5261da177e4SLinus Torvalds case XFS_TRANS_SB_RBMBLOCKS: 5271da177e4SLinus Torvalds tp->t_rbmblocks_delta += delta; 5281da177e4SLinus Torvalds break; 5291da177e4SLinus Torvalds case XFS_TRANS_SB_RBLOCKS: 5301da177e4SLinus Torvalds tp->t_rblocks_delta += delta; 5311da177e4SLinus Torvalds break; 5321da177e4SLinus Torvalds case XFS_TRANS_SB_REXTENTS: 5331da177e4SLinus Torvalds tp->t_rextents_delta += delta; 5341da177e4SLinus Torvalds break; 5351da177e4SLinus Torvalds case XFS_TRANS_SB_REXTSLOG: 5361da177e4SLinus Torvalds tp->t_rextslog_delta += delta; 5371da177e4SLinus Torvalds break; 5381da177e4SLinus Torvalds default: 5391da177e4SLinus Torvalds ASSERT(0); 5401da177e4SLinus Torvalds return; 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds 543210c6f1cSDavid Chinner tp->t_flags |= flags; 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds /* 5471da177e4SLinus Torvalds * xfs_trans_apply_sb_deltas() is called from the commit code 5481da177e4SLinus Torvalds * to bring the superblock buffer into the current transaction 5491da177e4SLinus Torvalds * and modify it as requested by earlier calls to xfs_trans_mod_sb(). 5501da177e4SLinus Torvalds * 5511da177e4SLinus Torvalds * For now we just look at each field allowed to change and change 5521da177e4SLinus Torvalds * it if necessary. 5531da177e4SLinus Torvalds */ 5541da177e4SLinus Torvalds STATIC void 5551da177e4SLinus Torvalds xfs_trans_apply_sb_deltas( 5561da177e4SLinus Torvalds xfs_trans_t *tp) 5571da177e4SLinus Torvalds { 5582bdf7cd0SChristoph Hellwig xfs_dsb_t *sbp; 5591da177e4SLinus Torvalds xfs_buf_t *bp; 5601da177e4SLinus Torvalds int whole = 0; 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds bp = xfs_trans_getsb(tp, tp->t_mountp, 0); 5631da177e4SLinus Torvalds sbp = XFS_BUF_TO_SBP(bp); 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds /* 5661da177e4SLinus Torvalds * Check that superblock mods match the mods made to AGF counters. 5671da177e4SLinus Torvalds */ 5681da177e4SLinus Torvalds ASSERT((tp->t_fdblocks_delta + tp->t_res_fdblocks_delta) == 5691da177e4SLinus Torvalds (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta + 5701da177e4SLinus Torvalds tp->t_ag_btree_delta)); 5711da177e4SLinus Torvalds 57292821e2bSDavid Chinner /* 57392821e2bSDavid Chinner * Only update the superblock counters if we are logging them 57492821e2bSDavid Chinner */ 57592821e2bSDavid Chinner if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) { 5762bdf7cd0SChristoph Hellwig if (tp->t_icount_delta) 577413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_icount, tp->t_icount_delta); 5782bdf7cd0SChristoph Hellwig if (tp->t_ifree_delta) 579413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_ifree, tp->t_ifree_delta); 5802bdf7cd0SChristoph Hellwig if (tp->t_fdblocks_delta) 581413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_fdblocks, tp->t_fdblocks_delta); 5822bdf7cd0SChristoph Hellwig if (tp->t_res_fdblocks_delta) 583413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_fdblocks, tp->t_res_fdblocks_delta); 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds 5862bdf7cd0SChristoph Hellwig if (tp->t_frextents_delta) 587413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_frextents, tp->t_frextents_delta); 5882bdf7cd0SChristoph Hellwig if (tp->t_res_frextents_delta) 589413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_frextents, tp->t_res_frextents_delta); 5901da177e4SLinus Torvalds 5912bdf7cd0SChristoph Hellwig if (tp->t_dblocks_delta) { 592413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_dblocks, tp->t_dblocks_delta); 5931da177e4SLinus Torvalds whole = 1; 5941da177e4SLinus Torvalds } 5952bdf7cd0SChristoph Hellwig if (tp->t_agcount_delta) { 596413d57c9SMarcin Slusarz be32_add_cpu(&sbp->sb_agcount, tp->t_agcount_delta); 5971da177e4SLinus Torvalds whole = 1; 5981da177e4SLinus Torvalds } 5992bdf7cd0SChristoph Hellwig if (tp->t_imaxpct_delta) { 6002bdf7cd0SChristoph Hellwig sbp->sb_imax_pct += tp->t_imaxpct_delta; 6011da177e4SLinus Torvalds whole = 1; 6021da177e4SLinus Torvalds } 6032bdf7cd0SChristoph Hellwig if (tp->t_rextsize_delta) { 604413d57c9SMarcin Slusarz be32_add_cpu(&sbp->sb_rextsize, tp->t_rextsize_delta); 6051da177e4SLinus Torvalds whole = 1; 6061da177e4SLinus Torvalds } 6072bdf7cd0SChristoph Hellwig if (tp->t_rbmblocks_delta) { 608413d57c9SMarcin Slusarz be32_add_cpu(&sbp->sb_rbmblocks, tp->t_rbmblocks_delta); 6091da177e4SLinus Torvalds whole = 1; 6101da177e4SLinus Torvalds } 6112bdf7cd0SChristoph Hellwig if (tp->t_rblocks_delta) { 612413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_rblocks, tp->t_rblocks_delta); 6131da177e4SLinus Torvalds whole = 1; 6141da177e4SLinus Torvalds } 6152bdf7cd0SChristoph Hellwig if (tp->t_rextents_delta) { 616413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_rextents, tp->t_rextents_delta); 6171da177e4SLinus Torvalds whole = 1; 6181da177e4SLinus Torvalds } 6192bdf7cd0SChristoph Hellwig if (tp->t_rextslog_delta) { 6202bdf7cd0SChristoph Hellwig sbp->sb_rextslog += tp->t_rextslog_delta; 6211da177e4SLinus Torvalds whole = 1; 6221da177e4SLinus Torvalds } 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds if (whole) 6251da177e4SLinus Torvalds /* 626c41564b5SNathan Scott * Log the whole thing, the fields are noncontiguous. 6271da177e4SLinus Torvalds */ 6282bdf7cd0SChristoph Hellwig xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_dsb_t) - 1); 6291da177e4SLinus Torvalds else 6301da177e4SLinus Torvalds /* 6311da177e4SLinus Torvalds * Since all the modifiable fields are contiguous, we 6321da177e4SLinus Torvalds * can get away with this. 6331da177e4SLinus Torvalds */ 6342bdf7cd0SChristoph Hellwig xfs_trans_log_buf(tp, bp, offsetof(xfs_dsb_t, sb_icount), 6352bdf7cd0SChristoph Hellwig offsetof(xfs_dsb_t, sb_frextents) + 6361da177e4SLinus Torvalds sizeof(sbp->sb_frextents) - 1); 6371da177e4SLinus Torvalds } 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds /* 64045c34141SDavid Chinner * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations 64145c34141SDavid Chinner * and apply superblock counter changes to the in-core superblock. The 64245c34141SDavid Chinner * t_res_fdblocks_delta and t_res_frextents_delta fields are explicitly NOT 64345c34141SDavid Chinner * applied to the in-core superblock. The idea is that that has already been 64445c34141SDavid Chinner * done. 6451da177e4SLinus Torvalds * 6461da177e4SLinus Torvalds * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). 64745c34141SDavid Chinner * However, we have to ensure that we only modify each superblock field only 64845c34141SDavid Chinner * once because the application of the delta values may not be atomic. That can 64945c34141SDavid Chinner * lead to ENOSPC races occurring if we have two separate modifcations of the 65045c34141SDavid Chinner * free space counter to put back the entire reservation and then take away 65145c34141SDavid Chinner * what we used. 65245c34141SDavid Chinner * 65345c34141SDavid Chinner * If we are not logging superblock counters, then the inode allocated/free and 65445c34141SDavid Chinner * used block counts are not updated in the on disk superblock. In this case, 65545c34141SDavid Chinner * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we 65645c34141SDavid Chinner * still need to update the incore superblock with the changes. 6571da177e4SLinus Torvalds */ 658*71e330b5SDave Chinner void 6591da177e4SLinus Torvalds xfs_trans_unreserve_and_mod_sb( 6601da177e4SLinus Torvalds xfs_trans_t *tp) 6611da177e4SLinus Torvalds { 6621da177e4SLinus Torvalds xfs_mod_sb_t msb[14]; /* If you add cases, add entries */ 6631da177e4SLinus Torvalds xfs_mod_sb_t *msbp; 66492821e2bSDavid Chinner xfs_mount_t *mp = tp->t_mountp; 6651da177e4SLinus Torvalds /* REFERENCED */ 6661da177e4SLinus Torvalds int error; 6671da177e4SLinus Torvalds int rsvd; 66845c34141SDavid Chinner int64_t blkdelta = 0; 66945c34141SDavid Chinner int64_t rtxdelta = 0; 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds msbp = msb; 6721da177e4SLinus Torvalds rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; 6731da177e4SLinus Torvalds 67445c34141SDavid Chinner /* calculate free blocks delta */ 67545c34141SDavid Chinner if (tp->t_blk_res > 0) 67645c34141SDavid Chinner blkdelta = tp->t_blk_res; 67745c34141SDavid Chinner 67845c34141SDavid Chinner if ((tp->t_fdblocks_delta != 0) && 67945c34141SDavid Chinner (xfs_sb_version_haslazysbcount(&mp->m_sb) || 68045c34141SDavid Chinner (tp->t_flags & XFS_TRANS_SB_DIRTY))) 68145c34141SDavid Chinner blkdelta += tp->t_fdblocks_delta; 68245c34141SDavid Chinner 68345c34141SDavid Chinner if (blkdelta != 0) { 6841da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_FDBLOCKS; 68545c34141SDavid Chinner msbp->msb_delta = blkdelta; 6861da177e4SLinus Torvalds msbp++; 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 68945c34141SDavid Chinner /* calculate free realtime extents delta */ 69045c34141SDavid Chinner if (tp->t_rtx_res > 0) 69145c34141SDavid Chinner rtxdelta = tp->t_rtx_res; 69245c34141SDavid Chinner 69345c34141SDavid Chinner if ((tp->t_frextents_delta != 0) && 69445c34141SDavid Chinner (tp->t_flags & XFS_TRANS_SB_DIRTY)) 69545c34141SDavid Chinner rtxdelta += tp->t_frextents_delta; 69645c34141SDavid Chinner 69745c34141SDavid Chinner if (rtxdelta != 0) { 6981da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_FREXTENTS; 69945c34141SDavid Chinner msbp->msb_delta = rtxdelta; 7001da177e4SLinus Torvalds msbp++; 7011da177e4SLinus Torvalds } 7021da177e4SLinus Torvalds 70345c34141SDavid Chinner /* apply remaining deltas */ 70445c34141SDavid Chinner 70592821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb) || 70692821e2bSDavid Chinner (tp->t_flags & XFS_TRANS_SB_DIRTY)) { 7071da177e4SLinus Torvalds if (tp->t_icount_delta != 0) { 7081da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_ICOUNT; 70920f4ebf2SDavid Chinner msbp->msb_delta = tp->t_icount_delta; 7101da177e4SLinus Torvalds msbp++; 7111da177e4SLinus Torvalds } 7121da177e4SLinus Torvalds if (tp->t_ifree_delta != 0) { 7131da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_IFREE; 71420f4ebf2SDavid Chinner msbp->msb_delta = tp->t_ifree_delta; 7151da177e4SLinus Torvalds msbp++; 7161da177e4SLinus Torvalds } 71792821e2bSDavid Chinner } 71892821e2bSDavid Chinner 71992821e2bSDavid Chinner if (tp->t_flags & XFS_TRANS_SB_DIRTY) { 7201da177e4SLinus Torvalds if (tp->t_dblocks_delta != 0) { 7211da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_DBLOCKS; 72220f4ebf2SDavid Chinner msbp->msb_delta = tp->t_dblocks_delta; 7231da177e4SLinus Torvalds msbp++; 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds if (tp->t_agcount_delta != 0) { 7261da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_AGCOUNT; 72720f4ebf2SDavid Chinner msbp->msb_delta = tp->t_agcount_delta; 7281da177e4SLinus Torvalds msbp++; 7291da177e4SLinus Torvalds } 7301da177e4SLinus Torvalds if (tp->t_imaxpct_delta != 0) { 7311da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_IMAX_PCT; 73220f4ebf2SDavid Chinner msbp->msb_delta = tp->t_imaxpct_delta; 7331da177e4SLinus Torvalds msbp++; 7341da177e4SLinus Torvalds } 7351da177e4SLinus Torvalds if (tp->t_rextsize_delta != 0) { 7361da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_REXTSIZE; 73720f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rextsize_delta; 7381da177e4SLinus Torvalds msbp++; 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds if (tp->t_rbmblocks_delta != 0) { 7411da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_RBMBLOCKS; 74220f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rbmblocks_delta; 7431da177e4SLinus Torvalds msbp++; 7441da177e4SLinus Torvalds } 7451da177e4SLinus Torvalds if (tp->t_rblocks_delta != 0) { 7461da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_RBLOCKS; 74720f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rblocks_delta; 7481da177e4SLinus Torvalds msbp++; 7491da177e4SLinus Torvalds } 7501da177e4SLinus Torvalds if (tp->t_rextents_delta != 0) { 7511da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_REXTENTS; 75220f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rextents_delta; 7531da177e4SLinus Torvalds msbp++; 7541da177e4SLinus Torvalds } 7551da177e4SLinus Torvalds if (tp->t_rextslog_delta != 0) { 7561da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_REXTSLOG; 75720f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rextslog_delta; 7581da177e4SLinus Torvalds msbp++; 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds } 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds /* 7631da177e4SLinus Torvalds * If we need to change anything, do it. 7641da177e4SLinus Torvalds */ 7651da177e4SLinus Torvalds if (msbp > msb) { 7661da177e4SLinus Torvalds error = xfs_mod_incore_sb_batch(tp->t_mountp, msb, 7671da177e4SLinus Torvalds (uint)(msbp - msb), rsvd); 7681da177e4SLinus Torvalds ASSERT(error == 0); 7691da177e4SLinus Torvalds } 7701da177e4SLinus Torvalds } 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds /* 7730924378aSDave Chinner * Total up the number of log iovecs needed to commit this 7740924378aSDave Chinner * transaction. The transaction itself needs one for the 7750924378aSDave Chinner * transaction header. Ask each dirty item in turn how many 7760924378aSDave Chinner * it needs to get the total. 7771da177e4SLinus Torvalds */ 7780924378aSDave Chinner static uint 7790924378aSDave Chinner xfs_trans_count_vecs( 780b1c1b5b6SDave Chinner struct xfs_trans *tp) 7811da177e4SLinus Torvalds { 7820924378aSDave Chinner int nvecs; 7830924378aSDave Chinner xfs_log_item_desc_t *lidp; 7840924378aSDave Chinner 7850924378aSDave Chinner nvecs = 1; 7860924378aSDave Chinner lidp = xfs_trans_first_item(tp); 7870924378aSDave Chinner ASSERT(lidp != NULL); 7880924378aSDave Chinner 7890924378aSDave Chinner /* In the non-debug case we need to start bailing out if we 7900924378aSDave Chinner * didn't find a log_item here, return zero and let trans_commit 7910924378aSDave Chinner * deal with it. 7920924378aSDave Chinner */ 7930924378aSDave Chinner if (lidp == NULL) 7940924378aSDave Chinner return 0; 7950924378aSDave Chinner 7960924378aSDave Chinner while (lidp != NULL) { 7970924378aSDave Chinner /* 7980924378aSDave Chinner * Skip items which aren't dirty in this transaction. 7990924378aSDave Chinner */ 8000924378aSDave Chinner if (!(lidp->lid_flags & XFS_LID_DIRTY)) { 8010924378aSDave Chinner lidp = xfs_trans_next_item(tp, lidp); 8020924378aSDave Chinner continue; 8030924378aSDave Chinner } 8040924378aSDave Chinner lidp->lid_size = IOP_SIZE(lidp->lid_item); 8050924378aSDave Chinner nvecs += lidp->lid_size; 8060924378aSDave Chinner lidp = xfs_trans_next_item(tp, lidp); 8070924378aSDave Chinner } 8080924378aSDave Chinner 8090924378aSDave Chinner return nvecs; 8100924378aSDave Chinner } 8110924378aSDave Chinner 8120924378aSDave Chinner /* 8130924378aSDave Chinner * Fill in the vector with pointers to data to be logged 8140924378aSDave Chinner * by this transaction. The transaction header takes 8150924378aSDave Chinner * the first vector, and then each dirty item takes the 8160924378aSDave Chinner * number of vectors it indicated it needed in xfs_trans_count_vecs(). 8170924378aSDave Chinner * 8180924378aSDave Chinner * As each item fills in the entries it needs, also pin the item 8190924378aSDave Chinner * so that it cannot be flushed out until the log write completes. 8200924378aSDave Chinner */ 8210924378aSDave Chinner static void 8220924378aSDave Chinner xfs_trans_fill_vecs( 8230924378aSDave Chinner struct xfs_trans *tp, 8240924378aSDave Chinner struct xfs_log_iovec *log_vector) 8250924378aSDave Chinner { 8260924378aSDave Chinner xfs_log_item_desc_t *lidp; 8270924378aSDave Chinner struct xfs_log_iovec *vecp; 8280924378aSDave Chinner uint nitems; 8290924378aSDave Chinner 8300924378aSDave Chinner /* 8310924378aSDave Chinner * Skip over the entry for the transaction header, we'll 8320924378aSDave Chinner * fill that in at the end. 8330924378aSDave Chinner */ 8340924378aSDave Chinner vecp = log_vector + 1; 8350924378aSDave Chinner 8360924378aSDave Chinner nitems = 0; 8370924378aSDave Chinner lidp = xfs_trans_first_item(tp); 8380924378aSDave Chinner ASSERT(lidp); 8390924378aSDave Chinner while (lidp) { 8400924378aSDave Chinner /* Skip items which aren't dirty in this transaction. */ 8410924378aSDave Chinner if (!(lidp->lid_flags & XFS_LID_DIRTY)) { 8420924378aSDave Chinner lidp = xfs_trans_next_item(tp, lidp); 8430924378aSDave Chinner continue; 8440924378aSDave Chinner } 8450924378aSDave Chinner 8460924378aSDave Chinner /* 8470924378aSDave Chinner * The item may be marked dirty but not log anything. This can 8480924378aSDave Chinner * be used to get called when a transaction is committed. 8490924378aSDave Chinner */ 8500924378aSDave Chinner if (lidp->lid_size) 8510924378aSDave Chinner nitems++; 8520924378aSDave Chinner IOP_FORMAT(lidp->lid_item, vecp); 8530924378aSDave Chinner vecp += lidp->lid_size; 8540924378aSDave Chinner IOP_PIN(lidp->lid_item); 8550924378aSDave Chinner lidp = xfs_trans_next_item(tp, lidp); 8560924378aSDave Chinner } 8570924378aSDave Chinner 8580924378aSDave Chinner /* 8590924378aSDave Chinner * Now that we've counted the number of items in this transaction, fill 8600924378aSDave Chinner * in the transaction header. Note that the transaction header does not 8610924378aSDave Chinner * have a log item. 8620924378aSDave Chinner */ 8630924378aSDave Chinner tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC; 8640924378aSDave Chinner tp->t_header.th_type = tp->t_type; 8650924378aSDave Chinner tp->t_header.th_num_items = nitems; 8660924378aSDave Chinner log_vector->i_addr = (xfs_caddr_t)&tp->t_header; 8670924378aSDave Chinner log_vector->i_len = sizeof(xfs_trans_header_t); 8680924378aSDave Chinner log_vector->i_type = XLOG_REG_TYPE_TRANSHDR; 8690924378aSDave Chinner } 8700924378aSDave Chinner 8710924378aSDave Chinner /* 872b1c1b5b6SDave Chinner * The committed item processing consists of calling the committed routine of 873b1c1b5b6SDave Chinner * each logged item, updating the item's position in the AIL if necessary, and 874b1c1b5b6SDave Chinner * unpinning each item. If the committed routine returns -1, then do nothing 875b1c1b5b6SDave Chinner * further with the item because it may have been freed. 876b1c1b5b6SDave Chinner * 877b1c1b5b6SDave Chinner * Since items are unlocked when they are copied to the incore log, it is 878b1c1b5b6SDave Chinner * possible for two transactions to be completing and manipulating the same 879b1c1b5b6SDave Chinner * item simultaneously. The AIL lock will protect the lsn field of each item. 880b1c1b5b6SDave Chinner * The value of this field can never go backwards. 881b1c1b5b6SDave Chinner * 882b1c1b5b6SDave Chinner * We unpin the items after repositioning them in the AIL, because otherwise 883b1c1b5b6SDave Chinner * they could be immediately flushed and we'd have to race with the flusher 884b1c1b5b6SDave Chinner * trying to pull the item from the AIL as we add it. 885b1c1b5b6SDave Chinner */ 886*71e330b5SDave Chinner void 887b1c1b5b6SDave Chinner xfs_trans_item_committed( 888b1c1b5b6SDave Chinner struct xfs_log_item *lip, 889b1c1b5b6SDave Chinner xfs_lsn_t commit_lsn, 890b1c1b5b6SDave Chinner int aborted) 891b1c1b5b6SDave Chinner { 892b1c1b5b6SDave Chinner xfs_lsn_t item_lsn; 893b1c1b5b6SDave Chinner struct xfs_ail *ailp; 894b1c1b5b6SDave Chinner 895b1c1b5b6SDave Chinner if (aborted) 896b1c1b5b6SDave Chinner lip->li_flags |= XFS_LI_ABORTED; 897b1c1b5b6SDave Chinner item_lsn = IOP_COMMITTED(lip, commit_lsn); 898b1c1b5b6SDave Chinner 899b1c1b5b6SDave Chinner /* If the committed routine returns -1, item has been freed. */ 900b1c1b5b6SDave Chinner if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) 901b1c1b5b6SDave Chinner return; 902b1c1b5b6SDave Chinner 903b1c1b5b6SDave Chinner /* 904b1c1b5b6SDave Chinner * If the returned lsn is greater than what it contained before, update 905b1c1b5b6SDave Chinner * the location of the item in the AIL. If it is not, then do nothing. 906b1c1b5b6SDave Chinner * Items can never move backwards in the AIL. 907b1c1b5b6SDave Chinner * 908b1c1b5b6SDave Chinner * While the new lsn should usually be greater, it is possible that a 909b1c1b5b6SDave Chinner * later transaction completing simultaneously with an earlier one 910b1c1b5b6SDave Chinner * using the same item could complete first with a higher lsn. This 911b1c1b5b6SDave Chinner * would cause the earlier transaction to fail the test below. 912b1c1b5b6SDave Chinner */ 913b1c1b5b6SDave Chinner ailp = lip->li_ailp; 914b1c1b5b6SDave Chinner spin_lock(&ailp->xa_lock); 915b1c1b5b6SDave Chinner if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) { 916b1c1b5b6SDave Chinner /* 917b1c1b5b6SDave Chinner * This will set the item's lsn to item_lsn and update the 918b1c1b5b6SDave Chinner * position of the item in the AIL. 919b1c1b5b6SDave Chinner * 920b1c1b5b6SDave Chinner * xfs_trans_ail_update() drops the AIL lock. 921b1c1b5b6SDave Chinner */ 922b1c1b5b6SDave Chinner xfs_trans_ail_update(ailp, lip, item_lsn); 923b1c1b5b6SDave Chinner } else { 924b1c1b5b6SDave Chinner spin_unlock(&ailp->xa_lock); 925b1c1b5b6SDave Chinner } 926b1c1b5b6SDave Chinner 927b1c1b5b6SDave Chinner /* 928b1c1b5b6SDave Chinner * Now that we've repositioned the item in the AIL, unpin it so it can 929b1c1b5b6SDave Chinner * be flushed. Pass information about buffer stale state down from the 930b1c1b5b6SDave Chinner * log item flags, if anyone else stales the buffer we do not want to 931b1c1b5b6SDave Chinner * pay any attention to it. 932b1c1b5b6SDave Chinner */ 933b1c1b5b6SDave Chinner IOP_UNPIN(lip); 934b1c1b5b6SDave Chinner } 935b1c1b5b6SDave Chinner 936b1c1b5b6SDave Chinner /* 937b1c1b5b6SDave Chinner * This is typically called by the LM when a transaction has been fully 938b1c1b5b6SDave Chinner * committed to disk. It needs to unpin the items which have 939b1c1b5b6SDave Chinner * been logged by the transaction and update their positions 940b1c1b5b6SDave Chinner * in the AIL if necessary. 941b1c1b5b6SDave Chinner * 942b1c1b5b6SDave Chinner * This also gets called when the transactions didn't get written out 943b1c1b5b6SDave Chinner * because of an I/O error. Abortflag & XFS_LI_ABORTED is set then. 944b1c1b5b6SDave Chinner */ 945b1c1b5b6SDave Chinner STATIC void 946b1c1b5b6SDave Chinner xfs_trans_committed( 947b1c1b5b6SDave Chinner struct xfs_trans *tp, 948b1c1b5b6SDave Chinner int abortflag) 949b1c1b5b6SDave Chinner { 950b1c1b5b6SDave Chinner xfs_log_item_desc_t *lidp; 951b1c1b5b6SDave Chinner xfs_log_item_chunk_t *licp; 952b1c1b5b6SDave Chinner xfs_log_item_chunk_t *next_licp; 953b1c1b5b6SDave Chinner 954b1c1b5b6SDave Chinner /* Call the transaction's completion callback if there is one. */ 955b1c1b5b6SDave Chinner if (tp->t_callback != NULL) 956b1c1b5b6SDave Chinner tp->t_callback(tp, tp->t_callarg); 957b1c1b5b6SDave Chinner 958b1c1b5b6SDave Chinner for (lidp = xfs_trans_first_item(tp); 959b1c1b5b6SDave Chinner lidp != NULL; 960b1c1b5b6SDave Chinner lidp = xfs_trans_next_item(tp, lidp)) { 961b1c1b5b6SDave Chinner xfs_trans_item_committed(lidp->lid_item, tp->t_lsn, abortflag); 962b1c1b5b6SDave Chinner } 963b1c1b5b6SDave Chinner 964b1c1b5b6SDave Chinner /* free the item chunks, ignoring the embedded chunk */ 965b1c1b5b6SDave Chinner for (licp = tp->t_items.lic_next; licp != NULL; licp = next_licp) { 966b1c1b5b6SDave Chinner next_licp = licp->lic_next; 967b1c1b5b6SDave Chinner kmem_free(licp); 968b1c1b5b6SDave Chinner } 969b1c1b5b6SDave Chinner 970b1c1b5b6SDave Chinner xfs_trans_free(tp); 971b1c1b5b6SDave Chinner } 972b1c1b5b6SDave Chinner 973b1c1b5b6SDave Chinner /* 974b1c1b5b6SDave Chinner * Called from the trans_commit code when we notice that 975b1c1b5b6SDave Chinner * the filesystem is in the middle of a forced shutdown. 976b1c1b5b6SDave Chinner */ 977b1c1b5b6SDave Chinner STATIC void 978b1c1b5b6SDave Chinner xfs_trans_uncommit( 979b1c1b5b6SDave Chinner struct xfs_trans *tp, 980b1c1b5b6SDave Chinner uint flags) 981b1c1b5b6SDave Chinner { 982b1c1b5b6SDave Chinner xfs_log_item_desc_t *lidp; 983b1c1b5b6SDave Chinner 984b1c1b5b6SDave Chinner for (lidp = xfs_trans_first_item(tp); 985b1c1b5b6SDave Chinner lidp != NULL; 986b1c1b5b6SDave Chinner lidp = xfs_trans_next_item(tp, lidp)) { 987b1c1b5b6SDave Chinner /* 988b1c1b5b6SDave Chinner * Unpin all but those that aren't dirty. 989b1c1b5b6SDave Chinner */ 990b1c1b5b6SDave Chinner if (lidp->lid_flags & XFS_LID_DIRTY) 991b1c1b5b6SDave Chinner IOP_UNPIN_REMOVE(lidp->lid_item, tp); 992b1c1b5b6SDave Chinner } 993b1c1b5b6SDave Chinner 994b1c1b5b6SDave Chinner xfs_trans_unreserve_and_mod_sb(tp); 995b1c1b5b6SDave Chinner xfs_trans_unreserve_and_mod_dquots(tp); 996b1c1b5b6SDave Chinner 997*71e330b5SDave Chinner xfs_trans_free_items(tp, NULLCOMMITLSN, flags); 998b1c1b5b6SDave Chinner xfs_trans_free(tp); 999b1c1b5b6SDave Chinner } 1000b1c1b5b6SDave Chinner 1001b1c1b5b6SDave Chinner /* 10020924378aSDave Chinner * Format the transaction direct to the iclog. This isolates the physical 10030924378aSDave Chinner * transaction commit operation from the logical operation and hence allows 10040924378aSDave Chinner * other methods to be introduced without affecting the existing commit path. 10050924378aSDave Chinner */ 10060924378aSDave Chinner static int 10070924378aSDave Chinner xfs_trans_commit_iclog( 10080924378aSDave Chinner struct xfs_mount *mp, 10090924378aSDave Chinner struct xfs_trans *tp, 10100924378aSDave Chinner xfs_lsn_t *commit_lsn, 10110924378aSDave Chinner int flags) 10120924378aSDave Chinner { 10131da177e4SLinus Torvalds int shutdown; 10140924378aSDave Chinner int error; 10150924378aSDave Chinner int log_flags = 0; 10160924378aSDave Chinner struct xlog_in_core *commit_iclog; 10170924378aSDave Chinner #define XFS_TRANS_LOGVEC_COUNT 16 10180924378aSDave Chinner struct xfs_log_iovec log_vector_fast[XFS_TRANS_LOGVEC_COUNT]; 10190924378aSDave Chinner struct xfs_log_iovec *log_vector; 10200924378aSDave Chinner uint nvec; 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds /* 10241da177e4SLinus Torvalds * Ask each log item how many log_vector entries it will 10251da177e4SLinus Torvalds * need so we can figure out how many to allocate. 10261da177e4SLinus Torvalds * Try to avoid the kmem_alloc() call in the common case 10271da177e4SLinus Torvalds * by using a vector from the stack when it fits. 10281da177e4SLinus Torvalds */ 10291da177e4SLinus Torvalds nvec = xfs_trans_count_vecs(tp); 10301da177e4SLinus Torvalds if (nvec == 0) { 10310924378aSDave Chinner return ENOMEM; /* triggers a shutdown! */ 1032cfcbbbd0SNathan Scott } else if (nvec <= XFS_TRANS_LOGVEC_COUNT) { 10331da177e4SLinus Torvalds log_vector = log_vector_fast; 10341da177e4SLinus Torvalds } else { 10351da177e4SLinus Torvalds log_vector = (xfs_log_iovec_t *)kmem_alloc(nvec * 10361da177e4SLinus Torvalds sizeof(xfs_log_iovec_t), 10371da177e4SLinus Torvalds KM_SLEEP); 10381da177e4SLinus Torvalds } 10391da177e4SLinus Torvalds 10401da177e4SLinus Torvalds /* 10411da177e4SLinus Torvalds * Fill in the log_vector and pin the logged items, and 10421da177e4SLinus Torvalds * then write the transaction to the log. 10431da177e4SLinus Torvalds */ 10441da177e4SLinus Torvalds xfs_trans_fill_vecs(tp, log_vector); 10451da177e4SLinus Torvalds 10460924378aSDave Chinner if (flags & XFS_TRANS_RELEASE_LOG_RES) 10470924378aSDave Chinner log_flags = XFS_LOG_REL_PERM_RESERV; 10480924378aSDave Chinner 1049cfcbbbd0SNathan Scott error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, &(tp->t_lsn)); 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds /* 1052cfcbbbd0SNathan Scott * The transaction is committed incore here, and can go out to disk 1053cfcbbbd0SNathan Scott * at any time after this call. However, all the items associated 1054cfcbbbd0SNathan Scott * with the transaction are still locked and pinned in memory. 10551da177e4SLinus Torvalds */ 10560924378aSDave Chinner *commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags); 10571da177e4SLinus Torvalds 10580924378aSDave Chinner tp->t_commit_lsn = *commit_lsn; 1059ed3b4d6cSDave Chinner trace_xfs_trans_commit_lsn(tp); 1060ed3b4d6cSDave Chinner 10610924378aSDave Chinner if (nvec > XFS_TRANS_LOGVEC_COUNT) 1062f0e2d93cSDenys Vlasenko kmem_free(log_vector); 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds /* 10651da177e4SLinus Torvalds * If we got a log write error. Unpin the logitems that we 10661da177e4SLinus Torvalds * had pinned, clean up, free trans structure, and return error. 10671da177e4SLinus Torvalds */ 10680924378aSDave Chinner if (error || *commit_lsn == -1) { 106959c1b082SNathan Scott current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 10701da177e4SLinus Torvalds xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT); 10711da177e4SLinus Torvalds return XFS_ERROR(EIO); 10721da177e4SLinus Torvalds } 10731da177e4SLinus Torvalds 10741da177e4SLinus Torvalds /* 10751da177e4SLinus Torvalds * Once the transaction has committed, unused 10761da177e4SLinus Torvalds * reservations need to be released and changes to 10771da177e4SLinus Torvalds * the superblock need to be reflected in the in-core 10781da177e4SLinus Torvalds * version. Do that now. 10791da177e4SLinus Torvalds */ 10801da177e4SLinus Torvalds xfs_trans_unreserve_and_mod_sb(tp); 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds /* 10831da177e4SLinus Torvalds * Tell the LM to call the transaction completion routine 10841da177e4SLinus Torvalds * when the log write with LSN commit_lsn completes (e.g. 10851da177e4SLinus Torvalds * when the transaction commit really hits the on-disk log). 10861da177e4SLinus Torvalds * After this call we cannot reference tp, because the call 10871da177e4SLinus Torvalds * can happen at any time and the call will free the transaction 10881da177e4SLinus Torvalds * structure pointed to by tp. The only case where we call 10891da177e4SLinus Torvalds * the completion routine (xfs_trans_committed) directly is 10901da177e4SLinus Torvalds * if the log is turned off on a debug kernel or we're 10911da177e4SLinus Torvalds * running in simulation mode (the log is explicitly turned 10921da177e4SLinus Torvalds * off). 10931da177e4SLinus Torvalds */ 10941da177e4SLinus Torvalds tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed; 10951da177e4SLinus Torvalds tp->t_logcb.cb_arg = tp; 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds /* 10981da177e4SLinus Torvalds * We need to pass the iclog buffer which was used for the 10991da177e4SLinus Torvalds * transaction commit record into this function, and attach 11001da177e4SLinus Torvalds * the callback to it. The callback must be attached before 11011da177e4SLinus Torvalds * the items are unlocked to avoid racing with other threads 11021da177e4SLinus Torvalds * waiting for an item to unlock. 11031da177e4SLinus Torvalds */ 11041da177e4SLinus Torvalds shutdown = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb)); 11051da177e4SLinus Torvalds 11061da177e4SLinus Torvalds /* 11071da177e4SLinus Torvalds * Mark this thread as no longer being in a transaction 11081da177e4SLinus Torvalds */ 110959c1b082SNathan Scott current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 11101da177e4SLinus Torvalds 11111da177e4SLinus Torvalds /* 11121da177e4SLinus Torvalds * Once all the items of the transaction have been copied 11131da177e4SLinus Torvalds * to the in core log and the callback is attached, the 11141da177e4SLinus Torvalds * items can be unlocked. 11151da177e4SLinus Torvalds * 11161da177e4SLinus Torvalds * This will free descriptors pointing to items which were 11171da177e4SLinus Torvalds * not logged since there is nothing more to do with them. 11181da177e4SLinus Torvalds * For items which were logged, we will keep pointers to them 11191da177e4SLinus Torvalds * so they can be unpinned after the transaction commits to disk. 11201da177e4SLinus Torvalds * This will also stamp each modified meta-data item with 11211da177e4SLinus Torvalds * the commit lsn of this transaction for dependency tracking 11221da177e4SLinus Torvalds * purposes. 11231da177e4SLinus Torvalds */ 11240924378aSDave Chinner xfs_trans_unlock_items(tp, *commit_lsn); 11251da177e4SLinus Torvalds 11261da177e4SLinus Torvalds /* 11271da177e4SLinus Torvalds * If we detected a log error earlier, finish committing 11281da177e4SLinus Torvalds * the transaction now (unpin log items, etc). 11291da177e4SLinus Torvalds * 11301da177e4SLinus Torvalds * Order is critical here, to avoid using the transaction 11311da177e4SLinus Torvalds * pointer after its been freed (by xfs_trans_committed 11321da177e4SLinus Torvalds * either here now, or as a callback). We cannot do this 11331da177e4SLinus Torvalds * step inside xfs_log_notify as was done earlier because 11341da177e4SLinus Torvalds * of this issue. 11351da177e4SLinus Torvalds */ 11361da177e4SLinus Torvalds if (shutdown) 11371da177e4SLinus Torvalds xfs_trans_committed(tp, XFS_LI_ABORTED); 11381da177e4SLinus Torvalds 11391da177e4SLinus Torvalds /* 11401da177e4SLinus Torvalds * Now that the xfs_trans_committed callback has been attached, 11411da177e4SLinus Torvalds * and the items are released we can finally allow the iclog to 11421da177e4SLinus Torvalds * go to disk. 11431da177e4SLinus Torvalds */ 11440924378aSDave Chinner return xfs_log_release_iclog(mp, commit_iclog); 11450924378aSDave Chinner } 11460924378aSDave Chinner 1147*71e330b5SDave Chinner /* 1148*71e330b5SDave Chinner * Walk the log items and allocate log vector structures for 1149*71e330b5SDave Chinner * each item large enough to fit all the vectors they require. 1150*71e330b5SDave Chinner * Note that this format differs from the old log vector format in 1151*71e330b5SDave Chinner * that there is no transaction header in these log vectors. 1152*71e330b5SDave Chinner */ 1153*71e330b5SDave Chinner STATIC struct xfs_log_vec * 1154*71e330b5SDave Chinner xfs_trans_alloc_log_vecs( 1155*71e330b5SDave Chinner xfs_trans_t *tp) 1156*71e330b5SDave Chinner { 1157*71e330b5SDave Chinner xfs_log_item_desc_t *lidp; 1158*71e330b5SDave Chinner struct xfs_log_vec *lv = NULL; 1159*71e330b5SDave Chinner struct xfs_log_vec *ret_lv = NULL; 1160*71e330b5SDave Chinner 1161*71e330b5SDave Chinner lidp = xfs_trans_first_item(tp); 1162*71e330b5SDave Chinner 1163*71e330b5SDave Chinner /* Bail out if we didn't find a log item. */ 1164*71e330b5SDave Chinner if (!lidp) { 1165*71e330b5SDave Chinner ASSERT(0); 1166*71e330b5SDave Chinner return NULL; 1167*71e330b5SDave Chinner } 1168*71e330b5SDave Chinner 1169*71e330b5SDave Chinner while (lidp != NULL) { 1170*71e330b5SDave Chinner struct xfs_log_vec *new_lv; 1171*71e330b5SDave Chinner 1172*71e330b5SDave Chinner /* Skip items which aren't dirty in this transaction. */ 1173*71e330b5SDave Chinner if (!(lidp->lid_flags & XFS_LID_DIRTY)) { 1174*71e330b5SDave Chinner lidp = xfs_trans_next_item(tp, lidp); 1175*71e330b5SDave Chinner continue; 1176*71e330b5SDave Chinner } 1177*71e330b5SDave Chinner 1178*71e330b5SDave Chinner /* Skip items that do not have any vectors for writing */ 1179*71e330b5SDave Chinner lidp->lid_size = IOP_SIZE(lidp->lid_item); 1180*71e330b5SDave Chinner if (!lidp->lid_size) { 1181*71e330b5SDave Chinner lidp = xfs_trans_next_item(tp, lidp); 1182*71e330b5SDave Chinner continue; 1183*71e330b5SDave Chinner } 1184*71e330b5SDave Chinner 1185*71e330b5SDave Chinner new_lv = kmem_zalloc(sizeof(*new_lv) + 1186*71e330b5SDave Chinner lidp->lid_size * sizeof(struct xfs_log_iovec), 1187*71e330b5SDave Chinner KM_SLEEP); 1188*71e330b5SDave Chinner 1189*71e330b5SDave Chinner /* The allocated iovec region lies beyond the log vector. */ 1190*71e330b5SDave Chinner new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1]; 1191*71e330b5SDave Chinner new_lv->lv_niovecs = lidp->lid_size; 1192*71e330b5SDave Chinner new_lv->lv_item = lidp->lid_item; 1193*71e330b5SDave Chinner if (!ret_lv) 1194*71e330b5SDave Chinner ret_lv = new_lv; 1195*71e330b5SDave Chinner else 1196*71e330b5SDave Chinner lv->lv_next = new_lv; 1197*71e330b5SDave Chinner lv = new_lv; 1198*71e330b5SDave Chinner lidp = xfs_trans_next_item(tp, lidp); 1199*71e330b5SDave Chinner } 1200*71e330b5SDave Chinner 1201*71e330b5SDave Chinner return ret_lv; 1202*71e330b5SDave Chinner } 1203*71e330b5SDave Chinner 1204*71e330b5SDave Chinner static int 1205*71e330b5SDave Chinner xfs_trans_commit_cil( 1206*71e330b5SDave Chinner struct xfs_mount *mp, 1207*71e330b5SDave Chinner struct xfs_trans *tp, 1208*71e330b5SDave Chinner xfs_lsn_t *commit_lsn, 1209*71e330b5SDave Chinner int flags) 1210*71e330b5SDave Chinner { 1211*71e330b5SDave Chinner struct xfs_log_vec *log_vector; 1212*71e330b5SDave Chinner int error; 1213*71e330b5SDave Chinner 1214*71e330b5SDave Chinner /* 1215*71e330b5SDave Chinner * Get each log item to allocate a vector structure for 1216*71e330b5SDave Chinner * the log item to to pass to the log write code. The 1217*71e330b5SDave Chinner * CIL commit code will format the vector and save it away. 1218*71e330b5SDave Chinner */ 1219*71e330b5SDave Chinner log_vector = xfs_trans_alloc_log_vecs(tp); 1220*71e330b5SDave Chinner if (!log_vector) 1221*71e330b5SDave Chinner return ENOMEM; 1222*71e330b5SDave Chinner 1223*71e330b5SDave Chinner error = xfs_log_commit_cil(mp, tp, log_vector, commit_lsn, flags); 1224*71e330b5SDave Chinner if (error) 1225*71e330b5SDave Chinner return error; 1226*71e330b5SDave Chinner 1227*71e330b5SDave Chinner current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 1228*71e330b5SDave Chinner 1229*71e330b5SDave Chinner /* xfs_trans_free_items() unlocks them first */ 1230*71e330b5SDave Chinner xfs_trans_free_items(tp, *commit_lsn, 0); 1231*71e330b5SDave Chinner xfs_trans_free(tp); 1232*71e330b5SDave Chinner return 0; 1233*71e330b5SDave Chinner } 12340924378aSDave Chinner 12350924378aSDave Chinner /* 12360924378aSDave Chinner * xfs_trans_commit 12370924378aSDave Chinner * 12380924378aSDave Chinner * Commit the given transaction to the log a/synchronously. 12390924378aSDave Chinner * 12400924378aSDave Chinner * XFS disk error handling mechanism is not based on a typical 12410924378aSDave Chinner * transaction abort mechanism. Logically after the filesystem 12420924378aSDave Chinner * gets marked 'SHUTDOWN', we can't let any new transactions 12430924378aSDave Chinner * be durable - ie. committed to disk - because some metadata might 12440924378aSDave Chinner * be inconsistent. In such cases, this returns an error, and the 12450924378aSDave Chinner * caller may assume that all locked objects joined to the transaction 12460924378aSDave Chinner * have already been unlocked as if the commit had succeeded. 12470924378aSDave Chinner * Do not reference the transaction structure after this call. 12480924378aSDave Chinner */ 12490924378aSDave Chinner int 12500924378aSDave Chinner _xfs_trans_commit( 1251a3ccd2caSChristoph Hellwig struct xfs_trans *tp, 12520924378aSDave Chinner uint flags, 12530924378aSDave Chinner int *log_flushed) 12540924378aSDave Chinner { 1255a3ccd2caSChristoph Hellwig struct xfs_mount *mp = tp->t_mountp; 12560924378aSDave Chinner xfs_lsn_t commit_lsn = -1; 1257a3ccd2caSChristoph Hellwig int error = 0; 12580924378aSDave Chinner int log_flags = 0; 12590924378aSDave Chinner int sync = tp->t_flags & XFS_TRANS_SYNC; 12600924378aSDave Chinner 12610924378aSDave Chinner /* 12620924378aSDave Chinner * Determine whether this commit is releasing a permanent 12630924378aSDave Chinner * log reservation or not. 12640924378aSDave Chinner */ 12650924378aSDave Chinner if (flags & XFS_TRANS_RELEASE_LOG_RES) { 12660924378aSDave Chinner ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); 12670924378aSDave Chinner log_flags = XFS_LOG_REL_PERM_RESERV; 12680924378aSDave Chinner } 12690924378aSDave Chinner 12700924378aSDave Chinner /* 12710924378aSDave Chinner * If there is nothing to be logged by the transaction, 12720924378aSDave Chinner * then unlock all of the items associated with the 12730924378aSDave Chinner * transaction and free the transaction structure. 12740924378aSDave Chinner * Also make sure to return any reserved blocks to 12750924378aSDave Chinner * the free pool. 12760924378aSDave Chinner */ 1277a3ccd2caSChristoph Hellwig if (!(tp->t_flags & XFS_TRANS_DIRTY)) 1278a3ccd2caSChristoph Hellwig goto out_unreserve; 1279a3ccd2caSChristoph Hellwig 1280a3ccd2caSChristoph Hellwig if (XFS_FORCED_SHUTDOWN(mp)) { 1281a3ccd2caSChristoph Hellwig error = XFS_ERROR(EIO); 1282a3ccd2caSChristoph Hellwig goto out_unreserve; 12830924378aSDave Chinner } 1284a3ccd2caSChristoph Hellwig 12850924378aSDave Chinner ASSERT(tp->t_ticket != NULL); 12860924378aSDave Chinner 12870924378aSDave Chinner /* 12880924378aSDave Chinner * If we need to update the superblock, then do it now. 12890924378aSDave Chinner */ 12900924378aSDave Chinner if (tp->t_flags & XFS_TRANS_SB_DIRTY) 12910924378aSDave Chinner xfs_trans_apply_sb_deltas(tp); 12920924378aSDave Chinner xfs_trans_apply_dquot_deltas(tp); 12930924378aSDave Chinner 1294*71e330b5SDave Chinner if (mp->m_flags & XFS_MOUNT_DELAYLOG) 1295*71e330b5SDave Chinner error = xfs_trans_commit_cil(mp, tp, &commit_lsn, flags); 1296*71e330b5SDave Chinner else 12970924378aSDave Chinner error = xfs_trans_commit_iclog(mp, tp, &commit_lsn, flags); 1298*71e330b5SDave Chinner 12990924378aSDave Chinner if (error == ENOMEM) { 13000924378aSDave Chinner xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); 1301a3ccd2caSChristoph Hellwig error = XFS_ERROR(EIO); 1302a3ccd2caSChristoph Hellwig goto out_unreserve; 13030924378aSDave Chinner } 13041da177e4SLinus Torvalds 13051da177e4SLinus Torvalds /* 13061da177e4SLinus Torvalds * If the transaction needs to be synchronous, then force the 13071da177e4SLinus Torvalds * log out now and wait for it. 13081da177e4SLinus Torvalds */ 13091da177e4SLinus Torvalds if (sync) { 1310f538d4daSChristoph Hellwig if (!error) { 1311a14a348bSChristoph Hellwig error = _xfs_log_force_lsn(mp, commit_lsn, 1312a14a348bSChristoph Hellwig XFS_LOG_SYNC, log_flushed); 1313f538d4daSChristoph Hellwig } 13141da177e4SLinus Torvalds XFS_STATS_INC(xs_trans_sync); 13151da177e4SLinus Torvalds } else { 13161da177e4SLinus Torvalds XFS_STATS_INC(xs_trans_async); 13171da177e4SLinus Torvalds } 13181da177e4SLinus Torvalds 1319a3ccd2caSChristoph Hellwig return error; 1320a3ccd2caSChristoph Hellwig 1321a3ccd2caSChristoph Hellwig out_unreserve: 1322a3ccd2caSChristoph Hellwig xfs_trans_unreserve_and_mod_sb(tp); 1323a3ccd2caSChristoph Hellwig 1324a3ccd2caSChristoph Hellwig /* 1325a3ccd2caSChristoph Hellwig * It is indeed possible for the transaction to be not dirty but 1326a3ccd2caSChristoph Hellwig * the dqinfo portion to be. All that means is that we have some 1327a3ccd2caSChristoph Hellwig * (non-persistent) quota reservations that need to be unreserved. 1328a3ccd2caSChristoph Hellwig */ 1329a3ccd2caSChristoph Hellwig xfs_trans_unreserve_and_mod_dquots(tp); 1330a3ccd2caSChristoph Hellwig if (tp->t_ticket) { 1331a3ccd2caSChristoph Hellwig commit_lsn = xfs_log_done(mp, tp->t_ticket, NULL, log_flags); 1332a3ccd2caSChristoph Hellwig if (commit_lsn == -1 && !error) 1333a3ccd2caSChristoph Hellwig error = XFS_ERROR(EIO); 1334a3ccd2caSChristoph Hellwig } 1335a3ccd2caSChristoph Hellwig current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 1336*71e330b5SDave Chinner xfs_trans_free_items(tp, NULLCOMMITLSN, error ? XFS_TRANS_ABORT : 0); 1337a3ccd2caSChristoph Hellwig xfs_trans_free(tp); 1338a3ccd2caSChristoph Hellwig 1339a3ccd2caSChristoph Hellwig XFS_STATS_INC(xs_trans_empty); 1340a3ccd2caSChristoph Hellwig return error; 13411da177e4SLinus Torvalds } 13421da177e4SLinus Torvalds 13431da177e4SLinus Torvalds /* 13441da177e4SLinus Torvalds * Unlock all of the transaction's items and free the transaction. 13451da177e4SLinus Torvalds * The transaction must not have modified any of its items, because 13461da177e4SLinus Torvalds * there is no way to restore them to their previous state. 13471da177e4SLinus Torvalds * 13481da177e4SLinus Torvalds * If the transaction has made a log reservation, make sure to release 13491da177e4SLinus Torvalds * it as well. 13501da177e4SLinus Torvalds */ 13511da177e4SLinus Torvalds void 13521da177e4SLinus Torvalds xfs_trans_cancel( 13531da177e4SLinus Torvalds xfs_trans_t *tp, 13541da177e4SLinus Torvalds int flags) 13551da177e4SLinus Torvalds { 13561da177e4SLinus Torvalds int log_flags; 13571da177e4SLinus Torvalds #ifdef DEBUG 13581da177e4SLinus Torvalds xfs_log_item_chunk_t *licp; 13591da177e4SLinus Torvalds xfs_log_item_desc_t *lidp; 13601da177e4SLinus Torvalds xfs_log_item_t *lip; 13611da177e4SLinus Torvalds int i; 13621da177e4SLinus Torvalds #endif 13630733af21SRyan Hankins xfs_mount_t *mp = tp->t_mountp; 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds /* 13661da177e4SLinus Torvalds * See if the caller is being too lazy to figure out if 13671da177e4SLinus Torvalds * the transaction really needs an abort. 13681da177e4SLinus Torvalds */ 13691da177e4SLinus Torvalds if ((flags & XFS_TRANS_ABORT) && !(tp->t_flags & XFS_TRANS_DIRTY)) 13701da177e4SLinus Torvalds flags &= ~XFS_TRANS_ABORT; 13711da177e4SLinus Torvalds /* 13721da177e4SLinus Torvalds * See if the caller is relying on us to shut down the 13731da177e4SLinus Torvalds * filesystem. This happens in paths where we detect 13741da177e4SLinus Torvalds * corruption and decide to give up. 13751da177e4SLinus Torvalds */ 137660a204f0SNathan Scott if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) { 13770733af21SRyan Hankins XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp); 13787d04a335SNathan Scott xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 137960a204f0SNathan Scott } 13801da177e4SLinus Torvalds #ifdef DEBUG 13811da177e4SLinus Torvalds if (!(flags & XFS_TRANS_ABORT)) { 13821da177e4SLinus Torvalds licp = &(tp->t_items); 13831da177e4SLinus Torvalds while (licp != NULL) { 13841da177e4SLinus Torvalds lidp = licp->lic_descs; 13851da177e4SLinus Torvalds for (i = 0; i < licp->lic_unused; i++, lidp++) { 138639dab9d7SEric Sandeen if (xfs_lic_isfree(licp, i)) { 13871da177e4SLinus Torvalds continue; 13881da177e4SLinus Torvalds } 13891da177e4SLinus Torvalds 13901da177e4SLinus Torvalds lip = lidp->lid_item; 13910733af21SRyan Hankins if (!XFS_FORCED_SHUTDOWN(mp)) 13921da177e4SLinus Torvalds ASSERT(!(lip->li_type == XFS_LI_EFD)); 13931da177e4SLinus Torvalds } 13941da177e4SLinus Torvalds licp = licp->lic_next; 13951da177e4SLinus Torvalds } 13961da177e4SLinus Torvalds } 13971da177e4SLinus Torvalds #endif 13981da177e4SLinus Torvalds xfs_trans_unreserve_and_mod_sb(tp); 13997d095257SChristoph Hellwig xfs_trans_unreserve_and_mod_dquots(tp); 14001da177e4SLinus Torvalds 14011da177e4SLinus Torvalds if (tp->t_ticket) { 14021da177e4SLinus Torvalds if (flags & XFS_TRANS_RELEASE_LOG_RES) { 14031da177e4SLinus Torvalds ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); 14041da177e4SLinus Torvalds log_flags = XFS_LOG_REL_PERM_RESERV; 14051da177e4SLinus Torvalds } else { 14061da177e4SLinus Torvalds log_flags = 0; 14071da177e4SLinus Torvalds } 14080733af21SRyan Hankins xfs_log_done(mp, tp->t_ticket, NULL, log_flags); 14091da177e4SLinus Torvalds } 14101da177e4SLinus Torvalds 14111da177e4SLinus Torvalds /* mark this thread as no longer being in a transaction */ 141259c1b082SNathan Scott current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 14131da177e4SLinus Torvalds 1414*71e330b5SDave Chinner xfs_trans_free_items(tp, NULLCOMMITLSN, flags); 14151da177e4SLinus Torvalds xfs_trans_free(tp); 14161da177e4SLinus Torvalds } 14171da177e4SLinus Torvalds 1418322ff6b8SNiv Sardi /* 1419322ff6b8SNiv Sardi * Roll from one trans in the sequence of PERMANENT transactions to 1420322ff6b8SNiv Sardi * the next: permanent transactions are only flushed out when 1421322ff6b8SNiv Sardi * committed with XFS_TRANS_RELEASE_LOG_RES, but we still want as soon 1422322ff6b8SNiv Sardi * as possible to let chunks of it go to the log. So we commit the 1423322ff6b8SNiv Sardi * chunk we've been working on and get a new transaction to continue. 1424322ff6b8SNiv Sardi */ 1425322ff6b8SNiv Sardi int 1426322ff6b8SNiv Sardi xfs_trans_roll( 1427322ff6b8SNiv Sardi struct xfs_trans **tpp, 1428322ff6b8SNiv Sardi struct xfs_inode *dp) 1429322ff6b8SNiv Sardi { 1430322ff6b8SNiv Sardi struct xfs_trans *trans; 1431322ff6b8SNiv Sardi unsigned int logres, count; 1432322ff6b8SNiv Sardi int error; 1433322ff6b8SNiv Sardi 1434322ff6b8SNiv Sardi /* 1435322ff6b8SNiv Sardi * Ensure that the inode is always logged. 1436322ff6b8SNiv Sardi */ 1437322ff6b8SNiv Sardi trans = *tpp; 1438322ff6b8SNiv Sardi xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); 1439322ff6b8SNiv Sardi 1440322ff6b8SNiv Sardi /* 1441322ff6b8SNiv Sardi * Copy the critical parameters from one trans to the next. 1442322ff6b8SNiv Sardi */ 1443322ff6b8SNiv Sardi logres = trans->t_log_res; 1444322ff6b8SNiv Sardi count = trans->t_log_count; 1445322ff6b8SNiv Sardi *tpp = xfs_trans_dup(trans); 1446322ff6b8SNiv Sardi 1447322ff6b8SNiv Sardi /* 1448322ff6b8SNiv Sardi * Commit the current transaction. 1449322ff6b8SNiv Sardi * If this commit failed, then it'd just unlock those items that 1450322ff6b8SNiv Sardi * are not marked ihold. That also means that a filesystem shutdown 1451322ff6b8SNiv Sardi * is in progress. The caller takes the responsibility to cancel 1452322ff6b8SNiv Sardi * the duplicate transaction that gets returned. 1453322ff6b8SNiv Sardi */ 1454322ff6b8SNiv Sardi error = xfs_trans_commit(trans, 0); 1455322ff6b8SNiv Sardi if (error) 1456322ff6b8SNiv Sardi return (error); 1457322ff6b8SNiv Sardi 1458322ff6b8SNiv Sardi trans = *tpp; 1459322ff6b8SNiv Sardi 1460322ff6b8SNiv Sardi /* 1461cc09c0dcSDave Chinner * transaction commit worked ok so we can drop the extra ticket 1462cc09c0dcSDave Chinner * reference that we gained in xfs_trans_dup() 1463cc09c0dcSDave Chinner */ 1464cc09c0dcSDave Chinner xfs_log_ticket_put(trans->t_ticket); 1465cc09c0dcSDave Chinner 1466cc09c0dcSDave Chinner 1467cc09c0dcSDave Chinner /* 1468322ff6b8SNiv Sardi * Reserve space in the log for th next transaction. 1469322ff6b8SNiv Sardi * This also pushes items in the "AIL", the list of logged items, 1470322ff6b8SNiv Sardi * out to disk if they are taking up space at the tail of the log 1471322ff6b8SNiv Sardi * that we want to use. This requires that either nothing be locked 1472322ff6b8SNiv Sardi * across this call, or that anything that is locked be logged in 1473322ff6b8SNiv Sardi * the prior and the next transactions. 1474322ff6b8SNiv Sardi */ 1475322ff6b8SNiv Sardi error = xfs_trans_reserve(trans, 0, logres, 0, 1476322ff6b8SNiv Sardi XFS_TRANS_PERM_LOG_RES, count); 1477322ff6b8SNiv Sardi /* 1478322ff6b8SNiv Sardi * Ensure that the inode is in the new transaction and locked. 1479322ff6b8SNiv Sardi */ 1480322ff6b8SNiv Sardi if (error) 1481322ff6b8SNiv Sardi return error; 1482322ff6b8SNiv Sardi 1483322ff6b8SNiv Sardi xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); 1484322ff6b8SNiv Sardi xfs_trans_ihold(trans, dp); 1485322ff6b8SNiv Sardi return 0; 1486322ff6b8SNiv Sardi } 1487