1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2017 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_trans_resv.h"
11 #include "xfs_mount.h"
12 #include "xfs_btree.h"
14 #include "xfs_refcount.h"
15 #include "scrub/scrub.h"
16 #include "scrub/common.h"
17 #include "scrub/btree.h"
20 * Set us up to scrub reverse mapping btrees.
27 return xchk_setup_ag_btree(sc
, ip
, false);
30 /* Reverse-mapping scrubber. */
32 /* Cross-reference a rmap against the refcount btree. */
34 xchk_rmapbt_xref_refc(
36 struct xfs_rmap_irec
*irec
)
46 if (!sc
->sa
.refc_cur
|| xchk_skip_xref(sc
->sm
))
49 non_inode
= XFS_RMAP_NON_INODE_OWNER(irec
->rm_owner
);
50 is_bmbt
= irec
->rm_flags
& XFS_RMAP_BMBT_BLOCK
;
51 is_attr
= irec
->rm_flags
& XFS_RMAP_ATTR_FORK
;
52 is_unwritten
= irec
->rm_flags
& XFS_RMAP_UNWRITTEN
;
54 /* If this is shared, must be a data fork extent. */
55 error
= xfs_refcount_find_shared(sc
->sa
.refc_cur
, irec
->rm_startblock
,
56 irec
->rm_blockcount
, &fbno
, &flen
, false);
57 if (!xchk_should_check_xref(sc
, &error
, &sc
->sa
.refc_cur
))
59 if (flen
!= 0 && (non_inode
|| is_attr
|| is_bmbt
|| is_unwritten
))
60 xchk_btree_xref_set_corrupt(sc
, sc
->sa
.refc_cur
, 0);
63 /* Cross-reference with the other btrees. */
67 struct xfs_rmap_irec
*irec
)
69 xfs_agblock_t agbno
= irec
->rm_startblock
;
70 xfs_extlen_t len
= irec
->rm_blockcount
;
72 if (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
)
75 xchk_xref_is_used_space(sc
, agbno
, len
);
76 if (irec
->rm_owner
== XFS_RMAP_OWN_INODES
)
77 xchk_xref_is_inode_chunk(sc
, agbno
, len
);
79 xchk_xref_is_not_inode_chunk(sc
, agbno
, len
);
80 if (irec
->rm_owner
== XFS_RMAP_OWN_COW
)
81 xchk_xref_is_cow_staging(sc
, irec
->rm_startblock
,
84 xchk_rmapbt_xref_refc(sc
, irec
);
87 /* Scrub an rmapbt record. */
90 struct xchk_btree
*bs
,
91 union xfs_btree_rec
*rec
)
93 struct xfs_mount
*mp
= bs
->cur
->bc_mp
;
94 struct xfs_rmap_irec irec
;
95 xfs_agnumber_t agno
= bs
->cur
->bc_private
.a
.agno
;
102 error
= xfs_rmap_btrec_to_irec(rec
, &irec
);
103 if (!xchk_btree_process_error(bs
->sc
, bs
->cur
, 0, &error
))
107 if (irec
.rm_startblock
+ irec
.rm_blockcount
<= irec
.rm_startblock
)
108 xchk_btree_set_corrupt(bs
->sc
, bs
->cur
, 0);
110 if (irec
.rm_owner
== XFS_RMAP_OWN_FS
) {
112 * xfs_verify_agbno returns false for static fs metadata.
113 * Since that only exists at the start of the AG, validate
116 if (irec
.rm_startblock
!= 0 ||
117 irec
.rm_blockcount
!= XFS_AGFL_BLOCK(mp
) + 1)
118 xchk_btree_set_corrupt(bs
->sc
, bs
->cur
, 0);
121 * Otherwise we must point somewhere past the static metadata
122 * but before the end of the FS. Run the regular check.
124 if (!xfs_verify_agbno(mp
, agno
, irec
.rm_startblock
) ||
125 !xfs_verify_agbno(mp
, agno
, irec
.rm_startblock
+
126 irec
.rm_blockcount
- 1))
127 xchk_btree_set_corrupt(bs
->sc
, bs
->cur
, 0);
131 non_inode
= XFS_RMAP_NON_INODE_OWNER(irec
.rm_owner
);
132 is_bmbt
= irec
.rm_flags
& XFS_RMAP_BMBT_BLOCK
;
133 is_attr
= irec
.rm_flags
& XFS_RMAP_ATTR_FORK
;
134 is_unwritten
= irec
.rm_flags
& XFS_RMAP_UNWRITTEN
;
136 if (is_bmbt
&& irec
.rm_offset
!= 0)
137 xchk_btree_set_corrupt(bs
->sc
, bs
->cur
, 0);
139 if (non_inode
&& irec
.rm_offset
!= 0)
140 xchk_btree_set_corrupt(bs
->sc
, bs
->cur
, 0);
142 if (is_unwritten
&& (is_bmbt
|| non_inode
|| is_attr
))
143 xchk_btree_set_corrupt(bs
->sc
, bs
->cur
, 0);
145 if (non_inode
&& (is_bmbt
|| is_unwritten
|| is_attr
))
146 xchk_btree_set_corrupt(bs
->sc
, bs
->cur
, 0);
149 if (!xfs_verify_ino(mp
, irec
.rm_owner
))
150 xchk_btree_set_corrupt(bs
->sc
, bs
->cur
, 0);
152 /* Non-inode owner within the magic values? */
153 if (irec
.rm_owner
<= XFS_RMAP_OWN_MIN
||
154 irec
.rm_owner
> XFS_RMAP_OWN_FS
)
155 xchk_btree_set_corrupt(bs
->sc
, bs
->cur
, 0);
158 xchk_rmapbt_xref(bs
->sc
, &irec
);
163 /* Scrub the rmap btree for some AG. */
166 struct xfs_scrub
*sc
)
168 return xchk_btree(sc
, sc
->sa
.rmap_cur
, xchk_rmapbt_rec
,
169 &XFS_RMAP_OINFO_AG
, NULL
);
172 /* xref check that the extent is owned by a given owner */
174 xchk_xref_check_owner(
175 struct xfs_scrub
*sc
,
178 const struct xfs_owner_info
*oinfo
,
179 bool should_have_rmap
)
184 if (!sc
->sa
.rmap_cur
|| xchk_skip_xref(sc
->sm
))
187 error
= xfs_rmap_record_exists(sc
->sa
.rmap_cur
, bno
, len
, oinfo
,
189 if (!xchk_should_check_xref(sc
, &error
, &sc
->sa
.rmap_cur
))
191 if (has_rmap
!= should_have_rmap
)
192 xchk_btree_xref_set_corrupt(sc
, sc
->sa
.rmap_cur
, 0);
195 /* xref check that the extent is owned by a given owner */
197 xchk_xref_is_owned_by(
198 struct xfs_scrub
*sc
,
201 const struct xfs_owner_info
*oinfo
)
203 xchk_xref_check_owner(sc
, bno
, len
, oinfo
, true);
206 /* xref check that the extent is not owned by a given owner */
208 xchk_xref_is_not_owned_by(
209 struct xfs_scrub
*sc
,
212 const struct xfs_owner_info
*oinfo
)
214 xchk_xref_check_owner(sc
, bno
, len
, oinfo
, false);
217 /* xref check that the extent has no reverse mapping at all */
219 xchk_xref_has_no_owner(
220 struct xfs_scrub
*sc
,
227 if (!sc
->sa
.rmap_cur
|| xchk_skip_xref(sc
->sm
))
230 error
= xfs_rmap_has_record(sc
->sa
.rmap_cur
, bno
, len
, &has_rmap
);
231 if (!xchk_should_check_xref(sc
, &error
, &sc
->sa
.rmap_cur
))
234 xchk_btree_xref_set_corrupt(sc
, sc
->sa
.rmap_cur
, 0);