summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorGeorge Amanakis <[email protected]>2022-02-03 23:28:19 +0100
committerTony Hutter <[email protected]>2022-02-16 17:58:55 -0800
commit72a82f312f9fd0abd5b15f1d847e448a56353ec7 (patch)
tree563be7dc3fdc6e22525ba2b2bf8e7abe3c9ce0f4 /module
parent5753e7a7c503d7f903048163b370efa750209ee2 (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.c2
-rw-r--r--module/zfs/dnode_sync.c2
-rw-r--r--module/zfs/dsl_scan.c13
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;