2023-04-11 18:59:56 -07:00
// SPDX-License-Identifier: GPL-2.0-or-later
2017-10-17 21:37:41 -07:00
/*
2023-04-11 18:59:57 -07:00
* Copyright ( C ) 2017 - 2023 Oracle . All Rights Reserved .
2023-04-11 18:59:56 -07:00
* Author : Darrick J . Wong < djwong @ kernel . org >
2017-10-17 21:37:41 -07:00
*/
# include "xfs.h"
# include "xfs_fs.h"
# include "xfs_shared.h"
# include "xfs_format.h"
# include "xfs_trans_resv.h"
# include "xfs_mount.h"
# include "xfs_btree.h"
# include "xfs_rmap.h"
2018-01-16 18:53:09 -08:00
# include "xfs_refcount.h"
2017-10-17 21:37:41 -07:00
# include "scrub/scrub.h"
# include "scrub/common.h"
# include "scrub/btree.h"
2021-06-02 10:48:24 +10:00
# include "xfs_ag.h"
2017-10-17 21:37:41 -07:00
/*
* Set us up to scrub reverse mapping btrees .
*/
int
2018-07-19 12:29:11 -07:00
xchk_setup_ag_rmapbt (
2021-04-07 17:59:39 -07:00
struct xfs_scrub * sc )
2017-10-17 21:37:41 -07:00
{
2023-04-11 18:59:59 -07:00
if ( xchk_need_intent_drain ( sc ) )
xchk_fsgates_enable ( sc , XCHK_FSGATES_DRAIN ) ;
2021-04-07 17:59:39 -07:00
return xchk_setup_ag_btree ( sc , false ) ;
2017-10-17 21:37:41 -07:00
}
/* Reverse-mapping scrubber. */
2018-01-16 18:53:09 -08:00
/* Cross-reference a rmap against the refcount btree. */
STATIC void
2018-07-19 12:29:11 -07:00
xchk_rmapbt_xref_refc (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc ,
2018-07-19 12:29:12 -07:00
struct xfs_rmap_irec * irec )
2018-01-16 18:53:09 -08:00
{
2018-07-19 12:29:12 -07:00
xfs_agblock_t fbno ;
xfs_extlen_t flen ;
bool non_inode ;
bool is_bmbt ;
bool is_attr ;
bool is_unwritten ;
int error ;
2018-01-16 18:53:09 -08:00
2018-07-19 12:29:11 -07:00
if ( ! sc - > sa . refc_cur | | xchk_skip_xref ( sc - > sm ) )
2018-01-16 18:53:09 -08:00
return ;
non_inode = XFS_RMAP_NON_INODE_OWNER ( irec - > rm_owner ) ;
is_bmbt = irec - > rm_flags & XFS_RMAP_BMBT_BLOCK ;
is_attr = irec - > rm_flags & XFS_RMAP_ATTR_FORK ;
is_unwritten = irec - > rm_flags & XFS_RMAP_UNWRITTEN ;
/* If this is shared, must be a data fork extent. */
error = xfs_refcount_find_shared ( sc - > sa . refc_cur , irec - > rm_startblock ,
irec - > rm_blockcount , & fbno , & flen , false ) ;
2018-07-19 12:29:11 -07:00
if ( ! xchk_should_check_xref ( sc , & error , & sc - > sa . refc_cur ) )
2018-01-16 18:53:09 -08:00
return ;
if ( flen ! = 0 & & ( non_inode | | is_attr | | is_bmbt | | is_unwritten ) )
2018-07-19 12:29:11 -07:00
xchk_btree_xref_set_corrupt ( sc , sc - > sa . refc_cur , 0 ) ;
2018-01-16 18:53:09 -08:00
}
2018-01-16 18:53:05 -08:00
/* Cross-reference with the other btrees. */
STATIC void
2018-07-19 12:29:11 -07:00
xchk_rmapbt_xref (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc ,
2018-07-19 12:29:12 -07:00
struct xfs_rmap_irec * irec )
2018-01-16 18:53:05 -08:00
{
2018-07-19 12:29:12 -07:00
xfs_agblock_t agbno = irec - > rm_startblock ;
xfs_extlen_t len = irec - > rm_blockcount ;
2018-01-16 18:53:06 -08:00
2018-01-16 18:53:05 -08:00
if ( sc - > sm - > sm_flags & XFS_SCRUB_OFLAG_CORRUPT )
return ;
2018-01-16 18:53:06 -08:00
2018-07-19 12:29:11 -07:00
xchk_xref_is_used_space ( sc , agbno , len ) ;
2018-01-16 18:53:07 -08:00
if ( irec - > rm_owner = = XFS_RMAP_OWN_INODES )
2018-07-19 12:29:11 -07:00
xchk_xref_is_inode_chunk ( sc , agbno , len ) ;
2018-01-16 18:53:07 -08:00
else
2018-07-19 12:29:11 -07:00
xchk_xref_is_not_inode_chunk ( sc , agbno , len ) ;
2018-01-16 18:53:09 -08:00
if ( irec - > rm_owner = = XFS_RMAP_OWN_COW )
2018-07-19 12:29:11 -07:00
xchk_xref_is_cow_staging ( sc , irec - > rm_startblock ,
2018-01-16 18:53:09 -08:00
irec - > rm_blockcount ) ;
else
2018-07-19 12:29:11 -07:00
xchk_rmapbt_xref_refc ( sc , irec ) ;
2018-01-16 18:53:05 -08:00
}
2017-10-17 21:37:41 -07:00
/* Scrub an rmapbt record. */
STATIC int
2018-07-19 12:29:11 -07:00
xchk_rmapbt_rec (
2018-07-19 12:29:12 -07:00
struct xchk_btree * bs ,
2021-08-10 17:02:17 -07:00
const union xfs_btree_rec * rec )
2017-10-17 21:37:41 -07:00
{
2018-07-19 12:29:12 -07:00
struct xfs_rmap_irec irec ;
2017-10-17 21:37:41 -07:00
2023-04-11 19:00:03 -07:00
if ( xfs_rmap_btrec_to_irec ( rec , & irec ) ! = NULL | |
xfs_rmap_check_irec ( bs - > cur , & irec ) ! = NULL ) {
2023-04-11 19:00:02 -07:00
xchk_btree_set_corrupt ( bs - > sc , bs - > cur , 0 ) ;
return 0 ;
}
2017-10-17 21:37:41 -07:00
2018-07-19 12:29:11 -07:00
xchk_rmapbt_xref ( bs - > sc , & irec ) ;
2023-04-11 19:00:02 -07:00
return 0 ;
2017-10-17 21:37:41 -07:00
}
/* Scrub the rmap btree for some AG. */
int
2018-07-19 12:29:11 -07:00
xchk_rmapbt (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc )
2017-10-17 21:37:41 -07:00
{
2018-07-19 12:29:11 -07:00
return xchk_btree ( sc , sc - > sa . rmap_cur , xchk_rmapbt_rec ,
2018-12-12 08:46:23 -08:00
& XFS_RMAP_OINFO_AG , NULL ) ;
2017-10-17 21:37:41 -07:00
}
2018-01-16 18:53:08 -08:00
/* xref check that the extent is owned by a given owner */
static inline void
2018-07-19 12:29:11 -07:00
xchk_xref_check_owner (
2018-12-12 08:46:23 -08:00
struct xfs_scrub * sc ,
xfs_agblock_t bno ,
xfs_extlen_t len ,
const struct xfs_owner_info * oinfo ,
bool should_have_rmap )
2018-01-16 18:53:08 -08:00
{
2018-12-12 08:46:23 -08:00
bool has_rmap ;
int error ;
2018-01-16 18:53:08 -08:00
2018-07-19 12:29:11 -07:00
if ( ! sc - > sa . rmap_cur | | xchk_skip_xref ( sc - > sm ) )
2018-01-16 18:53:08 -08:00
return ;
error = xfs_rmap_record_exists ( sc - > sa . rmap_cur , bno , len , oinfo ,
& has_rmap ) ;
2018-07-19 12:29:11 -07:00
if ( ! xchk_should_check_xref ( sc , & error , & sc - > sa . rmap_cur ) )
2018-01-16 18:53:08 -08:00
return ;
if ( has_rmap ! = should_have_rmap )
2018-07-19 12:29:11 -07:00
xchk_btree_xref_set_corrupt ( sc , sc - > sa . rmap_cur , 0 ) ;
2018-01-16 18:53:08 -08:00
}
/* xref check that the extent is owned by a given owner */
void
2018-07-19 12:29:11 -07:00
xchk_xref_is_owned_by (
2018-12-12 08:46:23 -08:00
struct xfs_scrub * sc ,
xfs_agblock_t bno ,
xfs_extlen_t len ,
const struct xfs_owner_info * oinfo )
2018-01-16 18:53:08 -08:00
{
2018-07-19 12:29:11 -07:00
xchk_xref_check_owner ( sc , bno , len , oinfo , true ) ;
2018-01-16 18:53:08 -08:00
}
/* xref check that the extent is not owned by a given owner */
void
2018-07-19 12:29:11 -07:00
xchk_xref_is_not_owned_by (
2018-12-12 08:46:23 -08:00
struct xfs_scrub * sc ,
xfs_agblock_t bno ,
xfs_extlen_t len ,
const struct xfs_owner_info * oinfo )
2018-01-16 18:53:08 -08:00
{
2018-07-19 12:29:11 -07:00
xchk_xref_check_owner ( sc , bno , len , oinfo , false ) ;
2018-01-16 18:53:08 -08:00
}
/* xref check that the extent has no reverse mapping at all */
void
2018-07-19 12:29:11 -07:00
xchk_xref_has_no_owner (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc ,
2018-07-19 12:29:12 -07:00
xfs_agblock_t bno ,
xfs_extlen_t len )
2018-01-16 18:53:08 -08:00
{
2018-07-19 12:29:12 -07:00
bool has_rmap ;
int error ;
2018-01-16 18:53:08 -08:00
2018-07-19 12:29:11 -07:00
if ( ! sc - > sa . rmap_cur | | xchk_skip_xref ( sc - > sm ) )
2018-01-16 18:53:08 -08:00
return ;
error = xfs_rmap_has_record ( sc - > sa . rmap_cur , bno , len , & has_rmap ) ;
2018-07-19 12:29:11 -07:00
if ( ! xchk_should_check_xref ( sc , & error , & sc - > sa . rmap_cur ) )
2018-01-16 18:53:08 -08:00
return ;
if ( has_rmap )
2018-07-19 12:29:11 -07:00
xchk_btree_xref_set_corrupt ( sc , sc - > sa . rmap_cur , 0 ) ;
2018-01-16 18:53:08 -08:00
}