1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Chunwei Chen <david.chen@nutanix.com>
3 Date: Tue, 30 Jan 2018 13:39:11 -0800
4 Subject: [PATCH] Fix zdb -c traverse stop on damaged objset root
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 If a corruption happens to be on a root block of an objset, zdb -c will
10 not correctly report the error, and it will not traverse the datasets
11 that come after. This is because traverse_visitbp, which does the
12 callback and reset error for TRAVERSE_HARD, is skipped when traversing
13 zil is failed in traverse_impl.
15 Here's example of what 'zdb -eLcc' command looks like on a pool with
20 Traversing all blocks to verify checksums ...
25 block traversal size 379392 != alloc 33987072 (unreachable 33607680)
29 bp logical: 1678336 avg: 9757
30 bp physical: 130560 avg: 759 compression: 12.85
31 bp allocated: 379392 avg: 2205 compression: 4.42
32 bp deduped: 0 ref>1: 0 deduplication: 1.00
33 SPA allocated: 33987072 used: 0.80%
35 additional, non-pointer bps of type 0: 71
36 Dittoed blocks on same vdev: 101
40 Traversing all blocks to verify checksums ...
42 zdb_blkptr_cb: Got error 52 reading <54, 0, -1, 0> -- skipping
48 block traversal size 33963520 != alloc 33987072 (unreachable 23552)
52 bp logical: 36093440 avg: 80745
53 bp physical: 33699840 avg: 75391 compression: 1.07
54 bp allocated: 33963520 avg: 75981 compression: 1.06
55 bp deduped: 0 ref>1: 0 deduplication: 1.00
56 SPA allocated: 33987072 used: 0.80%
58 additional, non-pointer bps of type 0: 76
59 Dittoed blocks on same vdev: 115
63 Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
64 Reviewed-by: loli10K <ezomori.nozomu@gmail.com>
65 Signed-off-by: Chunwei Chen <david.chen@nutanix.com>
67 (cherry picked from commit 23227313a2016449176cbfcbae2d4fc463a2bc09)
68 Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
70 module/zfs/dmu_traverse.c | 26 +++++++++++++++++---------
71 1 file changed, 17 insertions(+), 9 deletions(-)
73 diff --git a/module/zfs/dmu_traverse.c b/module/zfs/dmu_traverse.c
74 index c78228d74..b494bef35 100644
75 --- a/module/zfs/dmu_traverse.c
76 +++ b/module/zfs/dmu_traverse.c
77 @@ -599,19 +599,27 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
79 /* See comment on ZIL traversal in dsl_scan_visitds. */
80 if (ds != NULL && !ds->ds_is_snapshot && !BP_IS_HOLE(rootbp)) {
81 + enum zio_flag zio_flags = ZIO_FLAG_CANFAIL;
82 uint32_t flags = ARC_FLAG_WAIT;
86 - err = arc_read(NULL, td->td_spa, rootbp,
87 - arc_getbuf_func, &buf,
88 - ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, czb);
93 - traverse_zil(td, &osp->os_zil_header);
94 - arc_buf_destroy(buf, &buf);
95 + err = arc_read(NULL, td->td_spa, rootbp, arc_getbuf_func,
96 + &buf, ZIO_PRIORITY_ASYNC_READ, zio_flags, &flags, czb);
99 + * If both TRAVERSE_HARD and TRAVERSE_PRE are set,
100 + * continue to visitbp so that td_func can be called
101 + * in pre stage, and err will reset to zero.
103 + if (!(td->td_flags & TRAVERSE_HARD) ||
104 + !(td->td_flags & TRAVERSE_PRE))
108 + traverse_zil(td, &osp->os_zil_header);
109 + arc_buf_destroy(buf, &buf);
113 if (!(flags & TRAVERSE_PREFETCH_DATA) ||