Skip to content

Commit a6a76ad

Browse files
behlendorfandrewc12
authored andcommitted
Verify BPs in spa_load_verify_cb() and dsl_scan_visitbp()
We want `zpool import` to be highly robust and never panic, even when encountering corrupt metadata. This is already handled in the arc_read() code path, which covers most cases, but spa_load_verify_cb() relies on zio_read() and is responsible for verifying the block pointer. During import it is also possible to encounter blocks pointers which contain ZIO_COMPRESS_INHERIT and ZIO_CHECKSUM_INHERIT values. Relax the verification function slightly to allow this. Futhermore, extend dsl_scan_recurse() to verify the block pointer contents of level zero blocks which are not of type DMU_OT_DNODE or DMU_OT_OBJSET. This is handled by arc_read() in the other cases. Reviewed-by: Paul Dagnelie <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes openzfs#13124 Closes openzfs#13360
1 parent a7786d6 commit a6a76ad

File tree

3 files changed

+31
-24
lines changed

3 files changed

+31
-24
lines changed

module/zfs/dsl_scan.c

+13-17
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
18241824
const zbookmark_phys_t *zb, dmu_tx_t *tx)
18251825
{
18261826
dsl_pool_t *dp = scn->scn_dp;
1827+
spa_t *spa = dp->dp_spa;
18271828
int zio_flags = ZIO_FLAG_CANFAIL | ZIO_FLAG_SCAN_THREAD;
18281829
int err;
18291830

@@ -1838,7 +1839,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
18381839
if (dnp != NULL &&
18391840
dnp->dn_bonuslen > DN_MAX_BONUS_LEN(dnp)) {
18401841
scn->scn_phys.scn_errors++;
1841-
spa_log_error(dp->dp_spa, zb);
1842+
spa_log_error(spa, zb);
18421843
return (SET_ERROR(EINVAL));
18431844
}
18441845

@@ -1849,7 +1850,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
18491850
int epb = BP_GET_LSIZE(bp) >> SPA_BLKPTRSHIFT;
18501851
arc_buf_t *buf;
18511852

1852-
err = arc_read(NULL, dp->dp_spa, bp, arc_getbuf_func, &buf,
1853+
err = arc_read(NULL, spa, bp, arc_getbuf_func, &buf,
18531854
ZIO_PRIORITY_SCRUB, zio_flags, &flags, zb);
18541855
if (err) {
18551856
scn->scn_phys.scn_errors++;
@@ -1877,7 +1878,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
18771878
zio_flags |= ZIO_FLAG_RAW;
18781879
}
18791880

1880-
err = arc_read(NULL, dp->dp_spa, bp, arc_getbuf_func, &buf,
1881+
err = arc_read(NULL, spa, bp, arc_getbuf_func, &buf,
18811882
ZIO_PRIORITY_SCRUB, zio_flags, &flags, zb);
18821883
if (err) {
18831884
scn->scn_phys.scn_errors++;
@@ -1896,7 +1897,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
18961897
objset_phys_t *osp;
18971898
arc_buf_t *buf;
18981899

1899-
err = arc_read(NULL, dp->dp_spa, bp, arc_getbuf_func, &buf,
1900+
err = arc_read(NULL, spa, bp, arc_getbuf_func, &buf,
19001901
ZIO_PRIORITY_SCRUB, zio_flags, &flags, zb);
19011902
if (err) {
19021903
scn->scn_phys.scn_errors++;
@@ -1927,6 +1928,14 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
19271928
DMU_USERUSED_OBJECT, tx);
19281929
}
19291930
arc_buf_destroy(buf, &buf);
1931+
} else if (!zfs_blkptr_verify(spa, bp, B_FALSE, BLK_VERIFY_LOG)) {
1932+
/*
1933+
* Sanity check the block pointer contents, this is handled
1934+
* by arc_read() for the cases above.
1935+
*/
1936+
scn->scn_phys.scn_errors++;
1937+
spa_log_error(spa, zb);
1938+
return (SET_ERROR(EINVAL));
19301939
}
19311940

19321941
return (0);
@@ -1977,19 +1986,6 @@ dsl_scan_visitbp(blkptr_t *bp, const zbookmark_phys_t *zb,
19771986

19781987
scn->scn_visited_this_txg++;
19791988

1980-
/*
1981-
* This debugging is commented out to conserve stack space. This
1982-
* function is called recursively and the debugging adds several
1983-
* bytes to the stack for each call. It can be commented back in
1984-
* if required to debug an issue in dsl_scan_visitbp().
1985-
*
1986-
* dprintf_bp(bp,
1987-
* "visiting ds=%p/%llu zb=%llx/%llx/%llx/%llx bp=%p",
1988-
* ds, ds ? ds->ds_object : 0,
1989-
* zb->zb_objset, zb->zb_object, zb->zb_level, zb->zb_blkid,
1990-
* bp);
1991-
*/
1992-
19931989
if (BP_IS_HOLE(bp)) {
19941990
scn->scn_holes_this_txg++;
19951991
return;

module/zfs/spa.c

+16-3
Original file line numberDiff line numberDiff line change
@@ -2312,16 +2312,29 @@ spa_load_verify_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
23122312

23132313
(void) zilog, (void) dnp;
23142314

2315-
if (zb->zb_level == ZB_DNODE_LEVEL || BP_IS_HOLE(bp) ||
2316-
BP_IS_EMBEDDED(bp) || BP_IS_REDACTED(bp))
2317-
return (0);
23182315
/*
23192316
* Note: normally this routine will not be called if
23202317
* spa_load_verify_metadata is not set. However, it may be useful
23212318
* to manually set the flag after the traversal has begun.
23222319
*/
23232320
if (!spa_load_verify_metadata)
23242321
return (0);
2322+
2323+
/*
2324+
* Sanity check the block pointer in order to detect obvious damage
2325+
* before using the contents in subsequent checks or in zio_read().
2326+
* When damaged consider it to be a metadata error since we cannot
2327+
* trust the BP_GET_TYPE and BP_GET_LEVEL values.
2328+
*/
2329+
if (!zfs_blkptr_verify(spa, bp, B_FALSE, BLK_VERIFY_LOG)) {
2330+
atomic_inc_64(&sle->sle_meta_count);
2331+
return (0);
2332+
}
2333+
2334+
if (zb->zb_level == ZB_DNODE_LEVEL || BP_IS_HOLE(bp) ||
2335+
BP_IS_EMBEDDED(bp) || BP_IS_REDACTED(bp))
2336+
return (0);
2337+
23252338
if (!BP_IS_METADATA(bp) &&
23262339
(!spa_load_verify_data || !sle->sle_verify_data))
23272340
return (0);

module/zfs/zio.c

+2-4
Original file line numberDiff line numberDiff line change
@@ -962,14 +962,12 @@ zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp, boolean_t config_held,
962962
"blkptr at %p has invalid TYPE %llu",
963963
bp, (longlong_t)BP_GET_TYPE(bp));
964964
}
965-
if (BP_GET_CHECKSUM(bp) >= ZIO_CHECKSUM_FUNCTIONS ||
966-
BP_GET_CHECKSUM(bp) <= ZIO_CHECKSUM_ON) {
965+
if (BP_GET_CHECKSUM(bp) >= ZIO_CHECKSUM_FUNCTIONS) {
967966
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
968967
"blkptr at %p has invalid CHECKSUM %llu",
969968
bp, (longlong_t)BP_GET_CHECKSUM(bp));
970969
}
971-
if (BP_GET_COMPRESS(bp) >= ZIO_COMPRESS_FUNCTIONS ||
972-
BP_GET_COMPRESS(bp) <= ZIO_COMPRESS_ON) {
970+
if (BP_GET_COMPRESS(bp) >= ZIO_COMPRESS_FUNCTIONS) {
973971
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
974972
"blkptr at %p has invalid COMPRESS %llu",
975973
bp, (longlong_t)BP_GET_COMPRESS(bp));

0 commit comments

Comments
 (0)