2018-06-06 05:42:14 +03:00
// SPDX-License-Identifier: GPL-2.0
2013-08-12 14:49:39 +04:00
/*
* Copyright ( c ) 2000 - 2005 Silicon Graphics , Inc .
* Copyright ( c ) 2013 Red Hat , Inc .
* All Rights Reserved .
*/
# include "xfs.h"
# include "xfs_fs.h"
2013-10-23 03:36:05 +04:00
# include "xfs_shared.h"
2013-10-23 03:50:10 +04:00
# include "xfs_format.h"
# include "xfs_log_format.h"
# include "xfs_trans_resv.h"
2013-08-12 14:49:39 +04:00
# include "xfs_bit.h"
# include "xfs_mount.h"
2013-10-15 02:17:51 +04:00
# include "xfs_da_format.h"
2013-08-12 14:49:39 +04:00
# include "xfs_da_btree.h"
2013-10-23 03:51:50 +04:00
# include "xfs_inode.h"
2021-04-27 01:00:33 +03:00
# include "xfs_attr.h"
2013-08-12 14:49:39 +04:00
# include "xfs_attr_remote.h"
2013-10-23 03:50:10 +04:00
# include "xfs_trans.h"
2013-08-12 14:49:39 +04:00
# include "xfs_bmap.h"
# include "xfs_attr_leaf.h"
# include "xfs_quota.h"
2013-10-29 15:11:51 +04:00
# include "xfs_dir2.h"
2019-11-02 19:40:53 +03:00
# include "xfs_error.h"
2013-08-12 14:49:39 +04:00
/*
xfs: fix memory corruption during remote attr value buffer invalidation
While running generic/103, I observed what looks like memory corruption
and (with slub debugging turned on) a slub redzone warning on i386 when
inactivating an inode with a 64k remote attr value.
On a v5 filesystem, maximally sized remote attr values require one block
more than 64k worth of space to hold both the remote attribute value
header (64 bytes). On a 4k block filesystem this results in a 68k
buffer; on a 64k block filesystem, this would be a 128k buffer. Note
that even though we'll never use more than 65,600 bytes of this buffer,
XFS_MAX_BLOCKSIZE is 64k.
This is a problem because the definition of struct xfs_buf_log_format
allows for XFS_MAX_BLOCKSIZE worth of dirty bitmap (64k). On i386 when we
invalidate a remote attribute, xfs_trans_binval zeroes all 68k worth of
the dirty map, writing right off the end of the log item and corrupting
memory. We've gotten away with this on x86_64 for years because the
compiler inserts a u32 padding on the end of struct xfs_buf_log_format.
Fortunately for us, remote attribute values are written to disk with
xfs_bwrite(), which is to say that they are not logged. Fix the problem
by removing all places where we could end up creating a buffer log item
for a remote attribute value and leave a note explaining why. Next,
replace the open-coded buffer invalidation with a call to the helper we
created in the previous patch that does better checking for bad metadata
before marking the buffer stale.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
2020-01-08 03:11:45 +03:00
* Invalidate any incore buffers associated with this remote attribute value
* extent . We never log remote attribute value buffers , which means that they
* won ' t be attached to a transaction and are therefore safe to mark stale .
* The actual bunmapi will be taken care of later .
2013-08-12 14:49:39 +04:00
*/
STATIC int
xfs: fix memory corruption during remote attr value buffer invalidation
While running generic/103, I observed what looks like memory corruption
and (with slub debugging turned on) a slub redzone warning on i386 when
inactivating an inode with a 64k remote attr value.
On a v5 filesystem, maximally sized remote attr values require one block
more than 64k worth of space to hold both the remote attribute value
header (64 bytes). On a 4k block filesystem this results in a 68k
buffer; on a 64k block filesystem, this would be a 128k buffer. Note
that even though we'll never use more than 65,600 bytes of this buffer,
XFS_MAX_BLOCKSIZE is 64k.
This is a problem because the definition of struct xfs_buf_log_format
allows for XFS_MAX_BLOCKSIZE worth of dirty bitmap (64k). On i386 when we
invalidate a remote attribute, xfs_trans_binval zeroes all 68k worth of
the dirty map, writing right off the end of the log item and corrupting
memory. We've gotten away with this on x86_64 for years because the
compiler inserts a u32 padding on the end of struct xfs_buf_log_format.
Fortunately for us, remote attribute values are written to disk with
xfs_bwrite(), which is to say that they are not logged. Fix the problem
by removing all places where we could end up creating a buffer log item
for a remote attribute value and leave a note explaining why. Next,
replace the open-coded buffer invalidation with a call to the helper we
created in the previous patch that does better checking for bad metadata
before marking the buffer stale.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
2020-01-08 03:11:45 +03:00
xfs_attr3_rmt_stale (
2013-08-12 14:49:39 +04:00
struct xfs_inode * dp ,
xfs_dablk_t blkno ,
int blkcnt )
{
struct xfs_bmbt_irec map ;
int nmap ;
int error ;
/*
* Roll through the " value " , invalidating the attribute value ' s
* blocks .
*/
2020-01-15 01:31:49 +03:00
while ( blkcnt > 0 ) {
2013-08-12 14:49:39 +04:00
/*
* Try to remember where we decided to put the value .
*/
nmap = 1 ;
2020-01-15 01:31:49 +03:00
error = xfs_bmapi_read ( dp , ( xfs_fileoff_t ) blkno , blkcnt ,
2013-08-12 14:49:39 +04:00
& map , & nmap , XFS_BMAPI_ATTRFORK ) ;
xfs: fix memory corruption during remote attr value buffer invalidation
While running generic/103, I observed what looks like memory corruption
and (with slub debugging turned on) a slub redzone warning on i386 when
inactivating an inode with a 64k remote attr value.
On a v5 filesystem, maximally sized remote attr values require one block
more than 64k worth of space to hold both the remote attribute value
header (64 bytes). On a 4k block filesystem this results in a 68k
buffer; on a 64k block filesystem, this would be a 128k buffer. Note
that even though we'll never use more than 65,600 bytes of this buffer,
XFS_MAX_BLOCKSIZE is 64k.
This is a problem because the definition of struct xfs_buf_log_format
allows for XFS_MAX_BLOCKSIZE worth of dirty bitmap (64k). On i386 when we
invalidate a remote attribute, xfs_trans_binval zeroes all 68k worth of
the dirty map, writing right off the end of the log item and corrupting
memory. We've gotten away with this on x86_64 for years because the
compiler inserts a u32 padding on the end of struct xfs_buf_log_format.
Fortunately for us, remote attribute values are written to disk with
xfs_bwrite(), which is to say that they are not logged. Fix the problem
by removing all places where we could end up creating a buffer log item
for a remote attribute value and leave a note explaining why. Next,
replace the open-coded buffer invalidation with a call to the helper we
created in the previous patch that does better checking for bad metadata
before marking the buffer stale.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
2020-01-08 03:11:45 +03:00
if ( error )
2014-06-22 09:03:54 +04:00
return error ;
xfs: fix memory corruption during remote attr value buffer invalidation
While running generic/103, I observed what looks like memory corruption
and (with slub debugging turned on) a slub redzone warning on i386 when
inactivating an inode with a 64k remote attr value.
On a v5 filesystem, maximally sized remote attr values require one block
more than 64k worth of space to hold both the remote attribute value
header (64 bytes). On a 4k block filesystem this results in a 68k
buffer; on a 64k block filesystem, this would be a 128k buffer. Note
that even though we'll never use more than 65,600 bytes of this buffer,
XFS_MAX_BLOCKSIZE is 64k.
This is a problem because the definition of struct xfs_buf_log_format
allows for XFS_MAX_BLOCKSIZE worth of dirty bitmap (64k). On i386 when we
invalidate a remote attribute, xfs_trans_binval zeroes all 68k worth of
the dirty map, writing right off the end of the log item and corrupting
memory. We've gotten away with this on x86_64 for years because the
compiler inserts a u32 padding on the end of struct xfs_buf_log_format.
Fortunately for us, remote attribute values are written to disk with
xfs_bwrite(), which is to say that they are not logged. Fix the problem
by removing all places where we could end up creating a buffer log item
for a remote attribute value and leave a note explaining why. Next,
replace the open-coded buffer invalidation with a call to the helper we
created in the previous patch that does better checking for bad metadata
before marking the buffer stale.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
2020-01-08 03:11:45 +03:00
if ( XFS_IS_CORRUPT ( dp - > i_mount , nmap ! = 1 ) )
return - EFSCORRUPTED ;
2013-08-12 14:49:39 +04:00
/*
xfs: fix memory corruption during remote attr value buffer invalidation
While running generic/103, I observed what looks like memory corruption
and (with slub debugging turned on) a slub redzone warning on i386 when
inactivating an inode with a 64k remote attr value.
On a v5 filesystem, maximally sized remote attr values require one block
more than 64k worth of space to hold both the remote attribute value
header (64 bytes). On a 4k block filesystem this results in a 68k
buffer; on a 64k block filesystem, this would be a 128k buffer. Note
that even though we'll never use more than 65,600 bytes of this buffer,
XFS_MAX_BLOCKSIZE is 64k.
This is a problem because the definition of struct xfs_buf_log_format
allows for XFS_MAX_BLOCKSIZE worth of dirty bitmap (64k). On i386 when we
invalidate a remote attribute, xfs_trans_binval zeroes all 68k worth of
the dirty map, writing right off the end of the log item and corrupting
memory. We've gotten away with this on x86_64 for years because the
compiler inserts a u32 padding on the end of struct xfs_buf_log_format.
Fortunately for us, remote attribute values are written to disk with
xfs_bwrite(), which is to say that they are not logged. Fix the problem
by removing all places where we could end up creating a buffer log item
for a remote attribute value and leave a note explaining why. Next,
replace the open-coded buffer invalidation with a call to the helper we
created in the previous patch that does better checking for bad metadata
before marking the buffer stale.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
2020-01-08 03:11:45 +03:00
* Mark any incore buffers for the remote value as stale . We
* never log remote attr value buffers , so the buffer should be
* easy to kill .
2013-08-12 14:49:39 +04:00
*/
xfs: fix memory corruption during remote attr value buffer invalidation
While running generic/103, I observed what looks like memory corruption
and (with slub debugging turned on) a slub redzone warning on i386 when
inactivating an inode with a 64k remote attr value.
On a v5 filesystem, maximally sized remote attr values require one block
more than 64k worth of space to hold both the remote attribute value
header (64 bytes). On a 4k block filesystem this results in a 68k
buffer; on a 64k block filesystem, this would be a 128k buffer. Note
that even though we'll never use more than 65,600 bytes of this buffer,
XFS_MAX_BLOCKSIZE is 64k.
This is a problem because the definition of struct xfs_buf_log_format
allows for XFS_MAX_BLOCKSIZE worth of dirty bitmap (64k). On i386 when we
invalidate a remote attribute, xfs_trans_binval zeroes all 68k worth of
the dirty map, writing right off the end of the log item and corrupting
memory. We've gotten away with this on x86_64 for years because the
compiler inserts a u32 padding on the end of struct xfs_buf_log_format.
Fortunately for us, remote attribute values are written to disk with
xfs_bwrite(), which is to say that they are not logged. Fix the problem
by removing all places where we could end up creating a buffer log item
for a remote attribute value and leave a note explaining why. Next,
replace the open-coded buffer invalidation with a call to the helper we
created in the previous patch that does better checking for bad metadata
before marking the buffer stale.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
2020-01-08 03:11:45 +03:00
error = xfs_attr_rmtval_stale ( dp , & map , 0 ) ;
if ( error )
return error ;
2013-08-12 14:49:39 +04:00
2020-01-15 01:31:49 +03:00
blkno + = map . br_blockcount ;
blkcnt - = map . br_blockcount ;
2013-08-12 14:49:39 +04:00
}
2014-06-22 09:03:54 +04:00
return 0 ;
2013-08-12 14:49:39 +04:00
}
/*
* Invalidate all of the " remote " value regions pointed to by a particular
* leaf block .
* Note that we must release the lock on the buffer so that we are not
* caught holding something that the logging code wants to flush to disk .
*/
STATIC int
xfs_attr3_leaf_inactive (
2020-01-15 01:31:49 +03:00
struct xfs_trans * * trans ,
struct xfs_inode * dp ,
struct xfs_buf * bp )
2013-08-12 14:49:39 +04:00
{
2020-01-15 01:31:49 +03:00
struct xfs_attr3_icleaf_hdr ichdr ;
struct xfs_mount * mp = bp - > b_mount ;
struct xfs_attr_leafblock * leaf = bp - > b_addr ;
struct xfs_attr_leaf_entry * entry ;
2013-08-12 14:49:39 +04:00
struct xfs_attr_leaf_name_remote * name_rmt ;
2020-01-23 18:54:09 +03:00
int error = 0 ;
2020-01-15 01:31:49 +03:00
int i ;
2013-08-12 14:49:39 +04:00
2015-04-13 04:26:02 +03:00
xfs_attr3_leaf_hdr_from_disk ( mp - > m_attr_geo , & ichdr , leaf ) ;
2013-08-12 14:49:39 +04:00
/*
2020-01-15 01:31:49 +03:00
* Find the remote value extents for this leaf and invalidate their
* incore buffers .
2013-08-12 14:49:39 +04:00
*/
entry = xfs_attr3_leaf_entryp ( leaf ) ;
for ( i = 0 ; i < ichdr . count ; entry + + , i + + ) {
2020-01-15 01:31:49 +03:00
int blkcnt ;
2013-08-12 14:49:39 +04:00
2020-01-15 01:31:49 +03:00
if ( ! entry - > nameidx | | ( entry - > flags & XFS_ATTR_LOCAL ) )
continue ;
2013-08-12 14:49:39 +04:00
2020-01-15 01:31:49 +03:00
name_rmt = xfs_attr3_leaf_name_remote ( leaf , i ) ;
if ( ! name_rmt - > valueblk )
continue ;
2013-08-12 14:49:39 +04:00
2020-01-15 01:31:49 +03:00
blkcnt = xfs_attr3_rmt_blocks ( dp - > i_mount ,
be32_to_cpu ( name_rmt - > valuelen ) ) ;
error = xfs_attr3_rmt_stale ( dp ,
be32_to_cpu ( name_rmt - > valueblk ) , blkcnt ) ;
if ( error )
goto err ;
2013-08-12 14:49:39 +04:00
}
2020-01-15 01:31:49 +03:00
xfs_trans_brelse ( * trans , bp ) ;
err :
2013-08-12 14:49:39 +04:00
return error ;
}
/*
* Recurse ( gasp ! ) through the attribute nodes until we find leaves .
* We ' re doing a depth - first traversal in order to invalidate everything .
*/
STATIC int
xfs_attr3_node_inactive (
2019-11-09 01:57:48 +03:00
struct xfs_trans * * trans ,
struct xfs_inode * dp ,
struct xfs_buf * bp ,
int level )
2013-08-12 14:49:39 +04:00
{
2019-11-20 20:46:05 +03:00
struct xfs_mount * mp = dp - > i_mount ;
2019-11-09 01:57:48 +03:00
struct xfs_da_blkinfo * info ;
xfs_dablk_t child_fsb ;
xfs_daddr_t parent_blkno , child_blkno ;
struct xfs_buf * child_bp ;
2013-08-12 14:49:39 +04:00
struct xfs_da3_icnode_hdr ichdr ;
2019-11-09 01:57:48 +03:00
int error , i ;
2013-08-12 14:49:39 +04:00
/*
* Since this code is recursive ( gasp ! ) we must protect ourselves .
*/
if ( level > XFS_DA_NODE_MAXDEPTH ) {
2020-03-11 20:37:54 +03:00
xfs_buf_mark_corrupt ( bp ) ;
2020-03-11 20:37:53 +03:00
xfs_trans_brelse ( * trans , bp ) ; /* no locks for later trans */
2019-10-29 02:12:34 +03:00
return - EFSCORRUPTED ;
2013-08-12 14:49:39 +04:00
}
2019-11-09 01:57:48 +03:00
xfs_da3_node_hdr_from_disk ( dp - > i_mount , & ichdr , bp - > b_addr ) ;
2021-08-19 04:47:05 +03:00
parent_blkno = xfs_buf_daddr ( bp ) ;
2013-08-12 14:49:39 +04:00
if ( ! ichdr . count ) {
xfs_trans_brelse ( * trans , bp ) ;
return 0 ;
}
2019-11-09 01:57:48 +03:00
child_fsb = be32_to_cpu ( ichdr . btree [ 0 ] . before ) ;
2013-08-12 14:49:39 +04:00
xfs_trans_brelse ( * trans , bp ) ; /* no locks for later trans */
/*
* If this is the node level just above the leaves , simply loop
* over the leaves removing all of them . If this is higher up
* in the tree , recurse downward .
*/
for ( i = 0 ; i < ichdr . count ; i + + ) {
/*
* Read the subsidiary block to see what we have to work with .
* Don ' t do this in a transaction . This is a depth - first
* traversal of the tree so we may deal with many blocks
* before we come back to this one .
*/
2019-11-20 20:46:04 +03:00
error = xfs_da3_node_read ( * trans , dp , child_fsb , & child_bp ,
2017-10-18 00:16:28 +03:00
XFS_ATTR_FORK ) ;
2013-08-12 14:49:39 +04:00
if ( error )
2014-06-22 09:03:54 +04:00
return error ;
2013-08-12 14:49:39 +04:00
2017-10-18 00:16:28 +03:00
/* save for re-read later */
2021-08-19 04:46:57 +03:00
child_blkno = xfs_buf_daddr ( child_bp ) ;
2013-08-12 14:49:39 +04:00
2017-10-18 00:16:28 +03:00
/*
* Invalidate the subtree , however we have to .
*/
info = child_bp - > b_addr ;
switch ( info - > magic ) {
case cpu_to_be16 ( XFS_DA_NODE_MAGIC ) :
case cpu_to_be16 ( XFS_DA3_NODE_MAGIC ) :
error = xfs_attr3_node_inactive ( trans , dp , child_bp ,
level + 1 ) ;
break ;
case cpu_to_be16 ( XFS_ATTR_LEAF_MAGIC ) :
case cpu_to_be16 ( XFS_ATTR3_LEAF_MAGIC ) :
error = xfs_attr3_leaf_inactive ( trans , dp , child_bp ) ;
break ;
default :
2020-03-11 20:37:54 +03:00
xfs_buf_mark_corrupt ( child_bp ) ;
2017-10-18 00:16:28 +03:00
xfs_trans_brelse ( * trans , child_bp ) ;
2019-11-02 19:40:53 +03:00
error = - EFSCORRUPTED ;
2017-10-18 00:16:28 +03:00
break ;
2013-08-12 14:49:39 +04:00
}
2017-10-18 00:16:28 +03:00
if ( error )
return error ;
/*
* Remove the subsidiary block from the cache and from the log .
*/
2020-01-24 04:01:18 +03:00
error = xfs_trans_get_buf ( * trans , mp - > m_ddev_targp ,
2019-11-20 20:46:05 +03:00
child_blkno ,
2020-01-24 04:01:18 +03:00
XFS_FSB_TO_BB ( mp , mp - > m_attr_geo - > fsbcount ) , 0 ,
& child_bp ) ;
if ( error )
return error ;
2019-11-20 20:46:05 +03:00
error = bp - > b_error ;
if ( error ) {
xfs_trans_brelse ( * trans , child_bp ) ;
2017-10-18 00:16:28 +03:00
return error ;
2019-11-20 20:46:05 +03:00
}
2017-10-18 00:16:28 +03:00
xfs_trans_binval ( * trans , child_bp ) ;
2013-08-12 14:49:39 +04:00
/*
* If we ' re not done , re - read the parent to get the next
* child block number .
*/
if ( i + 1 < ichdr . count ) {
2019-11-09 01:57:48 +03:00
struct xfs_da3_icnode_hdr phdr ;
2019-11-20 20:46:04 +03:00
error = xfs_da3_node_read_mapped ( * trans , dp ,
parent_blkno , & bp , XFS_ATTR_FORK ) ;
2013-08-12 14:49:39 +04:00
if ( error )
return error ;
2019-11-09 01:57:48 +03:00
xfs_da3_node_hdr_from_disk ( dp - > i_mount , & phdr ,
bp - > b_addr ) ;
child_fsb = be32_to_cpu ( phdr . btree [ i + 1 ] . before ) ;
2013-08-12 14:49:39 +04:00
xfs_trans_brelse ( * trans , bp ) ;
}
/*
* Atomically commit the whole invalidate stuff .
*/
2017-08-28 20:21:03 +03:00
error = xfs_trans_roll_inode ( trans , dp ) ;
2013-08-12 14:49:39 +04:00
if ( error )
return error ;
}
return 0 ;
}
/*
* Indiscriminately delete the entire attribute fork
*
* Recurse ( gasp ! ) through the attribute nodes until we find leaves .
* We ' re doing a depth - first traversal in order to invalidate everything .
*/
2016-06-01 10:38:15 +03:00
static int
2013-08-12 14:49:39 +04:00
xfs_attr3_root_inactive (
struct xfs_trans * * trans ,
struct xfs_inode * dp )
{
2019-11-20 20:46:05 +03:00
struct xfs_mount * mp = dp - > i_mount ;
2013-08-12 14:49:39 +04:00
struct xfs_da_blkinfo * info ;
struct xfs_buf * bp ;
xfs_daddr_t blkno ;
int error ;
/*
* Read block 0 to see what we have to work with .
* We only get here if we have extents , since we remove
* the extents in reverse order the extent containing
* block 0 must still be there .
*/
2019-11-20 20:46:04 +03:00
error = xfs_da3_node_read ( * trans , dp , 0 , & bp , XFS_ATTR_FORK ) ;
2013-08-12 14:49:39 +04:00
if ( error )
return error ;
2021-08-19 04:47:05 +03:00
blkno = xfs_buf_daddr ( bp ) ;
2013-08-12 14:49:39 +04:00
/*
* Invalidate the tree , even if the " tree " is only a single leaf block .
* This is a depth - first traversal !
*/
info = bp - > b_addr ;
switch ( info - > magic ) {
case cpu_to_be16 ( XFS_DA_NODE_MAGIC ) :
case cpu_to_be16 ( XFS_DA3_NODE_MAGIC ) :
error = xfs_attr3_node_inactive ( trans , dp , bp , 1 ) ;
break ;
case cpu_to_be16 ( XFS_ATTR_LEAF_MAGIC ) :
case cpu_to_be16 ( XFS_ATTR3_LEAF_MAGIC ) :
error = xfs_attr3_leaf_inactive ( trans , dp , bp ) ;
break ;
default :
2019-10-29 02:12:34 +03:00
error = - EFSCORRUPTED ;
2020-03-11 20:37:54 +03:00
xfs_buf_mark_corrupt ( bp ) ;
2013-08-12 14:49:39 +04:00
xfs_trans_brelse ( * trans , bp ) ;
break ;
}
if ( error )
return error ;
/*
* Invalidate the incore copy of the root block .
*/
2020-01-24 04:01:18 +03:00
error = xfs_trans_get_buf ( * trans , mp - > m_ddev_targp , blkno ,
XFS_FSB_TO_BB ( mp , mp - > m_attr_geo - > fsbcount ) , 0 , & bp ) ;
if ( error )
return error ;
2019-11-20 20:46:05 +03:00
error = bp - > b_error ;
if ( error ) {
xfs_trans_brelse ( * trans , bp ) ;
2013-08-12 14:49:39 +04:00
return error ;
2019-11-20 20:46:05 +03:00
}
2013-08-12 14:49:39 +04:00
xfs_trans_binval ( * trans , bp ) ; /* remove from cache */
/*
* Commit the invalidate and start the next transaction .
*/
2017-08-28 20:21:03 +03:00
error = xfs_trans_roll_inode ( trans , dp ) ;
2013-08-12 14:49:39 +04:00
return error ;
}
2015-05-29 00:40:08 +03:00
/*
* xfs_attr_inactive kills all traces of an attribute fork on an inode . It
* removes both the on - disk and in - memory inode fork . Note that this also has to
* handle the condition of inodes without attributes but with an attribute fork
* configured , so we can ' t use xfs_inode_hasattr ( ) here .
*
* The in - memory attribute fork is removed even on error .
*/
2013-08-12 14:49:39 +04:00
int
2015-05-29 00:40:08 +03:00
xfs_attr_inactive (
struct xfs_inode * dp )
2013-08-12 14:49:39 +04:00
{
2015-05-29 00:40:08 +03:00
struct xfs_trans * trans ;
struct xfs_mount * mp ;
int lock_mode = XFS_ILOCK_SHARED ;
int error = 0 ;
2013-08-12 14:49:39 +04:00
mp = dp - > i_mount ;
ASSERT ( ! XFS_NOT_DQATTACHED ( mp , dp ) ) ;
2015-05-29 00:40:08 +03:00
xfs_ilock ( dp , lock_mode ) ;
if ( ! XFS_IFORK_Q ( dp ) )
goto out_destroy_fork ;
xfs_iunlock ( dp , lock_mode ) ;
2013-08-12 14:49:39 +04:00
2015-05-29 00:40:08 +03:00
lock_mode = 0 ;
2016-04-06 02:19:55 +03:00
error = xfs_trans_alloc ( mp , & M_RES ( mp ) - > tr_attrinval , 0 , 0 , 0 , & trans ) ;
2015-05-29 00:40:08 +03:00
if ( error )
2016-04-06 02:19:55 +03:00
goto out_destroy_fork ;
2015-05-29 00:40:08 +03:00
lock_mode = XFS_ILOCK_EXCL ;
xfs_ilock ( dp , lock_mode ) ;
if ( ! XFS_IFORK_Q ( dp ) )
goto out_cancel ;
2013-08-12 14:49:39 +04:00
/*
* No need to make quota reservations here . We expect to release some
* blocks , not allocate , in the common case .
*/
xfs_trans_ijoin ( trans , dp , 0 ) ;
2015-06-23 01:47:20 +03:00
/*
* Invalidate and truncate the attribute fork extents . Make sure the
* fork actually has attributes as otherwise the invalidation has no
* blocks to read and returns an error . In this case , just do the fork
* removal below .
*/
if ( xfs_inode_hasattr ( dp ) & &
2020-05-18 20:28:05 +03:00
dp - > i_afp - > if_format ! = XFS_DINODE_FMT_LOCAL ) {
2015-05-29 00:40:08 +03:00
error = xfs_attr3_root_inactive ( & trans , dp ) ;
if ( error )
goto out_cancel ;
error = xfs_itruncate_extents ( & trans , dp , XFS_ATTR_FORK , 0 ) ;
if ( error )
goto out_cancel ;
2013-08-12 14:49:39 +04:00
}
2015-05-29 00:40:08 +03:00
/* Reset the attribute fork - this also destroys the in-core fork */
xfs_attr_fork_remove ( dp , trans ) ;
2013-08-12 14:49:39 +04:00
2015-06-04 06:48:08 +03:00
error = xfs_trans_commit ( trans ) ;
2015-05-29 00:40:08 +03:00
xfs_iunlock ( dp , lock_mode ) ;
2014-06-22 09:03:54 +04:00
return error ;
2013-08-12 14:49:39 +04:00
2015-05-29 00:40:08 +03:00
out_cancel :
2015-06-04 06:47:56 +03:00
xfs_trans_cancel ( trans ) ;
2015-05-29 00:40:08 +03:00
out_destroy_fork :
/* kill the in-core attr fork before we drop the inode lock */
2020-05-18 20:29:27 +03:00
if ( dp - > i_afp ) {
xfs_idestroy_fork ( dp - > i_afp ) ;
kmem_cache_free ( xfs_ifork_zone , dp - > i_afp ) ;
dp - > i_afp = NULL ;
}
2015-05-29 00:40:08 +03:00
if ( lock_mode )
xfs_iunlock ( dp , lock_mode ) ;
2014-06-22 09:03:54 +04:00
return error ;
2013-08-12 14:49:39 +04:00
}