162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2000-2002,2005 Silicon Graphics, 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_inode_item.h" 1662306a36Sopenharmony_ci#include "xfs_trace.h" 1762306a36Sopenharmony_ci#include "xfs_trans_priv.h" 1862306a36Sopenharmony_ci#include "xfs_buf_item.h" 1962306a36Sopenharmony_ci#include "xfs_log.h" 2062306a36Sopenharmony_ci#include "xfs_log_priv.h" 2162306a36Sopenharmony_ci#include "xfs_error.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/iversion.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct kmem_cache *xfs_ili_cache; /* inode log item */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic inline struct xfs_inode_log_item *INODE_ITEM(struct xfs_log_item *lip) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci return container_of(lip, struct xfs_inode_log_item, ili_item); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic uint64_t 3362306a36Sopenharmony_cixfs_inode_item_sort( 3462306a36Sopenharmony_ci struct xfs_log_item *lip) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci return INODE_ITEM(lip)->ili_inode->i_ino; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * Prior to finally logging the inode, we have to ensure that all the 4162306a36Sopenharmony_ci * per-modification inode state changes are applied. This includes VFS inode 4262306a36Sopenharmony_ci * state updates, format conversions, verifier state synchronisation and 4362306a36Sopenharmony_ci * ensuring the inode buffer remains in memory whilst the inode is dirty. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * We have to be careful when we grab the inode cluster buffer due to lock 4662306a36Sopenharmony_ci * ordering constraints. The unlinked inode modifications (xfs_iunlink_item) 4762306a36Sopenharmony_ci * require AGI -> inode cluster buffer lock order. The inode cluster buffer is 4862306a36Sopenharmony_ci * not locked until ->precommit, so it happens after everything else has been 4962306a36Sopenharmony_ci * modified. 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * Further, we have AGI -> AGF lock ordering, and with O_TMPFILE handling we 5262306a36Sopenharmony_ci * have AGI -> AGF -> iunlink item -> inode cluster buffer lock order. Hence we 5362306a36Sopenharmony_ci * cannot safely lock the inode cluster buffer in xfs_trans_log_inode() because 5462306a36Sopenharmony_ci * it can be called on a inode (e.g. via bumplink/droplink) before we take the 5562306a36Sopenharmony_ci * AGF lock modifying directory blocks. 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * Rather than force a complete rework of all the transactions to call 5862306a36Sopenharmony_ci * xfs_trans_log_inode() once and once only at the end of every transaction, we 5962306a36Sopenharmony_ci * move the pinning of the inode cluster buffer to a ->precommit operation. This 6062306a36Sopenharmony_ci * matches how the xfs_iunlink_item locks the inode cluster buffer, and it 6162306a36Sopenharmony_ci * ensures that the inode cluster buffer locking is always done last in a 6262306a36Sopenharmony_ci * transaction. i.e. we ensure the lock order is always AGI -> AGF -> inode 6362306a36Sopenharmony_ci * cluster buffer. 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * If we return the inode number as the precommit sort key then we'll also 6662306a36Sopenharmony_ci * guarantee that the order all inode cluster buffer locking is the same all the 6762306a36Sopenharmony_ci * inodes and unlink items in the transaction. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_cistatic int 7062306a36Sopenharmony_cixfs_inode_item_precommit( 7162306a36Sopenharmony_ci struct xfs_trans *tp, 7262306a36Sopenharmony_ci struct xfs_log_item *lip) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct xfs_inode_log_item *iip = INODE_ITEM(lip); 7562306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 7662306a36Sopenharmony_ci struct inode *inode = VFS_I(ip); 7762306a36Sopenharmony_ci unsigned int flags = iip->ili_dirty_flags; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * Don't bother with i_lock for the I_DIRTY_TIME check here, as races 8162306a36Sopenharmony_ci * don't matter - we either will need an extra transaction in 24 hours 8262306a36Sopenharmony_ci * to log the timestamps, or will clear already cleared fields in the 8362306a36Sopenharmony_ci * worst case. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci if (inode->i_state & I_DIRTY_TIME) { 8662306a36Sopenharmony_ci spin_lock(&inode->i_lock); 8762306a36Sopenharmony_ci inode->i_state &= ~I_DIRTY_TIME; 8862306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * If we're updating the inode core or the timestamps and it's possible 9362306a36Sopenharmony_ci * to upgrade this inode to bigtime format, do so now. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci if ((flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) && 9662306a36Sopenharmony_ci xfs_has_bigtime(ip->i_mount) && 9762306a36Sopenharmony_ci !xfs_inode_has_bigtime(ip)) { 9862306a36Sopenharmony_ci ip->i_diflags2 |= XFS_DIFLAG2_BIGTIME; 9962306a36Sopenharmony_ci flags |= XFS_ILOG_CORE; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* 10362306a36Sopenharmony_ci * Inode verifiers do not check that the extent size hint is an integer 10462306a36Sopenharmony_ci * multiple of the rt extent size on a directory with both rtinherit 10562306a36Sopenharmony_ci * and extszinherit flags set. If we're logging a directory that is 10662306a36Sopenharmony_ci * misconfigured in this way, clear the hint. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) && 10962306a36Sopenharmony_ci (ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) && 11062306a36Sopenharmony_ci (ip->i_extsize % ip->i_mount->m_sb.sb_rextsize) > 0) { 11162306a36Sopenharmony_ci ip->i_diflags &= ~(XFS_DIFLAG_EXTSIZE | 11262306a36Sopenharmony_ci XFS_DIFLAG_EXTSZINHERIT); 11362306a36Sopenharmony_ci ip->i_extsize = 0; 11462306a36Sopenharmony_ci flags |= XFS_ILOG_CORE; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* 11862306a36Sopenharmony_ci * Record the specific change for fdatasync optimisation. This allows 11962306a36Sopenharmony_ci * fdatasync to skip log forces for inodes that are only timestamp 12062306a36Sopenharmony_ci * dirty. Once we've processed the XFS_ILOG_IVERSION flag, convert it 12162306a36Sopenharmony_ci * to XFS_ILOG_CORE so that the actual on-disk dirty tracking 12262306a36Sopenharmony_ci * (ili_fields) correctly tracks that the version has changed. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci spin_lock(&iip->ili_lock); 12562306a36Sopenharmony_ci iip->ili_fsync_fields |= (flags & ~XFS_ILOG_IVERSION); 12662306a36Sopenharmony_ci if (flags & XFS_ILOG_IVERSION) 12762306a36Sopenharmony_ci flags = ((flags & ~XFS_ILOG_IVERSION) | XFS_ILOG_CORE); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (!iip->ili_item.li_buf) { 13062306a36Sopenharmony_ci struct xfs_buf *bp; 13162306a36Sopenharmony_ci int error; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* 13462306a36Sopenharmony_ci * We hold the ILOCK here, so this inode is not going to be 13562306a36Sopenharmony_ci * flushed while we are here. Further, because there is no 13662306a36Sopenharmony_ci * buffer attached to the item, we know that there is no IO in 13762306a36Sopenharmony_ci * progress, so nothing will clear the ili_fields while we read 13862306a36Sopenharmony_ci * in the buffer. Hence we can safely drop the spin lock and 13962306a36Sopenharmony_ci * read the buffer knowing that the state will not change from 14062306a36Sopenharmony_ci * here. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci spin_unlock(&iip->ili_lock); 14362306a36Sopenharmony_ci error = xfs_imap_to_bp(ip->i_mount, tp, &ip->i_imap, &bp); 14462306a36Sopenharmony_ci if (error) 14562306a36Sopenharmony_ci return error; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * We need an explicit buffer reference for the log item but 14962306a36Sopenharmony_ci * don't want the buffer to remain attached to the transaction. 15062306a36Sopenharmony_ci * Hold the buffer but release the transaction reference once 15162306a36Sopenharmony_ci * we've attached the inode log item to the buffer log item 15262306a36Sopenharmony_ci * list. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci xfs_buf_hold(bp); 15562306a36Sopenharmony_ci spin_lock(&iip->ili_lock); 15662306a36Sopenharmony_ci iip->ili_item.li_buf = bp; 15762306a36Sopenharmony_ci bp->b_flags |= _XBF_INODES; 15862306a36Sopenharmony_ci list_add_tail(&iip->ili_item.li_bio_list, &bp->b_li_list); 15962306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* 16362306a36Sopenharmony_ci * Always OR in the bits from the ili_last_fields field. This is to 16462306a36Sopenharmony_ci * coordinate with the xfs_iflush() and xfs_buf_inode_iodone() routines 16562306a36Sopenharmony_ci * in the eventual clearing of the ili_fields bits. See the big comment 16662306a36Sopenharmony_ci * in xfs_iflush() for an explanation of this coordination mechanism. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci iip->ili_fields |= (flags | iip->ili_last_fields); 16962306a36Sopenharmony_ci spin_unlock(&iip->ili_lock); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* 17262306a36Sopenharmony_ci * We are done with the log item transaction dirty state, so clear it so 17362306a36Sopenharmony_ci * that it doesn't pollute future transactions. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci iip->ili_dirty_flags = 0; 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * The logged size of an inode fork is always the current size of the inode 18162306a36Sopenharmony_ci * fork. This means that when an inode fork is relogged, the size of the logged 18262306a36Sopenharmony_ci * region is determined by the current state, not the combination of the 18362306a36Sopenharmony_ci * previously logged state + the current state. This is different relogging 18462306a36Sopenharmony_ci * behaviour to most other log items which will retain the size of the 18562306a36Sopenharmony_ci * previously logged changes when smaller regions are relogged. 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * Hence operations that remove data from the inode fork (e.g. shortform 18862306a36Sopenharmony_ci * dir/attr remove, extent form extent removal, etc), the size of the relogged 18962306a36Sopenharmony_ci * inode gets -smaller- rather than stays the same size as the previously logged 19062306a36Sopenharmony_ci * size and this can result in the committing transaction reducing the amount of 19162306a36Sopenharmony_ci * space being consumed by the CIL. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ciSTATIC void 19462306a36Sopenharmony_cixfs_inode_item_data_fork_size( 19562306a36Sopenharmony_ci struct xfs_inode_log_item *iip, 19662306a36Sopenharmony_ci int *nvecs, 19762306a36Sopenharmony_ci int *nbytes) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci switch (ip->i_df.if_format) { 20262306a36Sopenharmony_ci case XFS_DINODE_FMT_EXTENTS: 20362306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_DEXT) && 20462306a36Sopenharmony_ci ip->i_df.if_nextents > 0 && 20562306a36Sopenharmony_ci ip->i_df.if_bytes > 0) { 20662306a36Sopenharmony_ci /* worst case, doesn't subtract delalloc extents */ 20762306a36Sopenharmony_ci *nbytes += xfs_inode_data_fork_size(ip); 20862306a36Sopenharmony_ci *nvecs += 1; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci case XFS_DINODE_FMT_BTREE: 21262306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_DBROOT) && 21362306a36Sopenharmony_ci ip->i_df.if_broot_bytes > 0) { 21462306a36Sopenharmony_ci *nbytes += ip->i_df.if_broot_bytes; 21562306a36Sopenharmony_ci *nvecs += 1; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci break; 21862306a36Sopenharmony_ci case XFS_DINODE_FMT_LOCAL: 21962306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_DDATA) && 22062306a36Sopenharmony_ci ip->i_df.if_bytes > 0) { 22162306a36Sopenharmony_ci *nbytes += xlog_calc_iovec_len(ip->i_df.if_bytes); 22262306a36Sopenharmony_ci *nvecs += 1; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci case XFS_DINODE_FMT_DEV: 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci default: 22962306a36Sopenharmony_ci ASSERT(0); 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciSTATIC void 23562306a36Sopenharmony_cixfs_inode_item_attr_fork_size( 23662306a36Sopenharmony_ci struct xfs_inode_log_item *iip, 23762306a36Sopenharmony_ci int *nvecs, 23862306a36Sopenharmony_ci int *nbytes) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci switch (ip->i_af.if_format) { 24362306a36Sopenharmony_ci case XFS_DINODE_FMT_EXTENTS: 24462306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_AEXT) && 24562306a36Sopenharmony_ci ip->i_af.if_nextents > 0 && 24662306a36Sopenharmony_ci ip->i_af.if_bytes > 0) { 24762306a36Sopenharmony_ci /* worst case, doesn't subtract unused space */ 24862306a36Sopenharmony_ci *nbytes += xfs_inode_attr_fork_size(ip); 24962306a36Sopenharmony_ci *nvecs += 1; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci case XFS_DINODE_FMT_BTREE: 25362306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_ABROOT) && 25462306a36Sopenharmony_ci ip->i_af.if_broot_bytes > 0) { 25562306a36Sopenharmony_ci *nbytes += ip->i_af.if_broot_bytes; 25662306a36Sopenharmony_ci *nvecs += 1; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci case XFS_DINODE_FMT_LOCAL: 26062306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_ADATA) && 26162306a36Sopenharmony_ci ip->i_af.if_bytes > 0) { 26262306a36Sopenharmony_ci *nbytes += xlog_calc_iovec_len(ip->i_af.if_bytes); 26362306a36Sopenharmony_ci *nvecs += 1; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci default: 26762306a36Sopenharmony_ci ASSERT(0); 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* 27362306a36Sopenharmony_ci * This returns the number of iovecs needed to log the given inode item. 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * We need one iovec for the inode log format structure, one for the 27662306a36Sopenharmony_ci * inode core, and possibly one for the inode data/extents/b-tree root 27762306a36Sopenharmony_ci * and one for the inode attribute data/extents/b-tree root. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ciSTATIC void 28062306a36Sopenharmony_cixfs_inode_item_size( 28162306a36Sopenharmony_ci struct xfs_log_item *lip, 28262306a36Sopenharmony_ci int *nvecs, 28362306a36Sopenharmony_ci int *nbytes) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct xfs_inode_log_item *iip = INODE_ITEM(lip); 28662306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci *nvecs += 2; 28962306a36Sopenharmony_ci *nbytes += sizeof(struct xfs_inode_log_format) + 29062306a36Sopenharmony_ci xfs_log_dinode_size(ip->i_mount); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci xfs_inode_item_data_fork_size(iip, nvecs, nbytes); 29362306a36Sopenharmony_ci if (xfs_inode_has_attr_fork(ip)) 29462306a36Sopenharmony_ci xfs_inode_item_attr_fork_size(iip, nvecs, nbytes); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ciSTATIC void 29862306a36Sopenharmony_cixfs_inode_item_format_data_fork( 29962306a36Sopenharmony_ci struct xfs_inode_log_item *iip, 30062306a36Sopenharmony_ci struct xfs_inode_log_format *ilf, 30162306a36Sopenharmony_ci struct xfs_log_vec *lv, 30262306a36Sopenharmony_ci struct xfs_log_iovec **vecp) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 30562306a36Sopenharmony_ci size_t data_bytes; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci switch (ip->i_df.if_format) { 30862306a36Sopenharmony_ci case XFS_DINODE_FMT_EXTENTS: 30962306a36Sopenharmony_ci iip->ili_fields &= 31062306a36Sopenharmony_ci ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | XFS_ILOG_DEV); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_DEXT) && 31362306a36Sopenharmony_ci ip->i_df.if_nextents > 0 && 31462306a36Sopenharmony_ci ip->i_df.if_bytes > 0) { 31562306a36Sopenharmony_ci struct xfs_bmbt_rec *p; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci ASSERT(xfs_iext_count(&ip->i_df) > 0); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci p = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_IEXT); 32062306a36Sopenharmony_ci data_bytes = xfs_iextents_copy(ip, p, XFS_DATA_FORK); 32162306a36Sopenharmony_ci xlog_finish_iovec(lv, *vecp, data_bytes); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ASSERT(data_bytes <= ip->i_df.if_bytes); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci ilf->ilf_dsize = data_bytes; 32662306a36Sopenharmony_ci ilf->ilf_size++; 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci iip->ili_fields &= ~XFS_ILOG_DEXT; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci case XFS_DINODE_FMT_BTREE: 33262306a36Sopenharmony_ci iip->ili_fields &= 33362306a36Sopenharmony_ci ~(XFS_ILOG_DDATA | XFS_ILOG_DEXT | XFS_ILOG_DEV); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_DBROOT) && 33662306a36Sopenharmony_ci ip->i_df.if_broot_bytes > 0) { 33762306a36Sopenharmony_ci ASSERT(ip->i_df.if_broot != NULL); 33862306a36Sopenharmony_ci xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IBROOT, 33962306a36Sopenharmony_ci ip->i_df.if_broot, 34062306a36Sopenharmony_ci ip->i_df.if_broot_bytes); 34162306a36Sopenharmony_ci ilf->ilf_dsize = ip->i_df.if_broot_bytes; 34262306a36Sopenharmony_ci ilf->ilf_size++; 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci ASSERT(!(iip->ili_fields & 34562306a36Sopenharmony_ci XFS_ILOG_DBROOT)); 34662306a36Sopenharmony_ci iip->ili_fields &= ~XFS_ILOG_DBROOT; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci case XFS_DINODE_FMT_LOCAL: 35062306a36Sopenharmony_ci iip->ili_fields &= 35162306a36Sopenharmony_ci ~(XFS_ILOG_DEXT | XFS_ILOG_DBROOT | XFS_ILOG_DEV); 35262306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_DDATA) && 35362306a36Sopenharmony_ci ip->i_df.if_bytes > 0) { 35462306a36Sopenharmony_ci ASSERT(ip->i_df.if_u1.if_data != NULL); 35562306a36Sopenharmony_ci ASSERT(ip->i_disk_size > 0); 35662306a36Sopenharmony_ci xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL, 35762306a36Sopenharmony_ci ip->i_df.if_u1.if_data, 35862306a36Sopenharmony_ci ip->i_df.if_bytes); 35962306a36Sopenharmony_ci ilf->ilf_dsize = (unsigned)ip->i_df.if_bytes; 36062306a36Sopenharmony_ci ilf->ilf_size++; 36162306a36Sopenharmony_ci } else { 36262306a36Sopenharmony_ci iip->ili_fields &= ~XFS_ILOG_DDATA; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci case XFS_DINODE_FMT_DEV: 36662306a36Sopenharmony_ci iip->ili_fields &= 36762306a36Sopenharmony_ci ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | XFS_ILOG_DEXT); 36862306a36Sopenharmony_ci if (iip->ili_fields & XFS_ILOG_DEV) 36962306a36Sopenharmony_ci ilf->ilf_u.ilfu_rdev = sysv_encode_dev(VFS_I(ip)->i_rdev); 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci default: 37262306a36Sopenharmony_ci ASSERT(0); 37362306a36Sopenharmony_ci break; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciSTATIC void 37862306a36Sopenharmony_cixfs_inode_item_format_attr_fork( 37962306a36Sopenharmony_ci struct xfs_inode_log_item *iip, 38062306a36Sopenharmony_ci struct xfs_inode_log_format *ilf, 38162306a36Sopenharmony_ci struct xfs_log_vec *lv, 38262306a36Sopenharmony_ci struct xfs_log_iovec **vecp) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 38562306a36Sopenharmony_ci size_t data_bytes; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci switch (ip->i_af.if_format) { 38862306a36Sopenharmony_ci case XFS_DINODE_FMT_EXTENTS: 38962306a36Sopenharmony_ci iip->ili_fields &= 39062306a36Sopenharmony_ci ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_AEXT) && 39362306a36Sopenharmony_ci ip->i_af.if_nextents > 0 && 39462306a36Sopenharmony_ci ip->i_af.if_bytes > 0) { 39562306a36Sopenharmony_ci struct xfs_bmbt_rec *p; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ASSERT(xfs_iext_count(&ip->i_af) == 39862306a36Sopenharmony_ci ip->i_af.if_nextents); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci p = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_EXT); 40162306a36Sopenharmony_ci data_bytes = xfs_iextents_copy(ip, p, XFS_ATTR_FORK); 40262306a36Sopenharmony_ci xlog_finish_iovec(lv, *vecp, data_bytes); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci ilf->ilf_asize = data_bytes; 40562306a36Sopenharmony_ci ilf->ilf_size++; 40662306a36Sopenharmony_ci } else { 40762306a36Sopenharmony_ci iip->ili_fields &= ~XFS_ILOG_AEXT; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci case XFS_DINODE_FMT_BTREE: 41162306a36Sopenharmony_ci iip->ili_fields &= 41262306a36Sopenharmony_ci ~(XFS_ILOG_ADATA | XFS_ILOG_AEXT); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_ABROOT) && 41562306a36Sopenharmony_ci ip->i_af.if_broot_bytes > 0) { 41662306a36Sopenharmony_ci ASSERT(ip->i_af.if_broot != NULL); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_BROOT, 41962306a36Sopenharmony_ci ip->i_af.if_broot, 42062306a36Sopenharmony_ci ip->i_af.if_broot_bytes); 42162306a36Sopenharmony_ci ilf->ilf_asize = ip->i_af.if_broot_bytes; 42262306a36Sopenharmony_ci ilf->ilf_size++; 42362306a36Sopenharmony_ci } else { 42462306a36Sopenharmony_ci iip->ili_fields &= ~XFS_ILOG_ABROOT; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci case XFS_DINODE_FMT_LOCAL: 42862306a36Sopenharmony_ci iip->ili_fields &= 42962306a36Sopenharmony_ci ~(XFS_ILOG_AEXT | XFS_ILOG_ABROOT); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if ((iip->ili_fields & XFS_ILOG_ADATA) && 43262306a36Sopenharmony_ci ip->i_af.if_bytes > 0) { 43362306a36Sopenharmony_ci ASSERT(ip->i_af.if_u1.if_data != NULL); 43462306a36Sopenharmony_ci xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_LOCAL, 43562306a36Sopenharmony_ci ip->i_af.if_u1.if_data, 43662306a36Sopenharmony_ci ip->i_af.if_bytes); 43762306a36Sopenharmony_ci ilf->ilf_asize = (unsigned)ip->i_af.if_bytes; 43862306a36Sopenharmony_ci ilf->ilf_size++; 43962306a36Sopenharmony_ci } else { 44062306a36Sopenharmony_ci iip->ili_fields &= ~XFS_ILOG_ADATA; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci default: 44462306a36Sopenharmony_ci ASSERT(0); 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci/* 45062306a36Sopenharmony_ci * Convert an incore timestamp to a log timestamp. Note that the log format 45162306a36Sopenharmony_ci * specifies host endian format! 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_cistatic inline xfs_log_timestamp_t 45462306a36Sopenharmony_cixfs_inode_to_log_dinode_ts( 45562306a36Sopenharmony_ci struct xfs_inode *ip, 45662306a36Sopenharmony_ci const struct timespec64 tv) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct xfs_log_legacy_timestamp *lits; 45962306a36Sopenharmony_ci xfs_log_timestamp_t its; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (xfs_inode_has_bigtime(ip)) 46262306a36Sopenharmony_ci return xfs_inode_encode_bigtime(tv); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci lits = (struct xfs_log_legacy_timestamp *)&its; 46562306a36Sopenharmony_ci lits->t_sec = tv.tv_sec; 46662306a36Sopenharmony_ci lits->t_nsec = tv.tv_nsec; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return its; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* 47262306a36Sopenharmony_ci * The legacy DMAPI fields are only present in the on-disk and in-log inodes, 47362306a36Sopenharmony_ci * but not in the in-memory one. But we are guaranteed to have an inode buffer 47462306a36Sopenharmony_ci * in memory when logging an inode, so we can just copy it from the on-disk 47562306a36Sopenharmony_ci * inode to the in-log inode here so that recovery of file system with these 47662306a36Sopenharmony_ci * fields set to non-zero values doesn't lose them. For all other cases we zero 47762306a36Sopenharmony_ci * the fields. 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_cistatic void 48062306a36Sopenharmony_cixfs_copy_dm_fields_to_log_dinode( 48162306a36Sopenharmony_ci struct xfs_inode *ip, 48262306a36Sopenharmony_ci struct xfs_log_dinode *to) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci struct xfs_dinode *dip; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci dip = xfs_buf_offset(ip->i_itemp->ili_item.li_buf, 48762306a36Sopenharmony_ci ip->i_imap.im_boffset); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (xfs_iflags_test(ip, XFS_IPRESERVE_DM_FIELDS)) { 49062306a36Sopenharmony_ci to->di_dmevmask = be32_to_cpu(dip->di_dmevmask); 49162306a36Sopenharmony_ci to->di_dmstate = be16_to_cpu(dip->di_dmstate); 49262306a36Sopenharmony_ci } else { 49362306a36Sopenharmony_ci to->di_dmevmask = 0; 49462306a36Sopenharmony_ci to->di_dmstate = 0; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic inline void 49962306a36Sopenharmony_cixfs_inode_to_log_dinode_iext_counters( 50062306a36Sopenharmony_ci struct xfs_inode *ip, 50162306a36Sopenharmony_ci struct xfs_log_dinode *to) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci if (xfs_inode_has_large_extent_counts(ip)) { 50462306a36Sopenharmony_ci to->di_big_nextents = xfs_ifork_nextents(&ip->i_df); 50562306a36Sopenharmony_ci to->di_big_anextents = xfs_ifork_nextents(&ip->i_af); 50662306a36Sopenharmony_ci to->di_nrext64_pad = 0; 50762306a36Sopenharmony_ci } else { 50862306a36Sopenharmony_ci to->di_nextents = xfs_ifork_nextents(&ip->i_df); 50962306a36Sopenharmony_ci to->di_anextents = xfs_ifork_nextents(&ip->i_af); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic void 51462306a36Sopenharmony_cixfs_inode_to_log_dinode( 51562306a36Sopenharmony_ci struct xfs_inode *ip, 51662306a36Sopenharmony_ci struct xfs_log_dinode *to, 51762306a36Sopenharmony_ci xfs_lsn_t lsn) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci struct inode *inode = VFS_I(ip); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci to->di_magic = XFS_DINODE_MAGIC; 52262306a36Sopenharmony_ci to->di_format = xfs_ifork_format(&ip->i_df); 52362306a36Sopenharmony_ci to->di_uid = i_uid_read(inode); 52462306a36Sopenharmony_ci to->di_gid = i_gid_read(inode); 52562306a36Sopenharmony_ci to->di_projid_lo = ip->i_projid & 0xffff; 52662306a36Sopenharmony_ci to->di_projid_hi = ip->i_projid >> 16; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci memset(to->di_pad3, 0, sizeof(to->di_pad3)); 52962306a36Sopenharmony_ci to->di_atime = xfs_inode_to_log_dinode_ts(ip, inode->i_atime); 53062306a36Sopenharmony_ci to->di_mtime = xfs_inode_to_log_dinode_ts(ip, inode->i_mtime); 53162306a36Sopenharmony_ci to->di_ctime = xfs_inode_to_log_dinode_ts(ip, inode_get_ctime(inode)); 53262306a36Sopenharmony_ci to->di_nlink = inode->i_nlink; 53362306a36Sopenharmony_ci to->di_gen = inode->i_generation; 53462306a36Sopenharmony_ci to->di_mode = inode->i_mode; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci to->di_size = ip->i_disk_size; 53762306a36Sopenharmony_ci to->di_nblocks = ip->i_nblocks; 53862306a36Sopenharmony_ci to->di_extsize = ip->i_extsize; 53962306a36Sopenharmony_ci to->di_forkoff = ip->i_forkoff; 54062306a36Sopenharmony_ci to->di_aformat = xfs_ifork_format(&ip->i_af); 54162306a36Sopenharmony_ci to->di_flags = ip->i_diflags; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci xfs_copy_dm_fields_to_log_dinode(ip, to); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* log a dummy value to ensure log structure is fully initialised */ 54662306a36Sopenharmony_ci to->di_next_unlinked = NULLAGINO; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (xfs_has_v3inodes(ip->i_mount)) { 54962306a36Sopenharmony_ci to->di_version = 3; 55062306a36Sopenharmony_ci to->di_changecount = inode_peek_iversion(inode); 55162306a36Sopenharmony_ci to->di_crtime = xfs_inode_to_log_dinode_ts(ip, ip->i_crtime); 55262306a36Sopenharmony_ci to->di_flags2 = ip->i_diflags2; 55362306a36Sopenharmony_ci to->di_cowextsize = ip->i_cowextsize; 55462306a36Sopenharmony_ci to->di_ino = ip->i_ino; 55562306a36Sopenharmony_ci to->di_lsn = lsn; 55662306a36Sopenharmony_ci memset(to->di_pad2, 0, sizeof(to->di_pad2)); 55762306a36Sopenharmony_ci uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid); 55862306a36Sopenharmony_ci to->di_v3_pad = 0; 55962306a36Sopenharmony_ci } else { 56062306a36Sopenharmony_ci to->di_version = 2; 56162306a36Sopenharmony_ci to->di_flushiter = ip->i_flushiter; 56262306a36Sopenharmony_ci memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad)); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci xfs_inode_to_log_dinode_iext_counters(ip, to); 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/* 56962306a36Sopenharmony_ci * Format the inode core. Current timestamp data is only in the VFS inode 57062306a36Sopenharmony_ci * fields, so we need to grab them from there. Hence rather than just copying 57162306a36Sopenharmony_ci * the XFS inode core structure, format the fields directly into the iovec. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_cistatic void 57462306a36Sopenharmony_cixfs_inode_item_format_core( 57562306a36Sopenharmony_ci struct xfs_inode *ip, 57662306a36Sopenharmony_ci struct xfs_log_vec *lv, 57762306a36Sopenharmony_ci struct xfs_log_iovec **vecp) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct xfs_log_dinode *dic; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci dic = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_ICORE); 58262306a36Sopenharmony_ci xfs_inode_to_log_dinode(ip, dic, ip->i_itemp->ili_item.li_lsn); 58362306a36Sopenharmony_ci xlog_finish_iovec(lv, *vecp, xfs_log_dinode_size(ip->i_mount)); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci/* 58762306a36Sopenharmony_ci * This is called to fill in the vector of log iovecs for the given inode 58862306a36Sopenharmony_ci * log item. It fills the first item with an inode log format structure, 58962306a36Sopenharmony_ci * the second with the on-disk inode structure, and a possible third and/or 59062306a36Sopenharmony_ci * fourth with the inode data/extents/b-tree root and inode attributes 59162306a36Sopenharmony_ci * data/extents/b-tree root. 59262306a36Sopenharmony_ci * 59362306a36Sopenharmony_ci * Note: Always use the 64 bit inode log format structure so we don't 59462306a36Sopenharmony_ci * leave an uninitialised hole in the format item on 64 bit systems. Log 59562306a36Sopenharmony_ci * recovery on 32 bit systems handles this just fine, so there's no reason 59662306a36Sopenharmony_ci * for not using an initialising the properly padded structure all the time. 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_ciSTATIC void 59962306a36Sopenharmony_cixfs_inode_item_format( 60062306a36Sopenharmony_ci struct xfs_log_item *lip, 60162306a36Sopenharmony_ci struct xfs_log_vec *lv) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct xfs_inode_log_item *iip = INODE_ITEM(lip); 60462306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 60562306a36Sopenharmony_ci struct xfs_log_iovec *vecp = NULL; 60662306a36Sopenharmony_ci struct xfs_inode_log_format *ilf; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci ilf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_IFORMAT); 60962306a36Sopenharmony_ci ilf->ilf_type = XFS_LI_INODE; 61062306a36Sopenharmony_ci ilf->ilf_ino = ip->i_ino; 61162306a36Sopenharmony_ci ilf->ilf_blkno = ip->i_imap.im_blkno; 61262306a36Sopenharmony_ci ilf->ilf_len = ip->i_imap.im_len; 61362306a36Sopenharmony_ci ilf->ilf_boffset = ip->i_imap.im_boffset; 61462306a36Sopenharmony_ci ilf->ilf_fields = XFS_ILOG_CORE; 61562306a36Sopenharmony_ci ilf->ilf_size = 2; /* format + core */ 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* 61862306a36Sopenharmony_ci * make sure we don't leak uninitialised data into the log in the case 61962306a36Sopenharmony_ci * when we don't log every field in the inode. 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_ci ilf->ilf_dsize = 0; 62262306a36Sopenharmony_ci ilf->ilf_asize = 0; 62362306a36Sopenharmony_ci ilf->ilf_pad = 0; 62462306a36Sopenharmony_ci memset(&ilf->ilf_u, 0, sizeof(ilf->ilf_u)); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci xlog_finish_iovec(lv, vecp, sizeof(*ilf)); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci xfs_inode_item_format_core(ip, lv, &vecp); 62962306a36Sopenharmony_ci xfs_inode_item_format_data_fork(iip, ilf, lv, &vecp); 63062306a36Sopenharmony_ci if (xfs_inode_has_attr_fork(ip)) { 63162306a36Sopenharmony_ci xfs_inode_item_format_attr_fork(iip, ilf, lv, &vecp); 63262306a36Sopenharmony_ci } else { 63362306a36Sopenharmony_ci iip->ili_fields &= 63462306a36Sopenharmony_ci ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* update the format with the exact fields we actually logged */ 63862306a36Sopenharmony_ci ilf->ilf_fields |= (iip->ili_fields & ~XFS_ILOG_TIMESTAMP); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/* 64262306a36Sopenharmony_ci * This is called to pin the inode associated with the inode log 64362306a36Sopenharmony_ci * item in memory so it cannot be written out. 64462306a36Sopenharmony_ci */ 64562306a36Sopenharmony_ciSTATIC void 64662306a36Sopenharmony_cixfs_inode_item_pin( 64762306a36Sopenharmony_ci struct xfs_log_item *lip) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); 65262306a36Sopenharmony_ci ASSERT(lip->li_buf); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci trace_xfs_inode_pin(ip, _RET_IP_); 65562306a36Sopenharmony_ci atomic_inc(&ip->i_pincount); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/* 66062306a36Sopenharmony_ci * This is called to unpin the inode associated with the inode log 66162306a36Sopenharmony_ci * item which was previously pinned with a call to xfs_inode_item_pin(). 66262306a36Sopenharmony_ci * 66362306a36Sopenharmony_ci * Also wake up anyone in xfs_iunpin_wait() if the count goes to 0. 66462306a36Sopenharmony_ci * 66562306a36Sopenharmony_ci * Note that unpin can race with inode cluster buffer freeing marking the buffer 66662306a36Sopenharmony_ci * stale. In that case, flush completions are run from the buffer unpin call, 66762306a36Sopenharmony_ci * which may happen before the inode is unpinned. If we lose the race, there 66862306a36Sopenharmony_ci * will be no buffer attached to the log item, but the inode will be marked 66962306a36Sopenharmony_ci * XFS_ISTALE. 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ciSTATIC void 67262306a36Sopenharmony_cixfs_inode_item_unpin( 67362306a36Sopenharmony_ci struct xfs_log_item *lip, 67462306a36Sopenharmony_ci int remove) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci trace_xfs_inode_unpin(ip, _RET_IP_); 67962306a36Sopenharmony_ci ASSERT(lip->li_buf || xfs_iflags_test(ip, XFS_ISTALE)); 68062306a36Sopenharmony_ci ASSERT(atomic_read(&ip->i_pincount) > 0); 68162306a36Sopenharmony_ci if (atomic_dec_and_test(&ip->i_pincount)) 68262306a36Sopenharmony_ci wake_up_bit(&ip->i_flags, __XFS_IPINNED_BIT); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ciSTATIC uint 68662306a36Sopenharmony_cixfs_inode_item_push( 68762306a36Sopenharmony_ci struct xfs_log_item *lip, 68862306a36Sopenharmony_ci struct list_head *buffer_list) 68962306a36Sopenharmony_ci __releases(&lip->li_ailp->ail_lock) 69062306a36Sopenharmony_ci __acquires(&lip->li_ailp->ail_lock) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct xfs_inode_log_item *iip = INODE_ITEM(lip); 69362306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 69462306a36Sopenharmony_ci struct xfs_buf *bp = lip->li_buf; 69562306a36Sopenharmony_ci uint rval = XFS_ITEM_SUCCESS; 69662306a36Sopenharmony_ci int error; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (!bp || (ip->i_flags & XFS_ISTALE)) { 69962306a36Sopenharmony_ci /* 70062306a36Sopenharmony_ci * Inode item/buffer is being aborted due to cluster 70162306a36Sopenharmony_ci * buffer deletion. Trigger a log force to have that operation 70262306a36Sopenharmony_ci * completed and items removed from the AIL before the next push 70362306a36Sopenharmony_ci * attempt. 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci return XFS_ITEM_PINNED; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (xfs_ipincount(ip) > 0 || xfs_buf_ispinned(bp)) 70962306a36Sopenharmony_ci return XFS_ITEM_PINNED; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (xfs_iflags_test(ip, XFS_IFLUSHING)) 71262306a36Sopenharmony_ci return XFS_ITEM_FLUSHING; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (!xfs_buf_trylock(bp)) 71562306a36Sopenharmony_ci return XFS_ITEM_LOCKED; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci spin_unlock(&lip->li_ailp->ail_lock); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* 72062306a36Sopenharmony_ci * We need to hold a reference for flushing the cluster buffer as it may 72162306a36Sopenharmony_ci * fail the buffer without IO submission. In which case, we better get a 72262306a36Sopenharmony_ci * reference for that completion because otherwise we don't get a 72362306a36Sopenharmony_ci * reference for IO until we queue the buffer for delwri submission. 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_ci xfs_buf_hold(bp); 72662306a36Sopenharmony_ci error = xfs_iflush_cluster(bp); 72762306a36Sopenharmony_ci if (!error) { 72862306a36Sopenharmony_ci if (!xfs_buf_delwri_queue(bp, buffer_list)) 72962306a36Sopenharmony_ci rval = XFS_ITEM_FLUSHING; 73062306a36Sopenharmony_ci xfs_buf_relse(bp); 73162306a36Sopenharmony_ci } else { 73262306a36Sopenharmony_ci /* 73362306a36Sopenharmony_ci * Release the buffer if we were unable to flush anything. On 73462306a36Sopenharmony_ci * any other error, the buffer has already been released. 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci if (error == -EAGAIN) 73762306a36Sopenharmony_ci xfs_buf_relse(bp); 73862306a36Sopenharmony_ci rval = XFS_ITEM_LOCKED; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci spin_lock(&lip->li_ailp->ail_lock); 74262306a36Sopenharmony_ci return rval; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci/* 74662306a36Sopenharmony_ci * Unlock the inode associated with the inode log item. 74762306a36Sopenharmony_ci */ 74862306a36Sopenharmony_ciSTATIC void 74962306a36Sopenharmony_cixfs_inode_item_release( 75062306a36Sopenharmony_ci struct xfs_log_item *lip) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct xfs_inode_log_item *iip = INODE_ITEM(lip); 75362306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 75462306a36Sopenharmony_ci unsigned short lock_flags; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci ASSERT(ip->i_itemp != NULL); 75762306a36Sopenharmony_ci ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci lock_flags = iip->ili_lock_flags; 76062306a36Sopenharmony_ci iip->ili_lock_flags = 0; 76162306a36Sopenharmony_ci if (lock_flags) 76262306a36Sopenharmony_ci xfs_iunlock(ip, lock_flags); 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci/* 76662306a36Sopenharmony_ci * This is called to find out where the oldest active copy of the inode log 76762306a36Sopenharmony_ci * item in the on disk log resides now that the last log write of it completed 76862306a36Sopenharmony_ci * at the given lsn. Since we always re-log all dirty data in an inode, the 76962306a36Sopenharmony_ci * latest copy in the on disk log is the only one that matters. Therefore, 77062306a36Sopenharmony_ci * simply return the given lsn. 77162306a36Sopenharmony_ci * 77262306a36Sopenharmony_ci * If the inode has been marked stale because the cluster is being freed, we 77362306a36Sopenharmony_ci * don't want to (re-)insert this inode into the AIL. There is a race condition 77462306a36Sopenharmony_ci * where the cluster buffer may be unpinned before the inode is inserted into 77562306a36Sopenharmony_ci * the AIL during transaction committed processing. If the buffer is unpinned 77662306a36Sopenharmony_ci * before the inode item has been committed and inserted, then it is possible 77762306a36Sopenharmony_ci * for the buffer to be written and IO completes before the inode is inserted 77862306a36Sopenharmony_ci * into the AIL. In that case, we'd be inserting a clean, stale inode into the 77962306a36Sopenharmony_ci * AIL which will never get removed. It will, however, get reclaimed which 78062306a36Sopenharmony_ci * triggers an assert in xfs_inode_free() complaining about freein an inode 78162306a36Sopenharmony_ci * still in the AIL. 78262306a36Sopenharmony_ci * 78362306a36Sopenharmony_ci * To avoid this, just unpin the inode directly and return a LSN of -1 so the 78462306a36Sopenharmony_ci * transaction committed code knows that it does not need to do any further 78562306a36Sopenharmony_ci * processing on the item. 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ciSTATIC xfs_lsn_t 78862306a36Sopenharmony_cixfs_inode_item_committed( 78962306a36Sopenharmony_ci struct xfs_log_item *lip, 79062306a36Sopenharmony_ci xfs_lsn_t lsn) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci struct xfs_inode_log_item *iip = INODE_ITEM(lip); 79362306a36Sopenharmony_ci struct xfs_inode *ip = iip->ili_inode; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (xfs_iflags_test(ip, XFS_ISTALE)) { 79662306a36Sopenharmony_ci xfs_inode_item_unpin(lip, 0); 79762306a36Sopenharmony_ci return -1; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci return lsn; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ciSTATIC void 80362306a36Sopenharmony_cixfs_inode_item_committing( 80462306a36Sopenharmony_ci struct xfs_log_item *lip, 80562306a36Sopenharmony_ci xfs_csn_t seq) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci INODE_ITEM(lip)->ili_commit_seq = seq; 80862306a36Sopenharmony_ci return xfs_inode_item_release(lip); 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_inode_item_ops = { 81262306a36Sopenharmony_ci .iop_sort = xfs_inode_item_sort, 81362306a36Sopenharmony_ci .iop_precommit = xfs_inode_item_precommit, 81462306a36Sopenharmony_ci .iop_size = xfs_inode_item_size, 81562306a36Sopenharmony_ci .iop_format = xfs_inode_item_format, 81662306a36Sopenharmony_ci .iop_pin = xfs_inode_item_pin, 81762306a36Sopenharmony_ci .iop_unpin = xfs_inode_item_unpin, 81862306a36Sopenharmony_ci .iop_release = xfs_inode_item_release, 81962306a36Sopenharmony_ci .iop_committed = xfs_inode_item_committed, 82062306a36Sopenharmony_ci .iop_push = xfs_inode_item_push, 82162306a36Sopenharmony_ci .iop_committing = xfs_inode_item_committing, 82262306a36Sopenharmony_ci}; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci/* 82662306a36Sopenharmony_ci * Initialize the inode log item for a newly allocated (in-core) inode. 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_civoid 82962306a36Sopenharmony_cixfs_inode_item_init( 83062306a36Sopenharmony_ci struct xfs_inode *ip, 83162306a36Sopenharmony_ci struct xfs_mount *mp) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct xfs_inode_log_item *iip; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci ASSERT(ip->i_itemp == NULL); 83662306a36Sopenharmony_ci iip = ip->i_itemp = kmem_cache_zalloc(xfs_ili_cache, 83762306a36Sopenharmony_ci GFP_KERNEL | __GFP_NOFAIL); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci iip->ili_inode = ip; 84062306a36Sopenharmony_ci spin_lock_init(&iip->ili_lock); 84162306a36Sopenharmony_ci xfs_log_item_init(mp, &iip->ili_item, XFS_LI_INODE, 84262306a36Sopenharmony_ci &xfs_inode_item_ops); 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci/* 84662306a36Sopenharmony_ci * Free the inode log item and any memory hanging off of it. 84762306a36Sopenharmony_ci */ 84862306a36Sopenharmony_civoid 84962306a36Sopenharmony_cixfs_inode_item_destroy( 85062306a36Sopenharmony_ci struct xfs_inode *ip) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct xfs_inode_log_item *iip = ip->i_itemp; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci ASSERT(iip->ili_item.li_buf == NULL); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci ip->i_itemp = NULL; 85762306a36Sopenharmony_ci kmem_free(iip->ili_item.li_lv_shadow); 85862306a36Sopenharmony_ci kmem_cache_free(xfs_ili_cache, iip); 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci/* 86362306a36Sopenharmony_ci * We only want to pull the item from the AIL if it is actually there 86462306a36Sopenharmony_ci * and its location in the log has not changed since we started the 86562306a36Sopenharmony_ci * flush. Thus, we only bother if the inode's lsn has not changed. 86662306a36Sopenharmony_ci */ 86762306a36Sopenharmony_cistatic void 86862306a36Sopenharmony_cixfs_iflush_ail_updates( 86962306a36Sopenharmony_ci struct xfs_ail *ailp, 87062306a36Sopenharmony_ci struct list_head *list) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct xfs_log_item *lip; 87362306a36Sopenharmony_ci xfs_lsn_t tail_lsn = 0; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* this is an opencoded batch version of xfs_trans_ail_delete */ 87662306a36Sopenharmony_ci spin_lock(&ailp->ail_lock); 87762306a36Sopenharmony_ci list_for_each_entry(lip, list, li_bio_list) { 87862306a36Sopenharmony_ci xfs_lsn_t lsn; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci clear_bit(XFS_LI_FAILED, &lip->li_flags); 88162306a36Sopenharmony_ci if (INODE_ITEM(lip)->ili_flush_lsn != lip->li_lsn) 88262306a36Sopenharmony_ci continue; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* 88562306a36Sopenharmony_ci * dgc: Not sure how this happens, but it happens very 88662306a36Sopenharmony_ci * occassionaly via generic/388. xfs_iflush_abort() also 88762306a36Sopenharmony_ci * silently handles this same "under writeback but not in AIL at 88862306a36Sopenharmony_ci * shutdown" condition via xfs_trans_ail_delete(). 88962306a36Sopenharmony_ci */ 89062306a36Sopenharmony_ci if (!test_bit(XFS_LI_IN_AIL, &lip->li_flags)) { 89162306a36Sopenharmony_ci ASSERT(xlog_is_shutdown(lip->li_log)); 89262306a36Sopenharmony_ci continue; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci lsn = xfs_ail_delete_one(ailp, lip); 89662306a36Sopenharmony_ci if (!tail_lsn && lsn) 89762306a36Sopenharmony_ci tail_lsn = lsn; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci xfs_ail_update_finish(ailp, tail_lsn); 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci/* 90362306a36Sopenharmony_ci * Walk the list of inodes that have completed their IOs. If they are clean 90462306a36Sopenharmony_ci * remove them from the list and dissociate them from the buffer. Buffers that 90562306a36Sopenharmony_ci * are still dirty remain linked to the buffer and on the list. Caller must 90662306a36Sopenharmony_ci * handle them appropriately. 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_cistatic void 90962306a36Sopenharmony_cixfs_iflush_finish( 91062306a36Sopenharmony_ci struct xfs_buf *bp, 91162306a36Sopenharmony_ci struct list_head *list) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci struct xfs_log_item *lip, *n; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci list_for_each_entry_safe(lip, n, list, li_bio_list) { 91662306a36Sopenharmony_ci struct xfs_inode_log_item *iip = INODE_ITEM(lip); 91762306a36Sopenharmony_ci bool drop_buffer = false; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci spin_lock(&iip->ili_lock); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* 92262306a36Sopenharmony_ci * Remove the reference to the cluster buffer if the inode is 92362306a36Sopenharmony_ci * clean in memory and drop the buffer reference once we've 92462306a36Sopenharmony_ci * dropped the locks we hold. 92562306a36Sopenharmony_ci */ 92662306a36Sopenharmony_ci ASSERT(iip->ili_item.li_buf == bp); 92762306a36Sopenharmony_ci if (!iip->ili_fields) { 92862306a36Sopenharmony_ci iip->ili_item.li_buf = NULL; 92962306a36Sopenharmony_ci list_del_init(&lip->li_bio_list); 93062306a36Sopenharmony_ci drop_buffer = true; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci iip->ili_last_fields = 0; 93362306a36Sopenharmony_ci iip->ili_flush_lsn = 0; 93462306a36Sopenharmony_ci spin_unlock(&iip->ili_lock); 93562306a36Sopenharmony_ci xfs_iflags_clear(iip->ili_inode, XFS_IFLUSHING); 93662306a36Sopenharmony_ci if (drop_buffer) 93762306a36Sopenharmony_ci xfs_buf_rele(bp); 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci/* 94262306a36Sopenharmony_ci * Inode buffer IO completion routine. It is responsible for removing inodes 94362306a36Sopenharmony_ci * attached to the buffer from the AIL if they have not been re-logged and 94462306a36Sopenharmony_ci * completing the inode flush. 94562306a36Sopenharmony_ci */ 94662306a36Sopenharmony_civoid 94762306a36Sopenharmony_cixfs_buf_inode_iodone( 94862306a36Sopenharmony_ci struct xfs_buf *bp) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci struct xfs_log_item *lip, *n; 95162306a36Sopenharmony_ci LIST_HEAD(flushed_inodes); 95262306a36Sopenharmony_ci LIST_HEAD(ail_updates); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* 95562306a36Sopenharmony_ci * Pull the attached inodes from the buffer one at a time and take the 95662306a36Sopenharmony_ci * appropriate action on them. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_ci list_for_each_entry_safe(lip, n, &bp->b_li_list, li_bio_list) { 95962306a36Sopenharmony_ci struct xfs_inode_log_item *iip = INODE_ITEM(lip); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (xfs_iflags_test(iip->ili_inode, XFS_ISTALE)) { 96262306a36Sopenharmony_ci xfs_iflush_abort(iip->ili_inode); 96362306a36Sopenharmony_ci continue; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci if (!iip->ili_last_fields) 96662306a36Sopenharmony_ci continue; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* Do an unlocked check for needing the AIL lock. */ 96962306a36Sopenharmony_ci if (iip->ili_flush_lsn == lip->li_lsn || 97062306a36Sopenharmony_ci test_bit(XFS_LI_FAILED, &lip->li_flags)) 97162306a36Sopenharmony_ci list_move_tail(&lip->li_bio_list, &ail_updates); 97262306a36Sopenharmony_ci else 97362306a36Sopenharmony_ci list_move_tail(&lip->li_bio_list, &flushed_inodes); 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (!list_empty(&ail_updates)) { 97762306a36Sopenharmony_ci xfs_iflush_ail_updates(bp->b_mount->m_ail, &ail_updates); 97862306a36Sopenharmony_ci list_splice_tail(&ail_updates, &flushed_inodes); 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci xfs_iflush_finish(bp, &flushed_inodes); 98262306a36Sopenharmony_ci if (!list_empty(&flushed_inodes)) 98362306a36Sopenharmony_ci list_splice_tail(&flushed_inodes, &bp->b_li_list); 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_civoid 98762306a36Sopenharmony_cixfs_buf_inode_io_fail( 98862306a36Sopenharmony_ci struct xfs_buf *bp) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct xfs_log_item *lip; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci list_for_each_entry(lip, &bp->b_li_list, li_bio_list) 99362306a36Sopenharmony_ci set_bit(XFS_LI_FAILED, &lip->li_flags); 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci/* 99762306a36Sopenharmony_ci * Clear the inode logging fields so no more flushes are attempted. If we are 99862306a36Sopenharmony_ci * on a buffer list, it is now safe to remove it because the buffer is 99962306a36Sopenharmony_ci * guaranteed to be locked. The caller will drop the reference to the buffer 100062306a36Sopenharmony_ci * the log item held. 100162306a36Sopenharmony_ci */ 100262306a36Sopenharmony_cistatic void 100362306a36Sopenharmony_cixfs_iflush_abort_clean( 100462306a36Sopenharmony_ci struct xfs_inode_log_item *iip) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci iip->ili_last_fields = 0; 100762306a36Sopenharmony_ci iip->ili_fields = 0; 100862306a36Sopenharmony_ci iip->ili_fsync_fields = 0; 100962306a36Sopenharmony_ci iip->ili_flush_lsn = 0; 101062306a36Sopenharmony_ci iip->ili_item.li_buf = NULL; 101162306a36Sopenharmony_ci list_del_init(&iip->ili_item.li_bio_list); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci/* 101562306a36Sopenharmony_ci * Abort flushing the inode from a context holding the cluster buffer locked. 101662306a36Sopenharmony_ci * 101762306a36Sopenharmony_ci * This is the normal runtime method of aborting writeback of an inode that is 101862306a36Sopenharmony_ci * attached to a cluster buffer. It occurs when the inode and the backing 101962306a36Sopenharmony_ci * cluster buffer have been freed (i.e. inode is XFS_ISTALE), or when cluster 102062306a36Sopenharmony_ci * flushing or buffer IO completion encounters a log shutdown situation. 102162306a36Sopenharmony_ci * 102262306a36Sopenharmony_ci * If we need to abort inode writeback and we don't already hold the buffer 102362306a36Sopenharmony_ci * locked, call xfs_iflush_shutdown_abort() instead as this should only ever be 102462306a36Sopenharmony_ci * necessary in a shutdown situation. 102562306a36Sopenharmony_ci */ 102662306a36Sopenharmony_civoid 102762306a36Sopenharmony_cixfs_iflush_abort( 102862306a36Sopenharmony_ci struct xfs_inode *ip) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct xfs_inode_log_item *iip = ip->i_itemp; 103162306a36Sopenharmony_ci struct xfs_buf *bp; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (!iip) { 103462306a36Sopenharmony_ci /* clean inode, nothing to do */ 103562306a36Sopenharmony_ci xfs_iflags_clear(ip, XFS_IFLUSHING); 103662306a36Sopenharmony_ci return; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* 104062306a36Sopenharmony_ci * Remove the inode item from the AIL before we clear its internal 104162306a36Sopenharmony_ci * state. Whilst the inode is in the AIL, it should have a valid buffer 104262306a36Sopenharmony_ci * pointer for push operations to access - it is only safe to remove the 104362306a36Sopenharmony_ci * inode from the buffer once it has been removed from the AIL. 104462306a36Sopenharmony_ci * 104562306a36Sopenharmony_ci * We also clear the failed bit before removing the item from the AIL 104662306a36Sopenharmony_ci * as xfs_trans_ail_delete()->xfs_clear_li_failed() will release buffer 104762306a36Sopenharmony_ci * references the inode item owns and needs to hold until we've fully 104862306a36Sopenharmony_ci * aborted the inode log item and detached it from the buffer. 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_ci clear_bit(XFS_LI_FAILED, &iip->ili_item.li_flags); 105162306a36Sopenharmony_ci xfs_trans_ail_delete(&iip->ili_item, 0); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* 105462306a36Sopenharmony_ci * Grab the inode buffer so can we release the reference the inode log 105562306a36Sopenharmony_ci * item holds on it. 105662306a36Sopenharmony_ci */ 105762306a36Sopenharmony_ci spin_lock(&iip->ili_lock); 105862306a36Sopenharmony_ci bp = iip->ili_item.li_buf; 105962306a36Sopenharmony_ci xfs_iflush_abort_clean(iip); 106062306a36Sopenharmony_ci spin_unlock(&iip->ili_lock); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci xfs_iflags_clear(ip, XFS_IFLUSHING); 106362306a36Sopenharmony_ci if (bp) 106462306a36Sopenharmony_ci xfs_buf_rele(bp); 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci/* 106862306a36Sopenharmony_ci * Abort an inode flush in the case of a shutdown filesystem. This can be called 106962306a36Sopenharmony_ci * from anywhere with just an inode reference and does not require holding the 107062306a36Sopenharmony_ci * inode cluster buffer locked. If the inode is attached to a cluster buffer, 107162306a36Sopenharmony_ci * it will grab and lock it safely, then abort the inode flush. 107262306a36Sopenharmony_ci */ 107362306a36Sopenharmony_civoid 107462306a36Sopenharmony_cixfs_iflush_shutdown_abort( 107562306a36Sopenharmony_ci struct xfs_inode *ip) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci struct xfs_inode_log_item *iip = ip->i_itemp; 107862306a36Sopenharmony_ci struct xfs_buf *bp; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (!iip) { 108162306a36Sopenharmony_ci /* clean inode, nothing to do */ 108262306a36Sopenharmony_ci xfs_iflags_clear(ip, XFS_IFLUSHING); 108362306a36Sopenharmony_ci return; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci spin_lock(&iip->ili_lock); 108762306a36Sopenharmony_ci bp = iip->ili_item.li_buf; 108862306a36Sopenharmony_ci if (!bp) { 108962306a36Sopenharmony_ci spin_unlock(&iip->ili_lock); 109062306a36Sopenharmony_ci xfs_iflush_abort(ip); 109162306a36Sopenharmony_ci return; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* 109562306a36Sopenharmony_ci * We have to take a reference to the buffer so that it doesn't get 109662306a36Sopenharmony_ci * freed when we drop the ili_lock and then wait to lock the buffer. 109762306a36Sopenharmony_ci * We'll clean up the extra reference after we pick up the ili_lock 109862306a36Sopenharmony_ci * again. 109962306a36Sopenharmony_ci */ 110062306a36Sopenharmony_ci xfs_buf_hold(bp); 110162306a36Sopenharmony_ci spin_unlock(&iip->ili_lock); 110262306a36Sopenharmony_ci xfs_buf_lock(bp); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci spin_lock(&iip->ili_lock); 110562306a36Sopenharmony_ci if (!iip->ili_item.li_buf) { 110662306a36Sopenharmony_ci /* 110762306a36Sopenharmony_ci * Raced with another removal, hold the only reference 110862306a36Sopenharmony_ci * to bp now. Inode should not be in the AIL now, so just clean 110962306a36Sopenharmony_ci * up and return; 111062306a36Sopenharmony_ci */ 111162306a36Sopenharmony_ci ASSERT(list_empty(&iip->ili_item.li_bio_list)); 111262306a36Sopenharmony_ci ASSERT(!test_bit(XFS_LI_IN_AIL, &iip->ili_item.li_flags)); 111362306a36Sopenharmony_ci xfs_iflush_abort_clean(iip); 111462306a36Sopenharmony_ci spin_unlock(&iip->ili_lock); 111562306a36Sopenharmony_ci xfs_iflags_clear(ip, XFS_IFLUSHING); 111662306a36Sopenharmony_ci xfs_buf_relse(bp); 111762306a36Sopenharmony_ci return; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* 112162306a36Sopenharmony_ci * Got two references to bp. The first will get dropped by 112262306a36Sopenharmony_ci * xfs_iflush_abort() when the item is removed from the buffer list, but 112362306a36Sopenharmony_ci * we can't drop our reference until _abort() returns because we have to 112462306a36Sopenharmony_ci * unlock the buffer as well. Hence we abort and then unlock and release 112562306a36Sopenharmony_ci * our reference to the buffer. 112662306a36Sopenharmony_ci */ 112762306a36Sopenharmony_ci ASSERT(iip->ili_item.li_buf == bp); 112862306a36Sopenharmony_ci spin_unlock(&iip->ili_lock); 112962306a36Sopenharmony_ci xfs_iflush_abort(ip); 113062306a36Sopenharmony_ci xfs_buf_relse(bp); 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci/* 113562306a36Sopenharmony_ci * convert an xfs_inode_log_format struct from the old 32 bit version 113662306a36Sopenharmony_ci * (which can have different field alignments) to the native 64 bit version 113762306a36Sopenharmony_ci */ 113862306a36Sopenharmony_ciint 113962306a36Sopenharmony_cixfs_inode_item_format_convert( 114062306a36Sopenharmony_ci struct xfs_log_iovec *buf, 114162306a36Sopenharmony_ci struct xfs_inode_log_format *in_f) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct xfs_inode_log_format_32 *in_f32 = buf->i_addr; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if (buf->i_len != sizeof(*in_f32)) { 114662306a36Sopenharmony_ci XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL); 114762306a36Sopenharmony_ci return -EFSCORRUPTED; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci in_f->ilf_type = in_f32->ilf_type; 115162306a36Sopenharmony_ci in_f->ilf_size = in_f32->ilf_size; 115262306a36Sopenharmony_ci in_f->ilf_fields = in_f32->ilf_fields; 115362306a36Sopenharmony_ci in_f->ilf_asize = in_f32->ilf_asize; 115462306a36Sopenharmony_ci in_f->ilf_dsize = in_f32->ilf_dsize; 115562306a36Sopenharmony_ci in_f->ilf_ino = in_f32->ilf_ino; 115662306a36Sopenharmony_ci memcpy(&in_f->ilf_u, &in_f32->ilf_u, sizeof(in_f->ilf_u)); 115762306a36Sopenharmony_ci in_f->ilf_blkno = in_f32->ilf_blkno; 115862306a36Sopenharmony_ci in_f->ilf_len = in_f32->ilf_len; 115962306a36Sopenharmony_ci in_f->ilf_boffset = in_f32->ilf_boffset; 116062306a36Sopenharmony_ci return 0; 116162306a36Sopenharmony_ci} 1162