Skip to content

Commit c0d5a92

Browse files
author
Darrick J. Wong
committed
xfs: split xchk_bmap_xref_rmap into two functions
There's more special-cased functionality than not in this function. Split it into two so that each can be far more cohesive. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 634d4a7 commit c0d5a92

1 file changed

Lines changed: 76 additions & 40 deletions

File tree

fs/xfs/scrub/bmap.c

Lines changed: 76 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ xchk_bmap_get_rmap(
165165
return has_rmap;
166166
}
167167

168-
/* Make sure that we have rmapbt records for this extent. */
168+
/* Make sure that we have rmapbt records for this data/attr fork extent. */
169169
STATIC void
170170
xchk_bmap_xref_rmap(
171171
struct xchk_bmap_info *info,
@@ -174,41 +174,39 @@ xchk_bmap_xref_rmap(
174174
{
175175
struct xfs_rmap_irec rmap;
176176
unsigned long long rmap_end;
177-
uint64_t owner;
177+
uint64_t owner = info->sc->ip->i_ino;
178178

179179
if (!info->sc->sa.rmap_cur || xchk_skip_xref(info->sc->sm))
180180
return;
181181

182-
if (info->whichfork == XFS_COW_FORK)
183-
owner = XFS_RMAP_OWN_COW;
184-
else
185-
owner = info->sc->ip->i_ino;
186-
187182
/* Find the rmap record for this irec. */
188183
if (!xchk_bmap_get_rmap(info, irec, agbno, owner, &rmap))
189184
return;
190185

191-
/* Check the rmap. */
186+
/*
187+
* The rmap must be an exact match for this incore file mapping record,
188+
* which may have arisen from multiple ondisk records.
189+
*/
190+
if (rmap.rm_startblock != agbno)
191+
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
192+
irec->br_startoff);
193+
192194
rmap_end = (unsigned long long)rmap.rm_startblock + rmap.rm_blockcount;
193-
if (rmap.rm_startblock > agbno ||
194-
agbno + irec->br_blockcount > rmap_end)
195+
if (rmap_end != agbno + irec->br_blockcount)
195196
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
196197
irec->br_startoff);
197198

198-
/*
199-
* Check the logical offsets if applicable. CoW staging extents
200-
* don't track logical offsets since the mappings only exist in
201-
* memory.
202-
*/
203-
if (info->whichfork != XFS_COW_FORK) {
204-
rmap_end = (unsigned long long)rmap.rm_offset +
205-
rmap.rm_blockcount;
206-
if (rmap.rm_offset > irec->br_startoff ||
207-
irec->br_startoff + irec->br_blockcount > rmap_end)
208-
xchk_fblock_xref_set_corrupt(info->sc,
209-
info->whichfork, irec->br_startoff);
210-
}
199+
/* Check the logical offsets. */
200+
if (rmap.rm_offset != irec->br_startoff)
201+
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
202+
irec->br_startoff);
203+
204+
rmap_end = (unsigned long long)rmap.rm_offset + rmap.rm_blockcount;
205+
if (rmap_end != irec->br_startoff + irec->br_blockcount)
206+
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
207+
irec->br_startoff);
211208

209+
/* Check the owner */
212210
if (rmap.rm_owner != owner)
213211
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
214212
irec->br_startoff);
@@ -220,8 +218,7 @@ xchk_bmap_xref_rmap(
220218
* records because the blocks are owned (on-disk) by the refcountbt,
221219
* which doesn't track unwritten state.
222220
*/
223-
if (owner != XFS_RMAP_OWN_COW &&
224-
!!(irec->br_state == XFS_EXT_UNWRITTEN) !=
221+
if (!!(irec->br_state == XFS_EXT_UNWRITTEN) !=
225222
!!(rmap.rm_flags & XFS_RMAP_UNWRITTEN))
226223
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
227224
irec->br_startoff);
@@ -233,23 +230,60 @@ xchk_bmap_xref_rmap(
233230
if (rmap.rm_flags & XFS_RMAP_BMBT_BLOCK)
234231
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
235232
irec->br_startoff);
233+
}
234+
235+
/* Make sure that we have rmapbt records for this COW fork extent. */
236+
STATIC void
237+
xchk_bmap_xref_rmap_cow(
238+
struct xchk_bmap_info *info,
239+
struct xfs_bmbt_irec *irec,
240+
xfs_agblock_t agbno)
241+
{
242+
struct xfs_rmap_irec rmap;
243+
unsigned long long rmap_end;
244+
uint64_t owner = XFS_RMAP_OWN_COW;
245+
246+
if (!info->sc->sa.rmap_cur || xchk_skip_xref(info->sc->sm))
247+
return;
248+
249+
/* Find the rmap record for this irec. */
250+
if (!xchk_bmap_get_rmap(info, irec, agbno, owner, &rmap))
251+
return;
236252

237253
/*
238-
* The rmap must correspond exactly with this bmbt record. Skip this
239-
* for CoW fork extents because the refcount btree (and not the inode)
240-
* is the ondisk owner for those extents.
254+
* CoW staging extents are owned by the refcount btree, so the rmap
255+
* can start before and end after the physical space allocated to this
256+
* mapping. There are no offsets to check.
241257
*/
242-
if (info->whichfork != XFS_COW_FORK) {
243-
if (rmap.rm_startblock != agbno)
244-
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
245-
irec->br_startoff);
246-
247-
rmap_end = (unsigned long long)rmap.rm_startblock +
248-
rmap.rm_blockcount;
249-
if (rmap_end != agbno + irec->br_blockcount)
250-
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
251-
irec->br_startoff);
252-
}
258+
if (rmap.rm_startblock > agbno)
259+
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
260+
irec->br_startoff);
261+
262+
rmap_end = (unsigned long long)rmap.rm_startblock + rmap.rm_blockcount;
263+
if (rmap_end < agbno + irec->br_blockcount)
264+
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
265+
irec->br_startoff);
266+
267+
/* Check the owner */
268+
if (rmap.rm_owner != owner)
269+
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
270+
irec->br_startoff);
271+
272+
/*
273+
* No flags allowed. Note that the (in-memory) CoW fork distinguishes
274+
* between unwritten and written extents, but we don't track that in
275+
* the rmap records because the blocks are owned (on-disk) by the
276+
* refcountbt, which doesn't track unwritten state.
277+
*/
278+
if (rmap.rm_flags & XFS_RMAP_ATTR_FORK)
279+
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
280+
irec->br_startoff);
281+
if (rmap.rm_flags & XFS_RMAP_BMBT_BLOCK)
282+
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
283+
irec->br_startoff);
284+
if (rmap.rm_flags & XFS_RMAP_UNWRITTEN)
285+
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
286+
irec->br_startoff);
253287
}
254288

255289
/* Cross-reference a single rtdev extent record. */
@@ -288,9 +322,9 @@ xchk_bmap_iextent_xref(
288322

289323
xchk_xref_is_used_space(info->sc, agbno, len);
290324
xchk_xref_is_not_inode_chunk(info->sc, agbno, len);
291-
xchk_bmap_xref_rmap(info, irec, agbno);
292325
switch (info->whichfork) {
293326
case XFS_DATA_FORK:
327+
xchk_bmap_xref_rmap(info, irec, agbno);
294328
if (!xfs_is_reflink_inode(info->sc->ip)) {
295329
xfs_rmap_ino_owner(&oinfo, info->sc->ip->i_ino,
296330
info->whichfork, irec->br_startoff);
@@ -303,6 +337,7 @@ xchk_bmap_iextent_xref(
303337
irec->br_blockcount);
304338
break;
305339
case XFS_ATTR_FORK:
340+
xchk_bmap_xref_rmap(info, irec, agbno);
306341
xfs_rmap_ino_owner(&oinfo, info->sc->ip->i_ino,
307342
info->whichfork, irec->br_startoff);
308343
xchk_xref_is_only_owned_by(info->sc, agbno, irec->br_blockcount,
@@ -313,6 +348,7 @@ xchk_bmap_iextent_xref(
313348
irec->br_blockcount);
314349
break;
315350
case XFS_COW_FORK:
351+
xchk_bmap_xref_rmap_cow(info, irec, agbno);
316352
xchk_xref_is_only_owned_by(info->sc, agbno, irec->br_blockcount,
317353
&XFS_RMAP_OINFO_COW);
318354
xchk_xref_is_cow_staging(info->sc, agbno,

0 commit comments

Comments
 (0)