18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Oracle. All Rights Reserved. 48c2ecf20Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include "xfs.h" 78c2ecf20Sopenharmony_ci#include "xfs_fs.h" 88c2ecf20Sopenharmony_ci#include "xfs_shared.h" 98c2ecf20Sopenharmony_ci#include "xfs_format.h" 108c2ecf20Sopenharmony_ci#include "xfs_log_format.h" 118c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h" 128c2ecf20Sopenharmony_ci#include "xfs_mount.h" 138c2ecf20Sopenharmony_ci#include "xfs_defer.h" 148c2ecf20Sopenharmony_ci#include "xfs_trans.h" 158c2ecf20Sopenharmony_ci#include "xfs_buf_item.h" 168c2ecf20Sopenharmony_ci#include "xfs_inode.h" 178c2ecf20Sopenharmony_ci#include "xfs_inode_item.h" 188c2ecf20Sopenharmony_ci#include "xfs_trace.h" 198c2ecf20Sopenharmony_ci#include "xfs_icache.h" 208c2ecf20Sopenharmony_ci#include "xfs_log.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * Deferred Operations in XFS 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Due to the way locking rules work in XFS, certain transactions (block 268c2ecf20Sopenharmony_ci * mapping and unmapping, typically) have permanent reservations so that 278c2ecf20Sopenharmony_ci * we can roll the transaction to adhere to AG locking order rules and 288c2ecf20Sopenharmony_ci * to unlock buffers between metadata updates. Prior to rmap/reflink, 298c2ecf20Sopenharmony_ci * the mapping code had a mechanism to perform these deferrals for 308c2ecf20Sopenharmony_ci * extents that were going to be freed; this code makes that facility 318c2ecf20Sopenharmony_ci * more generic. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * When adding the reverse mapping and reflink features, it became 348c2ecf20Sopenharmony_ci * necessary to perform complex remapping multi-transactions to comply 358c2ecf20Sopenharmony_ci * with AG locking order rules, and to be able to spread a single 368c2ecf20Sopenharmony_ci * refcount update operation (an operation on an n-block extent can 378c2ecf20Sopenharmony_ci * update as many as n records!) among multiple transactions. XFS can 388c2ecf20Sopenharmony_ci * roll a transaction to facilitate this, but using this facility 398c2ecf20Sopenharmony_ci * requires us to log "intent" items in case log recovery needs to 408c2ecf20Sopenharmony_ci * redo the operation, and to log "done" items to indicate that redo 418c2ecf20Sopenharmony_ci * is not necessary. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * Deferred work is tracked in xfs_defer_pending items. Each pending 448c2ecf20Sopenharmony_ci * item tracks one type of deferred work. Incoming work items (which 458c2ecf20Sopenharmony_ci * have not yet had an intent logged) are attached to a pending item 468c2ecf20Sopenharmony_ci * on the dop_intake list, where they wait for the caller to finish 478c2ecf20Sopenharmony_ci * the deferred operations. 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * Finishing a set of deferred operations is an involved process. To 508c2ecf20Sopenharmony_ci * start, we define "rolling a deferred-op transaction" as follows: 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * > For each xfs_defer_pending item on the dop_intake list, 538c2ecf20Sopenharmony_ci * - Sort the work items in AG order. XFS locking 548c2ecf20Sopenharmony_ci * order rules require us to lock buffers in AG order. 558c2ecf20Sopenharmony_ci * - Create a log intent item for that type. 568c2ecf20Sopenharmony_ci * - Attach it to the pending item. 578c2ecf20Sopenharmony_ci * - Move the pending item from the dop_intake list to the 588c2ecf20Sopenharmony_ci * dop_pending list. 598c2ecf20Sopenharmony_ci * > Roll the transaction. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * NOTE: To avoid exceeding the transaction reservation, we limit the 628c2ecf20Sopenharmony_ci * number of items that we attach to a given xfs_defer_pending. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * The actual finishing process looks like this: 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * > For each xfs_defer_pending in the dop_pending list, 678c2ecf20Sopenharmony_ci * - Roll the deferred-op transaction as above. 688c2ecf20Sopenharmony_ci * - Create a log done item for that type, and attach it to the 698c2ecf20Sopenharmony_ci * log intent item. 708c2ecf20Sopenharmony_ci * - For each work item attached to the log intent item, 718c2ecf20Sopenharmony_ci * * Perform the described action. 728c2ecf20Sopenharmony_ci * * Attach the work item to the log done item. 738c2ecf20Sopenharmony_ci * * If the result of doing the work was -EAGAIN, ->finish work 748c2ecf20Sopenharmony_ci * wants a new transaction. See the "Requesting a Fresh 758c2ecf20Sopenharmony_ci * Transaction while Finishing Deferred Work" section below for 768c2ecf20Sopenharmony_ci * details. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * The key here is that we must log an intent item for all pending 798c2ecf20Sopenharmony_ci * work items every time we roll the transaction, and that we must log 808c2ecf20Sopenharmony_ci * a done item as soon as the work is completed. With this mechanism 818c2ecf20Sopenharmony_ci * we can perform complex remapping operations, chaining intent items 828c2ecf20Sopenharmony_ci * as needed. 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * Requesting a Fresh Transaction while Finishing Deferred Work 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * If ->finish_item decides that it needs a fresh transaction to 878c2ecf20Sopenharmony_ci * finish the work, it must ask its caller (xfs_defer_finish) for a 888c2ecf20Sopenharmony_ci * continuation. The most likely cause of this circumstance are the 898c2ecf20Sopenharmony_ci * refcount adjust functions deciding that they've logged enough items 908c2ecf20Sopenharmony_ci * to be at risk of exceeding the transaction reservation. 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * To get a fresh transaction, we want to log the existing log done 938c2ecf20Sopenharmony_ci * item to prevent the log intent item from replaying, immediately log 948c2ecf20Sopenharmony_ci * a new log intent item with the unfinished work items, roll the 958c2ecf20Sopenharmony_ci * transaction, and re-call ->finish_item wherever it left off. The 968c2ecf20Sopenharmony_ci * log done item and the new log intent item must be in the same 978c2ecf20Sopenharmony_ci * transaction or atomicity cannot be guaranteed; defer_finish ensures 988c2ecf20Sopenharmony_ci * that this happens. 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * This requires some coordination between ->finish_item and 1018c2ecf20Sopenharmony_ci * defer_finish. Upon deciding to request a new transaction, 1028c2ecf20Sopenharmony_ci * ->finish_item should update the current work item to reflect the 1038c2ecf20Sopenharmony_ci * unfinished work. Next, it should reset the log done item's list 1048c2ecf20Sopenharmony_ci * count to the number of items finished, and return -EAGAIN. 1058c2ecf20Sopenharmony_ci * defer_finish sees the -EAGAIN, logs the new log intent item 1068c2ecf20Sopenharmony_ci * with the remaining work items, and leaves the xfs_defer_pending 1078c2ecf20Sopenharmony_ci * item at the head of the dop_work queue. Then it rolls the 1088c2ecf20Sopenharmony_ci * transaction and picks up processing where it left off. It is 1098c2ecf20Sopenharmony_ci * required that ->finish_item must be careful to leave enough 1108c2ecf20Sopenharmony_ci * transaction reservation to fit the new log intent item. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * This is an example of remapping the extent (E, E+B) into file X at 1138c2ecf20Sopenharmony_ci * offset A and dealing with the extent (C, C+B) already being mapped 1148c2ecf20Sopenharmony_ci * there: 1158c2ecf20Sopenharmony_ci * +-------------------------------------------------+ 1168c2ecf20Sopenharmony_ci * | Unmap file X startblock C offset A length B | t0 1178c2ecf20Sopenharmony_ci * | Intent to reduce refcount for extent (C, B) | 1188c2ecf20Sopenharmony_ci * | Intent to remove rmap (X, C, A, B) | 1198c2ecf20Sopenharmony_ci * | Intent to free extent (D, 1) (bmbt block) | 1208c2ecf20Sopenharmony_ci * | Intent to map (X, A, B) at startblock E | 1218c2ecf20Sopenharmony_ci * +-------------------------------------------------+ 1228c2ecf20Sopenharmony_ci * | Map file X startblock E offset A length B | t1 1238c2ecf20Sopenharmony_ci * | Done mapping (X, E, A, B) | 1248c2ecf20Sopenharmony_ci * | Intent to increase refcount for extent (E, B) | 1258c2ecf20Sopenharmony_ci * | Intent to add rmap (X, E, A, B) | 1268c2ecf20Sopenharmony_ci * +-------------------------------------------------+ 1278c2ecf20Sopenharmony_ci * | Reduce refcount for extent (C, B) | t2 1288c2ecf20Sopenharmony_ci * | Done reducing refcount for extent (C, 9) | 1298c2ecf20Sopenharmony_ci * | Intent to reduce refcount for extent (C+9, B-9) | 1308c2ecf20Sopenharmony_ci * | (ran out of space after 9 refcount updates) | 1318c2ecf20Sopenharmony_ci * +-------------------------------------------------+ 1328c2ecf20Sopenharmony_ci * | Reduce refcount for extent (C+9, B+9) | t3 1338c2ecf20Sopenharmony_ci * | Done reducing refcount for extent (C+9, B-9) | 1348c2ecf20Sopenharmony_ci * | Increase refcount for extent (E, B) | 1358c2ecf20Sopenharmony_ci * | Done increasing refcount for extent (E, B) | 1368c2ecf20Sopenharmony_ci * | Intent to free extent (C, B) | 1378c2ecf20Sopenharmony_ci * | Intent to free extent (F, 1) (refcountbt block) | 1388c2ecf20Sopenharmony_ci * | Intent to remove rmap (F, 1, REFC) | 1398c2ecf20Sopenharmony_ci * +-------------------------------------------------+ 1408c2ecf20Sopenharmony_ci * | Remove rmap (X, C, A, B) | t4 1418c2ecf20Sopenharmony_ci * | Done removing rmap (X, C, A, B) | 1428c2ecf20Sopenharmony_ci * | Add rmap (X, E, A, B) | 1438c2ecf20Sopenharmony_ci * | Done adding rmap (X, E, A, B) | 1448c2ecf20Sopenharmony_ci * | Remove rmap (F, 1, REFC) | 1458c2ecf20Sopenharmony_ci * | Done removing rmap (F, 1, REFC) | 1468c2ecf20Sopenharmony_ci * +-------------------------------------------------+ 1478c2ecf20Sopenharmony_ci * | Free extent (C, B) | t5 1488c2ecf20Sopenharmony_ci * | Done freeing extent (C, B) | 1498c2ecf20Sopenharmony_ci * | Free extent (D, 1) | 1508c2ecf20Sopenharmony_ci * | Done freeing extent (D, 1) | 1518c2ecf20Sopenharmony_ci * | Free extent (F, 1) | 1528c2ecf20Sopenharmony_ci * | Done freeing extent (F, 1) | 1538c2ecf20Sopenharmony_ci * +-------------------------------------------------+ 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * If we should crash before t2 commits, log recovery replays 1568c2ecf20Sopenharmony_ci * the following intent items: 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci * - Intent to reduce refcount for extent (C, B) 1598c2ecf20Sopenharmony_ci * - Intent to remove rmap (X, C, A, B) 1608c2ecf20Sopenharmony_ci * - Intent to free extent (D, 1) (bmbt block) 1618c2ecf20Sopenharmony_ci * - Intent to increase refcount for extent (E, B) 1628c2ecf20Sopenharmony_ci * - Intent to add rmap (X, E, A, B) 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * In the process of recovering, it should also generate and take care 1658c2ecf20Sopenharmony_ci * of these intent items: 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * - Intent to free extent (C, B) 1688c2ecf20Sopenharmony_ci * - Intent to free extent (F, 1) (refcountbt block) 1698c2ecf20Sopenharmony_ci * - Intent to remove rmap (F, 1, REFC) 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Note that the continuation requested between t2 and t3 is likely to 1728c2ecf20Sopenharmony_ci * reoccur. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic const struct xfs_defer_op_type *defer_op_types[] = { 1768c2ecf20Sopenharmony_ci [XFS_DEFER_OPS_TYPE_BMAP] = &xfs_bmap_update_defer_type, 1778c2ecf20Sopenharmony_ci [XFS_DEFER_OPS_TYPE_REFCOUNT] = &xfs_refcount_update_defer_type, 1788c2ecf20Sopenharmony_ci [XFS_DEFER_OPS_TYPE_RMAP] = &xfs_rmap_update_defer_type, 1798c2ecf20Sopenharmony_ci [XFS_DEFER_OPS_TYPE_FREE] = &xfs_extent_free_defer_type, 1808c2ecf20Sopenharmony_ci [XFS_DEFER_OPS_TYPE_AGFL_FREE] = &xfs_agfl_free_defer_type, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic void 1848c2ecf20Sopenharmony_cixfs_defer_create_intent( 1858c2ecf20Sopenharmony_ci struct xfs_trans *tp, 1868c2ecf20Sopenharmony_ci struct xfs_defer_pending *dfp, 1878c2ecf20Sopenharmony_ci bool sort) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (!dfp->dfp_intent) 1928c2ecf20Sopenharmony_ci dfp->dfp_intent = ops->create_intent(tp, &dfp->dfp_work, 1938c2ecf20Sopenharmony_ci dfp->dfp_count, sort); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * For each pending item in the intake list, log its intent item and the 1988c2ecf20Sopenharmony_ci * associated extents, then add the entire intake list to the end of 1998c2ecf20Sopenharmony_ci * the pending list. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ciSTATIC void 2028c2ecf20Sopenharmony_cixfs_defer_create_intents( 2038c2ecf20Sopenharmony_ci struct xfs_trans *tp) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct xfs_defer_pending *dfp; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci list_for_each_entry(dfp, &tp->t_dfops, dfp_list) { 2088c2ecf20Sopenharmony_ci trace_xfs_defer_create_intent(tp->t_mountp, dfp); 2098c2ecf20Sopenharmony_ci xfs_defer_create_intent(tp, dfp, true); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* Abort all the intents that were committed. */ 2148c2ecf20Sopenharmony_ciSTATIC void 2158c2ecf20Sopenharmony_cixfs_defer_trans_abort( 2168c2ecf20Sopenharmony_ci struct xfs_trans *tp, 2178c2ecf20Sopenharmony_ci struct list_head *dop_pending) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct xfs_defer_pending *dfp; 2208c2ecf20Sopenharmony_ci const struct xfs_defer_op_type *ops; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci trace_xfs_defer_trans_abort(tp, _RET_IP_); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* Abort intent items that don't have a done item. */ 2258c2ecf20Sopenharmony_ci list_for_each_entry(dfp, dop_pending, dfp_list) { 2268c2ecf20Sopenharmony_ci ops = defer_op_types[dfp->dfp_type]; 2278c2ecf20Sopenharmony_ci trace_xfs_defer_pending_abort(tp->t_mountp, dfp); 2288c2ecf20Sopenharmony_ci if (dfp->dfp_intent && !dfp->dfp_done) { 2298c2ecf20Sopenharmony_ci ops->abort_intent(dfp->dfp_intent); 2308c2ecf20Sopenharmony_ci dfp->dfp_intent = NULL; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* Roll a transaction so we can do some deferred op processing. */ 2368c2ecf20Sopenharmony_ciSTATIC int 2378c2ecf20Sopenharmony_cixfs_defer_trans_roll( 2388c2ecf20Sopenharmony_ci struct xfs_trans **tpp) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct xfs_trans *tp = *tpp; 2418c2ecf20Sopenharmony_ci struct xfs_buf_log_item *bli; 2428c2ecf20Sopenharmony_ci struct xfs_inode_log_item *ili; 2438c2ecf20Sopenharmony_ci struct xfs_log_item *lip; 2448c2ecf20Sopenharmony_ci struct xfs_buf *bplist[XFS_DEFER_OPS_NR_BUFS]; 2458c2ecf20Sopenharmony_ci struct xfs_inode *iplist[XFS_DEFER_OPS_NR_INODES]; 2468c2ecf20Sopenharmony_ci unsigned int ordered = 0; /* bitmap */ 2478c2ecf20Sopenharmony_ci int bpcount = 0, ipcount = 0; 2488c2ecf20Sopenharmony_ci int i; 2498c2ecf20Sopenharmony_ci int error; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci BUILD_BUG_ON(NBBY * sizeof(ordered) < XFS_DEFER_OPS_NR_BUFS); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci list_for_each_entry(lip, &tp->t_items, li_trans) { 2548c2ecf20Sopenharmony_ci switch (lip->li_type) { 2558c2ecf20Sopenharmony_ci case XFS_LI_BUF: 2568c2ecf20Sopenharmony_ci bli = container_of(lip, struct xfs_buf_log_item, 2578c2ecf20Sopenharmony_ci bli_item); 2588c2ecf20Sopenharmony_ci if (bli->bli_flags & XFS_BLI_HOLD) { 2598c2ecf20Sopenharmony_ci if (bpcount >= XFS_DEFER_OPS_NR_BUFS) { 2608c2ecf20Sopenharmony_ci ASSERT(0); 2618c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci if (bli->bli_flags & XFS_BLI_ORDERED) 2648c2ecf20Sopenharmony_ci ordered |= (1U << bpcount); 2658c2ecf20Sopenharmony_ci else 2668c2ecf20Sopenharmony_ci xfs_trans_dirty_buf(tp, bli->bli_buf); 2678c2ecf20Sopenharmony_ci bplist[bpcount++] = bli->bli_buf; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci case XFS_LI_INODE: 2718c2ecf20Sopenharmony_ci ili = container_of(lip, struct xfs_inode_log_item, 2728c2ecf20Sopenharmony_ci ili_item); 2738c2ecf20Sopenharmony_ci if (ili->ili_lock_flags == 0) { 2748c2ecf20Sopenharmony_ci if (ipcount >= XFS_DEFER_OPS_NR_INODES) { 2758c2ecf20Sopenharmony_ci ASSERT(0); 2768c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci xfs_trans_log_inode(tp, ili->ili_inode, 2798c2ecf20Sopenharmony_ci XFS_ILOG_CORE); 2808c2ecf20Sopenharmony_ci iplist[ipcount++] = ili->ili_inode; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci default: 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci trace_xfs_defer_trans_roll(tp, _RET_IP_); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * Roll the transaction. Rolling always given a new transaction (even 2928c2ecf20Sopenharmony_ci * if committing the old one fails!) to hand back to the caller, so we 2938c2ecf20Sopenharmony_ci * join the held resources to the new transaction so that we always 2948c2ecf20Sopenharmony_ci * return with the held resources joined to @tpp, no matter what 2958c2ecf20Sopenharmony_ci * happened. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci error = xfs_trans_roll(tpp); 2988c2ecf20Sopenharmony_ci tp = *tpp; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Rejoin the joined inodes. */ 3018c2ecf20Sopenharmony_ci for (i = 0; i < ipcount; i++) 3028c2ecf20Sopenharmony_ci xfs_trans_ijoin(tp, iplist[i], 0); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* Rejoin the buffers and dirty them so the log moves forward. */ 3058c2ecf20Sopenharmony_ci for (i = 0; i < bpcount; i++) { 3068c2ecf20Sopenharmony_ci xfs_trans_bjoin(tp, bplist[i]); 3078c2ecf20Sopenharmony_ci if (ordered & (1U << i)) 3088c2ecf20Sopenharmony_ci xfs_trans_ordered_buf(tp, bplist[i]); 3098c2ecf20Sopenharmony_ci xfs_trans_bhold(tp, bplist[i]); 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (error) 3138c2ecf20Sopenharmony_ci trace_xfs_defer_trans_roll_error(tp, error); 3148c2ecf20Sopenharmony_ci return error; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* 3188c2ecf20Sopenharmony_ci * Free up any items left in the list. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_cistatic void 3218c2ecf20Sopenharmony_cixfs_defer_cancel_list( 3228c2ecf20Sopenharmony_ci struct xfs_mount *mp, 3238c2ecf20Sopenharmony_ci struct list_head *dop_list) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct xfs_defer_pending *dfp; 3268c2ecf20Sopenharmony_ci struct xfs_defer_pending *pli; 3278c2ecf20Sopenharmony_ci struct list_head *pwi; 3288c2ecf20Sopenharmony_ci struct list_head *n; 3298c2ecf20Sopenharmony_ci const struct xfs_defer_op_type *ops; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* 3328c2ecf20Sopenharmony_ci * Free the pending items. Caller should already have arranged 3338c2ecf20Sopenharmony_ci * for the intent items to be released. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci list_for_each_entry_safe(dfp, pli, dop_list, dfp_list) { 3368c2ecf20Sopenharmony_ci ops = defer_op_types[dfp->dfp_type]; 3378c2ecf20Sopenharmony_ci trace_xfs_defer_cancel_list(mp, dfp); 3388c2ecf20Sopenharmony_ci list_del(&dfp->dfp_list); 3398c2ecf20Sopenharmony_ci list_for_each_safe(pwi, n, &dfp->dfp_work) { 3408c2ecf20Sopenharmony_ci list_del(pwi); 3418c2ecf20Sopenharmony_ci dfp->dfp_count--; 3428c2ecf20Sopenharmony_ci ops->cancel_item(pwi); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci ASSERT(dfp->dfp_count == 0); 3458c2ecf20Sopenharmony_ci kmem_free(dfp); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* 3508c2ecf20Sopenharmony_ci * Prevent a log intent item from pinning the tail of the log by logging a 3518c2ecf20Sopenharmony_ci * done item to release the intent item; and then log a new intent item. 3528c2ecf20Sopenharmony_ci * The caller should provide a fresh transaction and roll it after we're done. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_cistatic int 3558c2ecf20Sopenharmony_cixfs_defer_relog( 3568c2ecf20Sopenharmony_ci struct xfs_trans **tpp, 3578c2ecf20Sopenharmony_ci struct list_head *dfops) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct xlog *log = (*tpp)->t_mountp->m_log; 3608c2ecf20Sopenharmony_ci struct xfs_defer_pending *dfp; 3618c2ecf20Sopenharmony_ci xfs_lsn_t threshold_lsn = NULLCOMMITLSN; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci list_for_each_entry(dfp, dfops, dfp_list) { 3678c2ecf20Sopenharmony_ci /* 3688c2ecf20Sopenharmony_ci * If the log intent item for this deferred op is not a part of 3698c2ecf20Sopenharmony_ci * the current log checkpoint, relog the intent item to keep 3708c2ecf20Sopenharmony_ci * the log tail moving forward. We're ok with this being racy 3718c2ecf20Sopenharmony_ci * because an incorrect decision means we'll be a little slower 3728c2ecf20Sopenharmony_ci * at pushing the tail. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci if (dfp->dfp_intent == NULL || 3758c2ecf20Sopenharmony_ci xfs_log_item_in_current_chkpt(dfp->dfp_intent)) 3768c2ecf20Sopenharmony_ci continue; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* 3798c2ecf20Sopenharmony_ci * Figure out where we need the tail to be in order to maintain 3808c2ecf20Sopenharmony_ci * the minimum required free space in the log. Only sample 3818c2ecf20Sopenharmony_ci * the log threshold once per call. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci if (threshold_lsn == NULLCOMMITLSN) { 3848c2ecf20Sopenharmony_ci threshold_lsn = xlog_grant_push_threshold(log, 0); 3858c2ecf20Sopenharmony_ci if (threshold_lsn == NULLCOMMITLSN) 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci if (XFS_LSN_CMP(dfp->dfp_intent->li_lsn, threshold_lsn) >= 0) 3898c2ecf20Sopenharmony_ci continue; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci trace_xfs_defer_relog_intent((*tpp)->t_mountp, dfp); 3928c2ecf20Sopenharmony_ci XFS_STATS_INC((*tpp)->t_mountp, defer_relog); 3938c2ecf20Sopenharmony_ci dfp->dfp_intent = xfs_trans_item_relog(dfp->dfp_intent, *tpp); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if ((*tpp)->t_flags & XFS_TRANS_DIRTY) 3978c2ecf20Sopenharmony_ci return xfs_defer_trans_roll(tpp); 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci/* 4028c2ecf20Sopenharmony_ci * Log an intent-done item for the first pending intent, and finish the work 4038c2ecf20Sopenharmony_ci * items. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_cistatic int 4068c2ecf20Sopenharmony_cixfs_defer_finish_one( 4078c2ecf20Sopenharmony_ci struct xfs_trans *tp, 4088c2ecf20Sopenharmony_ci struct xfs_defer_pending *dfp) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; 4118c2ecf20Sopenharmony_ci struct xfs_btree_cur *state = NULL; 4128c2ecf20Sopenharmony_ci struct list_head *li, *n; 4138c2ecf20Sopenharmony_ci int error; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci trace_xfs_defer_pending_finish(tp->t_mountp, dfp); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci dfp->dfp_done = ops->create_done(tp, dfp->dfp_intent, dfp->dfp_count); 4188c2ecf20Sopenharmony_ci list_for_each_safe(li, n, &dfp->dfp_work) { 4198c2ecf20Sopenharmony_ci list_del(li); 4208c2ecf20Sopenharmony_ci dfp->dfp_count--; 4218c2ecf20Sopenharmony_ci error = ops->finish_item(tp, dfp->dfp_done, li, &state); 4228c2ecf20Sopenharmony_ci if (error == -EAGAIN) { 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * Caller wants a fresh transaction; put the work item 4258c2ecf20Sopenharmony_ci * back on the list and log a new log intent item to 4268c2ecf20Sopenharmony_ci * replace the old one. See "Requesting a Fresh 4278c2ecf20Sopenharmony_ci * Transaction while Finishing Deferred Work" above. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci list_add(li, &dfp->dfp_work); 4308c2ecf20Sopenharmony_ci dfp->dfp_count++; 4318c2ecf20Sopenharmony_ci dfp->dfp_done = NULL; 4328c2ecf20Sopenharmony_ci dfp->dfp_intent = NULL; 4338c2ecf20Sopenharmony_ci xfs_defer_create_intent(tp, dfp, false); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (error) 4378c2ecf20Sopenharmony_ci goto out; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Done with the dfp, free it. */ 4418c2ecf20Sopenharmony_ci list_del(&dfp->dfp_list); 4428c2ecf20Sopenharmony_ci kmem_free(dfp); 4438c2ecf20Sopenharmony_ciout: 4448c2ecf20Sopenharmony_ci if (ops->finish_cleanup) 4458c2ecf20Sopenharmony_ci ops->finish_cleanup(tp, state, error); 4468c2ecf20Sopenharmony_ci return error; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci/* 4508c2ecf20Sopenharmony_ci * Finish all the pending work. This involves logging intent items for 4518c2ecf20Sopenharmony_ci * any work items that wandered in since the last transaction roll (if 4528c2ecf20Sopenharmony_ci * one has even happened), rolling the transaction, and finishing the 4538c2ecf20Sopenharmony_ci * work items in the first item on the logged-and-pending list. 4548c2ecf20Sopenharmony_ci * 4558c2ecf20Sopenharmony_ci * If an inode is provided, relog it to the new transaction. 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_ciint 4588c2ecf20Sopenharmony_cixfs_defer_finish_noroll( 4598c2ecf20Sopenharmony_ci struct xfs_trans **tp) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct xfs_defer_pending *dfp; 4628c2ecf20Sopenharmony_ci int error = 0; 4638c2ecf20Sopenharmony_ci LIST_HEAD(dop_pending); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci trace_xfs_defer_finish(*tp, _RET_IP_); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Until we run out of pending work to finish... */ 4708c2ecf20Sopenharmony_ci while (!list_empty(&dop_pending) || !list_empty(&(*tp)->t_dfops)) { 4718c2ecf20Sopenharmony_ci /* 4728c2ecf20Sopenharmony_ci * Deferred items that are created in the process of finishing 4738c2ecf20Sopenharmony_ci * other deferred work items should be queued at the head of 4748c2ecf20Sopenharmony_ci * the pending list, which puts them ahead of the deferred work 4758c2ecf20Sopenharmony_ci * that was created by the caller. This keeps the number of 4768c2ecf20Sopenharmony_ci * pending work items to a minimum, which decreases the amount 4778c2ecf20Sopenharmony_ci * of time that any one intent item can stick around in memory, 4788c2ecf20Sopenharmony_ci * pinning the log tail. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci xfs_defer_create_intents(*tp); 4818c2ecf20Sopenharmony_ci list_splice_init(&(*tp)->t_dfops, &dop_pending); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci error = xfs_defer_trans_roll(tp); 4848c2ecf20Sopenharmony_ci if (error) 4858c2ecf20Sopenharmony_ci goto out_shutdown; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* Possibly relog intent items to keep the log moving. */ 4888c2ecf20Sopenharmony_ci error = xfs_defer_relog(tp, &dop_pending); 4898c2ecf20Sopenharmony_ci if (error) 4908c2ecf20Sopenharmony_ci goto out_shutdown; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci dfp = list_first_entry(&dop_pending, struct xfs_defer_pending, 4938c2ecf20Sopenharmony_ci dfp_list); 4948c2ecf20Sopenharmony_ci error = xfs_defer_finish_one(*tp, dfp); 4958c2ecf20Sopenharmony_ci if (error && error != -EAGAIN) 4968c2ecf20Sopenharmony_ci goto out_shutdown; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci trace_xfs_defer_finish_done(*tp, _RET_IP_); 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ciout_shutdown: 5038c2ecf20Sopenharmony_ci xfs_defer_trans_abort(*tp, &dop_pending); 5048c2ecf20Sopenharmony_ci xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE); 5058c2ecf20Sopenharmony_ci trace_xfs_defer_finish_error(*tp, error); 5068c2ecf20Sopenharmony_ci xfs_defer_cancel_list((*tp)->t_mountp, &dop_pending); 5078c2ecf20Sopenharmony_ci xfs_defer_cancel(*tp); 5088c2ecf20Sopenharmony_ci return error; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ciint 5128c2ecf20Sopenharmony_cixfs_defer_finish( 5138c2ecf20Sopenharmony_ci struct xfs_trans **tp) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci int error; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* 5188c2ecf20Sopenharmony_ci * Finish and roll the transaction once more to avoid returning to the 5198c2ecf20Sopenharmony_ci * caller with a dirty transaction. 5208c2ecf20Sopenharmony_ci */ 5218c2ecf20Sopenharmony_ci error = xfs_defer_finish_noroll(tp); 5228c2ecf20Sopenharmony_ci if (error) 5238c2ecf20Sopenharmony_ci return error; 5248c2ecf20Sopenharmony_ci if ((*tp)->t_flags & XFS_TRANS_DIRTY) { 5258c2ecf20Sopenharmony_ci error = xfs_defer_trans_roll(tp); 5268c2ecf20Sopenharmony_ci if (error) { 5278c2ecf20Sopenharmony_ci xfs_force_shutdown((*tp)->t_mountp, 5288c2ecf20Sopenharmony_ci SHUTDOWN_CORRUPT_INCORE); 5298c2ecf20Sopenharmony_ci return error; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* Reset LOWMODE now that we've finished all the dfops. */ 5348c2ecf20Sopenharmony_ci ASSERT(list_empty(&(*tp)->t_dfops)); 5358c2ecf20Sopenharmony_ci (*tp)->t_flags &= ~XFS_TRANS_LOWMODE; 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_civoid 5408c2ecf20Sopenharmony_cixfs_defer_cancel( 5418c2ecf20Sopenharmony_ci struct xfs_trans *tp) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct xfs_mount *mp = tp->t_mountp; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci trace_xfs_defer_cancel(tp, _RET_IP_); 5468c2ecf20Sopenharmony_ci xfs_defer_cancel_list(mp, &tp->t_dfops); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/* Add an item for later deferred processing. */ 5508c2ecf20Sopenharmony_civoid 5518c2ecf20Sopenharmony_cixfs_defer_add( 5528c2ecf20Sopenharmony_ci struct xfs_trans *tp, 5538c2ecf20Sopenharmony_ci enum xfs_defer_ops_type type, 5548c2ecf20Sopenharmony_ci struct list_head *li) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct xfs_defer_pending *dfp = NULL; 5578c2ecf20Sopenharmony_ci const struct xfs_defer_op_type *ops; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); 5608c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(defer_op_types) != XFS_DEFER_OPS_TYPE_MAX); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* 5638c2ecf20Sopenharmony_ci * Add the item to a pending item at the end of the intake list. 5648c2ecf20Sopenharmony_ci * If the last pending item has the same type, reuse it. Else, 5658c2ecf20Sopenharmony_ci * create a new pending item at the end of the intake list. 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ci if (!list_empty(&tp->t_dfops)) { 5688c2ecf20Sopenharmony_ci dfp = list_last_entry(&tp->t_dfops, 5698c2ecf20Sopenharmony_ci struct xfs_defer_pending, dfp_list); 5708c2ecf20Sopenharmony_ci ops = defer_op_types[dfp->dfp_type]; 5718c2ecf20Sopenharmony_ci if (dfp->dfp_type != type || 5728c2ecf20Sopenharmony_ci (ops->max_items && dfp->dfp_count >= ops->max_items)) 5738c2ecf20Sopenharmony_ci dfp = NULL; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci if (!dfp) { 5768c2ecf20Sopenharmony_ci dfp = kmem_alloc(sizeof(struct xfs_defer_pending), 5778c2ecf20Sopenharmony_ci KM_NOFS); 5788c2ecf20Sopenharmony_ci dfp->dfp_type = type; 5798c2ecf20Sopenharmony_ci dfp->dfp_intent = NULL; 5808c2ecf20Sopenharmony_ci dfp->dfp_done = NULL; 5818c2ecf20Sopenharmony_ci dfp->dfp_count = 0; 5828c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dfp->dfp_work); 5838c2ecf20Sopenharmony_ci list_add_tail(&dfp->dfp_list, &tp->t_dfops); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci list_add_tail(li, &dfp->dfp_work); 5878c2ecf20Sopenharmony_ci dfp->dfp_count++; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci/* 5918c2ecf20Sopenharmony_ci * Move deferred ops from one transaction to another and reset the source to 5928c2ecf20Sopenharmony_ci * initial state. This is primarily used to carry state forward across 5938c2ecf20Sopenharmony_ci * transaction rolls with pending dfops. 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_civoid 5968c2ecf20Sopenharmony_cixfs_defer_move( 5978c2ecf20Sopenharmony_ci struct xfs_trans *dtp, 5988c2ecf20Sopenharmony_ci struct xfs_trans *stp) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci list_splice_init(&stp->t_dfops, &dtp->t_dfops); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* 6038c2ecf20Sopenharmony_ci * Low free space mode was historically controlled by a dfops field. 6048c2ecf20Sopenharmony_ci * This meant that low mode state potentially carried across multiple 6058c2ecf20Sopenharmony_ci * transaction rolls. Transfer low mode on a dfops move to preserve 6068c2ecf20Sopenharmony_ci * that behavior. 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ci dtp->t_flags |= (stp->t_flags & XFS_TRANS_LOWMODE); 6098c2ecf20Sopenharmony_ci stp->t_flags &= ~XFS_TRANS_LOWMODE; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci/* 6138c2ecf20Sopenharmony_ci * Prepare a chain of fresh deferred ops work items to be completed later. Log 6148c2ecf20Sopenharmony_ci * recovery requires the ability to put off until later the actual finishing 6158c2ecf20Sopenharmony_ci * work so that it can process unfinished items recovered from the log in 6168c2ecf20Sopenharmony_ci * correct order. 6178c2ecf20Sopenharmony_ci * 6188c2ecf20Sopenharmony_ci * Create and log intent items for all the work that we're capturing so that we 6198c2ecf20Sopenharmony_ci * can be assured that the items will get replayed if the system goes down 6208c2ecf20Sopenharmony_ci * before log recovery gets a chance to finish the work it put off. The entire 6218c2ecf20Sopenharmony_ci * deferred ops state is transferred to the capture structure and the 6228c2ecf20Sopenharmony_ci * transaction is then ready for the caller to commit it. If there are no 6238c2ecf20Sopenharmony_ci * intent items to capture, this function returns NULL. 6248c2ecf20Sopenharmony_ci * 6258c2ecf20Sopenharmony_ci * If capture_ip is not NULL, the capture structure will obtain an extra 6268c2ecf20Sopenharmony_ci * reference to the inode. 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_cistatic struct xfs_defer_capture * 6298c2ecf20Sopenharmony_cixfs_defer_ops_capture( 6308c2ecf20Sopenharmony_ci struct xfs_trans *tp, 6318c2ecf20Sopenharmony_ci struct xfs_inode *capture_ip) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci struct xfs_defer_capture *dfc; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (list_empty(&tp->t_dfops)) 6368c2ecf20Sopenharmony_ci return NULL; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* Create an object to capture the defer ops. */ 6398c2ecf20Sopenharmony_ci dfc = kmem_zalloc(sizeof(*dfc), KM_NOFS); 6408c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dfc->dfc_list); 6418c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dfc->dfc_dfops); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci xfs_defer_create_intents(tp); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Move the dfops chain and transaction state to the capture struct. */ 6468c2ecf20Sopenharmony_ci list_splice_init(&tp->t_dfops, &dfc->dfc_dfops); 6478c2ecf20Sopenharmony_ci dfc->dfc_tpflags = tp->t_flags & XFS_TRANS_LOWMODE; 6488c2ecf20Sopenharmony_ci tp->t_flags &= ~XFS_TRANS_LOWMODE; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Capture the remaining block reservations along with the dfops. */ 6518c2ecf20Sopenharmony_ci dfc->dfc_blkres = tp->t_blk_res - tp->t_blk_res_used; 6528c2ecf20Sopenharmony_ci dfc->dfc_rtxres = tp->t_rtx_res - tp->t_rtx_res_used; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* Preserve the log reservation size. */ 6558c2ecf20Sopenharmony_ci dfc->dfc_logres = tp->t_log_res; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* 6588c2ecf20Sopenharmony_ci * Grab an extra reference to this inode and attach it to the capture 6598c2ecf20Sopenharmony_ci * structure. 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_ci if (capture_ip) { 6628c2ecf20Sopenharmony_ci ihold(VFS_I(capture_ip)); 6638c2ecf20Sopenharmony_ci dfc->dfc_capture_ip = capture_ip; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci return dfc; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci/* Release all resources that we used to capture deferred ops. */ 6708c2ecf20Sopenharmony_civoid 6718c2ecf20Sopenharmony_cixfs_defer_ops_release( 6728c2ecf20Sopenharmony_ci struct xfs_mount *mp, 6738c2ecf20Sopenharmony_ci struct xfs_defer_capture *dfc) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci xfs_defer_cancel_list(mp, &dfc->dfc_dfops); 6768c2ecf20Sopenharmony_ci if (dfc->dfc_capture_ip) 6778c2ecf20Sopenharmony_ci xfs_irele(dfc->dfc_capture_ip); 6788c2ecf20Sopenharmony_ci kmem_free(dfc); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci/* 6828c2ecf20Sopenharmony_ci * Capture any deferred ops and commit the transaction. This is the last step 6838c2ecf20Sopenharmony_ci * needed to finish a log intent item that we recovered from the log. If any 6848c2ecf20Sopenharmony_ci * of the deferred ops operate on an inode, the caller must pass in that inode 6858c2ecf20Sopenharmony_ci * so that the reference can be transferred to the capture structure. The 6868c2ecf20Sopenharmony_ci * caller must hold ILOCK_EXCL on the inode, and must unlock it before calling 6878c2ecf20Sopenharmony_ci * xfs_defer_ops_continue. 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_ciint 6908c2ecf20Sopenharmony_cixfs_defer_ops_capture_and_commit( 6918c2ecf20Sopenharmony_ci struct xfs_trans *tp, 6928c2ecf20Sopenharmony_ci struct xfs_inode *capture_ip, 6938c2ecf20Sopenharmony_ci struct list_head *capture_list) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct xfs_mount *mp = tp->t_mountp; 6968c2ecf20Sopenharmony_ci struct xfs_defer_capture *dfc; 6978c2ecf20Sopenharmony_ci int error; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci ASSERT(!capture_ip || xfs_isilocked(capture_ip, XFS_ILOCK_EXCL)); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* If we don't capture anything, commit transaction and exit. */ 7028c2ecf20Sopenharmony_ci dfc = xfs_defer_ops_capture(tp, capture_ip); 7038c2ecf20Sopenharmony_ci if (!dfc) 7048c2ecf20Sopenharmony_ci return xfs_trans_commit(tp); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* Commit the transaction and add the capture structure to the list. */ 7078c2ecf20Sopenharmony_ci error = xfs_trans_commit(tp); 7088c2ecf20Sopenharmony_ci if (error) { 7098c2ecf20Sopenharmony_ci xfs_defer_ops_release(mp, dfc); 7108c2ecf20Sopenharmony_ci return error; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci list_add_tail(&dfc->dfc_list, capture_list); 7148c2ecf20Sopenharmony_ci return 0; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci/* 7188c2ecf20Sopenharmony_ci * Attach a chain of captured deferred ops to a new transaction and free the 7198c2ecf20Sopenharmony_ci * capture structure. If an inode was captured, it will be passed back to the 7208c2ecf20Sopenharmony_ci * caller with ILOCK_EXCL held and joined to the transaction with lockflags==0. 7218c2ecf20Sopenharmony_ci * The caller now owns the inode reference. 7228c2ecf20Sopenharmony_ci */ 7238c2ecf20Sopenharmony_civoid 7248c2ecf20Sopenharmony_cixfs_defer_ops_continue( 7258c2ecf20Sopenharmony_ci struct xfs_defer_capture *dfc, 7268c2ecf20Sopenharmony_ci struct xfs_trans *tp, 7278c2ecf20Sopenharmony_ci struct xfs_inode **captured_ipp) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); 7308c2ecf20Sopenharmony_ci ASSERT(!(tp->t_flags & XFS_TRANS_DIRTY)); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* Lock and join the captured inode to the new transaction. */ 7338c2ecf20Sopenharmony_ci if (dfc->dfc_capture_ip) { 7348c2ecf20Sopenharmony_ci xfs_ilock(dfc->dfc_capture_ip, XFS_ILOCK_EXCL); 7358c2ecf20Sopenharmony_ci xfs_trans_ijoin(tp, dfc->dfc_capture_ip, 0); 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci *captured_ipp = dfc->dfc_capture_ip; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* Move captured dfops chain and state to the transaction. */ 7408c2ecf20Sopenharmony_ci list_splice_init(&dfc->dfc_dfops, &tp->t_dfops); 7418c2ecf20Sopenharmony_ci tp->t_flags |= dfc->dfc_tpflags; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci kmem_free(dfc); 7448c2ecf20Sopenharmony_ci} 745