12
12
from drgn import FaultError
13
13
from drgn import Object
14
14
from drgn import Program
15
+ from drgn import sizeof
15
16
from drgn .helpers .linux .block import _class_to_subsys
16
17
from drgn .helpers .linux .block import for_each_disk
17
18
from drgn .helpers .linux .list import list_for_each_entry
18
19
20
+ from drgn_tools .block import for_each_mq_pending_request
21
+ from drgn_tools .block import for_each_sq_pending_request
19
22
from drgn_tools .corelens import CorelensModule
20
23
from drgn_tools .module import ensure_debuginfo
21
24
from drgn_tools .table import print_table
22
25
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
31
27
32
28
33
29
def for_each_scsi_host (prog : Program ) -> Iterator [Object ]:
@@ -79,7 +75,45 @@ def for_each_scsi_host_device(shost: Object) -> Iterator[Object]:
79
75
yield scsi_dev
80
76
81
77
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 :
83
117
"""
84
118
Get the device name associated with scsi_device.
85
119
:return ``str``
@@ -92,21 +126,6 @@ def scsi_device_name(prog: Program, sdev: Object) -> str:
92
126
return ""
93
127
94
128
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
-
110
129
def scsi_id (scsi_dev : Object ) -> str :
111
130
"""
112
131
Return Host:Controller:Target:Lun as a string.
@@ -241,20 +260,12 @@ def print_shost_devs(prog: Program) -> None:
241
260
]
242
261
243
262
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
-
252
263
vendor = scsi_dev .vendor .string_ ().decode ()
253
264
devstate = str (scsi_dev .sdev_state .format_ (type_name = False ))
254
265
255
266
output .append (
256
267
[
257
- str ( diskname ),
268
+ scsi_device_name ( scsi_dev ),
258
269
scsi_id (scsi_dev ),
259
270
hex (scsi_dev ),
260
271
str (vendor ),
@@ -267,6 +278,90 @@ def print_shost_devs(prog: Program) -> None:
267
278
print_table (output )
268
279
269
280
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 \t SCSI Device Addr : { hex (scsi_device .value_ ())} " )
316
+ print (f" Vendor : { vendor } \t Device 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
+
270
365
class ScsiInfo (CorelensModule ):
271
366
"""
272
367
Corelens Module for scsi device information
@@ -280,6 +375,7 @@ class ScsiInfo(CorelensModule):
280
375
[
281
376
"--hosts" ,
282
377
"--devices" ,
378
+ "--queue" ,
283
379
]
284
380
]
285
381
@@ -294,10 +390,16 @@ def add_args(self, parser: argparse.ArgumentParser) -> None:
294
390
action = "store_true" ,
295
391
help = "Print Scsi Devices" ,
296
392
)
393
+ parser .add_argument (
394
+ "--queue" ,
395
+ action = "store_true" ,
396
+ help = "Print Inflight SCSI commands" ,
397
+ )
297
398
298
399
def run (self , prog : Program , args : argparse .Namespace ) -> None :
299
400
if args .hosts :
300
401
print_scsi_hosts (prog )
301
402
if args .devices :
302
- load_gendisk (prog )
303
403
print_shost_devs (prog )
404
+ if args .queue :
405
+ print_scsi_cmnds (prog )
0 commit comments