Skip to content

Commit 0aec3a9

Browse files
committed
Create a znode command for sdb. Also create znode2inode and
inode2znode commands. Signed-off-by: Paul Zuchowski <[email protected]>
1 parent 3e6c69a commit 0aec3a9

6 files changed

+184
-0
lines changed

sdb/commands/zfs/znode.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#
2+
# Copyright 2019 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+
import os
22+
import drgn
23+
from drgn.helpers.linux.fs import inode_path
24+
import sdb
25+
from sdb.target import type_canonicalize, get_prog
26+
from sdb.command import Command
27+
28+
29+
class Inode2znode(Command):
30+
"""
31+
Convert an inode to a znode and display it.
32+
33+
sdb> echo 0xffff9ca45647f588 | cast struct inode * | itoz
34+
ADDR OBJ UNLINKED BLKSZ SIZE ...
35+
0xffff9ca45647f398 2 0 29184 28772 ...
36+
"""
37+
38+
names = ["inode2znode", "i2z", "itoz"]
39+
40+
def _call(self, objs: Iterable[drgn.Object]) -> None:
41+
for obj in objs:
42+
obj_type = type_canonicalize(obj.type_)
43+
if obj_type.kind != drgn.TypeKind.POINTER:
44+
raise sdb.CommandError(
45+
self.name,
46+
f"'{obj.type_.type_name()}' is not a valid pointer type")
47+
obj = drgn.Object(get_prog(),
48+
type=obj.type_.type,
49+
address=obj.value_())
50+
znode = drgn.container_of(obj.address_of_(), 'struct znode',
51+
'z_inode')
52+
znodes = sdb.execute_pipeline([znode], [Znode()])
53+
Znode.pretty_print(znode, znodes)
54+
55+
56+
class Znode2inode(Command):
57+
"""
58+
Convert a znode to an inode and display it.
59+
60+
sdb> echo 0xffff9ca45647f398 | znode | ztoi
61+
ADDR INO MODE LINKS BLOCKS SB
62+
0xffff9ca45647f588 2 33184 1 1 0xffff9ca464ae8800
63+
64+
sdb> znode | znode2inode
65+
ADDR INO MODE LINKS BLOCKS SB
66+
0xffff9ca456478638 2 16877 2 1 0xffff9ca486819800
67+
0xffff9ca456478a80 34 16877 2 1 0xffff9ca464ae8800
68+
0xffff9ca456478ec8 -1 16895 1 0 0xffff9ca464ae8800
69+
0xffff9ca45647b108 3 33184 1 1 0xffff9ca464ae8800
70+
0xffff9ca45647b998 -1 16895 1 0 0xffff9ca486819800
71+
0xffff9ca45647c228 3 16877 2 1 0xffff9ca486819800
72+
0xffff9ca45647dbd8 34 16877 4 1 0xffff9ca486819800
73+
0xffff9ca45647e8b0 34 16877 2 1 0xffff9ca464aeb000
74+
0xffff9ca45647f588 2 33184 1 1 0xffff9ca464ae8800
75+
0xffff9ca45647f9d0 -1 16895 1 0 0xffff9ca464aeb000
76+
"""
77+
78+
names = ["znode2inode", "z2i", "ztoi"]
79+
80+
@staticmethod
81+
def inode_print(znode: drgn.Object) -> None:
82+
inode = znode.z_inode
83+
i = drgn.cast('int', znode.z_id)
84+
print("{:18} {:>8} {:>8} {:>8} {:>8} {:18}".format(
85+
hex(inode.address_), int(i), int(inode.i_mode), int(inode.i_nlink),
86+
int(inode.i_blocks), hex(int(inode.i_sb))))
87+
88+
def _call(self, objs: Iterable[drgn.Object]) -> None:
89+
print("{:18} {:>8} {:>8} {:>8} {:>8} {:18}".format(
90+
"ADDR", "INO", "MODE", "LINKS", "BLOCKS", "SB"))
91+
for obj in objs:
92+
obj_type = type_canonicalize(obj.type_)
93+
if obj_type.kind != drgn.TypeKind.POINTER:
94+
raise sdb.CommandError(
95+
self.name,
96+
f"'{obj.type_.type_name()}' is not a valid pointer type")
97+
obj = drgn.Object(get_prog(),
98+
type=obj.type_.type,
99+
address=obj.value_())
100+
self.inode_print(obj)
101+
102+
103+
class Znode(sdb.Locator, sdb.PrettyPrinter):
104+
"""
105+
Iterate and pretty-print znodes
106+
107+
DESCRIPTION
108+
109+
Iterate znodes or convert an address to a znode
110+
and display it.
111+
112+
sdb> znode
113+
ADDR OBJ UNLINKED BLKSZ SIZE ...
114+
0xffff9ca456478448 2 0 512 2 ...
115+
0xffff9ca456478890 34 0 512 6 ...
116+
0xffff9ca456478cd8 -1 0 0 0 ...
117+
0xffff9ca45647af18 3 0 29696 29257 ...
118+
0xffff9ca45647b7a8 -1 0 0 0 ...
119+
0xffff9ca45647c038 3 0 512 2 ...
120+
0xffff9ca45647d9e8 34 0 512 4 ...
121+
0xffff9ca45647e6c0 34 0 512 4 ...
122+
0xffff9ca45647f398 2 0 29184 28772 ...
123+
0xffff9ca45647f7e0 -1 0 0 0 ...
124+
125+
sdb> echo 0xffff9ca45647f398 | znode
126+
ADDR OBJ UNLINKED BLKSZ SIZE ...
127+
0xffff9ca45647f398 2 0 29184 28772 ...
128+
"""
129+
130+
names = ["znode"]
131+
input_type = "znode_t *"
132+
output_type = "znode_t *"
133+
134+
def pretty_print(self, objs: Iterable[drgn.Object]) -> None:
135+
print("{:18} {:>8} {:8} {:>8} {:>18} {:>18} {:>18} {:<18}".format(
136+
"ADDR", "OBJ", "UNLINKED", "BLKSZ", "SIZE", "INODE", "ZFSVFS", "FILENAME"))
137+
for znode in objs:
138+
i = drgn.cast('int', znode.z_id)
139+
inode = znode.z_inode
140+
ipath = inode_path(inode)
141+
fn = ""
142+
if ipath is not None:
143+
fn = os.fsdecode(ipath)
144+
print(
145+
"{:18} {:>8d} {:>8d} {:>8d} {:>18} {:>18} {:>18} {:<18}".format(
146+
hex(znode), int(i), int(znode.z_unlinked),
147+
int(znode.z_blksz), int(znode.z_size),
148+
hex(znode.z_inode.address_of_()),
149+
hex(znode.z_inode.i_sb.s_fs_info), str(fn)))
150+
151+
def no_input(self) -> drgn.Object:
152+
znode_cache = drgn.cast("spl_kmem_cache_t *",
153+
sdb.get_object("znode_cache"))
154+
znode_kmem = znode_cache.skc_linux_cache
155+
znodes = sdb.execute_pipeline(
156+
[znode_kmem],
157+
[sdb.Walk(), sdb.Cast(["znode_t *"])],
158+
)
159+
for znode in znodes:
160+
if znode.z_id != 0:
161+
yield znode
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ADDR OBJ UNLINKED BLKSZ SIZE INODE ZFSVFS FILENAME
2+
0xffffa08884646ec0 1032 0 1024 581 0xffffa088846470b8 0xffffa08953ea8000 etc/profile
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ADDR INO MODE LINKS BLOCKS SB
2+
0xffffa088846470b8 1032 33188 1 2 0xffffa08955983800
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ADDR OBJ UNLINKED BLKSZ SIZE INODE ZFSVFS FILENAME
2+
0xffffa08884646ec0 1032 0 1024 581 0xffffa088846470b8 0xffffa08953ea8000 etc/profile
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
ADDR OBJ UNLINKED BLKSZ SIZE INODE ZFSVFS FILENAME
2+
0xffffa08884644000 123 0 512 7 0xffffa088846441f8 0xffffa08953ea8000 etc/profile.d
3+
0xffffa08884644440 68902 0 512 298 0xffffa08884644638 0xffffa08953ea8000 usr/lib/systemd/user/gpg-agent-browser.socket
4+
0xffffa08884644880 68905 0 512 223 0xffffa08884644a78 0xffffa08953ea8000 usr/lib/systemd/user/gpg-agent.service
5+
0xffffa08884644cc0 68898 0 512 231 0xffffa08884644eb8 0xffffa08953ea8000 usr/lib/systemd/user/dirmngr.service
6+
0xffffa08884645100 1900 0 4096 3635 0xffffa088846452f8 0xffffa08953ea8000 etc/security/group.conf
7+
0xffffa08884645540 68904 0 512 308 0xffffa08884645738 0xffffa08953ea8000 usr/lib/systemd/user/gpg-agent-ssh.socket
8+
0xffffa08884645980 2037 0 512 96 0xffffa08884645b78 0xffffa08953ea8000 etc/profile.d/01-locale-fix.sh
9+
0xffffa08884645dc0 67553 0 512 27 0xffffa08884645fb8 0xffffa08953ea8000 usr/lib/systemd/user/sockets.target.wants/gpg-agent-browser.socket
10+
0xffffa08884646200 68899 0 512 204 0xffffa088846463f8 0xffffa08953ea8000 usr/lib/systemd/user/dirmngr.socket
11+
0xffffa08884646640 67554 0 512 25 0xffffa08884646838 0xffffa08953ea8000 usr/lib/systemd/user/sockets.target.wants/gpg-agent-extra.socket

tests/integration/test_zfs_generic.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@
6161
"spa data | vdev | metaslab | filter 'obj.ms_loaded == 1' | head 1 | member ms_sm.sm_phys.smp_histogram | zhist",
6262
"spa data | vdev | metaslab | filter 'obj.ms_loaded == 1' | head 1 | member ms_sm.sm_phys.smp_histogram | zhist 9",
6363
"spa data | vdev | metaslab | filter 'obj.ms_loaded == 1' | head 1 | member ms_allocatable.rt_histogram | zhist",
64+
65+
# znode
66+
"znode |head 10 |znode",
67+
"echo 0xffffa08884646ec0 | znode",
68+
"echo 0xffffa08884646ec0 | znode | znode2inode",
69+
"echo 0xffffa088846470b8 | cast struct inode * | inode2znode",
6470
] # yapf: disable
6571

6672

0 commit comments

Comments
 (0)