diff options
author | George Amanakis <[email protected]> | 2022-02-03 23:28:19 +0100 |
---|---|---|
committer | Tony Hutter <[email protected]> | 2022-02-16 17:58:55 -0800 |
commit | 72a82f312f9fd0abd5b15f1d847e448a56353ec7 (patch) | |
tree | 563be7dc3fdc6e22525ba2b2bf8e7abe3c9ce0f4 /module | |
parent | 5753e7a7c503d7f903048163b370efa750209ee2 (diff) |
Report dnodes with faulty bonuslen
In files created/modified before 4254acb there may be a corruption of
xattrs which is not reported during scrub and normal send/receive. It
manifests only as an error when raw sending/receiving. This happens
because currently only the raw receive path checks for discrepancies
between the dnode bonus length and the spill pointer flag.
In case we encounter a dnode whose bonus length is greater than the
predicted one, we should report an error. Modify in this regard
dnode_sync() with an assertion at the end, dump_dnode() to error out,
dsl_scan_recurse() to report errors during a scrub, and zstream to
report a warning when dumping. Also added a test to verify spill blocks
are sent correctly in a raw send.
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: George Amanakis <[email protected]>
Closes #12720
Closes #13014
Diffstat (limited to 'module')
-rw-r--r-- | module/zfs/dmu_send.c | 2 | ||||
-rw-r--r-- | module/zfs/dnode_sync.c | 2 | ||||
-rw-r--r-- | module/zfs/dsl_scan.c | 13 |
3 files changed, 17 insertions, 0 deletions
diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 2f2fd4c3d..58a72a68a 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -763,6 +763,8 @@ dump_dnode(dmu_send_cookie_t *dscp, const blkptr_t *bp, uint64_t object, * to send it. */ if (bonuslen != 0) { + if (drro->drr_bonuslen > DN_MAX_BONUS_LEN(dnp)) + return (SET_ERROR(EINVAL)); drro->drr_raw_bonuslen = DN_MAX_BONUS_LEN(dnp); bonuslen = drro->drr_raw_bonuslen; } diff --git a/module/zfs/dnode_sync.c b/module/zfs/dnode_sync.c index f574130e5..12ab4bea1 100644 --- a/module/zfs/dnode_sync.c +++ b/module/zfs/dnode_sync.c @@ -854,6 +854,8 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx) dnode_rele(dn, (void *)(uintptr_t)tx->tx_txg); } + ASSERT3U(dnp->dn_bonuslen, <=, DN_MAX_BONUS_LEN(dnp)); + /* * Although we have dropped our reference to the dnode, it * can't be evicted until its written, and we haven't yet diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c index 62ee9bb9a..765998417 100644 --- a/module/zfs/dsl_scan.c +++ b/module/zfs/dsl_scan.c @@ -1821,6 +1821,19 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype, ASSERT(!BP_IS_REDACTED(bp)); + /* + * There is an unlikely case of encountering dnodes with contradicting + * dn_bonuslen and DNODE_FLAG_SPILL_BLKPTR flag before in files created + * or modified before commit 4254acb was merged. As it is not possible + * to know which of the two is correct, report an error. + */ + if (dnp != NULL && + dnp->dn_bonuslen > DN_MAX_BONUS_LEN(dnp)) { + scn->scn_phys.scn_errors++; + spa_log_error(dp->dp_spa, zb); + return (SET_ERROR(EINVAL)); + } + if (BP_GET_LEVEL(bp) > 0) { arc_flags_t flags = ARC_FLAG_WAIT; int i; |