Skip to content

Commit 75bdd69

Browse files
committed
Added SCSI inflight commands, removed hash_map and fix bugs.
Signed-off-by: Rajan Shanmugavelu <[email protected]
1 parent fe64b49 commit 75bdd69

File tree

2 files changed

+137
-35
lines changed

2 files changed

+137
-35
lines changed

drgn_tools/iscsi.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def print_iscsi_sessions(prog: Program) -> None:
122122
)
123123

124124
for scsi_dev in for_each_scsi_host_device(prog):
125-
name = scsi_device_name(prog, scsi_dev)
125+
name = scsi_device_name(scsi_dev)
126126
print(
127127
"scsi{} Channel {} Id {} Lun: {}".format(
128128
session.host.host_no.value_(),

drgn_tools/scsi.py

+136-34
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,18 @@
1212
from drgn import FaultError
1313
from drgn import Object
1414
from drgn import Program
15+
from drgn import sizeof
1516
from drgn.helpers.linux.block import _class_to_subsys
1617
from drgn.helpers.linux.block import for_each_disk
1718
from drgn.helpers.linux.list import list_for_each_entry
1819

20+
from drgn_tools.block import for_each_mq_pending_request
21+
from drgn_tools.block import for_each_sq_pending_request
1922
from drgn_tools.corelens import CorelensModule
2023
from drgn_tools.module import ensure_debuginfo
2124
from drgn_tools.table import print_table
2225
from drgn_tools.util import has_member
23-
24-
25-
"""
26-
Dictionary of gendisks being used as hashmap with request_queue address as the key,
27-
this is need to lookup the disk names for UEK6 or older kernel where gendisk is not
28-
part of the request_queue structure.
29-
"""
30-
gendisk_map = {}
26+
from drgn_tools.util import timestamp_str
3127

3228

3329
def for_each_scsi_host(prog: Program) -> Iterator[Object]:
@@ -79,7 +75,45 @@ def for_each_scsi_host_device(shost: Object) -> Iterator[Object]:
7975
yield scsi_dev
8076

8177

82-
def scsi_device_name(prog: Program, sdev: Object) -> str:
78+
def for_each_scsi_cmnd(prog: Program, scsi_disk: Object) -> Iterator[Object]:
79+
"""
80+
Iterates thru all scsi commands for a given scsi device.
81+
Return each scsi_cmnd for a given scsi device.
82+
"""
83+
rq = scsi_disk.queue
84+
if has_member(rq, "mq_ops") and rq.mq_ops:
85+
for scmnd in for_each_scsi_cmd_mq(prog, rq):
86+
yield scmnd
87+
else:
88+
for scmnd in for_each_scsi_cmd_sq(prog, rq):
89+
yield scmnd
90+
91+
92+
def for_each_scsi_cmd_sq(prog: Program, requestq: Object) -> Iterator[Object]:
93+
"""
94+
Iterates thru all SCSI commands from the block layer pending requests.
95+
Return each scsi_command
96+
"""
97+
for rq in for_each_sq_pending_request(requestq):
98+
scmnd = rq.value_() + sizeof(prog.type("struct request"))
99+
if scmnd == 0:
100+
continue
101+
yield Object(prog, "struct scsi_cmnd *", value=scmnd)
102+
103+
104+
def for_each_scsi_cmd_mq(prog: Program, requestq: Object):
105+
"""
106+
Iterates thru all SCSI commands in all multi hardware queue.
107+
Return each scsi_command
108+
"""
109+
for _, rq in for_each_mq_pending_request(requestq):
110+
scmnd = rq.value_() + sizeof(prog.type("struct request"))
111+
if scmnd == 0:
112+
continue
113+
yield Object(prog, "struct scsi_cmnd *", value=scmnd)
114+
115+
116+
def scsi_device_name(sdev: Object) -> str:
83117
"""
84118
Get the device name associated with scsi_device.
85119
:return ``str``
@@ -92,21 +126,6 @@ def scsi_device_name(prog: Program, sdev: Object) -> str:
92126
return ""
93127

94128

95-
def load_gendisk(prog: Program) -> None:
96-
"""
97-
This method loads the all the gendisk into the global hashmap.
98-
"""
99-
msg = ensure_debuginfo(prog, ["sd_mod"])
100-
if msg:
101-
print(msg)
102-
return
103-
104-
for disk in for_each_disk(prog):
105-
disk_rq = hex(disk.queue)
106-
gendisk_map[disk_rq] = disk
107-
return
108-
109-
110129
def scsi_id(scsi_dev: Object) -> str:
111130
"""
112131
Return Host:Controller:Target:Lun as a string.
@@ -241,20 +260,12 @@ def print_shost_devs(prog: Program) -> None:
241260
]
242261

243262
for scsi_dev in for_each_scsi_host_device(shost):
244-
if prog.type("struct request_queue").has_member("disk"):
245-
gendisk = cast("struct gendisk *", scsi_dev.request_queue.disk)
246-
if not gendisk:
247-
continue
248-
diskname = gendisk.disk_name.address_of_().string_().decode()
249-
else:
250-
diskname = gendisk_map[hex(scsi_dev.request_queue)].disk_name.string_().decode()
251-
252263
vendor = scsi_dev.vendor.string_().decode()
253264
devstate = str(scsi_dev.sdev_state.format_(type_name=False))
254265

255266
output.append(
256267
[
257-
str(diskname),
268+
scsi_device_name(scsi_dev),
258269
scsi_id(scsi_dev),
259270
hex(scsi_dev),
260271
str(vendor),
@@ -267,6 +278,90 @@ def print_shost_devs(prog: Program) -> None:
267278
print_table(output)
268279

269280

281+
def print_scsi_cmnds(prog: Program):
282+
283+
for disk in for_each_disk(prog):
284+
285+
counter = 0
286+
output = [
287+
[
288+
"Count",
289+
"Request",
290+
"Bio",
291+
"SCSI Cmnd",
292+
"Opcode",
293+
"Length",
294+
"Age",
295+
"Sector",
296+
]
297+
]
298+
299+
for scsi_cmnd in for_each_scsi_cmnd(prog, disk):
300+
301+
if not scsi_cmnd:
302+
continue
303+
304+
if counter == 0:
305+
scsi_disk = cast("struct scsi_disk *", disk.private_data)
306+
scsi_device = cast("struct scsi_device *", scsi_disk.device)
307+
if not scsi_disk or not scsi_device:
308+
continue
309+
310+
vendor = scsi_device.vendor.string_().decode()
311+
devstate = str(scsi_device.sdev_state.format_(type_name=False))
312+
diskname = disk.disk_name.string_().decode()
313+
scsiid = scsi_id(scsi_device)
314+
315+
print(f" Diskname : {diskname} {scsiid}\t\t\tSCSI Device Addr : {hex(scsi_device.value_())}")
316+
print(f" Vendor : {vendor} \tDevice State\t : {devstate}")
317+
print(
318+
"--------------------------------------------------"
319+
"-------------------------------------------------"
320+
)
321+
322+
if has_member(scsi_cmnd, "request"):
323+
req = scsi_cmnd.request
324+
else:
325+
reqp = scsi_cmnd.value_() - sizeof(prog.type("struct request"))
326+
req = Object(prog, "struct request *", value=reqp)
327+
328+
if scsi_cmnd.cmnd[0] == 0x2a or scsi_cmnd.cmnd[0] == 0x28:
329+
xfer_len = (scsi_cmnd.cmnd[7] << 8 | scsi_cmnd.cmnd[8]) \
330+
* scsi_cmnd.transfersize
331+
else:
332+
xfer_len = 0
333+
334+
if req.bio:
335+
if has_member(req.bio, "bi_sector"):
336+
sector = req.bio.bi_sector
337+
else:
338+
sector = req.bio.bi_iter.bi_sector
339+
340+
age = (prog["jiffies"] - scsi_cmnd.jiffies_at_alloc).value_() * 1000000
341+
counter += 1
342+
343+
output.append(
344+
[
345+
str(counter),
346+
hex(req.value_()),
347+
hex(req.bio.value_()),
348+
hex(scsi_cmnd.value_()),
349+
hex(scsi_cmnd.cmnd[0].value_()),
350+
str(int(xfer_len)),
351+
timestamp_str(age),
352+
str(int(sector)),
353+
]
354+
)
355+
356+
if len(output) > 1:
357+
print_table(output)
358+
print(
359+
"--------------------------------------------------"
360+
"-------------------------------------------------"
361+
)
362+
return
363+
364+
270365
class ScsiInfo(CorelensModule):
271366
"""
272367
Corelens Module for scsi device information
@@ -280,6 +375,7 @@ class ScsiInfo(CorelensModule):
280375
[
281376
"--hosts",
282377
"--devices",
378+
"--queue",
283379
]
284380
]
285381

@@ -294,10 +390,16 @@ def add_args(self, parser: argparse.ArgumentParser) -> None:
294390
action="store_true",
295391
help="Print Scsi Devices",
296392
)
393+
parser.add_argument(
394+
"--queue",
395+
action="store_true",
396+
help="Print Inflight SCSI commands",
397+
)
297398

298399
def run(self, prog: Program, args: argparse.Namespace) -> None:
299400
if args.hosts:
300401
print_scsi_hosts(prog)
301402
if args.devices:
302-
load_gendisk(prog)
303403
print_shost_devs(prog)
404+
if args.queue:
405+
print_scsi_cmnds(prog)

0 commit comments

Comments
 (0)