162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc. 462306a36Sopenharmony_ci * Copyright (c) 2013 Red Hat, Inc. 562306a36Sopenharmony_ci * All Rights Reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include "xfs.h" 862306a36Sopenharmony_ci#include "xfs_fs.h" 962306a36Sopenharmony_ci#include "xfs_shared.h" 1062306a36Sopenharmony_ci#include "xfs_format.h" 1162306a36Sopenharmony_ci#include "xfs_log_format.h" 1262306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1362306a36Sopenharmony_ci#include "xfs_bit.h" 1462306a36Sopenharmony_ci#include "xfs_mount.h" 1562306a36Sopenharmony_ci#include "xfs_da_format.h" 1662306a36Sopenharmony_ci#include "xfs_da_btree.h" 1762306a36Sopenharmony_ci#include "xfs_inode.h" 1862306a36Sopenharmony_ci#include "xfs_attr.h" 1962306a36Sopenharmony_ci#include "xfs_attr_remote.h" 2062306a36Sopenharmony_ci#include "xfs_trans.h" 2162306a36Sopenharmony_ci#include "xfs_bmap.h" 2262306a36Sopenharmony_ci#include "xfs_attr_leaf.h" 2362306a36Sopenharmony_ci#include "xfs_quota.h" 2462306a36Sopenharmony_ci#include "xfs_dir2.h" 2562306a36Sopenharmony_ci#include "xfs_error.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Invalidate any incore buffers associated with this remote attribute value 2962306a36Sopenharmony_ci * extent. We never log remote attribute value buffers, which means that they 3062306a36Sopenharmony_ci * won't be attached to a transaction and are therefore safe to mark stale. 3162306a36Sopenharmony_ci * The actual bunmapi will be taken care of later. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ciSTATIC int 3462306a36Sopenharmony_cixfs_attr3_rmt_stale( 3562306a36Sopenharmony_ci struct xfs_inode *dp, 3662306a36Sopenharmony_ci xfs_dablk_t blkno, 3762306a36Sopenharmony_ci int blkcnt) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct xfs_bmbt_irec map; 4062306a36Sopenharmony_ci int nmap; 4162306a36Sopenharmony_ci int error; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* 4462306a36Sopenharmony_ci * Roll through the "value", invalidating the attribute value's 4562306a36Sopenharmony_ci * blocks. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci while (blkcnt > 0) { 4862306a36Sopenharmony_ci /* 4962306a36Sopenharmony_ci * Try to remember where we decided to put the value. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci nmap = 1; 5262306a36Sopenharmony_ci error = xfs_bmapi_read(dp, (xfs_fileoff_t)blkno, blkcnt, 5362306a36Sopenharmony_ci &map, &nmap, XFS_BMAPI_ATTRFORK); 5462306a36Sopenharmony_ci if (error) 5562306a36Sopenharmony_ci return error; 5662306a36Sopenharmony_ci if (XFS_IS_CORRUPT(dp->i_mount, nmap != 1)) 5762306a36Sopenharmony_ci return -EFSCORRUPTED; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* 6062306a36Sopenharmony_ci * Mark any incore buffers for the remote value as stale. We 6162306a36Sopenharmony_ci * never log remote attr value buffers, so the buffer should be 6262306a36Sopenharmony_ci * easy to kill. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci error = xfs_attr_rmtval_stale(dp, &map, 0); 6562306a36Sopenharmony_ci if (error) 6662306a36Sopenharmony_ci return error; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci blkno += map.br_blockcount; 6962306a36Sopenharmony_ci blkcnt -= map.br_blockcount; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * Invalidate all of the "remote" value regions pointed to by a particular 7762306a36Sopenharmony_ci * leaf block. 7862306a36Sopenharmony_ci * Note that we must release the lock on the buffer so that we are not 7962306a36Sopenharmony_ci * caught holding something that the logging code wants to flush to disk. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ciSTATIC int 8262306a36Sopenharmony_cixfs_attr3_leaf_inactive( 8362306a36Sopenharmony_ci struct xfs_trans **trans, 8462306a36Sopenharmony_ci struct xfs_inode *dp, 8562306a36Sopenharmony_ci struct xfs_buf *bp) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct xfs_attr3_icleaf_hdr ichdr; 8862306a36Sopenharmony_ci struct xfs_mount *mp = bp->b_mount; 8962306a36Sopenharmony_ci struct xfs_attr_leafblock *leaf = bp->b_addr; 9062306a36Sopenharmony_ci struct xfs_attr_leaf_entry *entry; 9162306a36Sopenharmony_ci struct xfs_attr_leaf_name_remote *name_rmt; 9262306a36Sopenharmony_ci int error = 0; 9362306a36Sopenharmony_ci int i; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * Find the remote value extents for this leaf and invalidate their 9962306a36Sopenharmony_ci * incore buffers. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci entry = xfs_attr3_leaf_entryp(leaf); 10262306a36Sopenharmony_ci for (i = 0; i < ichdr.count; entry++, i++) { 10362306a36Sopenharmony_ci int blkcnt; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (!entry->nameidx || (entry->flags & XFS_ATTR_LOCAL)) 10662306a36Sopenharmony_ci continue; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci name_rmt = xfs_attr3_leaf_name_remote(leaf, i); 10962306a36Sopenharmony_ci if (!name_rmt->valueblk) 11062306a36Sopenharmony_ci continue; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci blkcnt = xfs_attr3_rmt_blocks(dp->i_mount, 11362306a36Sopenharmony_ci be32_to_cpu(name_rmt->valuelen)); 11462306a36Sopenharmony_ci error = xfs_attr3_rmt_stale(dp, 11562306a36Sopenharmony_ci be32_to_cpu(name_rmt->valueblk), blkcnt); 11662306a36Sopenharmony_ci if (error) 11762306a36Sopenharmony_ci goto err; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci xfs_trans_brelse(*trans, bp); 12162306a36Sopenharmony_cierr: 12262306a36Sopenharmony_ci return error; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* 12662306a36Sopenharmony_ci * Recurse (gasp!) through the attribute nodes until we find leaves. 12762306a36Sopenharmony_ci * We're doing a depth-first traversal in order to invalidate everything. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ciSTATIC int 13062306a36Sopenharmony_cixfs_attr3_node_inactive( 13162306a36Sopenharmony_ci struct xfs_trans **trans, 13262306a36Sopenharmony_ci struct xfs_inode *dp, 13362306a36Sopenharmony_ci struct xfs_buf *bp, 13462306a36Sopenharmony_ci int level) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct xfs_mount *mp = dp->i_mount; 13762306a36Sopenharmony_ci struct xfs_da_blkinfo *info; 13862306a36Sopenharmony_ci xfs_dablk_t child_fsb; 13962306a36Sopenharmony_ci xfs_daddr_t parent_blkno, child_blkno; 14062306a36Sopenharmony_ci struct xfs_buf *child_bp; 14162306a36Sopenharmony_ci struct xfs_da3_icnode_hdr ichdr; 14262306a36Sopenharmony_ci int error, i; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* 14562306a36Sopenharmony_ci * Since this code is recursive (gasp!) we must protect ourselves. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci if (level > XFS_DA_NODE_MAXDEPTH) { 14862306a36Sopenharmony_ci xfs_buf_mark_corrupt(bp); 14962306a36Sopenharmony_ci xfs_trans_brelse(*trans, bp); /* no locks for later trans */ 15062306a36Sopenharmony_ci return -EFSCORRUPTED; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci xfs_da3_node_hdr_from_disk(dp->i_mount, &ichdr, bp->b_addr); 15462306a36Sopenharmony_ci parent_blkno = xfs_buf_daddr(bp); 15562306a36Sopenharmony_ci if (!ichdr.count) { 15662306a36Sopenharmony_ci xfs_trans_brelse(*trans, bp); 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci child_fsb = be32_to_cpu(ichdr.btree[0].before); 16062306a36Sopenharmony_ci xfs_trans_brelse(*trans, bp); /* no locks for later trans */ 16162306a36Sopenharmony_ci bp = NULL; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* 16462306a36Sopenharmony_ci * If this is the node level just above the leaves, simply loop 16562306a36Sopenharmony_ci * over the leaves removing all of them. If this is higher up 16662306a36Sopenharmony_ci * in the tree, recurse downward. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci for (i = 0; i < ichdr.count; i++) { 16962306a36Sopenharmony_ci /* 17062306a36Sopenharmony_ci * Read the subsidiary block to see what we have to work with. 17162306a36Sopenharmony_ci * Don't do this in a transaction. This is a depth-first 17262306a36Sopenharmony_ci * traversal of the tree so we may deal with many blocks 17362306a36Sopenharmony_ci * before we come back to this one. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci error = xfs_da3_node_read(*trans, dp, child_fsb, &child_bp, 17662306a36Sopenharmony_ci XFS_ATTR_FORK); 17762306a36Sopenharmony_ci if (error) 17862306a36Sopenharmony_ci return error; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* save for re-read later */ 18162306a36Sopenharmony_ci child_blkno = xfs_buf_daddr(child_bp); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * Invalidate the subtree, however we have to. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci info = child_bp->b_addr; 18762306a36Sopenharmony_ci switch (info->magic) { 18862306a36Sopenharmony_ci case cpu_to_be16(XFS_DA_NODE_MAGIC): 18962306a36Sopenharmony_ci case cpu_to_be16(XFS_DA3_NODE_MAGIC): 19062306a36Sopenharmony_ci error = xfs_attr3_node_inactive(trans, dp, child_bp, 19162306a36Sopenharmony_ci level + 1); 19262306a36Sopenharmony_ci break; 19362306a36Sopenharmony_ci case cpu_to_be16(XFS_ATTR_LEAF_MAGIC): 19462306a36Sopenharmony_ci case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): 19562306a36Sopenharmony_ci error = xfs_attr3_leaf_inactive(trans, dp, child_bp); 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci default: 19862306a36Sopenharmony_ci xfs_buf_mark_corrupt(child_bp); 19962306a36Sopenharmony_ci xfs_trans_brelse(*trans, child_bp); 20062306a36Sopenharmony_ci error = -EFSCORRUPTED; 20162306a36Sopenharmony_ci break; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci if (error) 20462306a36Sopenharmony_ci return error; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * Remove the subsidiary block from the cache and from the log. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_ci error = xfs_trans_get_buf(*trans, mp->m_ddev_targp, 21062306a36Sopenharmony_ci child_blkno, 21162306a36Sopenharmony_ci XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0, 21262306a36Sopenharmony_ci &child_bp); 21362306a36Sopenharmony_ci if (error) 21462306a36Sopenharmony_ci return error; 21562306a36Sopenharmony_ci xfs_trans_binval(*trans, child_bp); 21662306a36Sopenharmony_ci child_bp = NULL; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* 21962306a36Sopenharmony_ci * If we're not done, re-read the parent to get the next 22062306a36Sopenharmony_ci * child block number. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci if (i + 1 < ichdr.count) { 22362306a36Sopenharmony_ci struct xfs_da3_icnode_hdr phdr; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci error = xfs_da3_node_read_mapped(*trans, dp, 22662306a36Sopenharmony_ci parent_blkno, &bp, XFS_ATTR_FORK); 22762306a36Sopenharmony_ci if (error) 22862306a36Sopenharmony_ci return error; 22962306a36Sopenharmony_ci xfs_da3_node_hdr_from_disk(dp->i_mount, &phdr, 23062306a36Sopenharmony_ci bp->b_addr); 23162306a36Sopenharmony_ci child_fsb = be32_to_cpu(phdr.btree[i + 1].before); 23262306a36Sopenharmony_ci xfs_trans_brelse(*trans, bp); 23362306a36Sopenharmony_ci bp = NULL; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci /* 23662306a36Sopenharmony_ci * Atomically commit the whole invalidate stuff. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci error = xfs_trans_roll_inode(trans, dp); 23962306a36Sopenharmony_ci if (error) 24062306a36Sopenharmony_ci return error; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* 24762306a36Sopenharmony_ci * Indiscriminately delete the entire attribute fork 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * Recurse (gasp!) through the attribute nodes until we find leaves. 25062306a36Sopenharmony_ci * We're doing a depth-first traversal in order to invalidate everything. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cistatic int 25362306a36Sopenharmony_cixfs_attr3_root_inactive( 25462306a36Sopenharmony_ci struct xfs_trans **trans, 25562306a36Sopenharmony_ci struct xfs_inode *dp) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct xfs_mount *mp = dp->i_mount; 25862306a36Sopenharmony_ci struct xfs_da_blkinfo *info; 25962306a36Sopenharmony_ci struct xfs_buf *bp; 26062306a36Sopenharmony_ci xfs_daddr_t blkno; 26162306a36Sopenharmony_ci int error; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * Read block 0 to see what we have to work with. 26562306a36Sopenharmony_ci * We only get here if we have extents, since we remove 26662306a36Sopenharmony_ci * the extents in reverse order the extent containing 26762306a36Sopenharmony_ci * block 0 must still be there. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci error = xfs_da3_node_read(*trans, dp, 0, &bp, XFS_ATTR_FORK); 27062306a36Sopenharmony_ci if (error) 27162306a36Sopenharmony_ci return error; 27262306a36Sopenharmony_ci blkno = xfs_buf_daddr(bp); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* 27562306a36Sopenharmony_ci * Invalidate the tree, even if the "tree" is only a single leaf block. 27662306a36Sopenharmony_ci * This is a depth-first traversal! 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_ci info = bp->b_addr; 27962306a36Sopenharmony_ci switch (info->magic) { 28062306a36Sopenharmony_ci case cpu_to_be16(XFS_DA_NODE_MAGIC): 28162306a36Sopenharmony_ci case cpu_to_be16(XFS_DA3_NODE_MAGIC): 28262306a36Sopenharmony_ci error = xfs_attr3_node_inactive(trans, dp, bp, 1); 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci case cpu_to_be16(XFS_ATTR_LEAF_MAGIC): 28562306a36Sopenharmony_ci case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): 28662306a36Sopenharmony_ci error = xfs_attr3_leaf_inactive(trans, dp, bp); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci default: 28962306a36Sopenharmony_ci error = -EFSCORRUPTED; 29062306a36Sopenharmony_ci xfs_buf_mark_corrupt(bp); 29162306a36Sopenharmony_ci xfs_trans_brelse(*trans, bp); 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci if (error) 29562306a36Sopenharmony_ci return error; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* 29862306a36Sopenharmony_ci * Invalidate the incore copy of the root block. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci error = xfs_trans_get_buf(*trans, mp->m_ddev_targp, blkno, 30162306a36Sopenharmony_ci XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0, &bp); 30262306a36Sopenharmony_ci if (error) 30362306a36Sopenharmony_ci return error; 30462306a36Sopenharmony_ci error = bp->b_error; 30562306a36Sopenharmony_ci if (error) { 30662306a36Sopenharmony_ci xfs_trans_brelse(*trans, bp); 30762306a36Sopenharmony_ci return error; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci xfs_trans_binval(*trans, bp); /* remove from cache */ 31062306a36Sopenharmony_ci /* 31162306a36Sopenharmony_ci * Commit the invalidate and start the next transaction. 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_ci error = xfs_trans_roll_inode(trans, dp); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return error; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/* 31962306a36Sopenharmony_ci * xfs_attr_inactive kills all traces of an attribute fork on an inode. It 32062306a36Sopenharmony_ci * removes both the on-disk and in-memory inode fork. Note that this also has to 32162306a36Sopenharmony_ci * handle the condition of inodes without attributes but with an attribute fork 32262306a36Sopenharmony_ci * configured, so we can't use xfs_inode_hasattr() here. 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * The in-memory attribute fork is removed even on error. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ciint 32762306a36Sopenharmony_cixfs_attr_inactive( 32862306a36Sopenharmony_ci struct xfs_inode *dp) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct xfs_trans *trans; 33162306a36Sopenharmony_ci struct xfs_mount *mp; 33262306a36Sopenharmony_ci int lock_mode = XFS_ILOCK_SHARED; 33362306a36Sopenharmony_ci int error = 0; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci mp = dp->i_mount; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci xfs_ilock(dp, lock_mode); 33862306a36Sopenharmony_ci if (!xfs_inode_has_attr_fork(dp)) 33962306a36Sopenharmony_ci goto out_destroy_fork; 34062306a36Sopenharmony_ci xfs_iunlock(dp, lock_mode); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci lock_mode = 0; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrinval, 0, 0, 0, &trans); 34562306a36Sopenharmony_ci if (error) 34662306a36Sopenharmony_ci goto out_destroy_fork; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci lock_mode = XFS_ILOCK_EXCL; 34962306a36Sopenharmony_ci xfs_ilock(dp, lock_mode); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (!xfs_inode_has_attr_fork(dp)) 35262306a36Sopenharmony_ci goto out_cancel; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* 35562306a36Sopenharmony_ci * No need to make quota reservations here. We expect to release some 35662306a36Sopenharmony_ci * blocks, not allocate, in the common case. 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci xfs_trans_ijoin(trans, dp, 0); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* 36162306a36Sopenharmony_ci * Invalidate and truncate the attribute fork extents. Make sure the 36262306a36Sopenharmony_ci * fork actually has xattr blocks as otherwise the invalidation has no 36362306a36Sopenharmony_ci * blocks to read and returns an error. In this case, just do the fork 36462306a36Sopenharmony_ci * removal below. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci if (dp->i_af.if_nextents > 0) { 36762306a36Sopenharmony_ci error = xfs_attr3_root_inactive(&trans, dp); 36862306a36Sopenharmony_ci if (error) 36962306a36Sopenharmony_ci goto out_cancel; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0); 37262306a36Sopenharmony_ci if (error) 37362306a36Sopenharmony_ci goto out_cancel; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Reset the attribute fork - this also destroys the in-core fork */ 37762306a36Sopenharmony_ci xfs_attr_fork_remove(dp, trans); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci error = xfs_trans_commit(trans); 38062306a36Sopenharmony_ci xfs_iunlock(dp, lock_mode); 38162306a36Sopenharmony_ci return error; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ciout_cancel: 38462306a36Sopenharmony_ci xfs_trans_cancel(trans); 38562306a36Sopenharmony_ciout_destroy_fork: 38662306a36Sopenharmony_ci /* kill the in-core attr fork before we drop the inode lock */ 38762306a36Sopenharmony_ci xfs_ifork_zap_attr(dp); 38862306a36Sopenharmony_ci if (lock_mode) 38962306a36Sopenharmony_ci xfs_iunlock(dp, lock_mode); 39062306a36Sopenharmony_ci return error; 39162306a36Sopenharmony_ci} 392