Skip to content

Commit 01017b0

Browse files
authored
Merge pull request #320 from grwilson/blkptr
Add blkptr command to sdb
2 parents cba0105 + 2e61ae7 commit 01017b0

12 files changed

+385
-0
lines changed

sdb/commands/zfs/blkptr.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#
2+
# Copyright 2019, 2023 Delphix
3+
# Copyright 2021 Datto, Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
# pylint: disable=missing-docstring
19+
20+
from typing import Iterable
21+
22+
import drgn
23+
import sdb
24+
from sdb.commands.zfs.internal import (
25+
BP_GET_TYPE, BP_GET_CHECKSUM, BP_GET_COMPRESS, BP_GET_LEVEL, BP_GET_LSIZE,
26+
BP_GET_BIRTH, BP_GET_PSIZE, BP_LOGICAL_BIRTH, BP_IS_HOLE, BP_GET_NDVAS,
27+
BP_IS_ENCRYPTED, BP_IS_GANG, BP_GET_LAYER, BP_IS_AUTHENTICATED,
28+
BP_HAS_INDIRECT_MAC_CKSUM, BP_GET_BYTEORDER, BP_GET_DEDUP, BP_IS_EMBEDDED,
29+
BP_IS_REDACTED, BP_GET_FILL, BP_GET_IV2, DVA_IS_VALID, DVA_GET_VDEV,
30+
DVA_GET_OFFSET, DVA_GET_ASIZE, BPE_GET_ETYPE)
31+
32+
33+
class Blkptr(sdb.PrettyPrinter):
34+
"""
35+
DESCRIPTION
36+
37+
Pretty-print zfs block pointers.
38+
39+
EXAMPLES
40+
41+
sdb> dbuf | head 1 | member db_blkptr | blkptr
42+
DVA[0]=<0:2cefd5e00:20000> [L0 ZFS plain file] fletcher4 uncompressed unencrypted LE
43+
contiguous unique single 20000L/20000P birth=1624L/1624P fill=1 cksum=3feb86d3fa14:
44+
ff98411222361a1:7cd8eb3816d141e1:2d65ae38a67197c7
45+
46+
sdb> echo 0xffffa0889343c680 | blkptr
47+
DVA[0]=<0:41e90000:30000> [L0 ZFS plain file] fletcher4 uncompressed unencrypted LE
48+
contiguous unique single 20000L/20000P birth=10L/10P fill=1 cksum=3ffba121eb4d:
49+
ffd4345f8d679e2:efa124922f72ec66:34642a9a05fbafef
50+
"""
51+
52+
names = ["blkptr"]
53+
input_type = "blkptr_t *"
54+
load_on = [sdb.Module("zfs"), sdb.Library("libzpool")]
55+
56+
def get_ot_name(self, bp: drgn.Object) -> str:
57+
return str(
58+
sdb.get_object("dmu_ot")[BP_GET_TYPE(bp)].ot_name.string_().decode(
59+
"utf-8"))
60+
61+
def get_checksum(self, bp: drgn.Object) -> str:
62+
checksum = sdb.get_object("zio_checksum_table")[BP_GET_CHECKSUM(
63+
bp)].ci_name
64+
return str(checksum.string_().decode("utf-8"))
65+
66+
def get_compress(self, bp: drgn.Object) -> str:
67+
compress = sdb.get_object("zio_compress_table")[BP_GET_COMPRESS(
68+
bp)].ci_name
69+
return str(compress.string_().decode("utf-8"))
70+
71+
def print_hole(self, bp: drgn.Object) -> None:
72+
print(f"HOLE [L{BP_GET_LEVEL(bp)} {self.get_ot_name(bp)}]", end=' ')
73+
print(f"size={BP_GET_LSIZE(bp):#x}L birth={BP_GET_BIRTH(bp):#x}L")
74+
75+
def print_embedded(self, bp: drgn.Object) -> None:
76+
print(f"EMBEDDED [L{BP_GET_LEVEL(bp)}", end=' ')
77+
print(f"{self.get_ot_name(bp)}]", end=' ')
78+
print(f"et={BPE_GET_ETYPE(bp)} {BP_GET_COMPRESS(bp)} ", end=' ')
79+
print(f"size={BP_GET_LSIZE(bp):#x}L/{BP_GET_PSIZE(bp):#x}P ", end=' ')
80+
print(f"birth={BP_LOGICAL_BIRTH(bp)}L")
81+
82+
def print_redacted(self, bp: drgn.Object) -> None:
83+
print(f"REDACTED [L{BP_GET_LEVEL(bp)}", end=' ')
84+
print(f"{self.get_ot_name(bp)}] size={BP_GET_LSIZE(bp):#x}", end=' ')
85+
print(f"birth={BP_LOGICAL_BIRTH(bp):#x}")
86+
87+
def get_byteorder(self, bp: drgn.Object) -> str:
88+
if BP_GET_BYTEORDER(bp) == 0:
89+
return "BE"
90+
return "LE"
91+
92+
def get_gang(self, bp: drgn.Object) -> str:
93+
if BP_IS_GANG(bp):
94+
return "gang"
95+
return "contiguous"
96+
97+
def get_dedup(self, bp: drgn.Object) -> str:
98+
if BP_GET_DEDUP(bp):
99+
return "dedup"
100+
return "unique"
101+
102+
def get_crypt(self, bp: drgn.Object) -> str:
103+
if BP_IS_ENCRYPTED(bp):
104+
return "encrypted"
105+
if BP_IS_AUTHENTICATED(bp):
106+
return "authenticated"
107+
if BP_HAS_INDIRECT_MAC_CKSUM(bp):
108+
return "indirect-MAC"
109+
return "unencrypted"
110+
111+
def pretty_print(self, objs: Iterable[drgn.Object]) -> None:
112+
copyname = ['zero', 'single', 'double', 'triple']
113+
copies = 0
114+
115+
for bp in objs:
116+
if bp is None:
117+
print("<NULL>")
118+
continue
119+
120+
if BP_IS_HOLE(bp):
121+
self.print_hole(bp)
122+
elif BP_IS_EMBEDDED(bp):
123+
self.print_embedded(bp)
124+
elif BP_IS_REDACTED(bp):
125+
self.print_redacted(bp)
126+
else:
127+
128+
for d in range(0, BP_GET_NDVAS(bp)):
129+
if DVA_IS_VALID(bp.blk_dva[d]):
130+
copies += 1
131+
print(f"DVA[{d}]=<{DVA_GET_VDEV(bp.blk_dva[d])}:", end='')
132+
print(f"{DVA_GET_OFFSET(bp.blk_dva[d]):#x}:", end='')
133+
print(f"{DVA_GET_ASIZE(bp.blk_dva[d]):#x}>")
134+
135+
if BP_IS_ENCRYPTED(bp):
136+
print(f"salt={bp.blk_dva[2].dva_word[0]:#x}", end=' ')
137+
print(f"iv={bp.blk_dva[2].dva_word[1]:#x}", end='')
138+
print(f"{BP_GET_IV2(bp):#x}")
139+
140+
if BP_IS_GANG(bp) and (DVA_GET_ASIZE(bp.blk_dva[2]) <=
141+
DVA_GET_ASIZE(bp.blk_dva[1]) / 2):
142+
copies -= 1
143+
144+
print(f"[L{BP_GET_LEVEL(bp)}", end=' ')
145+
print(f"{self.get_ot_name(bp)}]", end=' ')
146+
print(f"{self.get_checksum(bp)}", end=' ')
147+
print(f"{self.get_compress(bp)}", end=' ')
148+
149+
print(f"layer={BP_GET_LAYER(bp)}", end=' ')
150+
print(f"{self.get_crypt(bp)}", end=' ')
151+
print(f"{self.get_byteorder(bp)}", end=' ')
152+
print(f"{self.get_gang(bp)} {self.get_dedup(bp)}", end=' ')
153+
print(f"{copyname[copies]}")
154+
155+
print(f"size={BP_GET_LSIZE(bp):#x}L/{BP_GET_PSIZE(bp):#x}P",
156+
end=' ')
157+
print(f"birth={BP_LOGICAL_BIRTH(bp)}L", end='/')
158+
print(f"{BP_GET_BIRTH(bp)}P", end=' ')
159+
print(f"fill={int(BP_GET_FILL(bp))}")
160+
161+
print(f"cksum={int(bp.blk_cksum.zc_word[0]):#x}", end='')
162+
print(f":{int(bp.blk_cksum.zc_word[1]):#x}", end='')
163+
print(f":{int(bp.blk_cksum.zc_word[2]):#x}", end='')
164+
print(f":{int(bp.blk_cksum.zc_word[3]):#x}")

sdb/commands/zfs/internal/__init__.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ def BF64_GET(x: drgn.Object, low: int, length: int) -> int:
6969
return BF64_DECODE(x, low, length)
7070

7171

72+
def BF64_GET_SB(x: int, low: int, length: int, shift: int, bias: int) -> int:
73+
return (BF64_GET(x, low, length) + bias) << shift
74+
75+
7276
def WEIGHT_IS_SPACEBASED(weight: int) -> bool:
7377
return weight == 0 or (BF64_GET(weight, 60, 1) != 0)
7478

@@ -81,6 +85,184 @@ def WEIGHT_GET_COUNT(weight: int) -> int:
8185
return BF64_GET((weight), 0, 54)
8286

8387

88+
def BPE_GET_ETYPE(bp: drgn.Object) -> int:
89+
return BF64_GET(bp.blk_prop, 40, 8)
90+
91+
92+
def BPE_GET_LSIZE(bp: drgn.Object) -> int:
93+
return BF64_GET_SB(bp.blk_prop, 0, 25, 0, 1)
94+
95+
96+
def BPE_GET_PSIZE(bp: drgn.Object) -> int:
97+
return BF64_GET_SB(bp.blk_prop, 25, 7, 0, 1)
98+
99+
100+
def BP_GET_LSIZE(bp: drgn.Object) -> int:
101+
if BP_IS_EMBEDDED(bp):
102+
if BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA:
103+
return BPE_GET_LSIZE(bp)
104+
return 0
105+
return BF64_GET_SB(bp.blk_prop, 0, SPA_LSIZEBITS, SPA_MINBLOCKSHIFT, 1)
106+
107+
108+
def BP_GET_PSIZE(bp: drgn.Object) -> int:
109+
if BP_IS_EMBEDDED(bp):
110+
return 0
111+
return BF64_GET_SB(bp.blk_prop, 16, SPA_PSIZEBITS, SPA_MINBLOCKSHIFT, 1)
112+
113+
114+
def BP_GET_COMPRESS(bp: drgn.Object) -> int:
115+
return BF64_GET(bp.blk_prop, 32, SPA_COMPRESSBITS)
116+
117+
118+
def BP_IS_EMBEDDED(bp: drgn.Object) -> bool:
119+
return bool(BF64_GET(bp.blk_prop, 39, 1))
120+
121+
122+
def BP_GET_CHECKSUM(bp: drgn.Object) -> int:
123+
if BP_IS_EMBEDDED(bp):
124+
return ZIO_CHECKSUM_OFF
125+
return BF64_GET(bp.blk_prop, 40, 8)
126+
127+
128+
def BP_GET_TYPE(bp: drgn.Object) -> int:
129+
return BF64_GET(bp.blk_prop, 48, 8)
130+
131+
132+
def BP_GET_LEVEL(bp: drgn.Object) -> int:
133+
return BF64_GET(bp.blk_prop, 56, 5)
134+
135+
136+
def BP_USES_CRYPT(bp: drgn.Object) -> bool:
137+
return bool(BF64_GET(bp.blk_prop, 61, 1))
138+
139+
140+
def BP_IS_ENCRYPTED(bp: drgn.Object) -> bool:
141+
return (BP_USES_CRYPT(bp) and BP_GET_LEVEL(bp) <= 0 and
142+
DMU_OT_IS_ENCRYPTED(BP_GET_TYPE(bp)))
143+
144+
145+
def BP_IS_AUTHENTICATED(bp: drgn.Object) -> bool:
146+
return (BP_USES_CRYPT(bp) and BP_GET_LEVEL(bp) <= 0 and
147+
not DMU_OT_IS_ENCRYPTED(BP_GET_TYPE(bp)))
148+
149+
150+
def BP_HAS_INDIRECT_MAC_CKSUM(bp: drgn.Object) -> bool:
151+
return (BP_USES_CRYPT(bp) and BP_GET_LEVEL(bp) > 0)
152+
153+
154+
def BP_GET_DEDUP(bp: drgn.Object) -> bool:
155+
return bool(BF64_GET(bp.blk_prop, 62, 1))
156+
157+
158+
def BP_GET_BYTEORDER(bp: drgn.Object) -> int:
159+
return BF64_GET(bp.blk_prop, 63, 1)
160+
161+
162+
def BP_GET_LAYER(bp: drgn.Object) -> int:
163+
if sdb.get_type('blkptr_t').has_member('blk_logical_birth'):
164+
return BF64_GET(bp.blk_logical_birth, 56, 8)
165+
return BF64_GET(bp.blk_birth, 56, 8)
166+
167+
168+
def BP_LOGICAL_BIRTH(bp: drgn.Object) -> int:
169+
if sdb.get_type('blkptr_t').has_member('blk_logical_birth'):
170+
return BF64_GET(bp.blk_logical_birth, 0, 56)
171+
return BF64_GET(bp.blk_birth, 0, 56)
172+
173+
174+
def BP_PHYSICAL_BIRTH(bp: drgn.Object) -> int:
175+
if sdb.get_type('blkptr_t').has_member('blk_physical_birth'):
176+
return BF64_GET(bp.blk_physical_birth, 0, 56)
177+
return BF64_GET(bp.blk_phys_birth, 0, 56)
178+
179+
180+
def BP_GET_BIRTH(bp: drgn.Object) -> int:
181+
if BP_IS_EMBEDDED(bp):
182+
return 0
183+
if BP_PHYSICAL_BIRTH(bp):
184+
return BP_PHYSICAL_BIRTH(bp)
185+
return BP_LOGICAL_BIRTH(bp)
186+
187+
188+
def BP_GET_FILL(bp: drgn.Object) -> int:
189+
if BP_IS_ENCRYPTED(bp):
190+
return BF64_GET(bp.blk_fill, 0, 32)
191+
if BP_IS_EMBEDDED(bp):
192+
return 1
193+
return int(bp.blk_fill)
194+
195+
196+
def BP_GET_IV2(bp: drgn.Object) -> int:
197+
return BF64_GET(bp.blk_fill, 32, 32)
198+
199+
200+
def BP_IS_GANG(bp: drgn.Object) -> bool:
201+
if BP_IS_EMBEDDED(bp):
202+
return False
203+
return bool(BF64_GET(bp.blk_dva[0].dva_word[1], 63, 1))
204+
205+
206+
def BP_IS_REDACTED(bp: drgn.Object) -> bool:
207+
return (BP_IS_EMBEDDED(bp) and
208+
BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_REDACTED)
209+
210+
211+
def BP_IS_HOLE(bp: drgn.Object) -> bool:
212+
return (not BP_IS_EMBEDDED(bp) and DVA_IS_EMPTY(bp.blk_dva[0]))
213+
214+
215+
def BP_GET_NDVAS(bp: drgn.Object) -> int:
216+
if BP_IS_EMBEDDED(bp):
217+
return 0
218+
ndvas = 0
219+
for d in range(0, 3):
220+
ndvas += DVA_GET_ASIZE(bp.blk_dva[d]) != 0
221+
return ndvas
222+
223+
224+
def DVA_GET_ASIZE(dva: drgn.Object) -> int:
225+
return BF64_GET_SB(dva.dva_word[0], 0, SPA_ASIZEBITS, SPA_MINBLOCKSHIFT, 0)
226+
227+
228+
def DVA_GET_VDEV(dva: drgn.Object) -> int:
229+
return BF64_GET(dva.dva_word[0], 32, SPA_VDEVBITS)
230+
231+
232+
def DVA_GET_OFFSET(dva: drgn.Object) -> int:
233+
return BF64_GET_SB(dva.dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0)
234+
235+
236+
def DVA_IS_VALID(dva: drgn.Object) -> bool:
237+
return DVA_GET_ASIZE(dva) != 0
238+
239+
240+
def DVA_IS_EMPTY(dva: drgn.Object) -> bool:
241+
return bool(dva.dva_word[0] == 0 and dva.dva_word[1] == 0)
242+
243+
244+
def DMU_OT_IS_ENCRYPTED(ot: int) -> bool:
245+
if ot & DMU_OT_NEWTYPE:
246+
return bool(ot & DMU_OT_ENCRYPTED)
247+
return bool(sdb.get_object("dmu_ot")[ot].ot_encrypt)
248+
249+
250+
SPA_LSIZEBITS = 16
251+
SPA_PSIZEBITS = 16
252+
SPA_ASIZEBITS = 24
253+
SPA_COMPRESSBITS = 7
254+
SPA_VDEVBITS = 24
255+
SPA_MINBLOCKSHIFT = 9
256+
257+
ZIO_CHECKSUM_OFF = 2
258+
259+
DMU_OT_ENCRYPTED = 0x20
260+
DMU_OT_NEWTYPE = 0x80
261+
262+
BP_EMBEDDED_TYPE_DATA = 0
263+
BP_EMBEDDED_TYPE_RESERVED = 1
264+
BP_EMBEDDED_TYPE_REDACTED = 2
265+
84266
METASLAB_WEIGHT_PRIMARY = int(1 << 63)
85267
METASLAB_WEIGHT_SECONDARY = int(1 << 62)
86268
METASLAB_WEIGHT_CLAIM = int(1 << 61)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
DVA[0]=<0:0x42083400:0x800>
2+
DVA[1]=<0:0x20048000:0x800>
3+
DVA[2]=<0:0x50002c00:0x800>
4+
[L0 SPA space map] fletcher4 lz4 layer=0 unencrypted LE contiguous unique triple
5+
size=0x20000L/0x400P birth=10L/10P fill=1
6+
cksum=0x8c1caab0a6:0x45de629e8318:0x13bfbe391d06f8:0x41fc70c3e1d38f2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
HOLE [L0 unallocated] size=0x200L birth=0x0L
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DVA[0]=<0:0x2cefd5e00:0x20000>
2+
[L0 ZFS plain file] fletcher4 uncompressed layer=0 unencrypted LE contiguous unique single
3+
size=0x20000L/0x20000P birth=1624L/1624P fill=1
4+
cksum=0x3feb86d3fa14:0xff98411222361a1:0x7cd8eb3816d141e1:0x2d65ae38a67197c7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
DVA[0]=<0:0x80001e00:0x200>
2+
DVA[1]=<0:0xa0001e00:0x200>
3+
DVA[2]=<0:0x10000da00:0x200>
4+
[L0 DMU objset] fletcher4 lz4 layer=0 unencrypted LE contiguous unique triple
5+
size=0x1000L/0x200P birth=609L/609P fill=67
6+
cksum=0x98a43f544:0x3eab35f140c:0xd164e4328324:0x1da8f37ef09087
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DVA[0]=<0:0x50ad98800:0x600>
2+
[L0 ZFS plain file] fletcher4 lzjb layer=0 unencrypted LE contiguous unique single
3+
size=0xa00L/0x600P birth=691L/691P fill=1
4+
cksum=0x50b2435bac:0x4877d83d80e7:0x259e03cbed157d:0xe4d625e1f14d8cc
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DVA[0]=<0:0xe01bd200:0x2e00>
2+
[L0 ZFS plain file] fletcher4 lzjb layer=0 unencrypted LE contiguous unique single
3+
size=0x8e00L/0x2e00P birth=25L/25P fill=1
4+
cksum=0x2b4705c4d19:0xe6eacc837fede:0x3376b31cb9e47ade:0x6759b6b5446e1229
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DVA[0]=<0:0x103207c00:0x2e00>
2+
[L0 ZFS plain file] fletcher4 lz4 layer=0 unencrypted LE contiguous unique single
3+
size=0x20000L/0x2e00P birth=1197L/1197P fill=1
4+
cksum=0x5df05f0e3e3:0x229afb5d03e237:0x83ffb2e325a9e23a:0xbed1657fea4bbdb8

0 commit comments

Comments
 (0)