2023-04-11 18:59:56 -07:00
// SPDX-License-Identifier: GPL-2.0-or-later
2017-10-17 21:37:46 -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:46 -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_log_format.h"
# include "xfs_trans.h"
2023-10-16 09:21:47 -07:00
# include "xfs_rtbitmap.h"
2017-10-17 21:37:46 -07:00
# include "xfs_inode.h"
2020-07-02 08:42:12 -07:00
# include "xfs_bmap.h"
2023-12-15 10:03:41 -08:00
# include "xfs_bit.h"
2024-01-29 20:27:23 -08:00
# include "xfs_sb.h"
2017-10-17 21:37:46 -07:00
# include "scrub/scrub.h"
# include "scrub/common.h"
2023-12-15 10:03:43 -08:00
# include "scrub/repair.h"
# include "scrub/rtbitmap.h"
2023-12-15 10:03:41 -08:00
2017-10-17 21:37:46 -07:00
/* Set us up with the realtime metadata locked. */
int
2023-08-10 07:48:09 -07:00
xchk_setup_rtbitmap (
2021-04-07 17:59:39 -07:00
struct xfs_scrub * sc )
2017-10-17 21:37:46 -07:00
{
2023-12-15 10:03:41 -08:00
struct xfs_mount * mp = sc - > mp ;
struct xchk_rtbitmap * rtb ;
2018-07-19 12:29:12 -07:00
int error ;
2017-10-17 21:37:46 -07:00
2023-12-15 10:03:41 -08:00
rtb = kzalloc ( sizeof ( struct xchk_rtbitmap ) , XCHK_GFP_FLAGS ) ;
if ( ! rtb )
return - ENOMEM ;
sc - > buf = rtb ;
2023-12-15 10:03:43 -08:00
if ( xchk_could_repair ( sc ) ) {
error = xrep_setup_rtbitmap ( sc , rtb ) ;
if ( error )
return error ;
}
error = xchk_trans_alloc ( sc , rtb - > resblks ) ;
2017-10-17 21:37:46 -07:00
if ( error )
return error ;
2023-08-10 07:48:08 -07:00
error = xchk_install_live_inode ( sc , sc - > mp - > m_rbmip ) ;
if ( error )
return error ;
2023-12-15 10:03:34 -08:00
error = xchk_ino_dqattach ( sc ) ;
if ( error )
return error ;
2023-08-10 07:48:08 -07:00
xchk_ilock ( sc , XFS_ILOCK_EXCL | XFS_ILOCK_RTBITMAP ) ;
2023-12-15 10:03:41 -08:00
/*
* Now that we ' ve locked the rtbitmap , we can ' t race with growfsrt
* trying to expand the bitmap or change the size of the rt volume .
* Hence it is safe to compute and check the geometry values .
*/
if ( mp - > m_sb . sb_rblocks ) {
rtb - > rextents = xfs_rtb_to_rtx ( mp , mp - > m_sb . sb_rblocks ) ;
rtb - > rextslog = xfs_compute_rextslog ( rtb - > rextents ) ;
rtb - > rbmblocks = xfs_rtbitmap_blockcount ( mp , rtb - > rextents ) ;
}
2017-10-17 21:37:46 -07:00
return 0 ;
}
/* Realtime bitmap. */
/* Scrub a free extent record from the realtime bitmap. */
STATIC int
2018-07-19 12:29:11 -07:00
xchk_rtbitmap_rec (
2022-04-12 06:49:41 +10:00
struct xfs_mount * mp ,
2018-07-19 12:29:12 -07:00
struct xfs_trans * tp ,
2021-08-10 17:02:16 -07:00
const struct xfs_rtalloc_rec * rec ,
2018-07-19 12:29:12 -07:00
void * priv )
2017-10-17 21:37:46 -07:00
{
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc = priv ;
2018-07-19 12:29:12 -07:00
xfs_rtblock_t startblock ;
2023-10-16 09:31:22 -07:00
xfs_filblks_t blockcount ;
2017-10-17 21:37:46 -07:00
2023-10-16 09:32:54 -07:00
startblock = xfs_rtx_to_rtb ( mp , rec - > ar_startext ) ;
blockcount = xfs_rtx_to_rtb ( mp , rec - > ar_extcount ) ;
2018-05-31 09:12:10 -07:00
2023-10-16 09:31:22 -07:00
if ( ! xfs_verify_rtbext ( mp , startblock , blockcount ) )
2018-07-19 12:29:11 -07:00
xchk_fblock_set_corrupt ( sc , XFS_DATA_FORK , 0 ) ;
2017-10-17 21:37:46 -07:00
return 0 ;
}
2020-07-02 08:42:12 -07:00
/* Make sure the entire rtbitmap file is mapped with written extents. */
STATIC int
xchk_rtbitmap_check_extents (
struct xfs_scrub * sc )
{
struct xfs_bmbt_irec map ;
2023-12-15 10:03:41 -08:00
struct xfs_iext_cursor icur ;
struct xfs_mount * mp = sc - > mp ;
struct xfs_inode * ip = sc - > ip ;
xfs_fileoff_t off = 0 ;
xfs_fileoff_t endoff ;
2020-07-02 08:42:12 -07:00
int error = 0 ;
2023-12-15 10:03:41 -08:00
/* Mappings may not cross or lie beyond EOF. */
endoff = XFS_B_TO_FSB ( mp , ip - > i_disk_size ) ;
if ( xfs_iext_lookup_extent ( ip , & ip - > i_df , endoff , & icur , & map ) ) {
xchk_fblock_set_corrupt ( sc , XFS_DATA_FORK , endoff ) ;
return 0 ;
}
while ( off < endoff ) {
int nmap = 1 ;
2020-07-02 08:42:12 -07:00
if ( xchk_should_terminate ( sc , & error ) | |
( sc - > sm - > sm_flags & XFS_SCRUB_OFLAG_CORRUPT ) )
break ;
/* Make sure we have a written extent. */
2023-12-15 10:03:41 -08:00
error = xfs_bmapi_read ( ip , off , endoff - off , & map , & nmap ,
2020-07-02 08:42:12 -07:00
XFS_DATA_FORK ) ;
if ( ! xchk_fblock_process_error ( sc , XFS_DATA_FORK , off , & error ) )
break ;
if ( nmap ! = 1 | | ! xfs_bmap_is_written_extent ( & map ) ) {
xchk_fblock_set_corrupt ( sc , XFS_DATA_FORK , off ) ;
break ;
}
off + = map . br_blockcount ;
}
return error ;
}
2017-10-17 21:37:46 -07:00
/* Scrub the realtime bitmap. */
int
2018-07-19 12:29:11 -07:00
xchk_rtbitmap (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc )
2017-10-17 21:37:46 -07:00
{
2023-12-15 10:03:41 -08:00
struct xfs_mount * mp = sc - > mp ;
struct xchk_rtbitmap * rtb = sc - > buf ;
2018-07-19 12:29:12 -07:00
int error ;
2017-10-17 21:37:46 -07:00
2023-12-15 10:03:41 -08:00
/* Is sb_rextents correct? */
if ( mp - > m_sb . sb_rextents ! = rtb - > rextents ) {
xchk_ino_set_corrupt ( sc , mp - > m_rbmip - > i_ino ) ;
return 0 ;
}
/* Is sb_rextslog correct? */
if ( mp - > m_sb . sb_rextslog ! = rtb - > rextslog ) {
xchk_ino_set_corrupt ( sc , mp - > m_rbmip - > i_ino ) ;
return 0 ;
}
/*
* Is sb_rbmblocks large enough to handle the current rt volume ? In no
* case can we exceed 4 bn bitmap blocks since the super field is a u32 .
*/
if ( rtb - > rbmblocks > U32_MAX ) {
xchk_ino_set_corrupt ( sc , mp - > m_rbmip - > i_ino ) ;
return 0 ;
}
if ( mp - > m_sb . sb_rbmblocks ! = rtb - > rbmblocks ) {
xchk_ino_set_corrupt ( sc , mp - > m_rbmip - > i_ino ) ;
return 0 ;
}
/* The bitmap file length must be aligned to an fsblock. */
if ( mp - > m_rbmip - > i_disk_size & mp - > m_blockmask ) {
xchk_ino_set_corrupt ( sc , mp - > m_rbmip - > i_ino ) ;
return 0 ;
}
/*
* Is the bitmap file itself large enough to handle the rt volume ?
* growfsrt expands the bitmap file before updating sb_rextents , so the
* file can be larger than sb_rbmblocks .
*/
if ( mp - > m_rbmip - > i_disk_size < XFS_FSB_TO_B ( mp , rtb - > rbmblocks ) ) {
xchk_ino_set_corrupt ( sc , mp - > m_rbmip - > i_ino ) ;
2020-07-02 08:42:13 -07:00
return 0 ;
}
2018-05-14 06:34:33 -07:00
/* Invoke the fork scrubber. */
2018-07-19 12:29:11 -07:00
error = xchk_metadata_inode_forks ( sc ) ;
2018-05-14 06:34:33 -07:00
if ( error | | ( sc - > sm - > sm_flags & XFS_SCRUB_OFLAG_CORRUPT ) )
2020-07-02 08:42:12 -07:00
return error ;
error = xchk_rtbitmap_check_extents ( sc ) ;
if ( error | | ( sc - > sm - > sm_flags & XFS_SCRUB_OFLAG_CORRUPT ) )
2018-05-14 06:34:33 -07:00
return error ;
2023-12-15 10:03:41 -08:00
error = xfs_rtalloc_query_all ( mp , sc - > tp , xchk_rtbitmap_rec , sc ) ;
2018-07-19 12:29:11 -07:00
if ( ! xchk_fblock_process_error ( sc , XFS_DATA_FORK , 0 , & error ) )
2023-12-15 10:03:41 -08:00
return error ;
2017-10-17 21:37:46 -07:00
2023-12-15 10:03:41 -08:00
return 0 ;
2017-10-17 21:37:46 -07:00
}
2018-01-16 18:53:10 -08:00
/* xref check that the extent is not free in the rtbitmap */
void
2018-07-19 12:29:11 -07:00
xchk_xref_is_used_rt_space (
2018-07-19 12:29:12 -07:00
struct xfs_scrub * sc ,
2023-10-16 09:37:47 -07:00
xfs_rtblock_t rtbno ,
2018-07-19 12:29:12 -07:00
xfs_extlen_t len )
2018-01-16 18:53:10 -08:00
{
2023-10-16 09:32:45 -07:00
xfs_rtxnum_t startext ;
xfs_rtxnum_t endext ;
2018-07-19 12:29:12 -07:00
bool is_free ;
int error ;
2018-01-16 18:53:10 -08:00
2018-07-19 12:29:11 -07:00
if ( xchk_skip_xref ( sc - > sm ) )
2018-05-14 06:34:31 -07:00
return ;
2023-10-16 09:37:47 -07:00
startext = xfs_rtb_to_rtx ( sc - > mp , rtbno ) ;
endext = xfs_rtb_to_rtx ( sc - > mp , rtbno + len - 1 ) ;
2018-01-16 18:53:10 -08:00
xfs_ilock ( sc - > mp - > m_rbmip , XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP ) ;
2023-10-16 09:37:47 -07:00
error = xfs_rtalloc_extent_is_free ( sc - > mp , sc - > tp , startext ,
endext - startext + 1 , & is_free ) ;
2018-07-19 12:29:11 -07:00
if ( ! xchk_should_check_xref ( sc , & error , NULL ) )
2018-01-16 18:53:10 -08:00
goto out_unlock ;
if ( is_free )
2018-07-19 12:29:11 -07:00
xchk_ino_xref_set_corrupt ( sc , sc - > mp - > m_rbmip - > i_ino ) ;
2018-01-16 18:53:10 -08:00
out_unlock :
xfs_iunlock ( sc - > mp - > m_rbmip , XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP ) ;
}