162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2020-2022, Red Hat, Inc. 462306a36Sopenharmony_ci * All Rights Reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_shared.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_log_format.h" 1162306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1262306a36Sopenharmony_ci#include "xfs_mount.h" 1362306a36Sopenharmony_ci#include "xfs_inode.h" 1462306a36Sopenharmony_ci#include "xfs_trans.h" 1562306a36Sopenharmony_ci#include "xfs_trans_priv.h" 1662306a36Sopenharmony_ci#include "xfs_ag.h" 1762306a36Sopenharmony_ci#include "xfs_iunlink_item.h" 1862306a36Sopenharmony_ci#include "xfs_trace.h" 1962306a36Sopenharmony_ci#include "xfs_error.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct kmem_cache *xfs_iunlink_cache; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic inline struct xfs_iunlink_item *IUL_ITEM(struct xfs_log_item *lip) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci return container_of(lip, struct xfs_iunlink_item, item); 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void 2962306a36Sopenharmony_cixfs_iunlink_item_release( 3062306a36Sopenharmony_ci struct xfs_log_item *lip) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct xfs_iunlink_item *iup = IUL_ITEM(lip); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci xfs_perag_put(iup->pag); 3562306a36Sopenharmony_ci kmem_cache_free(xfs_iunlink_cache, IUL_ITEM(lip)); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic uint64_t 4062306a36Sopenharmony_cixfs_iunlink_item_sort( 4162306a36Sopenharmony_ci struct xfs_log_item *lip) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci return IUL_ITEM(lip)->ip->i_ino; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * Look up the inode cluster buffer and log the on-disk unlinked inode change 4862306a36Sopenharmony_ci * we need to make. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_cistatic int 5162306a36Sopenharmony_cixfs_iunlink_log_dinode( 5262306a36Sopenharmony_ci struct xfs_trans *tp, 5362306a36Sopenharmony_ci struct xfs_iunlink_item *iup) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct xfs_mount *mp = tp->t_mountp; 5662306a36Sopenharmony_ci struct xfs_inode *ip = iup->ip; 5762306a36Sopenharmony_ci struct xfs_dinode *dip; 5862306a36Sopenharmony_ci struct xfs_buf *ibp; 5962306a36Sopenharmony_ci int offset; 6062306a36Sopenharmony_ci int error; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp); 6362306a36Sopenharmony_ci if (error) 6462306a36Sopenharmony_ci return error; 6562306a36Sopenharmony_ci /* 6662306a36Sopenharmony_ci * Don't log the unlinked field on stale buffers as this may be the 6762306a36Sopenharmony_ci * transaction that frees the inode cluster and relogging the buffer 6862306a36Sopenharmony_ci * here will incorrectly remove the stale state. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci if (ibp->b_flags & XBF_STALE) 7162306a36Sopenharmony_ci goto out; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci dip = xfs_buf_offset(ibp, ip->i_imap.im_boffset); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* Make sure the old pointer isn't garbage. */ 7662306a36Sopenharmony_ci if (be32_to_cpu(dip->di_next_unlinked) != iup->old_agino) { 7762306a36Sopenharmony_ci xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip, 7862306a36Sopenharmony_ci sizeof(*dip), __this_address); 7962306a36Sopenharmony_ci error = -EFSCORRUPTED; 8062306a36Sopenharmony_ci goto out; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci trace_xfs_iunlink_update_dinode(mp, iup->pag->pag_agno, 8462306a36Sopenharmony_ci XFS_INO_TO_AGINO(mp, ip->i_ino), 8562306a36Sopenharmony_ci be32_to_cpu(dip->di_next_unlinked), iup->next_agino); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci dip->di_next_unlinked = cpu_to_be32(iup->next_agino); 8862306a36Sopenharmony_ci offset = ip->i_imap.im_boffset + 8962306a36Sopenharmony_ci offsetof(struct xfs_dinode, di_next_unlinked); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci xfs_dinode_calc_crc(mp, dip); 9262306a36Sopenharmony_ci xfs_trans_inode_buf(tp, ibp); 9362306a36Sopenharmony_ci xfs_trans_log_buf(tp, ibp, offset, offset + sizeof(xfs_agino_t) - 1); 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ciout: 9662306a36Sopenharmony_ci xfs_trans_brelse(tp, ibp); 9762306a36Sopenharmony_ci return error; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * On precommit, we grab the inode cluster buffer for the inode number we were 10262306a36Sopenharmony_ci * passed, then update the next unlinked field for that inode in the buffer and 10362306a36Sopenharmony_ci * log the buffer. This ensures that the inode cluster buffer was logged in the 10462306a36Sopenharmony_ci * correct order w.r.t. other inode cluster buffers. We can then remove the 10562306a36Sopenharmony_ci * iunlink item from the transaction and release it as it is has now served it's 10662306a36Sopenharmony_ci * purpose. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistatic int 10962306a36Sopenharmony_cixfs_iunlink_item_precommit( 11062306a36Sopenharmony_ci struct xfs_trans *tp, 11162306a36Sopenharmony_ci struct xfs_log_item *lip) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct xfs_iunlink_item *iup = IUL_ITEM(lip); 11462306a36Sopenharmony_ci int error; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci error = xfs_iunlink_log_dinode(tp, iup); 11762306a36Sopenharmony_ci list_del(&lip->li_trans); 11862306a36Sopenharmony_ci xfs_iunlink_item_release(lip); 11962306a36Sopenharmony_ci return error; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_iunlink_item_ops = { 12362306a36Sopenharmony_ci .iop_release = xfs_iunlink_item_release, 12462306a36Sopenharmony_ci .iop_sort = xfs_iunlink_item_sort, 12562306a36Sopenharmony_ci .iop_precommit = xfs_iunlink_item_precommit, 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* 13062306a36Sopenharmony_ci * Initialize the inode log item for a newly allocated (in-core) inode. 13162306a36Sopenharmony_ci * 13262306a36Sopenharmony_ci * Inode extents can only reside within an AG. Hence specify the starting 13362306a36Sopenharmony_ci * block for the inode chunk by offset within an AG as well as the 13462306a36Sopenharmony_ci * length of the allocated extent. 13562306a36Sopenharmony_ci * 13662306a36Sopenharmony_ci * This joins the item to the transaction and marks it dirty so 13762306a36Sopenharmony_ci * that we don't need a separate call to do this, nor does the 13862306a36Sopenharmony_ci * caller need to know anything about the iunlink item. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ciint 14162306a36Sopenharmony_cixfs_iunlink_log_inode( 14262306a36Sopenharmony_ci struct xfs_trans *tp, 14362306a36Sopenharmony_ci struct xfs_inode *ip, 14462306a36Sopenharmony_ci struct xfs_perag *pag, 14562306a36Sopenharmony_ci xfs_agino_t next_agino) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct xfs_mount *mp = tp->t_mountp; 14862306a36Sopenharmony_ci struct xfs_iunlink_item *iup; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ASSERT(xfs_verify_agino_or_null(pag, next_agino)); 15162306a36Sopenharmony_ci ASSERT(xfs_verify_agino_or_null(pag, ip->i_next_unlinked)); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * Since we're updating a linked list, we should never find that the 15562306a36Sopenharmony_ci * current pointer is the same as the new value, unless we're 15662306a36Sopenharmony_ci * terminating the list. 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ci if (ip->i_next_unlinked == next_agino) { 15962306a36Sopenharmony_ci if (next_agino != NULLAGINO) 16062306a36Sopenharmony_ci return -EFSCORRUPTED; 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci iup = kmem_cache_zalloc(xfs_iunlink_cache, GFP_KERNEL | __GFP_NOFAIL); 16562306a36Sopenharmony_ci xfs_log_item_init(mp, &iup->item, XFS_LI_IUNLINK, 16662306a36Sopenharmony_ci &xfs_iunlink_item_ops); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci iup->ip = ip; 16962306a36Sopenharmony_ci iup->next_agino = next_agino; 17062306a36Sopenharmony_ci iup->old_agino = ip->i_next_unlinked; 17162306a36Sopenharmony_ci iup->pag = xfs_perag_hold(pag); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci xfs_trans_add_item(tp, &iup->item); 17462306a36Sopenharmony_ci tp->t_flags |= XFS_TRANS_DIRTY; 17562306a36Sopenharmony_ci set_bit(XFS_LI_DIRTY, &iup->item.li_flags); 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 179