Skip to content

Commit

Permalink
Merge pull request #320 from grwilson/blkptr
Browse files Browse the repository at this point in the history
Add blkptr command to sdb
  • Loading branch information
grwilson authored Mar 28, 2023
2 parents cba0105 + 2e61ae7 commit 01017b0
Show file tree
Hide file tree
Showing 12 changed files with 385 additions and 0 deletions.
164 changes: 164 additions & 0 deletions sdb/commands/zfs/blkptr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#
# Copyright 2019, 2023 Delphix
# Copyright 2021 Datto, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# pylint: disable=missing-docstring

from typing import Iterable

import drgn
import sdb
from sdb.commands.zfs.internal import (
BP_GET_TYPE, BP_GET_CHECKSUM, BP_GET_COMPRESS, BP_GET_LEVEL, BP_GET_LSIZE,
BP_GET_BIRTH, BP_GET_PSIZE, BP_LOGICAL_BIRTH, BP_IS_HOLE, BP_GET_NDVAS,
BP_IS_ENCRYPTED, BP_IS_GANG, BP_GET_LAYER, BP_IS_AUTHENTICATED,
BP_HAS_INDIRECT_MAC_CKSUM, BP_GET_BYTEORDER, BP_GET_DEDUP, BP_IS_EMBEDDED,
BP_IS_REDACTED, BP_GET_FILL, BP_GET_IV2, DVA_IS_VALID, DVA_GET_VDEV,
DVA_GET_OFFSET, DVA_GET_ASIZE, BPE_GET_ETYPE)


class Blkptr(sdb.PrettyPrinter):
"""
DESCRIPTION
Pretty-print zfs block pointers.
EXAMPLES
sdb> dbuf | head 1 | member db_blkptr | blkptr
DVA[0]=<0:2cefd5e00:20000> [L0 ZFS plain file] fletcher4 uncompressed unencrypted LE
contiguous unique single 20000L/20000P birth=1624L/1624P fill=1 cksum=3feb86d3fa14:
ff98411222361a1:7cd8eb3816d141e1:2d65ae38a67197c7
sdb> echo 0xffffa0889343c680 | blkptr
DVA[0]=<0:41e90000:30000> [L0 ZFS plain file] fletcher4 uncompressed unencrypted LE
contiguous unique single 20000L/20000P birth=10L/10P fill=1 cksum=3ffba121eb4d:
ffd4345f8d679e2:efa124922f72ec66:34642a9a05fbafef
"""

names = ["blkptr"]
input_type = "blkptr_t *"
load_on = [sdb.Module("zfs"), sdb.Library("libzpool")]

def get_ot_name(self, bp: drgn.Object) -> str:
return str(
sdb.get_object("dmu_ot")[BP_GET_TYPE(bp)].ot_name.string_().decode(
"utf-8"))

def get_checksum(self, bp: drgn.Object) -> str:
checksum = sdb.get_object("zio_checksum_table")[BP_GET_CHECKSUM(
bp)].ci_name
return str(checksum.string_().decode("utf-8"))

def get_compress(self, bp: drgn.Object) -> str:
compress = sdb.get_object("zio_compress_table")[BP_GET_COMPRESS(
bp)].ci_name
return str(compress.string_().decode("utf-8"))

def print_hole(self, bp: drgn.Object) -> None:
print(f"HOLE [L{BP_GET_LEVEL(bp)} {self.get_ot_name(bp)}]", end=' ')
print(f"size={BP_GET_LSIZE(bp):#x}L birth={BP_GET_BIRTH(bp):#x}L")

def print_embedded(self, bp: drgn.Object) -> None:
print(f"EMBEDDED [L{BP_GET_LEVEL(bp)}", end=' ')
print(f"{self.get_ot_name(bp)}]", end=' ')
print(f"et={BPE_GET_ETYPE(bp)} {BP_GET_COMPRESS(bp)} ", end=' ')
print(f"size={BP_GET_LSIZE(bp):#x}L/{BP_GET_PSIZE(bp):#x}P ", end=' ')
print(f"birth={BP_LOGICAL_BIRTH(bp)}L")

def print_redacted(self, bp: drgn.Object) -> None:
print(f"REDACTED [L{BP_GET_LEVEL(bp)}", end=' ')
print(f"{self.get_ot_name(bp)}] size={BP_GET_LSIZE(bp):#x}", end=' ')
print(f"birth={BP_LOGICAL_BIRTH(bp):#x}")

def get_byteorder(self, bp: drgn.Object) -> str:
if BP_GET_BYTEORDER(bp) == 0:
return "BE"
return "LE"

def get_gang(self, bp: drgn.Object) -> str:
if BP_IS_GANG(bp):
return "gang"
return "contiguous"

def get_dedup(self, bp: drgn.Object) -> str:
if BP_GET_DEDUP(bp):
return "dedup"
return "unique"

def get_crypt(self, bp: drgn.Object) -> str:
if BP_IS_ENCRYPTED(bp):
return "encrypted"
if BP_IS_AUTHENTICATED(bp):
return "authenticated"
if BP_HAS_INDIRECT_MAC_CKSUM(bp):
return "indirect-MAC"
return "unencrypted"

def pretty_print(self, objs: Iterable[drgn.Object]) -> None:
copyname = ['zero', 'single', 'double', 'triple']
copies = 0

for bp in objs:
if bp is None:
print("<NULL>")
continue

if BP_IS_HOLE(bp):
self.print_hole(bp)
elif BP_IS_EMBEDDED(bp):
self.print_embedded(bp)
elif BP_IS_REDACTED(bp):
self.print_redacted(bp)
else:

for d in range(0, BP_GET_NDVAS(bp)):
if DVA_IS_VALID(bp.blk_dva[d]):
copies += 1
print(f"DVA[{d}]=<{DVA_GET_VDEV(bp.blk_dva[d])}:", end='')
print(f"{DVA_GET_OFFSET(bp.blk_dva[d]):#x}:", end='')
print(f"{DVA_GET_ASIZE(bp.blk_dva[d]):#x}>")

if BP_IS_ENCRYPTED(bp):
print(f"salt={bp.blk_dva[2].dva_word[0]:#x}", end=' ')
print(f"iv={bp.blk_dva[2].dva_word[1]:#x}", end='')
print(f"{BP_GET_IV2(bp):#x}")

if BP_IS_GANG(bp) and (DVA_GET_ASIZE(bp.blk_dva[2]) <=
DVA_GET_ASIZE(bp.blk_dva[1]) / 2):
copies -= 1

print(f"[L{BP_GET_LEVEL(bp)}", end=' ')
print(f"{self.get_ot_name(bp)}]", end=' ')
print(f"{self.get_checksum(bp)}", end=' ')
print(f"{self.get_compress(bp)}", end=' ')

print(f"layer={BP_GET_LAYER(bp)}", end=' ')
print(f"{self.get_crypt(bp)}", end=' ')
print(f"{self.get_byteorder(bp)}", end=' ')
print(f"{self.get_gang(bp)} {self.get_dedup(bp)}", end=' ')
print(f"{copyname[copies]}")

print(f"size={BP_GET_LSIZE(bp):#x}L/{BP_GET_PSIZE(bp):#x}P",
end=' ')
print(f"birth={BP_LOGICAL_BIRTH(bp)}L", end='/')
print(f"{BP_GET_BIRTH(bp)}P", end=' ')
print(f"fill={int(BP_GET_FILL(bp))}")

print(f"cksum={int(bp.blk_cksum.zc_word[0]):#x}", end='')
print(f":{int(bp.blk_cksum.zc_word[1]):#x}", end='')
print(f":{int(bp.blk_cksum.zc_word[2]):#x}", end='')
print(f":{int(bp.blk_cksum.zc_word[3]):#x}")
182 changes: 182 additions & 0 deletions sdb/commands/zfs/internal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ def BF64_GET(x: drgn.Object, low: int, length: int) -> int:
return BF64_DECODE(x, low, length)


def BF64_GET_SB(x: int, low: int, length: int, shift: int, bias: int) -> int:
return (BF64_GET(x, low, length) + bias) << shift


def WEIGHT_IS_SPACEBASED(weight: int) -> bool:
return weight == 0 or (BF64_GET(weight, 60, 1) != 0)

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


def BPE_GET_ETYPE(bp: drgn.Object) -> int:
return BF64_GET(bp.blk_prop, 40, 8)


def BPE_GET_LSIZE(bp: drgn.Object) -> int:
return BF64_GET_SB(bp.blk_prop, 0, 25, 0, 1)


def BPE_GET_PSIZE(bp: drgn.Object) -> int:
return BF64_GET_SB(bp.blk_prop, 25, 7, 0, 1)


def BP_GET_LSIZE(bp: drgn.Object) -> int:
if BP_IS_EMBEDDED(bp):
if BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA:
return BPE_GET_LSIZE(bp)
return 0
return BF64_GET_SB(bp.blk_prop, 0, SPA_LSIZEBITS, SPA_MINBLOCKSHIFT, 1)


def BP_GET_PSIZE(bp: drgn.Object) -> int:
if BP_IS_EMBEDDED(bp):
return 0
return BF64_GET_SB(bp.blk_prop, 16, SPA_PSIZEBITS, SPA_MINBLOCKSHIFT, 1)


def BP_GET_COMPRESS(bp: drgn.Object) -> int:
return BF64_GET(bp.blk_prop, 32, SPA_COMPRESSBITS)


def BP_IS_EMBEDDED(bp: drgn.Object) -> bool:
return bool(BF64_GET(bp.blk_prop, 39, 1))


def BP_GET_CHECKSUM(bp: drgn.Object) -> int:
if BP_IS_EMBEDDED(bp):
return ZIO_CHECKSUM_OFF
return BF64_GET(bp.blk_prop, 40, 8)


def BP_GET_TYPE(bp: drgn.Object) -> int:
return BF64_GET(bp.blk_prop, 48, 8)


def BP_GET_LEVEL(bp: drgn.Object) -> int:
return BF64_GET(bp.blk_prop, 56, 5)


def BP_USES_CRYPT(bp: drgn.Object) -> bool:
return bool(BF64_GET(bp.blk_prop, 61, 1))


def BP_IS_ENCRYPTED(bp: drgn.Object) -> bool:
return (BP_USES_CRYPT(bp) and BP_GET_LEVEL(bp) <= 0 and
DMU_OT_IS_ENCRYPTED(BP_GET_TYPE(bp)))


def BP_IS_AUTHENTICATED(bp: drgn.Object) -> bool:
return (BP_USES_CRYPT(bp) and BP_GET_LEVEL(bp) <= 0 and
not DMU_OT_IS_ENCRYPTED(BP_GET_TYPE(bp)))


def BP_HAS_INDIRECT_MAC_CKSUM(bp: drgn.Object) -> bool:
return (BP_USES_CRYPT(bp) and BP_GET_LEVEL(bp) > 0)


def BP_GET_DEDUP(bp: drgn.Object) -> bool:
return bool(BF64_GET(bp.blk_prop, 62, 1))


def BP_GET_BYTEORDER(bp: drgn.Object) -> int:
return BF64_GET(bp.blk_prop, 63, 1)


def BP_GET_LAYER(bp: drgn.Object) -> int:
if sdb.get_type('blkptr_t').has_member('blk_logical_birth'):
return BF64_GET(bp.blk_logical_birth, 56, 8)
return BF64_GET(bp.blk_birth, 56, 8)


def BP_LOGICAL_BIRTH(bp: drgn.Object) -> int:
if sdb.get_type('blkptr_t').has_member('blk_logical_birth'):
return BF64_GET(bp.blk_logical_birth, 0, 56)
return BF64_GET(bp.blk_birth, 0, 56)


def BP_PHYSICAL_BIRTH(bp: drgn.Object) -> int:
if sdb.get_type('blkptr_t').has_member('blk_physical_birth'):
return BF64_GET(bp.blk_physical_birth, 0, 56)
return BF64_GET(bp.blk_phys_birth, 0, 56)


def BP_GET_BIRTH(bp: drgn.Object) -> int:
if BP_IS_EMBEDDED(bp):
return 0
if BP_PHYSICAL_BIRTH(bp):
return BP_PHYSICAL_BIRTH(bp)
return BP_LOGICAL_BIRTH(bp)


def BP_GET_FILL(bp: drgn.Object) -> int:
if BP_IS_ENCRYPTED(bp):
return BF64_GET(bp.blk_fill, 0, 32)
if BP_IS_EMBEDDED(bp):
return 1
return int(bp.blk_fill)


def BP_GET_IV2(bp: drgn.Object) -> int:
return BF64_GET(bp.blk_fill, 32, 32)


def BP_IS_GANG(bp: drgn.Object) -> bool:
if BP_IS_EMBEDDED(bp):
return False
return bool(BF64_GET(bp.blk_dva[0].dva_word[1], 63, 1))


def BP_IS_REDACTED(bp: drgn.Object) -> bool:
return (BP_IS_EMBEDDED(bp) and
BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_REDACTED)


def BP_IS_HOLE(bp: drgn.Object) -> bool:
return (not BP_IS_EMBEDDED(bp) and DVA_IS_EMPTY(bp.blk_dva[0]))


def BP_GET_NDVAS(bp: drgn.Object) -> int:
if BP_IS_EMBEDDED(bp):
return 0
ndvas = 0
for d in range(0, 3):
ndvas += DVA_GET_ASIZE(bp.blk_dva[d]) != 0
return ndvas


def DVA_GET_ASIZE(dva: drgn.Object) -> int:
return BF64_GET_SB(dva.dva_word[0], 0, SPA_ASIZEBITS, SPA_MINBLOCKSHIFT, 0)


def DVA_GET_VDEV(dva: drgn.Object) -> int:
return BF64_GET(dva.dva_word[0], 32, SPA_VDEVBITS)


def DVA_GET_OFFSET(dva: drgn.Object) -> int:
return BF64_GET_SB(dva.dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0)


def DVA_IS_VALID(dva: drgn.Object) -> bool:
return DVA_GET_ASIZE(dva) != 0


def DVA_IS_EMPTY(dva: drgn.Object) -> bool:
return bool(dva.dva_word[0] == 0 and dva.dva_word[1] == 0)


def DMU_OT_IS_ENCRYPTED(ot: int) -> bool:
if ot & DMU_OT_NEWTYPE:
return bool(ot & DMU_OT_ENCRYPTED)
return bool(sdb.get_object("dmu_ot")[ot].ot_encrypt)


SPA_LSIZEBITS = 16
SPA_PSIZEBITS = 16
SPA_ASIZEBITS = 24
SPA_COMPRESSBITS = 7
SPA_VDEVBITS = 24
SPA_MINBLOCKSHIFT = 9

ZIO_CHECKSUM_OFF = 2

DMU_OT_ENCRYPTED = 0x20
DMU_OT_NEWTYPE = 0x80

BP_EMBEDDED_TYPE_DATA = 0
BP_EMBEDDED_TYPE_RESERVED = 1
BP_EMBEDDED_TYPE_REDACTED = 2

METASLAB_WEIGHT_PRIMARY = int(1 << 63)
METASLAB_WEIGHT_SECONDARY = int(1 << 62)
METASLAB_WEIGHT_CLAIM = int(1 << 61)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DVA[0]=<0:0x42083400:0x800>
DVA[1]=<0:0x20048000:0x800>
DVA[2]=<0:0x50002c00:0x800>
[L0 SPA space map] fletcher4 lz4 layer=0 unencrypted LE contiguous unique triple
size=0x20000L/0x400P birth=10L/10P fill=1
cksum=0x8c1caab0a6:0x45de629e8318:0x13bfbe391d06f8:0x41fc70c3e1d38f2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HOLE [L0 unallocated] size=0x200L birth=0x0L
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DVA[0]=<0:0x2cefd5e00:0x20000>
[L0 ZFS plain file] fletcher4 uncompressed layer=0 unencrypted LE contiguous unique single
size=0x20000L/0x20000P birth=1624L/1624P fill=1
cksum=0x3feb86d3fa14:0xff98411222361a1:0x7cd8eb3816d141e1:0x2d65ae38a67197c7
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DVA[0]=<0:0x80001e00:0x200>
DVA[1]=<0:0xa0001e00:0x200>
DVA[2]=<0:0x10000da00:0x200>
[L0 DMU objset] fletcher4 lz4 layer=0 unencrypted LE contiguous unique triple
size=0x1000L/0x200P birth=609L/609P fill=67
cksum=0x98a43f544:0x3eab35f140c:0xd164e4328324:0x1da8f37ef09087
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DVA[0]=<0:0x50ad98800:0x600>
[L0 ZFS plain file] fletcher4 lzjb layer=0 unencrypted LE contiguous unique single
size=0xa00L/0x600P birth=691L/691P fill=1
cksum=0x50b2435bac:0x4877d83d80e7:0x259e03cbed157d:0xe4d625e1f14d8cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DVA[0]=<0:0xe01bd200:0x2e00>
[L0 ZFS plain file] fletcher4 lzjb layer=0 unencrypted LE contiguous unique single
size=0x8e00L/0x2e00P birth=25L/25P fill=1
cksum=0x2b4705c4d19:0xe6eacc837fede:0x3376b31cb9e47ade:0x6759b6b5446e1229
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DVA[0]=<0:0x103207c00:0x2e00>
[L0 ZFS plain file] fletcher4 lz4 layer=0 unencrypted LE contiguous unique single
size=0x20000L/0x2e00P birth=1197L/1197P fill=1
cksum=0x5df05f0e3e3:0x229afb5d03e237:0x83ffb2e325a9e23a:0xbed1657fea4bbdb8
Loading

0 comments on commit 01017b0

Please sign in to comment.