11da177e4SLinus Torvalds /* 27b718769SNathan Scott * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. 3e98c414fSChristoph Hellwig * Copyright (C) 2010 Red Hat, Inc. 47b718769SNathan Scott * All Rights Reserved. 51da177e4SLinus Torvalds * 67b718769SNathan Scott * This program is free software; you can redistribute it and/or 77b718769SNathan Scott * modify it under the terms of the GNU General Public License as 81da177e4SLinus Torvalds * published by the Free Software Foundation. 91da177e4SLinus Torvalds * 107b718769SNathan Scott * This program is distributed in the hope that it would be useful, 117b718769SNathan Scott * but WITHOUT ANY WARRANTY; without even the implied warranty of 127b718769SNathan Scott * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 137b718769SNathan Scott * GNU General Public License for more details. 141da177e4SLinus Torvalds * 157b718769SNathan Scott * You should have received a copy of the GNU General Public License 167b718769SNathan Scott * along with this program; if not, write the Free Software Foundation, 177b718769SNathan Scott * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 181da177e4SLinus Torvalds */ 191da177e4SLinus Torvalds #include "xfs.h" 20a844f451SNathan Scott #include "xfs_fs.h" 2170a9883cSDave Chinner #include "xfs_shared.h" 22239880efSDave Chinner #include "xfs_format.h" 23239880efSDave Chinner #include "xfs_log_format.h" 24239880efSDave Chinner #include "xfs_trans_resv.h" 251da177e4SLinus Torvalds #include "xfs_mount.h" 26a844f451SNathan Scott #include "xfs_inode.h" 27efc27b52SDave Chinner #include "xfs_extent_busy.h" 281da177e4SLinus Torvalds #include "xfs_quota.h" 29239880efSDave Chinner #include "xfs_trans.h" 30a844f451SNathan Scott #include "xfs_trans_priv.h" 31239880efSDave Chinner #include "xfs_log.h" 32ed3b4d6cSDave Chinner #include "xfs_trace.h" 33a4fbe6abSDave Chinner #include "xfs_error.h" 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds kmem_zone_t *xfs_trans_zone; 36e98c414fSChristoph Hellwig kmem_zone_t *xfs_log_item_desc_zone; 371da177e4SLinus Torvalds 384f3b5783SJeff Liu /* 391da177e4SLinus Torvalds * Initialize the precomputed transaction reservation values 401da177e4SLinus Torvalds * in the mount structure. 411da177e4SLinus Torvalds */ 421da177e4SLinus Torvalds void 431da177e4SLinus Torvalds xfs_trans_init( 44025101dcSChristoph Hellwig struct xfs_mount *mp) 451da177e4SLinus Torvalds { 463d3c8b52SJie Liu xfs_trans_resv_calc(mp, M_RES(mp)); 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds /* 501da177e4SLinus Torvalds * This routine is called to allocate a transaction structure. 511da177e4SLinus Torvalds * The type parameter indicates the type of the transaction. These 521da177e4SLinus Torvalds * are enumerated in xfs_trans.h. 53b2ce3974SAlex Elder * 54b2ce3974SAlex Elder * Dynamically allocate the transaction structure from the transaction 55b2ce3974SAlex Elder * zone, initialize it, and return it to the caller. 561da177e4SLinus Torvalds */ 57b2ce3974SAlex Elder xfs_trans_t * 58b2ce3974SAlex Elder xfs_trans_alloc( 59b2ce3974SAlex Elder xfs_mount_t *mp, 60b2ce3974SAlex Elder uint type) 611da177e4SLinus Torvalds { 62d9457dc0SJan Kara xfs_trans_t *tp; 63d9457dc0SJan Kara 64d9457dc0SJan Kara sb_start_intwrite(mp->m_super); 65d9457dc0SJan Kara tp = _xfs_trans_alloc(mp, type, KM_SLEEP); 66d9457dc0SJan Kara tp->t_flags |= XFS_TRANS_FREEZE_PROT; 67d9457dc0SJan Kara return tp; 68b2ce3974SAlex Elder } 69b2ce3974SAlex Elder 70b2ce3974SAlex Elder xfs_trans_t * 71b2ce3974SAlex Elder _xfs_trans_alloc( 72b2ce3974SAlex Elder xfs_mount_t *mp, 73b2ce3974SAlex Elder uint type, 7477ba7877SAl Viro xfs_km_flags_t memflags) 75b2ce3974SAlex Elder { 76b2ce3974SAlex Elder xfs_trans_t *tp; 771da177e4SLinus Torvalds 78d9457dc0SJan Kara WARN_ON(mp->m_super->s_writers.frozen == SB_FREEZE_COMPLETE); 7934327e13SNathan Scott atomic_inc(&mp->m_active_trans); 801da177e4SLinus Torvalds 8180641dc6SChristoph Hellwig tp = kmem_zone_zalloc(xfs_trans_zone, memflags); 822a3c0accSDave Chinner tp->t_magic = XFS_TRANS_HEADER_MAGIC; 831da177e4SLinus Torvalds tp->t_type = type; 841da177e4SLinus Torvalds tp->t_mountp = mp; 85e98c414fSChristoph Hellwig INIT_LIST_HEAD(&tp->t_items); 86ed3b4d6cSDave Chinner INIT_LIST_HEAD(&tp->t_busy); 8734327e13SNathan Scott return tp; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds /* 91b1c1b5b6SDave Chinner * Free the transaction structure. If there is more clean up 92b1c1b5b6SDave Chinner * to do when the structure is freed, add it here. 93b1c1b5b6SDave Chinner */ 94b1c1b5b6SDave Chinner STATIC void 95b1c1b5b6SDave Chinner xfs_trans_free( 96ed3b4d6cSDave Chinner struct xfs_trans *tp) 97b1c1b5b6SDave Chinner { 984ecbfe63SDave Chinner xfs_extent_busy_sort(&tp->t_busy); 994ecbfe63SDave Chinner xfs_extent_busy_clear(tp->t_mountp, &tp->t_busy, false); 100ed3b4d6cSDave Chinner 101b1c1b5b6SDave Chinner atomic_dec(&tp->t_mountp->m_active_trans); 102d9457dc0SJan Kara if (tp->t_flags & XFS_TRANS_FREEZE_PROT) 103d9457dc0SJan Kara sb_end_intwrite(tp->t_mountp->m_super); 104b1c1b5b6SDave Chinner xfs_trans_free_dqinfo(tp); 105b1c1b5b6SDave Chinner kmem_zone_free(xfs_trans_zone, tp); 106b1c1b5b6SDave Chinner } 107b1c1b5b6SDave Chinner 108b1c1b5b6SDave Chinner /* 1091da177e4SLinus Torvalds * This is called to create a new transaction which will share the 1101da177e4SLinus Torvalds * permanent log reservation of the given transaction. The remaining 1111da177e4SLinus Torvalds * unused block and rt extent reservations are also inherited. This 1121da177e4SLinus Torvalds * implies that the original transaction is no longer allowed to allocate 1131da177e4SLinus Torvalds * blocks. Locks and log items, however, are no inherited. They must 1141da177e4SLinus Torvalds * be added to the new transaction explicitly. 1151da177e4SLinus Torvalds */ 1161da177e4SLinus Torvalds xfs_trans_t * 1171da177e4SLinus Torvalds xfs_trans_dup( 1181da177e4SLinus Torvalds xfs_trans_t *tp) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds xfs_trans_t *ntp; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds /* 1251da177e4SLinus Torvalds * Initialize the new transaction structure. 1261da177e4SLinus Torvalds */ 1272a3c0accSDave Chinner ntp->t_magic = XFS_TRANS_HEADER_MAGIC; 1281da177e4SLinus Torvalds ntp->t_type = tp->t_type; 1291da177e4SLinus Torvalds ntp->t_mountp = tp->t_mountp; 130e98c414fSChristoph Hellwig INIT_LIST_HEAD(&ntp->t_items); 131ed3b4d6cSDave Chinner INIT_LIST_HEAD(&ntp->t_busy); 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); 1341da177e4SLinus Torvalds ASSERT(tp->t_ticket != NULL); 135cfcbbbd0SNathan Scott 136d9457dc0SJan Kara ntp->t_flags = XFS_TRANS_PERM_LOG_RES | 137d9457dc0SJan Kara (tp->t_flags & XFS_TRANS_RESERVE) | 138d9457dc0SJan Kara (tp->t_flags & XFS_TRANS_FREEZE_PROT); 139d9457dc0SJan Kara /* We gave our writer reference to the new transaction */ 140d9457dc0SJan Kara tp->t_flags &= ~XFS_TRANS_FREEZE_PROT; 141cc09c0dcSDave Chinner ntp->t_ticket = xfs_log_ticket_get(tp->t_ticket); 1421da177e4SLinus Torvalds ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used; 1431da177e4SLinus Torvalds tp->t_blk_res = tp->t_blk_res_used; 1441da177e4SLinus Torvalds ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; 1451da177e4SLinus Torvalds tp->t_rtx_res = tp->t_rtx_res_used; 14659c1b082SNathan Scott ntp->t_pflags = tp->t_pflags; 1471da177e4SLinus Torvalds 1487d095257SChristoph Hellwig xfs_trans_dup_dqinfo(tp, ntp); 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds atomic_inc(&tp->t_mountp->m_active_trans); 1511da177e4SLinus Torvalds return ntp; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds /* 1551da177e4SLinus Torvalds * This is called to reserve free disk blocks and log space for the 1561da177e4SLinus Torvalds * given transaction. This must be done before allocating any resources 1571da177e4SLinus Torvalds * within the transaction. 1581da177e4SLinus Torvalds * 1591da177e4SLinus Torvalds * This will return ENOSPC if there are not enough blocks available. 1601da177e4SLinus Torvalds * It will sleep waiting for available log space. 1611da177e4SLinus Torvalds * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which 1621da177e4SLinus Torvalds * is used by long running transactions. If any one of the reservations 1631da177e4SLinus Torvalds * fails then they will all be backed out. 1641da177e4SLinus Torvalds * 1651da177e4SLinus Torvalds * This does not do quota reservations. That typically is done by the 1661da177e4SLinus Torvalds * caller afterwards. 1671da177e4SLinus Torvalds */ 1681da177e4SLinus Torvalds int 1691da177e4SLinus Torvalds xfs_trans_reserve( 1703d3c8b52SJie Liu struct xfs_trans *tp, 1713d3c8b52SJie Liu struct xfs_trans_res *resp, 1721da177e4SLinus Torvalds uint blocks, 1733d3c8b52SJie Liu uint rtextents) 1741da177e4SLinus Torvalds { 17559c1b082SNathan Scott int error = 0; 17659c1b082SNathan Scott int rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds /* Mark this thread as being in a transaction */ 17959c1b082SNathan Scott current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds /* 1821da177e4SLinus Torvalds * Attempt to reserve the needed disk blocks by decrementing 1831da177e4SLinus Torvalds * the number needed from the number available. This will 1841da177e4SLinus Torvalds * fail if the count would go below zero. 1851da177e4SLinus Torvalds */ 1861da177e4SLinus Torvalds if (blocks > 0) { 18796540c78SChristoph Hellwig error = xfs_icsb_modify_counters(tp->t_mountp, XFS_SBS_FDBLOCKS, 18820f4ebf2SDavid Chinner -((int64_t)blocks), rsvd); 1891da177e4SLinus Torvalds if (error != 0) { 19059c1b082SNathan Scott current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 1912451337dSDave Chinner return -ENOSPC; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds tp->t_blk_res += blocks; 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds /* 1971da177e4SLinus Torvalds * Reserve the log space needed for this transaction. 1981da177e4SLinus Torvalds */ 1993d3c8b52SJie Liu if (resp->tr_logres > 0) { 2009006fb91SChristoph Hellwig bool permanent = false; 2019006fb91SChristoph Hellwig 2023d3c8b52SJie Liu ASSERT(tp->t_log_res == 0 || 2033d3c8b52SJie Liu tp->t_log_res == resp->tr_logres); 2043d3c8b52SJie Liu ASSERT(tp->t_log_count == 0 || 2053d3c8b52SJie Liu tp->t_log_count == resp->tr_logcount); 2069006fb91SChristoph Hellwig 2073d3c8b52SJie Liu if (resp->tr_logflags & XFS_TRANS_PERM_LOG_RES) { 2081da177e4SLinus Torvalds tp->t_flags |= XFS_TRANS_PERM_LOG_RES; 2099006fb91SChristoph Hellwig permanent = true; 2101da177e4SLinus Torvalds } else { 2111da177e4SLinus Torvalds ASSERT(tp->t_ticket == NULL); 2121da177e4SLinus Torvalds ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2159006fb91SChristoph Hellwig if (tp->t_ticket != NULL) { 2163d3c8b52SJie Liu ASSERT(resp->tr_logflags & XFS_TRANS_PERM_LOG_RES); 2179006fb91SChristoph Hellwig error = xfs_log_regrant(tp->t_mountp, tp->t_ticket); 2189006fb91SChristoph Hellwig } else { 2193d3c8b52SJie Liu error = xfs_log_reserve(tp->t_mountp, 2203d3c8b52SJie Liu resp->tr_logres, 2213d3c8b52SJie Liu resp->tr_logcount, 2223d3c8b52SJie Liu &tp->t_ticket, XFS_TRANSACTION, 2233d3c8b52SJie Liu permanent, tp->t_type); 2241da177e4SLinus Torvalds } 2259006fb91SChristoph Hellwig 2269006fb91SChristoph Hellwig if (error) 2279006fb91SChristoph Hellwig goto undo_blocks; 2289006fb91SChristoph Hellwig 2293d3c8b52SJie Liu tp->t_log_res = resp->tr_logres; 2303d3c8b52SJie Liu tp->t_log_count = resp->tr_logcount; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /* 2341da177e4SLinus Torvalds * Attempt to reserve the needed realtime extents by decrementing 2351da177e4SLinus Torvalds * the number needed from the number available. This will 2361da177e4SLinus Torvalds * fail if the count would go below zero. 2371da177e4SLinus Torvalds */ 2381da177e4SLinus Torvalds if (rtextents > 0) { 2391da177e4SLinus Torvalds error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FREXTENTS, 24020f4ebf2SDavid Chinner -((int64_t)rtextents), rsvd); 2411da177e4SLinus Torvalds if (error) { 2422451337dSDave Chinner error = -ENOSPC; 2431da177e4SLinus Torvalds goto undo_log; 2441da177e4SLinus Torvalds } 2451da177e4SLinus Torvalds tp->t_rtx_res += rtextents; 2461da177e4SLinus Torvalds } 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds return 0; 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* 2511da177e4SLinus Torvalds * Error cases jump to one of these labels to undo any 2521da177e4SLinus Torvalds * reservations which have already been performed. 2531da177e4SLinus Torvalds */ 2541da177e4SLinus Torvalds undo_log: 2553d3c8b52SJie Liu if (resp->tr_logres > 0) { 2569006fb91SChristoph Hellwig int log_flags; 2579006fb91SChristoph Hellwig 2583d3c8b52SJie Liu if (resp->tr_logflags & XFS_TRANS_PERM_LOG_RES) { 2591da177e4SLinus Torvalds log_flags = XFS_LOG_REL_PERM_RESERV; 2601da177e4SLinus Torvalds } else { 2611da177e4SLinus Torvalds log_flags = 0; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, log_flags); 2641da177e4SLinus Torvalds tp->t_ticket = NULL; 2651da177e4SLinus Torvalds tp->t_log_res = 0; 2661da177e4SLinus Torvalds tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES; 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds undo_blocks: 2701da177e4SLinus Torvalds if (blocks > 0) { 27196540c78SChristoph Hellwig xfs_icsb_modify_counters(tp->t_mountp, XFS_SBS_FDBLOCKS, 27220f4ebf2SDavid Chinner (int64_t)blocks, rsvd); 2731da177e4SLinus Torvalds tp->t_blk_res = 0; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 27659c1b082SNathan Scott current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 2771da177e4SLinus Torvalds 27859c1b082SNathan Scott return error; 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds /* 2821da177e4SLinus Torvalds * Record the indicated change to the given field for application 2831da177e4SLinus Torvalds * to the file system's superblock when the transaction commits. 2841da177e4SLinus Torvalds * For now, just store the change in the transaction structure. 2851da177e4SLinus Torvalds * 2861da177e4SLinus Torvalds * Mark the transaction structure to indicate that the superblock 2871da177e4SLinus Torvalds * needs to be updated before committing. 28892821e2bSDavid Chinner * 28992821e2bSDavid Chinner * Because we may not be keeping track of allocated/free inodes and 29092821e2bSDavid Chinner * used filesystem blocks in the superblock, we do not mark the 29192821e2bSDavid Chinner * superblock dirty in this transaction if we modify these fields. 29292821e2bSDavid Chinner * We still need to update the transaction deltas so that they get 29392821e2bSDavid Chinner * applied to the incore superblock, but we don't want them to 29492821e2bSDavid Chinner * cause the superblock to get locked and logged if these are the 29592821e2bSDavid Chinner * only fields in the superblock that the transaction modifies. 2961da177e4SLinus Torvalds */ 2971da177e4SLinus Torvalds void 2981da177e4SLinus Torvalds xfs_trans_mod_sb( 2991da177e4SLinus Torvalds xfs_trans_t *tp, 3001da177e4SLinus Torvalds uint field, 30120f4ebf2SDavid Chinner int64_t delta) 3021da177e4SLinus Torvalds { 30392821e2bSDavid Chinner uint32_t flags = (XFS_TRANS_DIRTY|XFS_TRANS_SB_DIRTY); 30492821e2bSDavid Chinner xfs_mount_t *mp = tp->t_mountp; 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds switch (field) { 3071da177e4SLinus Torvalds case XFS_TRANS_SB_ICOUNT: 3081da177e4SLinus Torvalds tp->t_icount_delta += delta; 30992821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb)) 31092821e2bSDavid Chinner flags &= ~XFS_TRANS_SB_DIRTY; 3111da177e4SLinus Torvalds break; 3121da177e4SLinus Torvalds case XFS_TRANS_SB_IFREE: 3131da177e4SLinus Torvalds tp->t_ifree_delta += delta; 31492821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb)) 31592821e2bSDavid Chinner flags &= ~XFS_TRANS_SB_DIRTY; 3161da177e4SLinus Torvalds break; 3171da177e4SLinus Torvalds case XFS_TRANS_SB_FDBLOCKS: 3181da177e4SLinus Torvalds /* 3191da177e4SLinus Torvalds * Track the number of blocks allocated in the 3201da177e4SLinus Torvalds * transaction. Make sure it does not exceed the 3211da177e4SLinus Torvalds * number reserved. 3221da177e4SLinus Torvalds */ 3231da177e4SLinus Torvalds if (delta < 0) { 3241da177e4SLinus Torvalds tp->t_blk_res_used += (uint)-delta; 3251da177e4SLinus Torvalds ASSERT(tp->t_blk_res_used <= tp->t_blk_res); 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds tp->t_fdblocks_delta += delta; 32892821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb)) 32992821e2bSDavid Chinner flags &= ~XFS_TRANS_SB_DIRTY; 3301da177e4SLinus Torvalds break; 3311da177e4SLinus Torvalds case XFS_TRANS_SB_RES_FDBLOCKS: 3321da177e4SLinus Torvalds /* 3331da177e4SLinus Torvalds * The allocation has already been applied to the 3341da177e4SLinus Torvalds * in-core superblock's counter. This should only 3351da177e4SLinus Torvalds * be applied to the on-disk superblock. 3361da177e4SLinus Torvalds */ 3371da177e4SLinus Torvalds ASSERT(delta < 0); 3381da177e4SLinus Torvalds tp->t_res_fdblocks_delta += delta; 33992821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb)) 34092821e2bSDavid Chinner flags &= ~XFS_TRANS_SB_DIRTY; 3411da177e4SLinus Torvalds break; 3421da177e4SLinus Torvalds case XFS_TRANS_SB_FREXTENTS: 3431da177e4SLinus Torvalds /* 3441da177e4SLinus Torvalds * Track the number of blocks allocated in the 3451da177e4SLinus Torvalds * transaction. Make sure it does not exceed the 3461da177e4SLinus Torvalds * number reserved. 3471da177e4SLinus Torvalds */ 3481da177e4SLinus Torvalds if (delta < 0) { 3491da177e4SLinus Torvalds tp->t_rtx_res_used += (uint)-delta; 3501da177e4SLinus Torvalds ASSERT(tp->t_rtx_res_used <= tp->t_rtx_res); 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds tp->t_frextents_delta += delta; 3531da177e4SLinus Torvalds break; 3541da177e4SLinus Torvalds case XFS_TRANS_SB_RES_FREXTENTS: 3551da177e4SLinus Torvalds /* 3561da177e4SLinus Torvalds * The allocation has already been applied to the 357c41564b5SNathan Scott * in-core superblock's counter. This should only 3581da177e4SLinus Torvalds * be applied to the on-disk superblock. 3591da177e4SLinus Torvalds */ 3601da177e4SLinus Torvalds ASSERT(delta < 0); 3611da177e4SLinus Torvalds tp->t_res_frextents_delta += delta; 3621da177e4SLinus Torvalds break; 3631da177e4SLinus Torvalds case XFS_TRANS_SB_DBLOCKS: 3641da177e4SLinus Torvalds ASSERT(delta > 0); 3651da177e4SLinus Torvalds tp->t_dblocks_delta += delta; 3661da177e4SLinus Torvalds break; 3671da177e4SLinus Torvalds case XFS_TRANS_SB_AGCOUNT: 3681da177e4SLinus Torvalds ASSERT(delta > 0); 3691da177e4SLinus Torvalds tp->t_agcount_delta += delta; 3701da177e4SLinus Torvalds break; 3711da177e4SLinus Torvalds case XFS_TRANS_SB_IMAXPCT: 3721da177e4SLinus Torvalds tp->t_imaxpct_delta += delta; 3731da177e4SLinus Torvalds break; 3741da177e4SLinus Torvalds case XFS_TRANS_SB_REXTSIZE: 3751da177e4SLinus Torvalds tp->t_rextsize_delta += delta; 3761da177e4SLinus Torvalds break; 3771da177e4SLinus Torvalds case XFS_TRANS_SB_RBMBLOCKS: 3781da177e4SLinus Torvalds tp->t_rbmblocks_delta += delta; 3791da177e4SLinus Torvalds break; 3801da177e4SLinus Torvalds case XFS_TRANS_SB_RBLOCKS: 3811da177e4SLinus Torvalds tp->t_rblocks_delta += delta; 3821da177e4SLinus Torvalds break; 3831da177e4SLinus Torvalds case XFS_TRANS_SB_REXTENTS: 3841da177e4SLinus Torvalds tp->t_rextents_delta += delta; 3851da177e4SLinus Torvalds break; 3861da177e4SLinus Torvalds case XFS_TRANS_SB_REXTSLOG: 3871da177e4SLinus Torvalds tp->t_rextslog_delta += delta; 3881da177e4SLinus Torvalds break; 3891da177e4SLinus Torvalds default: 3901da177e4SLinus Torvalds ASSERT(0); 3911da177e4SLinus Torvalds return; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 394210c6f1cSDavid Chinner tp->t_flags |= flags; 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds /* 3981da177e4SLinus Torvalds * xfs_trans_apply_sb_deltas() is called from the commit code 3991da177e4SLinus Torvalds * to bring the superblock buffer into the current transaction 4001da177e4SLinus Torvalds * and modify it as requested by earlier calls to xfs_trans_mod_sb(). 4011da177e4SLinus Torvalds * 4021da177e4SLinus Torvalds * For now we just look at each field allowed to change and change 4031da177e4SLinus Torvalds * it if necessary. 4041da177e4SLinus Torvalds */ 4051da177e4SLinus Torvalds STATIC void 4061da177e4SLinus Torvalds xfs_trans_apply_sb_deltas( 4071da177e4SLinus Torvalds xfs_trans_t *tp) 4081da177e4SLinus Torvalds { 4092bdf7cd0SChristoph Hellwig xfs_dsb_t *sbp; 4101da177e4SLinus Torvalds xfs_buf_t *bp; 4111da177e4SLinus Torvalds int whole = 0; 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds bp = xfs_trans_getsb(tp, tp->t_mountp, 0); 4141da177e4SLinus Torvalds sbp = XFS_BUF_TO_SBP(bp); 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds /* 4171da177e4SLinus Torvalds * Check that superblock mods match the mods made to AGF counters. 4181da177e4SLinus Torvalds */ 4191da177e4SLinus Torvalds ASSERT((tp->t_fdblocks_delta + tp->t_res_fdblocks_delta) == 4201da177e4SLinus Torvalds (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta + 4211da177e4SLinus Torvalds tp->t_ag_btree_delta)); 4221da177e4SLinus Torvalds 42392821e2bSDavid Chinner /* 42492821e2bSDavid Chinner * Only update the superblock counters if we are logging them 42592821e2bSDavid Chinner */ 42692821e2bSDavid Chinner if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) { 4272bdf7cd0SChristoph Hellwig if (tp->t_icount_delta) 428413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_icount, tp->t_icount_delta); 4292bdf7cd0SChristoph Hellwig if (tp->t_ifree_delta) 430413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_ifree, tp->t_ifree_delta); 4312bdf7cd0SChristoph Hellwig if (tp->t_fdblocks_delta) 432413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_fdblocks, tp->t_fdblocks_delta); 4332bdf7cd0SChristoph Hellwig if (tp->t_res_fdblocks_delta) 434413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_fdblocks, tp->t_res_fdblocks_delta); 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds 4372bdf7cd0SChristoph Hellwig if (tp->t_frextents_delta) 438413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_frextents, tp->t_frextents_delta); 4392bdf7cd0SChristoph Hellwig if (tp->t_res_frextents_delta) 440413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_frextents, tp->t_res_frextents_delta); 4411da177e4SLinus Torvalds 4422bdf7cd0SChristoph Hellwig if (tp->t_dblocks_delta) { 443413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_dblocks, tp->t_dblocks_delta); 4441da177e4SLinus Torvalds whole = 1; 4451da177e4SLinus Torvalds } 4462bdf7cd0SChristoph Hellwig if (tp->t_agcount_delta) { 447413d57c9SMarcin Slusarz be32_add_cpu(&sbp->sb_agcount, tp->t_agcount_delta); 4481da177e4SLinus Torvalds whole = 1; 4491da177e4SLinus Torvalds } 4502bdf7cd0SChristoph Hellwig if (tp->t_imaxpct_delta) { 4512bdf7cd0SChristoph Hellwig sbp->sb_imax_pct += tp->t_imaxpct_delta; 4521da177e4SLinus Torvalds whole = 1; 4531da177e4SLinus Torvalds } 4542bdf7cd0SChristoph Hellwig if (tp->t_rextsize_delta) { 455413d57c9SMarcin Slusarz be32_add_cpu(&sbp->sb_rextsize, tp->t_rextsize_delta); 4561da177e4SLinus Torvalds whole = 1; 4571da177e4SLinus Torvalds } 4582bdf7cd0SChristoph Hellwig if (tp->t_rbmblocks_delta) { 459413d57c9SMarcin Slusarz be32_add_cpu(&sbp->sb_rbmblocks, tp->t_rbmblocks_delta); 4601da177e4SLinus Torvalds whole = 1; 4611da177e4SLinus Torvalds } 4622bdf7cd0SChristoph Hellwig if (tp->t_rblocks_delta) { 463413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_rblocks, tp->t_rblocks_delta); 4641da177e4SLinus Torvalds whole = 1; 4651da177e4SLinus Torvalds } 4662bdf7cd0SChristoph Hellwig if (tp->t_rextents_delta) { 467413d57c9SMarcin Slusarz be64_add_cpu(&sbp->sb_rextents, tp->t_rextents_delta); 4681da177e4SLinus Torvalds whole = 1; 4691da177e4SLinus Torvalds } 4702bdf7cd0SChristoph Hellwig if (tp->t_rextslog_delta) { 4712bdf7cd0SChristoph Hellwig sbp->sb_rextslog += tp->t_rextslog_delta; 4721da177e4SLinus Torvalds whole = 1; 4731da177e4SLinus Torvalds } 4741da177e4SLinus Torvalds 4753443a3bcSDave Chinner xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); 4761da177e4SLinus Torvalds if (whole) 4771da177e4SLinus Torvalds /* 478c41564b5SNathan Scott * Log the whole thing, the fields are noncontiguous. 4791da177e4SLinus Torvalds */ 4802bdf7cd0SChristoph Hellwig xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_dsb_t) - 1); 4811da177e4SLinus Torvalds else 4821da177e4SLinus Torvalds /* 4831da177e4SLinus Torvalds * Since all the modifiable fields are contiguous, we 4841da177e4SLinus Torvalds * can get away with this. 4851da177e4SLinus Torvalds */ 4862bdf7cd0SChristoph Hellwig xfs_trans_log_buf(tp, bp, offsetof(xfs_dsb_t, sb_icount), 4872bdf7cd0SChristoph Hellwig offsetof(xfs_dsb_t, sb_frextents) + 4881da177e4SLinus Torvalds sizeof(sbp->sb_frextents) - 1); 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds /* 49245c34141SDavid Chinner * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations 49345c34141SDavid Chinner * and apply superblock counter changes to the in-core superblock. The 49445c34141SDavid Chinner * t_res_fdblocks_delta and t_res_frextents_delta fields are explicitly NOT 49545c34141SDavid Chinner * applied to the in-core superblock. The idea is that that has already been 49645c34141SDavid Chinner * done. 4971da177e4SLinus Torvalds * 4981da177e4SLinus Torvalds * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). 49945c34141SDavid Chinner * However, we have to ensure that we only modify each superblock field only 50045c34141SDavid Chinner * once because the application of the delta values may not be atomic. That can 50145c34141SDavid Chinner * lead to ENOSPC races occurring if we have two separate modifcations of the 50245c34141SDavid Chinner * free space counter to put back the entire reservation and then take away 50345c34141SDavid Chinner * what we used. 50445c34141SDavid Chinner * 50545c34141SDavid Chinner * If we are not logging superblock counters, then the inode allocated/free and 50645c34141SDavid Chinner * used block counts are not updated in the on disk superblock. In this case, 50745c34141SDavid Chinner * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we 50845c34141SDavid Chinner * still need to update the incore superblock with the changes. 5091da177e4SLinus Torvalds */ 51071e330b5SDave Chinner void 5111da177e4SLinus Torvalds xfs_trans_unreserve_and_mod_sb( 5121da177e4SLinus Torvalds xfs_trans_t *tp) 5131da177e4SLinus Torvalds { 5141b040712SChristoph Hellwig xfs_mod_sb_t msb[9]; /* If you add cases, add entries */ 5151da177e4SLinus Torvalds xfs_mod_sb_t *msbp; 51692821e2bSDavid Chinner xfs_mount_t *mp = tp->t_mountp; 5171da177e4SLinus Torvalds /* REFERENCED */ 5181da177e4SLinus Torvalds int error; 5191da177e4SLinus Torvalds int rsvd; 52045c34141SDavid Chinner int64_t blkdelta = 0; 52145c34141SDavid Chinner int64_t rtxdelta = 0; 5221b040712SChristoph Hellwig int64_t idelta = 0; 5231b040712SChristoph Hellwig int64_t ifreedelta = 0; 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds msbp = msb; 5261da177e4SLinus Torvalds rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; 5271da177e4SLinus Torvalds 5281b040712SChristoph Hellwig /* calculate deltas */ 52945c34141SDavid Chinner if (tp->t_blk_res > 0) 53045c34141SDavid Chinner blkdelta = tp->t_blk_res; 53145c34141SDavid Chinner if ((tp->t_fdblocks_delta != 0) && 53245c34141SDavid Chinner (xfs_sb_version_haslazysbcount(&mp->m_sb) || 53345c34141SDavid Chinner (tp->t_flags & XFS_TRANS_SB_DIRTY))) 53445c34141SDavid Chinner blkdelta += tp->t_fdblocks_delta; 53545c34141SDavid Chinner 53645c34141SDavid Chinner if (tp->t_rtx_res > 0) 53745c34141SDavid Chinner rtxdelta = tp->t_rtx_res; 53845c34141SDavid Chinner if ((tp->t_frextents_delta != 0) && 53945c34141SDavid Chinner (tp->t_flags & XFS_TRANS_SB_DIRTY)) 54045c34141SDavid Chinner rtxdelta += tp->t_frextents_delta; 54145c34141SDavid Chinner 5421b040712SChristoph Hellwig if (xfs_sb_version_haslazysbcount(&mp->m_sb) || 5431b040712SChristoph Hellwig (tp->t_flags & XFS_TRANS_SB_DIRTY)) { 5441b040712SChristoph Hellwig idelta = tp->t_icount_delta; 5451b040712SChristoph Hellwig ifreedelta = tp->t_ifree_delta; 5461b040712SChristoph Hellwig } 5471b040712SChristoph Hellwig 5481b040712SChristoph Hellwig /* apply the per-cpu counters */ 5491b040712SChristoph Hellwig if (blkdelta) { 5501b040712SChristoph Hellwig error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, 5511b040712SChristoph Hellwig blkdelta, rsvd); 5521b040712SChristoph Hellwig if (error) 5531b040712SChristoph Hellwig goto out; 5541b040712SChristoph Hellwig } 5551b040712SChristoph Hellwig 5561b040712SChristoph Hellwig if (idelta) { 557*501ab323SDave Chinner error = xfs_mod_icount(mp, idelta); 5581b040712SChristoph Hellwig if (error) 5591b040712SChristoph Hellwig goto out_undo_fdblocks; 5601b040712SChristoph Hellwig } 5611b040712SChristoph Hellwig 5621b040712SChristoph Hellwig if (ifreedelta) { 5631b040712SChristoph Hellwig error = xfs_icsb_modify_counters(mp, XFS_SBS_IFREE, 5641b040712SChristoph Hellwig ifreedelta, rsvd); 5651b040712SChristoph Hellwig if (error) 5661b040712SChristoph Hellwig goto out_undo_icount; 5671b040712SChristoph Hellwig } 5681b040712SChristoph Hellwig 5691b040712SChristoph Hellwig /* apply remaining deltas */ 57045c34141SDavid Chinner if (rtxdelta != 0) { 5711da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_FREXTENTS; 57245c34141SDavid Chinner msbp->msb_delta = rtxdelta; 5731da177e4SLinus Torvalds msbp++; 5741da177e4SLinus Torvalds } 5751da177e4SLinus Torvalds 57692821e2bSDavid Chinner if (tp->t_flags & XFS_TRANS_SB_DIRTY) { 5771da177e4SLinus Torvalds if (tp->t_dblocks_delta != 0) { 5781da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_DBLOCKS; 57920f4ebf2SDavid Chinner msbp->msb_delta = tp->t_dblocks_delta; 5801da177e4SLinus Torvalds msbp++; 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds if (tp->t_agcount_delta != 0) { 5831da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_AGCOUNT; 58420f4ebf2SDavid Chinner msbp->msb_delta = tp->t_agcount_delta; 5851da177e4SLinus Torvalds msbp++; 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds if (tp->t_imaxpct_delta != 0) { 5881da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_IMAX_PCT; 58920f4ebf2SDavid Chinner msbp->msb_delta = tp->t_imaxpct_delta; 5901da177e4SLinus Torvalds msbp++; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds if (tp->t_rextsize_delta != 0) { 5931da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_REXTSIZE; 59420f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rextsize_delta; 5951da177e4SLinus Torvalds msbp++; 5961da177e4SLinus Torvalds } 5971da177e4SLinus Torvalds if (tp->t_rbmblocks_delta != 0) { 5981da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_RBMBLOCKS; 59920f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rbmblocks_delta; 6001da177e4SLinus Torvalds msbp++; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds if (tp->t_rblocks_delta != 0) { 6031da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_RBLOCKS; 60420f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rblocks_delta; 6051da177e4SLinus Torvalds msbp++; 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds if (tp->t_rextents_delta != 0) { 6081da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_REXTENTS; 60920f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rextents_delta; 6101da177e4SLinus Torvalds msbp++; 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds if (tp->t_rextslog_delta != 0) { 6131da177e4SLinus Torvalds msbp->msb_field = XFS_SBS_REXTSLOG; 61420f4ebf2SDavid Chinner msbp->msb_delta = tp->t_rextslog_delta; 6151da177e4SLinus Torvalds msbp++; 6161da177e4SLinus Torvalds } 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds /* 6201da177e4SLinus Torvalds * If we need to change anything, do it. 6211da177e4SLinus Torvalds */ 6221da177e4SLinus Torvalds if (msbp > msb) { 6231da177e4SLinus Torvalds error = xfs_mod_incore_sb_batch(tp->t_mountp, msb, 6241da177e4SLinus Torvalds (uint)(msbp - msb), rsvd); 6251b040712SChristoph Hellwig if (error) 6261b040712SChristoph Hellwig goto out_undo_ifreecount; 6271da177e4SLinus Torvalds } 6281b040712SChristoph Hellwig 6291b040712SChristoph Hellwig return; 6301b040712SChristoph Hellwig 6311b040712SChristoph Hellwig out_undo_ifreecount: 6321b040712SChristoph Hellwig if (ifreedelta) 6331b040712SChristoph Hellwig xfs_icsb_modify_counters(mp, XFS_SBS_IFREE, -ifreedelta, rsvd); 6341b040712SChristoph Hellwig out_undo_icount: 6351b040712SChristoph Hellwig if (idelta) 636*501ab323SDave Chinner xfs_mod_icount(mp, -idelta); 6371b040712SChristoph Hellwig out_undo_fdblocks: 6381b040712SChristoph Hellwig if (blkdelta) 6391b040712SChristoph Hellwig xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, -blkdelta, rsvd); 6401b040712SChristoph Hellwig out: 6411884bd83SJesper Juhl ASSERT(error == 0); 6421b040712SChristoph Hellwig return; 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds /* 646e98c414fSChristoph Hellwig * Add the given log item to the transaction's list of log items. 647e98c414fSChristoph Hellwig * 648e98c414fSChristoph Hellwig * The log item will now point to its new descriptor with its li_desc field. 649e98c414fSChristoph Hellwig */ 650e98c414fSChristoph Hellwig void 651e98c414fSChristoph Hellwig xfs_trans_add_item( 652e98c414fSChristoph Hellwig struct xfs_trans *tp, 653e98c414fSChristoph Hellwig struct xfs_log_item *lip) 654e98c414fSChristoph Hellwig { 655e98c414fSChristoph Hellwig struct xfs_log_item_desc *lidp; 656e98c414fSChristoph Hellwig 657f65020a8SJesper Juhl ASSERT(lip->li_mountp == tp->t_mountp); 658f65020a8SJesper Juhl ASSERT(lip->li_ailp == tp->t_mountp->m_ail); 659e98c414fSChristoph Hellwig 66043869706SDave Chinner lidp = kmem_zone_zalloc(xfs_log_item_desc_zone, KM_SLEEP | KM_NOFS); 661e98c414fSChristoph Hellwig 662e98c414fSChristoph Hellwig lidp->lid_item = lip; 663e98c414fSChristoph Hellwig lidp->lid_flags = 0; 664e98c414fSChristoph Hellwig list_add_tail(&lidp->lid_trans, &tp->t_items); 665e98c414fSChristoph Hellwig 666e98c414fSChristoph Hellwig lip->li_desc = lidp; 667e98c414fSChristoph Hellwig } 668e98c414fSChristoph Hellwig 669e98c414fSChristoph Hellwig STATIC void 670e98c414fSChristoph Hellwig xfs_trans_free_item_desc( 671e98c414fSChristoph Hellwig struct xfs_log_item_desc *lidp) 672e98c414fSChristoph Hellwig { 673e98c414fSChristoph Hellwig list_del_init(&lidp->lid_trans); 674e98c414fSChristoph Hellwig kmem_zone_free(xfs_log_item_desc_zone, lidp); 675e98c414fSChristoph Hellwig } 676e98c414fSChristoph Hellwig 677e98c414fSChristoph Hellwig /* 678e98c414fSChristoph Hellwig * Unlink and free the given descriptor. 679e98c414fSChristoph Hellwig */ 680e98c414fSChristoph Hellwig void 681e98c414fSChristoph Hellwig xfs_trans_del_item( 682e98c414fSChristoph Hellwig struct xfs_log_item *lip) 683e98c414fSChristoph Hellwig { 684e98c414fSChristoph Hellwig xfs_trans_free_item_desc(lip->li_desc); 685e98c414fSChristoph Hellwig lip->li_desc = NULL; 686e98c414fSChristoph Hellwig } 687e98c414fSChristoph Hellwig 688e98c414fSChristoph Hellwig /* 689e98c414fSChristoph Hellwig * Unlock all of the items of a transaction and free all the descriptors 690e98c414fSChristoph Hellwig * of that transaction. 691e98c414fSChristoph Hellwig */ 692d17c701cSDave Chinner void 693e98c414fSChristoph Hellwig xfs_trans_free_items( 694e98c414fSChristoph Hellwig struct xfs_trans *tp, 695e98c414fSChristoph Hellwig xfs_lsn_t commit_lsn, 696e98c414fSChristoph Hellwig int flags) 697e98c414fSChristoph Hellwig { 698e98c414fSChristoph Hellwig struct xfs_log_item_desc *lidp, *next; 699e98c414fSChristoph Hellwig 700e98c414fSChristoph Hellwig list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) { 701e98c414fSChristoph Hellwig struct xfs_log_item *lip = lidp->lid_item; 702e98c414fSChristoph Hellwig 703e98c414fSChristoph Hellwig lip->li_desc = NULL; 704e98c414fSChristoph Hellwig 705e98c414fSChristoph Hellwig if (commit_lsn != NULLCOMMITLSN) 706904c17e6SDave Chinner lip->li_ops->iop_committing(lip, commit_lsn); 707e98c414fSChristoph Hellwig if (flags & XFS_TRANS_ABORT) 708e98c414fSChristoph Hellwig lip->li_flags |= XFS_LI_ABORTED; 709904c17e6SDave Chinner lip->li_ops->iop_unlock(lip); 710e98c414fSChristoph Hellwig 711e98c414fSChristoph Hellwig xfs_trans_free_item_desc(lidp); 712e98c414fSChristoph Hellwig } 713e98c414fSChristoph Hellwig } 714e98c414fSChristoph Hellwig 7150e57f6a3SDave Chinner static inline void 7160e57f6a3SDave Chinner xfs_log_item_batch_insert( 7170e57f6a3SDave Chinner struct xfs_ail *ailp, 7181d8c95a3SDave Chinner struct xfs_ail_cursor *cur, 7190e57f6a3SDave Chinner struct xfs_log_item **log_items, 7200e57f6a3SDave Chinner int nr_items, 7210e57f6a3SDave Chinner xfs_lsn_t commit_lsn) 7220e57f6a3SDave Chinner { 7230e57f6a3SDave Chinner int i; 7240e57f6a3SDave Chinner 7250e57f6a3SDave Chinner spin_lock(&ailp->xa_lock); 7260e57f6a3SDave Chinner /* xfs_trans_ail_update_bulk drops ailp->xa_lock */ 7271d8c95a3SDave Chinner xfs_trans_ail_update_bulk(ailp, cur, log_items, nr_items, commit_lsn); 7280e57f6a3SDave Chinner 729904c17e6SDave Chinner for (i = 0; i < nr_items; i++) { 730904c17e6SDave Chinner struct xfs_log_item *lip = log_items[i]; 731904c17e6SDave Chinner 732904c17e6SDave Chinner lip->li_ops->iop_unpin(lip, 0); 733904c17e6SDave Chinner } 7340e57f6a3SDave Chinner } 7350e57f6a3SDave Chinner 7360e57f6a3SDave Chinner /* 7370e57f6a3SDave Chinner * Bulk operation version of xfs_trans_committed that takes a log vector of 7380e57f6a3SDave Chinner * items to insert into the AIL. This uses bulk AIL insertion techniques to 7390e57f6a3SDave Chinner * minimise lock traffic. 740e34a314cSDave Chinner * 741e34a314cSDave Chinner * If we are called with the aborted flag set, it is because a log write during 742e34a314cSDave Chinner * a CIL checkpoint commit has failed. In this case, all the items in the 743904c17e6SDave Chinner * checkpoint have already gone through iop_commited and iop_unlock, which 744e34a314cSDave Chinner * means that checkpoint commit abort handling is treated exactly the same 745e34a314cSDave Chinner * as an iclog write error even though we haven't started any IO yet. Hence in 746904c17e6SDave Chinner * this case all we need to do is iop_committed processing, followed by an 747904c17e6SDave Chinner * iop_unpin(aborted) call. 7481d8c95a3SDave Chinner * 7491d8c95a3SDave Chinner * The AIL cursor is used to optimise the insert process. If commit_lsn is not 7501d8c95a3SDave Chinner * at the end of the AIL, the insert cursor avoids the need to walk 7511d8c95a3SDave Chinner * the AIL to find the insertion point on every xfs_log_item_batch_insert() 7521d8c95a3SDave Chinner * call. This saves a lot of needless list walking and is a net win, even 7531d8c95a3SDave Chinner * though it slightly increases that amount of AIL lock traffic to set it up 7541d8c95a3SDave Chinner * and tear it down. 7550e57f6a3SDave Chinner */ 7560e57f6a3SDave Chinner void 7570e57f6a3SDave Chinner xfs_trans_committed_bulk( 7580e57f6a3SDave Chinner struct xfs_ail *ailp, 7590e57f6a3SDave Chinner struct xfs_log_vec *log_vector, 7600e57f6a3SDave Chinner xfs_lsn_t commit_lsn, 7610e57f6a3SDave Chinner int aborted) 7620e57f6a3SDave Chinner { 7630e57f6a3SDave Chinner #define LOG_ITEM_BATCH_SIZE 32 7640e57f6a3SDave Chinner struct xfs_log_item *log_items[LOG_ITEM_BATCH_SIZE]; 7650e57f6a3SDave Chinner struct xfs_log_vec *lv; 7661d8c95a3SDave Chinner struct xfs_ail_cursor cur; 7670e57f6a3SDave Chinner int i = 0; 7680e57f6a3SDave Chinner 7691d8c95a3SDave Chinner spin_lock(&ailp->xa_lock); 7701d8c95a3SDave Chinner xfs_trans_ail_cursor_last(ailp, &cur, commit_lsn); 7711d8c95a3SDave Chinner spin_unlock(&ailp->xa_lock); 7721d8c95a3SDave Chinner 7730e57f6a3SDave Chinner /* unpin all the log items */ 7740e57f6a3SDave Chinner for (lv = log_vector; lv; lv = lv->lv_next ) { 7750e57f6a3SDave Chinner struct xfs_log_item *lip = lv->lv_item; 7760e57f6a3SDave Chinner xfs_lsn_t item_lsn; 7770e57f6a3SDave Chinner 7780e57f6a3SDave Chinner if (aborted) 7790e57f6a3SDave Chinner lip->li_flags |= XFS_LI_ABORTED; 780904c17e6SDave Chinner item_lsn = lip->li_ops->iop_committed(lip, commit_lsn); 7810e57f6a3SDave Chinner 7821316d4daSDave Chinner /* item_lsn of -1 means the item needs no further processing */ 7830e57f6a3SDave Chinner if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) 7840e57f6a3SDave Chinner continue; 7850e57f6a3SDave Chinner 786e34a314cSDave Chinner /* 787e34a314cSDave Chinner * if we are aborting the operation, no point in inserting the 788e34a314cSDave Chinner * object into the AIL as we are in a shutdown situation. 789e34a314cSDave Chinner */ 790e34a314cSDave Chinner if (aborted) { 791e34a314cSDave Chinner ASSERT(XFS_FORCED_SHUTDOWN(ailp->xa_mount)); 792904c17e6SDave Chinner lip->li_ops->iop_unpin(lip, 1); 793e34a314cSDave Chinner continue; 794e34a314cSDave Chinner } 795e34a314cSDave Chinner 7960e57f6a3SDave Chinner if (item_lsn != commit_lsn) { 7970e57f6a3SDave Chinner 7980e57f6a3SDave Chinner /* 7990e57f6a3SDave Chinner * Not a bulk update option due to unusual item_lsn. 8000e57f6a3SDave Chinner * Push into AIL immediately, rechecking the lsn once 8011d8c95a3SDave Chinner * we have the ail lock. Then unpin the item. This does 8021d8c95a3SDave Chinner * not affect the AIL cursor the bulk insert path is 8031d8c95a3SDave Chinner * using. 8040e57f6a3SDave Chinner */ 8050e57f6a3SDave Chinner spin_lock(&ailp->xa_lock); 8060e57f6a3SDave Chinner if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) 8070e57f6a3SDave Chinner xfs_trans_ail_update(ailp, lip, item_lsn); 8080e57f6a3SDave Chinner else 8090e57f6a3SDave Chinner spin_unlock(&ailp->xa_lock); 810904c17e6SDave Chinner lip->li_ops->iop_unpin(lip, 0); 8110e57f6a3SDave Chinner continue; 8120e57f6a3SDave Chinner } 8130e57f6a3SDave Chinner 8140e57f6a3SDave Chinner /* Item is a candidate for bulk AIL insert. */ 8150e57f6a3SDave Chinner log_items[i++] = lv->lv_item; 8160e57f6a3SDave Chinner if (i >= LOG_ITEM_BATCH_SIZE) { 8171d8c95a3SDave Chinner xfs_log_item_batch_insert(ailp, &cur, log_items, 8180e57f6a3SDave Chinner LOG_ITEM_BATCH_SIZE, commit_lsn); 8190e57f6a3SDave Chinner i = 0; 8200e57f6a3SDave Chinner } 8210e57f6a3SDave Chinner } 8220e57f6a3SDave Chinner 8230e57f6a3SDave Chinner /* make sure we insert the remainder! */ 8240e57f6a3SDave Chinner if (i) 8251d8c95a3SDave Chinner xfs_log_item_batch_insert(ailp, &cur, log_items, i, commit_lsn); 8261d8c95a3SDave Chinner 8271d8c95a3SDave Chinner spin_lock(&ailp->xa_lock); 828e4a1e29cSEric Sandeen xfs_trans_ail_cursor_done(&cur); 8291d8c95a3SDave Chinner spin_unlock(&ailp->xa_lock); 8300e57f6a3SDave Chinner } 8310e57f6a3SDave Chinner 832b1c1b5b6SDave Chinner /* 833b1037058SChristoph Hellwig * Commit the given transaction to the log. 8340924378aSDave Chinner * 8350924378aSDave Chinner * XFS disk error handling mechanism is not based on a typical 8360924378aSDave Chinner * transaction abort mechanism. Logically after the filesystem 8370924378aSDave Chinner * gets marked 'SHUTDOWN', we can't let any new transactions 8380924378aSDave Chinner * be durable - ie. committed to disk - because some metadata might 8390924378aSDave Chinner * be inconsistent. In such cases, this returns an error, and the 8400924378aSDave Chinner * caller may assume that all locked objects joined to the transaction 8410924378aSDave Chinner * have already been unlocked as if the commit had succeeded. 8420924378aSDave Chinner * Do not reference the transaction structure after this call. 8430924378aSDave Chinner */ 8440924378aSDave Chinner int 845b1037058SChristoph Hellwig xfs_trans_commit( 846a3ccd2caSChristoph Hellwig struct xfs_trans *tp, 847b1037058SChristoph Hellwig uint flags) 8480924378aSDave Chinner { 849a3ccd2caSChristoph Hellwig struct xfs_mount *mp = tp->t_mountp; 8500924378aSDave Chinner xfs_lsn_t commit_lsn = -1; 851a3ccd2caSChristoph Hellwig int error = 0; 8520924378aSDave Chinner int log_flags = 0; 8530924378aSDave Chinner int sync = tp->t_flags & XFS_TRANS_SYNC; 8540924378aSDave Chinner 8550924378aSDave Chinner /* 8560924378aSDave Chinner * Determine whether this commit is releasing a permanent 8570924378aSDave Chinner * log reservation or not. 8580924378aSDave Chinner */ 8590924378aSDave Chinner if (flags & XFS_TRANS_RELEASE_LOG_RES) { 8600924378aSDave Chinner ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); 8610924378aSDave Chinner log_flags = XFS_LOG_REL_PERM_RESERV; 8620924378aSDave Chinner } 8630924378aSDave Chinner 8640924378aSDave Chinner /* 8650924378aSDave Chinner * If there is nothing to be logged by the transaction, 8660924378aSDave Chinner * then unlock all of the items associated with the 8670924378aSDave Chinner * transaction and free the transaction structure. 8680924378aSDave Chinner * Also make sure to return any reserved blocks to 8690924378aSDave Chinner * the free pool. 8700924378aSDave Chinner */ 871a3ccd2caSChristoph Hellwig if (!(tp->t_flags & XFS_TRANS_DIRTY)) 872a3ccd2caSChristoph Hellwig goto out_unreserve; 873a3ccd2caSChristoph Hellwig 874a3ccd2caSChristoph Hellwig if (XFS_FORCED_SHUTDOWN(mp)) { 8752451337dSDave Chinner error = -EIO; 876a3ccd2caSChristoph Hellwig goto out_unreserve; 8770924378aSDave Chinner } 878a3ccd2caSChristoph Hellwig 8790924378aSDave Chinner ASSERT(tp->t_ticket != NULL); 8800924378aSDave Chinner 8810924378aSDave Chinner /* 8820924378aSDave Chinner * If we need to update the superblock, then do it now. 8830924378aSDave Chinner */ 8840924378aSDave Chinner if (tp->t_flags & XFS_TRANS_SB_DIRTY) 8850924378aSDave Chinner xfs_trans_apply_sb_deltas(tp); 8860924378aSDave Chinner xfs_trans_apply_dquot_deltas(tp); 8870924378aSDave Chinner 888c6f97264SJie Liu xfs_log_commit_cil(mp, tp, &commit_lsn, flags); 8891da177e4SLinus Torvalds 8900244b960SChristoph Hellwig current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 8910244b960SChristoph Hellwig xfs_trans_free(tp); 8920244b960SChristoph Hellwig 8931da177e4SLinus Torvalds /* 8941da177e4SLinus Torvalds * If the transaction needs to be synchronous, then force the 8951da177e4SLinus Torvalds * log out now and wait for it. 8961da177e4SLinus Torvalds */ 8971da177e4SLinus Torvalds if (sync) { 898c6f97264SJie Liu error = _xfs_log_force_lsn(mp, commit_lsn, XFS_LOG_SYNC, NULL); 8991da177e4SLinus Torvalds XFS_STATS_INC(xs_trans_sync); 9001da177e4SLinus Torvalds } else { 9011da177e4SLinus Torvalds XFS_STATS_INC(xs_trans_async); 9021da177e4SLinus Torvalds } 9031da177e4SLinus Torvalds 904a3ccd2caSChristoph Hellwig return error; 905a3ccd2caSChristoph Hellwig 906a3ccd2caSChristoph Hellwig out_unreserve: 907a3ccd2caSChristoph Hellwig xfs_trans_unreserve_and_mod_sb(tp); 908a3ccd2caSChristoph Hellwig 909a3ccd2caSChristoph Hellwig /* 910a3ccd2caSChristoph Hellwig * It is indeed possible for the transaction to be not dirty but 911a3ccd2caSChristoph Hellwig * the dqinfo portion to be. All that means is that we have some 912a3ccd2caSChristoph Hellwig * (non-persistent) quota reservations that need to be unreserved. 913a3ccd2caSChristoph Hellwig */ 914a3ccd2caSChristoph Hellwig xfs_trans_unreserve_and_mod_dquots(tp); 915a3ccd2caSChristoph Hellwig if (tp->t_ticket) { 916a3ccd2caSChristoph Hellwig commit_lsn = xfs_log_done(mp, tp->t_ticket, NULL, log_flags); 917a3ccd2caSChristoph Hellwig if (commit_lsn == -1 && !error) 9182451337dSDave Chinner error = -EIO; 919a3ccd2caSChristoph Hellwig } 920a3ccd2caSChristoph Hellwig current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 92171e330b5SDave Chinner xfs_trans_free_items(tp, NULLCOMMITLSN, error ? XFS_TRANS_ABORT : 0); 922a3ccd2caSChristoph Hellwig xfs_trans_free(tp); 923a3ccd2caSChristoph Hellwig 924a3ccd2caSChristoph Hellwig XFS_STATS_INC(xs_trans_empty); 925a3ccd2caSChristoph Hellwig return error; 9261da177e4SLinus Torvalds } 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds /* 9291da177e4SLinus Torvalds * Unlock all of the transaction's items and free the transaction. 9301da177e4SLinus Torvalds * The transaction must not have modified any of its items, because 9311da177e4SLinus Torvalds * there is no way to restore them to their previous state. 9321da177e4SLinus Torvalds * 9331da177e4SLinus Torvalds * If the transaction has made a log reservation, make sure to release 9341da177e4SLinus Torvalds * it as well. 9351da177e4SLinus Torvalds */ 9361da177e4SLinus Torvalds void 9371da177e4SLinus Torvalds xfs_trans_cancel( 9381da177e4SLinus Torvalds xfs_trans_t *tp, 9391da177e4SLinus Torvalds int flags) 9401da177e4SLinus Torvalds { 9411da177e4SLinus Torvalds int log_flags; 9420733af21SRyan Hankins xfs_mount_t *mp = tp->t_mountp; 9431da177e4SLinus Torvalds 9441da177e4SLinus Torvalds /* 9451da177e4SLinus Torvalds * See if the caller is being too lazy to figure out if 9461da177e4SLinus Torvalds * the transaction really needs an abort. 9471da177e4SLinus Torvalds */ 9481da177e4SLinus Torvalds if ((flags & XFS_TRANS_ABORT) && !(tp->t_flags & XFS_TRANS_DIRTY)) 9491da177e4SLinus Torvalds flags &= ~XFS_TRANS_ABORT; 9501da177e4SLinus Torvalds /* 9511da177e4SLinus Torvalds * See if the caller is relying on us to shut down the 9521da177e4SLinus Torvalds * filesystem. This happens in paths where we detect 9531da177e4SLinus Torvalds * corruption and decide to give up. 9541da177e4SLinus Torvalds */ 95560a204f0SNathan Scott if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) { 9560733af21SRyan Hankins XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp); 9577d04a335SNathan Scott xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 95860a204f0SNathan Scott } 9591da177e4SLinus Torvalds #ifdef DEBUG 960e98c414fSChristoph Hellwig if (!(flags & XFS_TRANS_ABORT) && !XFS_FORCED_SHUTDOWN(mp)) { 961e98c414fSChristoph Hellwig struct xfs_log_item_desc *lidp; 9621da177e4SLinus Torvalds 963e98c414fSChristoph Hellwig list_for_each_entry(lidp, &tp->t_items, lid_trans) 964e98c414fSChristoph Hellwig ASSERT(!(lidp->lid_item->li_type == XFS_LI_EFD)); 9651da177e4SLinus Torvalds } 9661da177e4SLinus Torvalds #endif 9671da177e4SLinus Torvalds xfs_trans_unreserve_and_mod_sb(tp); 9687d095257SChristoph Hellwig xfs_trans_unreserve_and_mod_dquots(tp); 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds if (tp->t_ticket) { 9711da177e4SLinus Torvalds if (flags & XFS_TRANS_RELEASE_LOG_RES) { 9721da177e4SLinus Torvalds ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); 9731da177e4SLinus Torvalds log_flags = XFS_LOG_REL_PERM_RESERV; 9741da177e4SLinus Torvalds } else { 9751da177e4SLinus Torvalds log_flags = 0; 9761da177e4SLinus Torvalds } 9770733af21SRyan Hankins xfs_log_done(mp, tp->t_ticket, NULL, log_flags); 9781da177e4SLinus Torvalds } 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds /* mark this thread as no longer being in a transaction */ 98159c1b082SNathan Scott current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); 9821da177e4SLinus Torvalds 98371e330b5SDave Chinner xfs_trans_free_items(tp, NULLCOMMITLSN, flags); 9841da177e4SLinus Torvalds xfs_trans_free(tp); 9851da177e4SLinus Torvalds } 9861da177e4SLinus Torvalds 987322ff6b8SNiv Sardi /* 988322ff6b8SNiv Sardi * Roll from one trans in the sequence of PERMANENT transactions to 989322ff6b8SNiv Sardi * the next: permanent transactions are only flushed out when 990322ff6b8SNiv Sardi * committed with XFS_TRANS_RELEASE_LOG_RES, but we still want as soon 991322ff6b8SNiv Sardi * as possible to let chunks of it go to the log. So we commit the 992322ff6b8SNiv Sardi * chunk we've been working on and get a new transaction to continue. 993322ff6b8SNiv Sardi */ 994322ff6b8SNiv Sardi int 995322ff6b8SNiv Sardi xfs_trans_roll( 996322ff6b8SNiv Sardi struct xfs_trans **tpp, 997322ff6b8SNiv Sardi struct xfs_inode *dp) 998322ff6b8SNiv Sardi { 999322ff6b8SNiv Sardi struct xfs_trans *trans; 10003d3c8b52SJie Liu struct xfs_trans_res tres; 1001322ff6b8SNiv Sardi int error; 1002322ff6b8SNiv Sardi 1003322ff6b8SNiv Sardi /* 1004322ff6b8SNiv Sardi * Ensure that the inode is always logged. 1005322ff6b8SNiv Sardi */ 1006322ff6b8SNiv Sardi trans = *tpp; 1007322ff6b8SNiv Sardi xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); 1008322ff6b8SNiv Sardi 1009322ff6b8SNiv Sardi /* 1010322ff6b8SNiv Sardi * Copy the critical parameters from one trans to the next. 1011322ff6b8SNiv Sardi */ 10123d3c8b52SJie Liu tres.tr_logres = trans->t_log_res; 10133d3c8b52SJie Liu tres.tr_logcount = trans->t_log_count; 1014322ff6b8SNiv Sardi *tpp = xfs_trans_dup(trans); 1015322ff6b8SNiv Sardi 1016322ff6b8SNiv Sardi /* 1017322ff6b8SNiv Sardi * Commit the current transaction. 1018322ff6b8SNiv Sardi * If this commit failed, then it'd just unlock those items that 1019322ff6b8SNiv Sardi * are not marked ihold. That also means that a filesystem shutdown 1020322ff6b8SNiv Sardi * is in progress. The caller takes the responsibility to cancel 1021322ff6b8SNiv Sardi * the duplicate transaction that gets returned. 1022322ff6b8SNiv Sardi */ 1023322ff6b8SNiv Sardi error = xfs_trans_commit(trans, 0); 1024322ff6b8SNiv Sardi if (error) 1025d99831ffSEric Sandeen return error; 1026322ff6b8SNiv Sardi 1027322ff6b8SNiv Sardi trans = *tpp; 1028322ff6b8SNiv Sardi 1029322ff6b8SNiv Sardi /* 1030cc09c0dcSDave Chinner * transaction commit worked ok so we can drop the extra ticket 1031cc09c0dcSDave Chinner * reference that we gained in xfs_trans_dup() 1032cc09c0dcSDave Chinner */ 1033cc09c0dcSDave Chinner xfs_log_ticket_put(trans->t_ticket); 1034cc09c0dcSDave Chinner 1035cc09c0dcSDave Chinner 1036cc09c0dcSDave Chinner /* 1037322ff6b8SNiv Sardi * Reserve space in the log for th next transaction. 1038322ff6b8SNiv Sardi * This also pushes items in the "AIL", the list of logged items, 1039322ff6b8SNiv Sardi * out to disk if they are taking up space at the tail of the log 1040322ff6b8SNiv Sardi * that we want to use. This requires that either nothing be locked 1041322ff6b8SNiv Sardi * across this call, or that anything that is locked be logged in 1042322ff6b8SNiv Sardi * the prior and the next transactions. 1043322ff6b8SNiv Sardi */ 10443d3c8b52SJie Liu tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; 10453d3c8b52SJie Liu error = xfs_trans_reserve(trans, &tres, 0, 0); 1046322ff6b8SNiv Sardi /* 1047322ff6b8SNiv Sardi * Ensure that the inode is in the new transaction and locked. 1048322ff6b8SNiv Sardi */ 1049322ff6b8SNiv Sardi if (error) 1050322ff6b8SNiv Sardi return error; 1051322ff6b8SNiv Sardi 1052ddc3415aSChristoph Hellwig xfs_trans_ijoin(trans, dp, 0); 1053322ff6b8SNiv Sardi return 0; 1054322ff6b8SNiv Sardi } 1055