From 7a2b5107e87fedc3023f3272e650d26944f7c8e9 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Tue, 19 Mar 2024 04:44:42 +0000 Subject: [PATCH 1/5] block: support req op with type enum req_op Support new requet op type which was introduced by this commit: commit ff07a02e9e8e("treewide: Rename enum req_opf into enum req_op") Also just dump cmd_flags in binary mode if no enum type was used with it. Signed-off-by: Junxiao Bi --- drgn_tools/block.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drgn_tools/block.py b/drgn_tools/block.py index 00a3f36e..6868d619 100644 --- a/drgn_tools/block.py +++ b/drgn_tools/block.py @@ -278,9 +278,9 @@ def rq_op_ef295ecf(rq: Object) -> str: # rq.cmf_flags: 8 bits for encoding the operation, and the remaining 24 for flags REQ_OP_BITS = 8 op_mask = (1 << REQ_OP_BITS) - 1 - req_opf = { - value: name for (name, value) in prog.type("enum req_opf").enumerators - } + # commit ff07a02e9e8e6("treewide: Rename enum req_opf into enum req_op") + opf = "enum req_op" if type_exists(prog, "enum req_op") else "enum req_opf" + req_opf = {value: name for (name, value) in prog.type(opf).enumerators} cmd_flags = rq.cmd_flags.value_() key = cmd_flags & op_mask op = req_opf[key] if key in req_opf.keys() else "%s-%d" % ("UNKOP", key) @@ -318,12 +318,12 @@ def rq_op(rq: Object) -> str: :returns: combined request operation enum name as str """ prog = rq.prog_ - if type_exists(prog, "enum req_opf"): + if type_exists(prog, "enum req_opf") or type_exists(prog, "enum req_op"): return rq_op_ef295ecf(rq) elif type_exists(prog, "enum rq_flag_bits"): return rq_op_old(rq) else: - return "-" + return bin(rq.cmd_flags) def rq_flags(rq: Object) -> str: From 903945b36fcb1eb770d2d230b85bfe9a883845a6 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Tue, 19 Mar 2024 05:03:13 +0000 Subject: [PATCH 2/5] block: fix request target when RQF_IO_STAT is not set rq.part is set only when doing IO statistics, if RQF_IO_STAT is not set for the request, we got the target disk by scanning all disks to match request_queue. Signed-off-by: Junxiao Bi --- drgn_tools/block.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drgn_tools/block.py b/drgn_tools/block.py index 6868d619..3c75f24a 100644 --- a/drgn_tools/block.py +++ b/drgn_tools/block.py @@ -427,7 +427,14 @@ def request_target(rq: Object) -> Object: if has_member(rq, "rq_disk"): return rq.rq_disk else: - return rq.part.bd_disk + # rq.part not null only when doing IO statistics. + if rq.part.value_(): + return rq.part.bd_disk + else: + for _ in for_each_disk(rq.prog_): + if _.queue.value_() == rq.q.value_(): + return _.queue + return None def dump_inflight_io(prog: drgn.Program, diskname: str = "all") -> None: From 14dac4d5dfea8e7c13ea61746dfebd604a9741d4 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Tue, 19 Mar 2024 05:09:47 +0000 Subject: [PATCH 3/5] block: dump pending io that not yet dispatched from static_rqs Since commit 568f27006577("blk-mq: centralise related handling into blk_mq_get_driver_tag") was merged in v5.10, for requests that are not yet dispatched, like those in the plug list, we should get from "tags.static_rqs", otherwise we may get a wrong request. To resolve this, first check request from "tags.rqs" is valid or not, if not get it from "tags.static_rqs". Signed-off-by: Junxiao Bi --- drgn_tools/block.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drgn_tools/block.py b/drgn_tools/block.py index 3c75f24a..2ba14a02 100644 --- a/drgn_tools/block.py +++ b/drgn_tools/block.py @@ -215,7 +215,19 @@ def for_each_tag_pending_rq(tags: Object) -> Iterable[Object]: addr = tags.rqs[tag + reserved].value_() if addr == 0: continue - yield Object(prog, "struct request *", value=addr) + # Since commit 568f27006577("blk-mq: centralise related handling + # into blk_mq_get_driver_tag") was merged in v5.10, for requests + # that are not yet dispatched, like those in the plug list, we + # should get from "tags.static_rqs", otherwise we may get a wrong + # request. To resolve this, first check request from "tags.rqs" + # is valid or not, if not get it from "tags.static_rqs". + rq = Object(prog, "struct request *", value=addr) + if rq.tag == -1: + addr = tags.static_rqs[tag + reserved].value_() + if addr == 0: + continue + rq = Object(prog, "struct request *", value=addr) + yield rq def for_each_hwq_pending_rq(hwq: Object) -> Iterable[Object]: From cc2544e6a1318abbac016bc3fc6ba092e2b25e4f Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Tue, 19 Mar 2024 05:28:36 +0000 Subject: [PATCH 4/5] md: support mddev.active_io in percpu_ref type commit 72adae23a72c("md: Change active_io to percpu") which was introduced by v6.3 changed mddev.active_io from type atomic_t to percpu_ref. Signed-off-by: Junxiao Bi --- drgn_tools/md.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drgn_tools/md.py b/drgn_tools/md.py index 6a8f9f9e..c3a7f006 100644 --- a/drgn_tools/md.py +++ b/drgn_tools/md.py @@ -8,6 +8,7 @@ from drgn import Object from drgn import Program +from drgn import TypeKind from drgn.helpers.linux.list import list_for_each_entry from drgn_tools.block import blkdev_ro @@ -334,7 +335,15 @@ def show_md(prog: Program) -> None: mddev.suspend_hi, ) ) - print("%-10s: %d processes" % ("IO-issuing", mddev.active_io.counter)) + # commit 72adae23a72c("md: Change active_io to percpu") + if ( + mddev.active_io.type_.kind == TypeKind.STRUCT + and mddev.active_io.type_.tag == "percpu_ref" + ): + count = percpu_ref_sum(prog, mddev.active_io) + else: + count = mddev.active_io.counter + print("%-10s: %d processes" % ("IO-issuing", count)) print( "%10s: %-8s %-4s %-20s %-8s %-10s %-8s" % ( From 98b542f143d9137fc730e674c84224e9e1488323 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Wed, 27 Mar 2024 21:54:30 +0000 Subject: [PATCH 5/5] block: show cpu that request was issued from There were bugs which caused some inflight io requests was not drained when offline cpu. Add cpu filed in the output to show that. Signed-off-by: Junxiao Bi --- drgn_tools/block.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drgn_tools/block.py b/drgn_tools/block.py index 2ba14a02..47589dfc 100644 --- a/drgn_tools/block.py +++ b/drgn_tools/block.py @@ -15,6 +15,7 @@ from drgn import TypeKind from drgn.helpers.common.format import decode_enum_type_flags from drgn.helpers.linux.block import for_each_disk +from drgn.helpers.linux.cpumask import for_each_online_cpu from drgn.helpers.linux.list import list_for_each_entry from drgn.helpers.linux.xarray import xa_for_each @@ -449,6 +450,26 @@ def request_target(rq: Object) -> Object: return None +def show_rq_issued_cpu(rq: Object) -> str: + """ + Get the cpu that request was issued from, if cpu is offline, + it will be marked in the output with "offline". For sq, "-" + will be returned. + + :param rq: ``struct request *`` + :returns: str combining cpu number and offline status for mq, + '-' for sq. + """ + if has_member(rq, "mq_ctx") and rq.mq_ctx: + cpu = int(rq.mq_ctx.cpu) + else: + return "-" + if cpu not in for_each_online_cpu(rq.prog_): + return "%d(offline)" % cpu + else: + return str(cpu) + + def dump_inflight_io(prog: drgn.Program, diskname: str = "all") -> None: """ Dump all inflight io from all disks @@ -457,11 +478,12 @@ def dump_inflight_io(prog: drgn.Program, diskname: str = "all") -> None: :param diskname: name of some disk or "all" for all disks. """ print( - "%-20s %-20s %-20s %-16s\n%-20s %-20s %-20s %-16s" + "%-20s %-20s %-20s %-16s %-16s\n%-20s %-20s %-20s %-16s" % ( "device", "hwq", "request", + "cpu", "op", "flags", "offset", @@ -494,11 +516,12 @@ def dump_inflight_io(prog: drgn.Program, diskname: str = "all") -> None: ).value_() != disk.value_(): continue print( - "%-20s %-20lx %-20lx %-16s\n%-20s %-20d %-20d %-16s" + "%-20s %-20lx %-20lx %-16s %-16s\n%-20s %-20d %-20d %-16s" % ( name, hwq_ptr, rq_ptr, + show_rq_issued_cpu(rq), rq_op(rq), rq_flags(rq), rq.__sector, @@ -512,11 +535,12 @@ def dump_inflight_io(prog: drgn.Program, diskname: str = "all") -> None: ] for rq_ptr, rq in sq_pending: print( - "%-20s %-20s %-20lx %-16s\n%-20s %-20d %-20d %-16s" + "%-20s %-20s %-20lx %-16s %-16s\n%-20s %-20d %-20d %-16s" % ( name, "-", rq_ptr, + "-", rq_op(rq), rq_flags(rq), rq.__sector,