2023-04-11 18:59:56 -07:00
// SPDX-License-Identifier: GPL-2.0-or-later
2017-10-17 21:37:40 -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:40 -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_alloc.h"
# include "xfs_rmap.h"
# 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:40 -07:00
/*
* Set us up to scrub free space btrees .
*/
int
2018-07-19 12:29:11 -07:00
xchk_setup_ag_allocbt (
2021-04-07 17:59:39 -07:00
struct xfs_scrub * sc )
2017-10-17 21:37:40 -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:40 -07:00
}
/* Free space btree scrubber. */
2023-04-11 19:00:26 -07:00
struct xchk_alloc {
/* Previous free space extent. */
struct xfs_alloc_rec_incore prev ;
} ;
2018-01-16 18:53:07 -08:00
/*
* Ensure there ' s a corresponding cntbt / bnobt record matching this
* bnobt / cntbt record , respectively .
*/
STATIC void
2018-07-19 12:29:11 -07:00
xchk_allocbt_xref_other (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc ,
2018-07-19 12:29:12 -07:00
xfs_agblock_t agbno ,
xfs_extlen_t len )
2018-01-16 18:53:07 -08:00
{
2018-07-19 12:29:12 -07:00
struct xfs_btree_cur * * pcur ;
xfs_agblock_t fbno ;
xfs_extlen_t flen ;
int has_otherrec ;
int error ;
2018-01-16 18:53:07 -08:00
if ( sc - > sm - > sm_type = = XFS_SCRUB_TYPE_BNOBT )
pcur = & sc - > sa . cnt_cur ;
else
pcur = & sc - > sa . bno_cur ;
2018-07-19 12:29:11 -07:00
if ( ! * pcur | | xchk_skip_xref ( sc - > sm ) )
2018-01-16 18:53:07 -08:00
return ;
error = xfs_alloc_lookup_le ( * pcur , agbno , len , & has_otherrec ) ;
2018-07-19 12:29:11 -07:00
if ( ! xchk_should_check_xref ( sc , & error , pcur ) )
2018-01-16 18:53:07 -08:00
return ;
if ( ! has_otherrec ) {
2018-07-19 12:29:11 -07:00
xchk_btree_xref_set_corrupt ( sc , * pcur , 0 ) ;
2018-01-16 18:53:07 -08:00
return ;
}
error = xfs_alloc_get_rec ( * pcur , & fbno , & flen , & has_otherrec ) ;
2018-07-19 12:29:11 -07:00
if ( ! xchk_should_check_xref ( sc , & error , pcur ) )
2018-01-16 18:53:07 -08:00
return ;
if ( ! has_otherrec ) {
2018-07-19 12:29:11 -07:00
xchk_btree_xref_set_corrupt ( sc , * pcur , 0 ) ;
2018-01-16 18:53:07 -08:00
return ;
}
if ( fbno ! = agbno | | flen ! = len )
2018-07-19 12:29:11 -07:00
xchk_btree_xref_set_corrupt ( sc , * pcur , 0 ) ;
2018-01-16 18:53:07 -08:00
}
2017-10-17 21:37:40 -07: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_allocbt_xref (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc ,
2023-04-11 19:00:01 -07:00
const struct xfs_alloc_rec_incore * irec )
2018-01-16 18:53:05 -08:00
{
2023-04-11 19:00:01 -07:00
xfs_agblock_t agbno = irec - > ar_startblock ;
xfs_extlen_t len = irec - > ar_blockcount ;
2018-01-16 18:53:05 -08:00
if ( sc - > sm - > sm_flags & XFS_SCRUB_OFLAG_CORRUPT )
return ;
2018-01-16 18:53:07 -08:00
2018-07-19 12:29:11 -07:00
xchk_allocbt_xref_other ( sc , agbno , len ) ;
xchk_xref_is_not_inode_chunk ( sc , agbno , len ) ;
xchk_xref_has_no_owner ( sc , agbno , len ) ;
xchk_xref_is_not_shared ( sc , agbno , len ) ;
2023-04-11 19:00:12 -07:00
xchk_xref_is_not_cow_staging ( sc , agbno , len ) ;
2018-01-16 18:53:05 -08:00
}
2023-04-11 19:00:26 -07:00
/* Flag failures for records that could be merged. */
STATIC void
xchk_allocbt_mergeable (
struct xchk_btree * bs ,
struct xchk_alloc * ca ,
const struct xfs_alloc_rec_incore * irec )
{
if ( bs - > sc - > sm - > sm_flags & XFS_SCRUB_OFLAG_CORRUPT )
return ;
if ( ca - > prev . ar_blockcount > 0 & &
ca - > prev . ar_startblock + ca - > prev . ar_blockcount = = irec - > ar_startblock & &
ca - > prev . ar_blockcount + irec - > ar_blockcount < ( uint32_t ) ~ 0U )
xchk_btree_set_corrupt ( bs - > sc , bs - > cur , 0 ) ;
memcpy ( & ca - > prev , irec , sizeof ( * irec ) ) ;
}
2017-10-17 21:37:40 -07:00
/* Scrub a bnobt/cntbt record. */
STATIC int
2018-07-19 12:29:11 -07:00
xchk_allocbt_rec (
2023-04-11 19:00:01 -07:00
struct xchk_btree * bs ,
const union xfs_btree_rec * rec )
2017-10-17 21:37:40 -07:00
{
2023-04-11 19:00:01 -07:00
struct xfs_alloc_rec_incore irec ;
2023-04-11 19:00:26 -07:00
struct xchk_alloc * ca = bs - > private ;
2017-10-17 21:37:40 -07:00
2023-04-11 19:00:01 -07:00
xfs_alloc_btrec_to_irec ( rec , & irec ) ;
if ( xfs_alloc_check_irec ( bs - > cur , & irec ) ! = NULL ) {
2018-07-19 12:29:11 -07:00
xchk_btree_set_corrupt ( bs - > sc , bs - > cur , 0 ) ;
2023-04-11 19:00:01 -07:00
return 0 ;
}
2017-10-17 21:37:40 -07:00
2023-04-11 19:00:26 -07:00
xchk_allocbt_mergeable ( bs , ca , & irec ) ;
2023-04-11 19:00:01 -07:00
xchk_allocbt_xref ( bs - > sc , & irec ) ;
2018-01-16 18:53:05 -08:00
2019-09-23 13:00:56 -07:00
return 0 ;
2017-10-17 21:37:40 -07:00
}
/* Scrub the freespace btrees for some AG. */
STATIC int
2018-07-19 12:29:11 -07:00
xchk_allocbt (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc ,
2018-07-19 12:29:12 -07:00
xfs_btnum_t which )
2017-10-17 21:37:40 -07:00
{
2023-04-11 19:00:26 -07:00
struct xchk_alloc ca = { } ;
2018-07-19 12:29:12 -07:00
struct xfs_btree_cur * cur ;
2017-10-17 21:37:40 -07:00
cur = which = = XFS_BTNUM_BNO ? sc - > sa . bno_cur : sc - > sa . cnt_cur ;
2023-04-11 19:00:26 -07:00
return xchk_btree ( sc , cur , xchk_allocbt_rec , & XFS_RMAP_OINFO_AG , & ca ) ;
2017-10-17 21:37:40 -07:00
}
int
2018-07-19 12:29:11 -07:00
xchk_bnobt (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc )
2017-10-17 21:37:40 -07:00
{
2018-07-19 12:29:11 -07:00
return xchk_allocbt ( sc , XFS_BTNUM_BNO ) ;
2017-10-17 21:37:40 -07:00
}
int
2018-07-19 12:29:11 -07:00
xchk_cntbt (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc )
2017-10-17 21:37:40 -07:00
{
2018-07-19 12:29:11 -07:00
return xchk_allocbt ( sc , XFS_BTNUM_CNT ) ;
2017-10-17 21:37:40 -07:00
}
2018-01-16 18:53:06 -08:00
/* xref check that the extent is not free */
void
2018-07-19 12:29:11 -07:00
xchk_xref_is_used_space (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc ,
2018-07-19 12:29:12 -07:00
xfs_agblock_t agbno ,
xfs_extlen_t len )
2018-01-16 18:53:06 -08:00
{
2023-04-11 19:00:10 -07:00
enum xbtree_recpacking outcome ;
2018-07-19 12:29:12 -07:00
int error ;
2018-01-16 18:53:06 -08:00
2018-07-19 12:29:11 -07:00
if ( ! sc - > sa . bno_cur | | xchk_skip_xref ( sc - > sm ) )
2018-01-16 18:53:06 -08:00
return ;
2023-04-11 19:00:10 -07:00
error = xfs_alloc_has_records ( sc - > sa . bno_cur , agbno , len , & outcome ) ;
2018-07-19 12:29:11 -07:00
if ( ! xchk_should_check_xref ( sc , & error , & sc - > sa . bno_cur ) )
2018-01-16 18:53:06 -08:00
return ;
2023-04-11 19:00:10 -07:00
if ( outcome ! = XBTREE_RECPACKING_EMPTY )
2018-07-19 12:29:11 -07:00
xchk_btree_xref_set_corrupt ( sc , sc - > sa . bno_cur , 0 ) ;
2018-01-16 18:53:06 -08:00
}