Skip to content

Commit 651ec0d

Browse files
committed
Add blkptr command to sdb
1 parent cba0105 commit 651ec0d

12 files changed

+389
-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: 186 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,188 @@ 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 BP_IS_EMBEDDED(bp):
164+
if sdb.get_type('blkptr_t').has_member('blk_logical_birth'):
165+
return BF64_GET(bp.blk_logical_birth, 56, 8)
166+
return BF64_GET(bp.blk_birth, 56, 8)
167+
if sdb.get_type('blkptr_t').has_member('blk_physical_birth'):
168+
return BF64_GET(bp.blk_physical_birth, 56, 8)
169+
return BF64_GET(bp.blk_phys_birth, 56, 8)
170+
171+
172+
def BP_LOGICAL_BIRTH(bp: drgn.Object) -> int:
173+
if sdb.get_type('blkptr_t').has_member('blk_logical_birth'):
174+
return BF64_GET(bp.blk_logical_birth, 0, 56)
175+
return BF64_GET(bp.blk_birth, 0, 56)
176+
177+
178+
def BP_PHYSICAL_BIRTH(bp: drgn.Object) -> int:
179+
if sdb.get_type('blkptr_t').has_member('blk_physical_birth'):
180+
return BF64_GET(bp.blk_physical_birth, 0, 56)
181+
return BF64_GET(bp.blk_phys_birth, 0, 56)
182+
183+
184+
def BP_GET_BIRTH(bp: drgn.Object) -> int:
185+
if BP_IS_EMBEDDED(bp):
186+
return 0
187+
if BP_PHYSICAL_BIRTH(bp):
188+
return BP_PHYSICAL_BIRTH(bp)
189+
return BP_LOGICAL_BIRTH(bp)
190+
191+
192+
def BP_GET_FILL(bp: drgn.Object) -> int:
193+
if BP_IS_ENCRYPTED(bp):
194+
return BF64_GET(bp.blk_fill, 0, 32)
195+
if BP_IS_EMBEDDED(bp):
196+
return 1
197+
return int(bp.blk_fill)
198+
199+
200+
def BP_GET_IV2(bp: drgn.Object) -> int:
201+
return BF64_GET(bp.blk_fill, 32, 32)
202+
203+
204+
def BP_IS_GANG(bp: drgn.Object) -> bool:
205+
if BP_IS_EMBEDDED(bp):
206+
return False
207+
return bool(BF64_GET(bp.blk_dva[0].dva_word[1], 63, 1))
208+
209+
210+
def BP_IS_REDACTED(bp: drgn.Object) -> bool:
211+
return (BP_IS_EMBEDDED(bp) and
212+
BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_REDACTED)
213+
214+
215+
def BP_IS_HOLE(bp: drgn.Object) -> bool:
216+
return (not BP_IS_EMBEDDED(bp) and DVA_IS_EMPTY(bp.blk_dva[0]))
217+
218+
219+
def BP_GET_NDVAS(bp: drgn.Object) -> int:
220+
if BP_IS_EMBEDDED(bp):
221+
return 0
222+
ndvas = 0
223+
for d in range(0, 3):
224+
ndvas += DVA_GET_ASIZE(bp.blk_dva[d]) != 0
225+
return ndvas
226+
227+
228+
def DVA_GET_ASIZE(dva: drgn.Object) -> int:
229+
return BF64_GET_SB(dva.dva_word[0], 0, SPA_ASIZEBITS, SPA_MINBLOCKSHIFT, 0)
230+
231+
232+
def DVA_GET_VDEV(dva: drgn.Object) -> int:
233+
return BF64_GET(dva.dva_word[0], 32, SPA_VDEVBITS)
234+
235+
236+
def DVA_GET_OFFSET(dva: drgn.Object) -> int:
237+
return BF64_GET_SB(dva.dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0)
238+
239+
240+
def DVA_IS_VALID(dva: drgn.Object) -> bool:
241+
return DVA_GET_ASIZE(dva) != 0
242+
243+
244+
def DVA_IS_EMPTY(dva: drgn.Object) -> bool:
245+
return bool(dva.dva_word[0] == 0 and dva.dva_word[1] == 0)
246+
247+
248+
def DMU_OT_IS_ENCRYPTED(ot: int) -> bool:
249+
if ot & DMU_OT_NEWTYPE:
250+
return bool(ot & DMU_OT_ENCRYPTED)
251+
return bool(sdb.get_object("dmu_ot")[ot].ot_encrypt)
252+
253+
254+
SPA_LSIZEBITS = 16
255+
SPA_PSIZEBITS = 16
256+
SPA_ASIZEBITS = 24
257+
SPA_COMPRESSBITS = 7
258+
SPA_VDEVBITS = 24
259+
SPA_MINBLOCKSHIFT = 9
260+
261+
ZIO_CHECKSUM_OFF = 2
262+
263+
DMU_OT_ENCRYPTED = 0x20
264+
DMU_OT_NEWTYPE = 0x80
265+
266+
BP_EMBEDDED_TYPE_DATA = 0
267+
BP_EMBEDDED_TYPE_RESERVED = 1
268+
BP_EMBEDDED_TYPE_REDACTED = 2
269+
84270
METASLAB_WEIGHT_PRIMARY = int(1 << 63)
85271
METASLAB_WEIGHT_SECONDARY = int(1 << 62)
86272
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
Lines changed: 4 additions & 0 deletions
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

0 commit comments

Comments
 (0)