162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 Oracle. All Rights Reserved. 462306a36Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_format.h" 962306a36Sopenharmony_ci#include "xfs_log_format.h" 1062306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1162306a36Sopenharmony_ci#include "xfs_bit.h" 1262306a36Sopenharmony_ci#include "xfs_shared.h" 1362306a36Sopenharmony_ci#include "xfs_mount.h" 1462306a36Sopenharmony_ci#include "xfs_defer.h" 1562306a36Sopenharmony_ci#include "xfs_trans.h" 1662306a36Sopenharmony_ci#include "xfs_trans_priv.h" 1762306a36Sopenharmony_ci#include "xfs_refcount_item.h" 1862306a36Sopenharmony_ci#include "xfs_log.h" 1962306a36Sopenharmony_ci#include "xfs_refcount.h" 2062306a36Sopenharmony_ci#include "xfs_error.h" 2162306a36Sopenharmony_ci#include "xfs_log_priv.h" 2262306a36Sopenharmony_ci#include "xfs_log_recover.h" 2362306a36Sopenharmony_ci#include "xfs_ag.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct kmem_cache *xfs_cui_cache; 2662306a36Sopenharmony_cistruct kmem_cache *xfs_cud_cache; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_cui_item_ops; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic inline struct xfs_cui_log_item *CUI_ITEM(struct xfs_log_item *lip) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci return container_of(lip, struct xfs_cui_log_item, cui_item); 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciSTATIC void 3662306a36Sopenharmony_cixfs_cui_item_free( 3762306a36Sopenharmony_ci struct xfs_cui_log_item *cuip) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci kmem_free(cuip->cui_item.li_lv_shadow); 4062306a36Sopenharmony_ci if (cuip->cui_format.cui_nextents > XFS_CUI_MAX_FAST_EXTENTS) 4162306a36Sopenharmony_ci kmem_free(cuip); 4262306a36Sopenharmony_ci else 4362306a36Sopenharmony_ci kmem_cache_free(xfs_cui_cache, cuip); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * Freeing the CUI requires that we remove it from the AIL if it has already 4862306a36Sopenharmony_ci * been placed there. However, the CUI may not yet have been placed in the AIL 4962306a36Sopenharmony_ci * when called by xfs_cui_release() from CUD processing due to the ordering of 5062306a36Sopenharmony_ci * committed vs unpin operations in bulk insert operations. Hence the reference 5162306a36Sopenharmony_ci * count to ensure only the last caller frees the CUI. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ciSTATIC void 5462306a36Sopenharmony_cixfs_cui_release( 5562306a36Sopenharmony_ci struct xfs_cui_log_item *cuip) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci ASSERT(atomic_read(&cuip->cui_refcount) > 0); 5862306a36Sopenharmony_ci if (!atomic_dec_and_test(&cuip->cui_refcount)) 5962306a36Sopenharmony_ci return; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci xfs_trans_ail_delete(&cuip->cui_item, 0); 6262306a36Sopenharmony_ci xfs_cui_item_free(cuip); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciSTATIC void 6762306a36Sopenharmony_cixfs_cui_item_size( 6862306a36Sopenharmony_ci struct xfs_log_item *lip, 6962306a36Sopenharmony_ci int *nvecs, 7062306a36Sopenharmony_ci int *nbytes) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct xfs_cui_log_item *cuip = CUI_ITEM(lip); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci *nvecs += 1; 7562306a36Sopenharmony_ci *nbytes += xfs_cui_log_format_sizeof(cuip->cui_format.cui_nextents); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * This is called to fill in the vector of log iovecs for the 8062306a36Sopenharmony_ci * given cui log item. We use only 1 iovec, and we point that 8162306a36Sopenharmony_ci * at the cui_log_format structure embedded in the cui item. 8262306a36Sopenharmony_ci * It is at this point that we assert that all of the extent 8362306a36Sopenharmony_ci * slots in the cui item have been filled. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ciSTATIC void 8662306a36Sopenharmony_cixfs_cui_item_format( 8762306a36Sopenharmony_ci struct xfs_log_item *lip, 8862306a36Sopenharmony_ci struct xfs_log_vec *lv) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct xfs_cui_log_item *cuip = CUI_ITEM(lip); 9162306a36Sopenharmony_ci struct xfs_log_iovec *vecp = NULL; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci ASSERT(atomic_read(&cuip->cui_next_extent) == 9462306a36Sopenharmony_ci cuip->cui_format.cui_nextents); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci cuip->cui_format.cui_type = XFS_LI_CUI; 9762306a36Sopenharmony_ci cuip->cui_format.cui_size = 1; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_CUI_FORMAT, &cuip->cui_format, 10062306a36Sopenharmony_ci xfs_cui_log_format_sizeof(cuip->cui_format.cui_nextents)); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * The unpin operation is the last place an CUI is manipulated in the log. It is 10562306a36Sopenharmony_ci * either inserted in the AIL or aborted in the event of a log I/O error. In 10662306a36Sopenharmony_ci * either case, the CUI transaction has been successfully committed to make it 10762306a36Sopenharmony_ci * this far. Therefore, we expect whoever committed the CUI to either construct 10862306a36Sopenharmony_ci * and commit the CUD or drop the CUD's reference in the event of error. Simply 10962306a36Sopenharmony_ci * drop the log's CUI reference now that the log is done with it. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ciSTATIC void 11262306a36Sopenharmony_cixfs_cui_item_unpin( 11362306a36Sopenharmony_ci struct xfs_log_item *lip, 11462306a36Sopenharmony_ci int remove) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct xfs_cui_log_item *cuip = CUI_ITEM(lip); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci xfs_cui_release(cuip); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * The CUI has been either committed or aborted if the transaction has been 12362306a36Sopenharmony_ci * cancelled. If the transaction was cancelled, an CUD isn't going to be 12462306a36Sopenharmony_ci * constructed and thus we free the CUI here directly. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ciSTATIC void 12762306a36Sopenharmony_cixfs_cui_item_release( 12862306a36Sopenharmony_ci struct xfs_log_item *lip) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci xfs_cui_release(CUI_ITEM(lip)); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * Allocate and initialize an cui item with the given number of extents. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ciSTATIC struct xfs_cui_log_item * 13762306a36Sopenharmony_cixfs_cui_init( 13862306a36Sopenharmony_ci struct xfs_mount *mp, 13962306a36Sopenharmony_ci uint nextents) 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct xfs_cui_log_item *cuip; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ASSERT(nextents > 0); 14562306a36Sopenharmony_ci if (nextents > XFS_CUI_MAX_FAST_EXTENTS) 14662306a36Sopenharmony_ci cuip = kmem_zalloc(xfs_cui_log_item_sizeof(nextents), 14762306a36Sopenharmony_ci 0); 14862306a36Sopenharmony_ci else 14962306a36Sopenharmony_ci cuip = kmem_cache_zalloc(xfs_cui_cache, 15062306a36Sopenharmony_ci GFP_KERNEL | __GFP_NOFAIL); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci xfs_log_item_init(mp, &cuip->cui_item, XFS_LI_CUI, &xfs_cui_item_ops); 15362306a36Sopenharmony_ci cuip->cui_format.cui_nextents = nextents; 15462306a36Sopenharmony_ci cuip->cui_format.cui_id = (uintptr_t)(void *)cuip; 15562306a36Sopenharmony_ci atomic_set(&cuip->cui_next_extent, 0); 15662306a36Sopenharmony_ci atomic_set(&cuip->cui_refcount, 2); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return cuip; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic inline struct xfs_cud_log_item *CUD_ITEM(struct xfs_log_item *lip) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci return container_of(lip, struct xfs_cud_log_item, cud_item); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciSTATIC void 16762306a36Sopenharmony_cixfs_cud_item_size( 16862306a36Sopenharmony_ci struct xfs_log_item *lip, 16962306a36Sopenharmony_ci int *nvecs, 17062306a36Sopenharmony_ci int *nbytes) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci *nvecs += 1; 17362306a36Sopenharmony_ci *nbytes += sizeof(struct xfs_cud_log_format); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* 17762306a36Sopenharmony_ci * This is called to fill in the vector of log iovecs for the 17862306a36Sopenharmony_ci * given cud log item. We use only 1 iovec, and we point that 17962306a36Sopenharmony_ci * at the cud_log_format structure embedded in the cud item. 18062306a36Sopenharmony_ci * It is at this point that we assert that all of the extent 18162306a36Sopenharmony_ci * slots in the cud item have been filled. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ciSTATIC void 18462306a36Sopenharmony_cixfs_cud_item_format( 18562306a36Sopenharmony_ci struct xfs_log_item *lip, 18662306a36Sopenharmony_ci struct xfs_log_vec *lv) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct xfs_cud_log_item *cudp = CUD_ITEM(lip); 18962306a36Sopenharmony_ci struct xfs_log_iovec *vecp = NULL; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci cudp->cud_format.cud_type = XFS_LI_CUD; 19262306a36Sopenharmony_ci cudp->cud_format.cud_size = 1; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_CUD_FORMAT, &cudp->cud_format, 19562306a36Sopenharmony_ci sizeof(struct xfs_cud_log_format)); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* 19962306a36Sopenharmony_ci * The CUD is either committed or aborted if the transaction is cancelled. If 20062306a36Sopenharmony_ci * the transaction is cancelled, drop our reference to the CUI and free the 20162306a36Sopenharmony_ci * CUD. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ciSTATIC void 20462306a36Sopenharmony_cixfs_cud_item_release( 20562306a36Sopenharmony_ci struct xfs_log_item *lip) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct xfs_cud_log_item *cudp = CUD_ITEM(lip); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci xfs_cui_release(cudp->cud_cuip); 21062306a36Sopenharmony_ci kmem_free(cudp->cud_item.li_lv_shadow); 21162306a36Sopenharmony_ci kmem_cache_free(xfs_cud_cache, cudp); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic struct xfs_log_item * 21562306a36Sopenharmony_cixfs_cud_item_intent( 21662306a36Sopenharmony_ci struct xfs_log_item *lip) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci return &CUD_ITEM(lip)->cud_cuip->cui_item; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_cud_item_ops = { 22262306a36Sopenharmony_ci .flags = XFS_ITEM_RELEASE_WHEN_COMMITTED | 22362306a36Sopenharmony_ci XFS_ITEM_INTENT_DONE, 22462306a36Sopenharmony_ci .iop_size = xfs_cud_item_size, 22562306a36Sopenharmony_ci .iop_format = xfs_cud_item_format, 22662306a36Sopenharmony_ci .iop_release = xfs_cud_item_release, 22762306a36Sopenharmony_ci .iop_intent = xfs_cud_item_intent, 22862306a36Sopenharmony_ci}; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic struct xfs_cud_log_item * 23162306a36Sopenharmony_cixfs_trans_get_cud( 23262306a36Sopenharmony_ci struct xfs_trans *tp, 23362306a36Sopenharmony_ci struct xfs_cui_log_item *cuip) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct xfs_cud_log_item *cudp; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci cudp = kmem_cache_zalloc(xfs_cud_cache, GFP_KERNEL | __GFP_NOFAIL); 23862306a36Sopenharmony_ci xfs_log_item_init(tp->t_mountp, &cudp->cud_item, XFS_LI_CUD, 23962306a36Sopenharmony_ci &xfs_cud_item_ops); 24062306a36Sopenharmony_ci cudp->cud_cuip = cuip; 24162306a36Sopenharmony_ci cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci xfs_trans_add_item(tp, &cudp->cud_item); 24462306a36Sopenharmony_ci return cudp; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/* 24862306a36Sopenharmony_ci * Finish an refcount update and log it to the CUD. Note that the 24962306a36Sopenharmony_ci * transaction is marked dirty regardless of whether the refcount 25062306a36Sopenharmony_ci * update succeeds or fails to support the CUI/CUD lifecycle rules. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cistatic int 25362306a36Sopenharmony_cixfs_trans_log_finish_refcount_update( 25462306a36Sopenharmony_ci struct xfs_trans *tp, 25562306a36Sopenharmony_ci struct xfs_cud_log_item *cudp, 25662306a36Sopenharmony_ci struct xfs_refcount_intent *ri, 25762306a36Sopenharmony_ci struct xfs_btree_cur **pcur) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci int error; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci error = xfs_refcount_finish_one(tp, ri, pcur); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * Mark the transaction dirty, even on error. This ensures the 26562306a36Sopenharmony_ci * transaction is aborted, which: 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * 1.) releases the CUI and frees the CUD 26862306a36Sopenharmony_ci * 2.) shuts down the filesystem 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE; 27162306a36Sopenharmony_ci set_bit(XFS_LI_DIRTY, &cudp->cud_item.li_flags); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return error; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/* Sort refcount intents by AG. */ 27762306a36Sopenharmony_cistatic int 27862306a36Sopenharmony_cixfs_refcount_update_diff_items( 27962306a36Sopenharmony_ci void *priv, 28062306a36Sopenharmony_ci const struct list_head *a, 28162306a36Sopenharmony_ci const struct list_head *b) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct xfs_refcount_intent *ra; 28462306a36Sopenharmony_ci struct xfs_refcount_intent *rb; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ra = container_of(a, struct xfs_refcount_intent, ri_list); 28762306a36Sopenharmony_ci rb = container_of(b, struct xfs_refcount_intent, ri_list); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return ra->ri_pag->pag_agno - rb->ri_pag->pag_agno; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* Set the phys extent flags for this reverse mapping. */ 29362306a36Sopenharmony_cistatic void 29462306a36Sopenharmony_cixfs_trans_set_refcount_flags( 29562306a36Sopenharmony_ci struct xfs_phys_extent *pmap, 29662306a36Sopenharmony_ci enum xfs_refcount_intent_type type) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci pmap->pe_flags = 0; 29962306a36Sopenharmony_ci switch (type) { 30062306a36Sopenharmony_ci case XFS_REFCOUNT_INCREASE: 30162306a36Sopenharmony_ci case XFS_REFCOUNT_DECREASE: 30262306a36Sopenharmony_ci case XFS_REFCOUNT_ALLOC_COW: 30362306a36Sopenharmony_ci case XFS_REFCOUNT_FREE_COW: 30462306a36Sopenharmony_ci pmap->pe_flags |= type; 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci default: 30762306a36Sopenharmony_ci ASSERT(0); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* Log refcount updates in the intent item. */ 31262306a36Sopenharmony_ciSTATIC void 31362306a36Sopenharmony_cixfs_refcount_update_log_item( 31462306a36Sopenharmony_ci struct xfs_trans *tp, 31562306a36Sopenharmony_ci struct xfs_cui_log_item *cuip, 31662306a36Sopenharmony_ci struct xfs_refcount_intent *ri) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci uint next_extent; 31962306a36Sopenharmony_ci struct xfs_phys_extent *pmap; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci tp->t_flags |= XFS_TRANS_DIRTY; 32262306a36Sopenharmony_ci set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* 32562306a36Sopenharmony_ci * atomic_inc_return gives us the value after the increment; 32662306a36Sopenharmony_ci * we want to use it as an array index so we need to subtract 1 from 32762306a36Sopenharmony_ci * it. 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci next_extent = atomic_inc_return(&cuip->cui_next_extent) - 1; 33062306a36Sopenharmony_ci ASSERT(next_extent < cuip->cui_format.cui_nextents); 33162306a36Sopenharmony_ci pmap = &cuip->cui_format.cui_extents[next_extent]; 33262306a36Sopenharmony_ci pmap->pe_startblock = ri->ri_startblock; 33362306a36Sopenharmony_ci pmap->pe_len = ri->ri_blockcount; 33462306a36Sopenharmony_ci xfs_trans_set_refcount_flags(pmap, ri->ri_type); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic struct xfs_log_item * 33862306a36Sopenharmony_cixfs_refcount_update_create_intent( 33962306a36Sopenharmony_ci struct xfs_trans *tp, 34062306a36Sopenharmony_ci struct list_head *items, 34162306a36Sopenharmony_ci unsigned int count, 34262306a36Sopenharmony_ci bool sort) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct xfs_mount *mp = tp->t_mountp; 34562306a36Sopenharmony_ci struct xfs_cui_log_item *cuip = xfs_cui_init(mp, count); 34662306a36Sopenharmony_ci struct xfs_refcount_intent *ri; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ASSERT(count > 0); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci xfs_trans_add_item(tp, &cuip->cui_item); 35162306a36Sopenharmony_ci if (sort) 35262306a36Sopenharmony_ci list_sort(mp, items, xfs_refcount_update_diff_items); 35362306a36Sopenharmony_ci list_for_each_entry(ri, items, ri_list) 35462306a36Sopenharmony_ci xfs_refcount_update_log_item(tp, cuip, ri); 35562306a36Sopenharmony_ci return &cuip->cui_item; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/* Get an CUD so we can process all the deferred refcount updates. */ 35962306a36Sopenharmony_cistatic struct xfs_log_item * 36062306a36Sopenharmony_cixfs_refcount_update_create_done( 36162306a36Sopenharmony_ci struct xfs_trans *tp, 36262306a36Sopenharmony_ci struct xfs_log_item *intent, 36362306a36Sopenharmony_ci unsigned int count) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci return &xfs_trans_get_cud(tp, CUI_ITEM(intent))->cud_item; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/* Take a passive ref to the AG containing the space we're refcounting. */ 36962306a36Sopenharmony_civoid 37062306a36Sopenharmony_cixfs_refcount_update_get_group( 37162306a36Sopenharmony_ci struct xfs_mount *mp, 37262306a36Sopenharmony_ci struct xfs_refcount_intent *ri) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci xfs_agnumber_t agno; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci agno = XFS_FSB_TO_AGNO(mp, ri->ri_startblock); 37762306a36Sopenharmony_ci ri->ri_pag = xfs_perag_intent_get(mp, agno); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci/* Release a passive AG ref after finishing refcounting work. */ 38162306a36Sopenharmony_cistatic inline void 38262306a36Sopenharmony_cixfs_refcount_update_put_group( 38362306a36Sopenharmony_ci struct xfs_refcount_intent *ri) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci xfs_perag_intent_put(ri->ri_pag); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/* Process a deferred refcount update. */ 38962306a36Sopenharmony_ciSTATIC int 39062306a36Sopenharmony_cixfs_refcount_update_finish_item( 39162306a36Sopenharmony_ci struct xfs_trans *tp, 39262306a36Sopenharmony_ci struct xfs_log_item *done, 39362306a36Sopenharmony_ci struct list_head *item, 39462306a36Sopenharmony_ci struct xfs_btree_cur **state) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct xfs_refcount_intent *ri; 39762306a36Sopenharmony_ci int error; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci ri = container_of(item, struct xfs_refcount_intent, ri_list); 40062306a36Sopenharmony_ci error = xfs_trans_log_finish_refcount_update(tp, CUD_ITEM(done), ri, 40162306a36Sopenharmony_ci state); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Did we run out of reservation? Requeue what we didn't finish. */ 40462306a36Sopenharmony_ci if (!error && ri->ri_blockcount > 0) { 40562306a36Sopenharmony_ci ASSERT(ri->ri_type == XFS_REFCOUNT_INCREASE || 40662306a36Sopenharmony_ci ri->ri_type == XFS_REFCOUNT_DECREASE); 40762306a36Sopenharmony_ci return -EAGAIN; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci xfs_refcount_update_put_group(ri); 41162306a36Sopenharmony_ci kmem_cache_free(xfs_refcount_intent_cache, ri); 41262306a36Sopenharmony_ci return error; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/* Abort all pending CUIs. */ 41662306a36Sopenharmony_ciSTATIC void 41762306a36Sopenharmony_cixfs_refcount_update_abort_intent( 41862306a36Sopenharmony_ci struct xfs_log_item *intent) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci xfs_cui_release(CUI_ITEM(intent)); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/* Cancel a deferred refcount update. */ 42462306a36Sopenharmony_ciSTATIC void 42562306a36Sopenharmony_cixfs_refcount_update_cancel_item( 42662306a36Sopenharmony_ci struct list_head *item) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct xfs_refcount_intent *ri; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ri = container_of(item, struct xfs_refcount_intent, ri_list); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci xfs_refcount_update_put_group(ri); 43362306a36Sopenharmony_ci kmem_cache_free(xfs_refcount_intent_cache, ri); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ciconst struct xfs_defer_op_type xfs_refcount_update_defer_type = { 43762306a36Sopenharmony_ci .max_items = XFS_CUI_MAX_FAST_EXTENTS, 43862306a36Sopenharmony_ci .create_intent = xfs_refcount_update_create_intent, 43962306a36Sopenharmony_ci .abort_intent = xfs_refcount_update_abort_intent, 44062306a36Sopenharmony_ci .create_done = xfs_refcount_update_create_done, 44162306a36Sopenharmony_ci .finish_item = xfs_refcount_update_finish_item, 44262306a36Sopenharmony_ci .finish_cleanup = xfs_refcount_finish_one_cleanup, 44362306a36Sopenharmony_ci .cancel_item = xfs_refcount_update_cancel_item, 44462306a36Sopenharmony_ci}; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci/* Is this recovered CUI ok? */ 44762306a36Sopenharmony_cistatic inline bool 44862306a36Sopenharmony_cixfs_cui_validate_phys( 44962306a36Sopenharmony_ci struct xfs_mount *mp, 45062306a36Sopenharmony_ci struct xfs_phys_extent *pmap) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci if (!xfs_has_reflink(mp)) 45362306a36Sopenharmony_ci return false; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (pmap->pe_flags & ~XFS_REFCOUNT_EXTENT_FLAGS) 45662306a36Sopenharmony_ci return false; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci switch (pmap->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK) { 45962306a36Sopenharmony_ci case XFS_REFCOUNT_INCREASE: 46062306a36Sopenharmony_ci case XFS_REFCOUNT_DECREASE: 46162306a36Sopenharmony_ci case XFS_REFCOUNT_ALLOC_COW: 46262306a36Sopenharmony_ci case XFS_REFCOUNT_FREE_COW: 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci default: 46562306a36Sopenharmony_ci return false; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return xfs_verify_fsbext(mp, pmap->pe_startblock, pmap->pe_len); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* 47262306a36Sopenharmony_ci * Process a refcount update intent item that was recovered from the log. 47362306a36Sopenharmony_ci * We need to update the refcountbt. 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_ciSTATIC int 47662306a36Sopenharmony_cixfs_cui_item_recover( 47762306a36Sopenharmony_ci struct xfs_log_item *lip, 47862306a36Sopenharmony_ci struct list_head *capture_list) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct xfs_trans_res resv; 48162306a36Sopenharmony_ci struct xfs_cui_log_item *cuip = CUI_ITEM(lip); 48262306a36Sopenharmony_ci struct xfs_cud_log_item *cudp; 48362306a36Sopenharmony_ci struct xfs_trans *tp; 48462306a36Sopenharmony_ci struct xfs_btree_cur *rcur = NULL; 48562306a36Sopenharmony_ci struct xfs_mount *mp = lip->li_log->l_mp; 48662306a36Sopenharmony_ci unsigned int refc_type; 48762306a36Sopenharmony_ci bool requeue_only = false; 48862306a36Sopenharmony_ci int i; 48962306a36Sopenharmony_ci int error = 0; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* 49262306a36Sopenharmony_ci * First check the validity of the extents described by the 49362306a36Sopenharmony_ci * CUI. If any are bad, then assume that all are bad and 49462306a36Sopenharmony_ci * just toss the CUI. 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ci for (i = 0; i < cuip->cui_format.cui_nextents; i++) { 49762306a36Sopenharmony_ci if (!xfs_cui_validate_phys(mp, 49862306a36Sopenharmony_ci &cuip->cui_format.cui_extents[i])) { 49962306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 50062306a36Sopenharmony_ci &cuip->cui_format, 50162306a36Sopenharmony_ci sizeof(cuip->cui_format)); 50262306a36Sopenharmony_ci return -EFSCORRUPTED; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* 50762306a36Sopenharmony_ci * Under normal operation, refcount updates are deferred, so we 50862306a36Sopenharmony_ci * wouldn't be adding them directly to a transaction. All 50962306a36Sopenharmony_ci * refcount updates manage reservation usage internally and 51062306a36Sopenharmony_ci * dynamically by deferring work that won't fit in the 51162306a36Sopenharmony_ci * transaction. Normally, any work that needs to be deferred 51262306a36Sopenharmony_ci * gets attached to the same defer_ops that scheduled the 51362306a36Sopenharmony_ci * refcount update. However, we're in log recovery here, so we 51462306a36Sopenharmony_ci * use the passed in defer_ops and to finish up any work that 51562306a36Sopenharmony_ci * doesn't fit. We need to reserve enough blocks to handle a 51662306a36Sopenharmony_ci * full btree split on either end of the refcount range. 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ci resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate); 51962306a36Sopenharmony_ci error = xfs_trans_alloc(mp, &resv, mp->m_refc_maxlevels * 2, 0, 52062306a36Sopenharmony_ci XFS_TRANS_RESERVE, &tp); 52162306a36Sopenharmony_ci if (error) 52262306a36Sopenharmony_ci return error; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci cudp = xfs_trans_get_cud(tp, cuip); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci for (i = 0; i < cuip->cui_format.cui_nextents; i++) { 52762306a36Sopenharmony_ci struct xfs_refcount_intent fake = { }; 52862306a36Sopenharmony_ci struct xfs_phys_extent *pmap; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci pmap = &cuip->cui_format.cui_extents[i]; 53162306a36Sopenharmony_ci refc_type = pmap->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK; 53262306a36Sopenharmony_ci switch (refc_type) { 53362306a36Sopenharmony_ci case XFS_REFCOUNT_INCREASE: 53462306a36Sopenharmony_ci case XFS_REFCOUNT_DECREASE: 53562306a36Sopenharmony_ci case XFS_REFCOUNT_ALLOC_COW: 53662306a36Sopenharmony_ci case XFS_REFCOUNT_FREE_COW: 53762306a36Sopenharmony_ci fake.ri_type = refc_type; 53862306a36Sopenharmony_ci break; 53962306a36Sopenharmony_ci default: 54062306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 54162306a36Sopenharmony_ci &cuip->cui_format, 54262306a36Sopenharmony_ci sizeof(cuip->cui_format)); 54362306a36Sopenharmony_ci error = -EFSCORRUPTED; 54462306a36Sopenharmony_ci goto abort_error; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci fake.ri_startblock = pmap->pe_startblock; 54862306a36Sopenharmony_ci fake.ri_blockcount = pmap->pe_len; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (!requeue_only) { 55162306a36Sopenharmony_ci xfs_refcount_update_get_group(mp, &fake); 55262306a36Sopenharmony_ci error = xfs_trans_log_finish_refcount_update(tp, cudp, 55362306a36Sopenharmony_ci &fake, &rcur); 55462306a36Sopenharmony_ci xfs_refcount_update_put_group(&fake); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci if (error == -EFSCORRUPTED) 55762306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 55862306a36Sopenharmony_ci &cuip->cui_format, 55962306a36Sopenharmony_ci sizeof(cuip->cui_format)); 56062306a36Sopenharmony_ci if (error) 56162306a36Sopenharmony_ci goto abort_error; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* Requeue what we didn't finish. */ 56462306a36Sopenharmony_ci if (fake.ri_blockcount > 0) { 56562306a36Sopenharmony_ci struct xfs_bmbt_irec irec = { 56662306a36Sopenharmony_ci .br_startblock = fake.ri_startblock, 56762306a36Sopenharmony_ci .br_blockcount = fake.ri_blockcount, 56862306a36Sopenharmony_ci }; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci switch (fake.ri_type) { 57162306a36Sopenharmony_ci case XFS_REFCOUNT_INCREASE: 57262306a36Sopenharmony_ci xfs_refcount_increase_extent(tp, &irec); 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci case XFS_REFCOUNT_DECREASE: 57562306a36Sopenharmony_ci xfs_refcount_decrease_extent(tp, &irec); 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci case XFS_REFCOUNT_ALLOC_COW: 57862306a36Sopenharmony_ci xfs_refcount_alloc_cow_extent(tp, 57962306a36Sopenharmony_ci irec.br_startblock, 58062306a36Sopenharmony_ci irec.br_blockcount); 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci case XFS_REFCOUNT_FREE_COW: 58362306a36Sopenharmony_ci xfs_refcount_free_cow_extent(tp, 58462306a36Sopenharmony_ci irec.br_startblock, 58562306a36Sopenharmony_ci irec.br_blockcount); 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci default: 58862306a36Sopenharmony_ci ASSERT(0); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci requeue_only = true; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci xfs_refcount_finish_one_cleanup(tp, rcur, error); 59562306a36Sopenharmony_ci return xfs_defer_ops_capture_and_commit(tp, capture_list); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ciabort_error: 59862306a36Sopenharmony_ci xfs_refcount_finish_one_cleanup(tp, rcur, error); 59962306a36Sopenharmony_ci xfs_trans_cancel(tp); 60062306a36Sopenharmony_ci return error; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ciSTATIC bool 60462306a36Sopenharmony_cixfs_cui_item_match( 60562306a36Sopenharmony_ci struct xfs_log_item *lip, 60662306a36Sopenharmony_ci uint64_t intent_id) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci return CUI_ITEM(lip)->cui_format.cui_id == intent_id; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci/* Relog an intent item to push the log tail forward. */ 61262306a36Sopenharmony_cistatic struct xfs_log_item * 61362306a36Sopenharmony_cixfs_cui_item_relog( 61462306a36Sopenharmony_ci struct xfs_log_item *intent, 61562306a36Sopenharmony_ci struct xfs_trans *tp) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct xfs_cud_log_item *cudp; 61862306a36Sopenharmony_ci struct xfs_cui_log_item *cuip; 61962306a36Sopenharmony_ci struct xfs_phys_extent *pmap; 62062306a36Sopenharmony_ci unsigned int count; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci count = CUI_ITEM(intent)->cui_format.cui_nextents; 62362306a36Sopenharmony_ci pmap = CUI_ITEM(intent)->cui_format.cui_extents; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci tp->t_flags |= XFS_TRANS_DIRTY; 62662306a36Sopenharmony_ci cudp = xfs_trans_get_cud(tp, CUI_ITEM(intent)); 62762306a36Sopenharmony_ci set_bit(XFS_LI_DIRTY, &cudp->cud_item.li_flags); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci cuip = xfs_cui_init(tp->t_mountp, count); 63062306a36Sopenharmony_ci memcpy(cuip->cui_format.cui_extents, pmap, count * sizeof(*pmap)); 63162306a36Sopenharmony_ci atomic_set(&cuip->cui_next_extent, count); 63262306a36Sopenharmony_ci xfs_trans_add_item(tp, &cuip->cui_item); 63362306a36Sopenharmony_ci set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags); 63462306a36Sopenharmony_ci return &cuip->cui_item; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_cui_item_ops = { 63862306a36Sopenharmony_ci .flags = XFS_ITEM_INTENT, 63962306a36Sopenharmony_ci .iop_size = xfs_cui_item_size, 64062306a36Sopenharmony_ci .iop_format = xfs_cui_item_format, 64162306a36Sopenharmony_ci .iop_unpin = xfs_cui_item_unpin, 64262306a36Sopenharmony_ci .iop_release = xfs_cui_item_release, 64362306a36Sopenharmony_ci .iop_recover = xfs_cui_item_recover, 64462306a36Sopenharmony_ci .iop_match = xfs_cui_item_match, 64562306a36Sopenharmony_ci .iop_relog = xfs_cui_item_relog, 64662306a36Sopenharmony_ci}; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic inline void 64962306a36Sopenharmony_cixfs_cui_copy_format( 65062306a36Sopenharmony_ci struct xfs_cui_log_format *dst, 65162306a36Sopenharmony_ci const struct xfs_cui_log_format *src) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci unsigned int i; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci memcpy(dst, src, offsetof(struct xfs_cui_log_format, cui_extents)); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci for (i = 0; i < src->cui_nextents; i++) 65862306a36Sopenharmony_ci memcpy(&dst->cui_extents[i], &src->cui_extents[i], 65962306a36Sopenharmony_ci sizeof(struct xfs_phys_extent)); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci/* 66362306a36Sopenharmony_ci * This routine is called to create an in-core extent refcount update 66462306a36Sopenharmony_ci * item from the cui format structure which was logged on disk. 66562306a36Sopenharmony_ci * It allocates an in-core cui, copies the extents from the format 66662306a36Sopenharmony_ci * structure into it, and adds the cui to the AIL with the given 66762306a36Sopenharmony_ci * LSN. 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ciSTATIC int 67062306a36Sopenharmony_cixlog_recover_cui_commit_pass2( 67162306a36Sopenharmony_ci struct xlog *log, 67262306a36Sopenharmony_ci struct list_head *buffer_list, 67362306a36Sopenharmony_ci struct xlog_recover_item *item, 67462306a36Sopenharmony_ci xfs_lsn_t lsn) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct xfs_mount *mp = log->l_mp; 67762306a36Sopenharmony_ci struct xfs_cui_log_item *cuip; 67862306a36Sopenharmony_ci struct xfs_cui_log_format *cui_formatp; 67962306a36Sopenharmony_ci size_t len; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci cui_formatp = item->ri_buf[0].i_addr; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (item->ri_buf[0].i_len < xfs_cui_log_format_sizeof(0)) { 68462306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 68562306a36Sopenharmony_ci item->ri_buf[0].i_addr, item->ri_buf[0].i_len); 68662306a36Sopenharmony_ci return -EFSCORRUPTED; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci len = xfs_cui_log_format_sizeof(cui_formatp->cui_nextents); 69062306a36Sopenharmony_ci if (item->ri_buf[0].i_len != len) { 69162306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 69262306a36Sopenharmony_ci item->ri_buf[0].i_addr, item->ri_buf[0].i_len); 69362306a36Sopenharmony_ci return -EFSCORRUPTED; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci cuip = xfs_cui_init(mp, cui_formatp->cui_nextents); 69762306a36Sopenharmony_ci xfs_cui_copy_format(&cuip->cui_format, cui_formatp); 69862306a36Sopenharmony_ci atomic_set(&cuip->cui_next_extent, cui_formatp->cui_nextents); 69962306a36Sopenharmony_ci /* 70062306a36Sopenharmony_ci * Insert the intent into the AIL directly and drop one reference so 70162306a36Sopenharmony_ci * that finishing or canceling the work will drop the other. 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_ci xfs_trans_ail_insert(log->l_ailp, &cuip->cui_item, lsn); 70462306a36Sopenharmony_ci xfs_cui_release(cuip); 70562306a36Sopenharmony_ci return 0; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ciconst struct xlog_recover_item_ops xlog_cui_item_ops = { 70962306a36Sopenharmony_ci .item_type = XFS_LI_CUI, 71062306a36Sopenharmony_ci .commit_pass2 = xlog_recover_cui_commit_pass2, 71162306a36Sopenharmony_ci}; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci/* 71462306a36Sopenharmony_ci * This routine is called when an CUD format structure is found in a committed 71562306a36Sopenharmony_ci * transaction in the log. Its purpose is to cancel the corresponding CUI if it 71662306a36Sopenharmony_ci * was still in the log. To do this it searches the AIL for the CUI with an id 71762306a36Sopenharmony_ci * equal to that in the CUD format structure. If we find it we drop the CUD 71862306a36Sopenharmony_ci * reference, which removes the CUI from the AIL and frees it. 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ciSTATIC int 72162306a36Sopenharmony_cixlog_recover_cud_commit_pass2( 72262306a36Sopenharmony_ci struct xlog *log, 72362306a36Sopenharmony_ci struct list_head *buffer_list, 72462306a36Sopenharmony_ci struct xlog_recover_item *item, 72562306a36Sopenharmony_ci xfs_lsn_t lsn) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct xfs_cud_log_format *cud_formatp; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci cud_formatp = item->ri_buf[0].i_addr; 73062306a36Sopenharmony_ci if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format)) { 73162306a36Sopenharmony_ci XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp, 73262306a36Sopenharmony_ci item->ri_buf[0].i_addr, item->ri_buf[0].i_len); 73362306a36Sopenharmony_ci return -EFSCORRUPTED; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci xlog_recover_release_intent(log, XFS_LI_CUI, cud_formatp->cud_cui_id); 73762306a36Sopenharmony_ci return 0; 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ciconst struct xlog_recover_item_ops xlog_cud_item_ops = { 74162306a36Sopenharmony_ci .item_type = XFS_LI_CUD, 74262306a36Sopenharmony_ci .commit_pass2 = xlog_recover_cud_commit_pass2, 74362306a36Sopenharmony_ci}; 744