]>
Commit | Line | Data |
---|---|---|
75b07eca FG |
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 | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
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. | |
14 | ||
15 | Here's example of what 'zdb -eLcc' command looks like on a pool with | |
16 | damaged objset root: | |
17 | ||
18 | == before patch: | |
19 | ||
20 | Traversing all blocks to verify checksums ... | |
21 | ||
22 | Error counts: | |
23 | ||
24 | errno count | |
25 | block traversal size 379392 != alloc 33987072 (unreachable 33607680) | |
26 | ||
27 | bp count: 172 | |
28 | ganged count: 0 | |
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% | |
34 | ||
35 | additional, non-pointer bps of type 0: 71 | |
36 | Dittoed blocks on same vdev: 101 | |
37 | ||
38 | == after patch: | |
39 | ||
40 | Traversing all blocks to verify checksums ... | |
41 | ||
42 | zdb_blkptr_cb: Got error 52 reading <54, 0, -1, 0> -- skipping | |
43 | ||
44 | Error counts: | |
45 | ||
46 | errno count | |
47 | 52 1 | |
48 | block traversal size 33963520 != alloc 33987072 (unreachable 23552) | |
49 | ||
50 | bp count: 447 | |
51 | ganged count: 0 | |
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% | |
57 | ||
58 | additional, non-pointer bps of type 0: 76 | |
59 | Dittoed blocks on same vdev: 115 | |
60 | ||
61 | == | |
62 | ||
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> | |
66 | Closes #7099 | |
67 | (cherry picked from commit 23227313a2016449176cbfcbae2d4fc463a2bc09) | |
68 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
69 | --- | |
70 | module/zfs/dmu_traverse.c | 26 +++++++++++++++++--------- | |
71 | 1 file changed, 17 insertions(+), 9 deletions(-) | |
72 | ||
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, | |
78 | ||
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; | |
83 | objset_phys_t *osp; | |
84 | arc_buf_t *buf; | |
85 | ||
86 | - err = arc_read(NULL, td->td_spa, rootbp, | |
87 | - arc_getbuf_func, &buf, | |
88 | - ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, czb); | |
89 | - if (err != 0) | |
90 | - return (err); | |
91 | - | |
92 | - osp = buf->b_data; | |
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); | |
97 | + if (err != 0) { | |
98 | + /* | |
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. | |
102 | + */ | |
103 | + if (!(td->td_flags & TRAVERSE_HARD) || | |
104 | + !(td->td_flags & TRAVERSE_PRE)) | |
105 | + return (err); | |
106 | + } else { | |
107 | + osp = buf->b_data; | |
108 | + traverse_zil(td, &osp->os_zil_header); | |
109 | + arc_buf_destroy(buf, &buf); | |
110 | + } | |
111 | } | |
112 | ||
113 | if (!(flags & TRAVERSE_PREFETCH_DATA) || | |
114 | -- | |
115 | 2.14.2 | |
116 |