On Thu, May 26, 2022 at 3:55 PM HAGIO KAZUHITO(萩尾 一仁) <k-hagio-ab@nec.com> wrote:
On 2022/05/23 19:06, Lianbo Jiang wrote:
> Kernel commit 4e5cc99e1e48 ("blk-mq: manage hctx map via xarray") removed
> the "queue_hw_ctx" member from struct request_queue at Linux v5.18-rc1,
> and replaced it with a struct xarray "hctx_table".Without the patch,

more complex...

Totally agree. 

> the "dev -d|-D" options will print an error:
>
>    crash> dev -d
>    MAJOR GENDISK            NAME       REQUEST_QUEUE      TOTAL  READ WRITE
>
>    dev: invalid structure member offset: request_queue_queue_hw_ctx
>
> With the patch:
>    crash> dev -d
>    MAJOR GENDISK            NAME       REQUEST_QUEUE      TOTAL  READ WRITE
>        8 ffff8e99d0a1ae00   sda        ffff8e9c14c59980      10     6     4
>
> Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
> ---
>   defs.h    |  1 +
>   dev.c     | 44 ++++++++++++++++++++++++++++++++++----------
>   symbols.c |  2 ++
>   3 files changed, 37 insertions(+), 10 deletions(-)
>
> diff --git a/defs.h b/defs.h
> index c1626bc79d59..1e435ffe5535 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -2181,6 +2181,7 @@ struct offset_table {                    /* stash of commonly-used offsets */
>       long blk_mq_tags_nr_reserved_tags;
>       long blk_mq_tags_rqs;
>       long blk_mq_tags_static_rqs;
> +     long request_queue_hctx_table;
>   };
>   
>   struct size_table {         /* stash of commonly-used sizes */
> diff --git a/dev.c b/dev.c
> index 7e0b3d27888d..811414d93c94 100644
> --- a/dev.c
> +++ b/dev.c
> @@ -4406,24 +4406,46 @@ static void get_mq_diskio_from_hw_queues(ulong q, struct diskio *dio)
>       uint cnt = 0;
>       ulong addr = 0, hctx_addr = 0;
>       ulong *hctx_array = NULL;
> +     struct list_pair *lp = NULL;
>       struct diskio tmp = {0};
>   
> -     addr = q + OFFSET(request_queue_nr_hw_queues);
> -     readmem(addr, KVADDR, &cnt, sizeof(uint),
> -             "request_queue.nr_hw_queues", FAULT_ON_ERROR);
> +     if (MEMBER_EXISTS("request_queue", "hctx_table")) {

As MEMBER_OFFSET_INIT() was done, we can use VALID_MEMBER() macro,
which is faster than MEMBER_EXISTS(),

Right. Thanks.

Lianbo
 

Thanks,
Kazu

> +             addr = q + OFFSET(request_queue_hctx_table);
> +             cnt = do_xarray(addr, XARRAY_COUNT, NULL);
> +             lp = (struct list_pair *)GETBUF(sizeof(struct list_pair) * (cnt + 1));
> +             if (!lp)
> +                     error(FATAL, "fail to get memory for list_pair.\n");
> +             lp[0].index = cnt;
> +             cnt = do_xarray(addr, XARRAY_GATHER, lp);
> +     } else {
> +             addr = q + OFFSET(request_queue_nr_hw_queues);
> +             readmem(addr, KVADDR, &cnt, sizeof(uint),
> +                     "request_queue.nr_hw_queues", FAULT_ON_ERROR);
>   
> -     addr = q + OFFSET(request_queue_queue_hw_ctx);
> -     readmem(addr, KVADDR, &hctx_addr, sizeof(void *),
> -             "request_queue.queue_hw_ctx", FAULT_ON_ERROR);
> +             addr = q + OFFSET(request_queue_queue_hw_ctx);
> +             readmem(addr, KVADDR, &hctx_addr, sizeof(void *),
> +                     "request_queue.queue_hw_ctx", FAULT_ON_ERROR);
> +     }
>   
>       hctx_array = (ulong *)GETBUF(sizeof(void *) * cnt);
> -     if (!hctx_array)
> +     if (!hctx_array) {
> +             if (lp)
> +                     FREEBUF(lp);
>               error(FATAL, "fail to get memory for the hctx_array\n");
> +     }
> +
> +     if (lp && hctx_array) {
> +             uint i;
>   
> -     if (!readmem(hctx_addr, KVADDR, hctx_array, sizeof(void *) * cnt,
> +             /* copy it from list_pair to hctx_array */
> +             for (i = 0; i < cnt; i++) {
> +                     hctx_array[i] = (ulong)lp[i].value;
> +             }
> +             FREEBUF(lp);
> +     } else if (!readmem(hctx_addr, KVADDR, hctx_array, sizeof(void *) * cnt,
>                       "request_queue.queue_hw_ctx[]", RETURN_ON_ERROR)) {
> -             FREEBUF(hctx_array);
> -             return;
> +                     FREEBUF(hctx_array);
> +                     return;
>       }
>   
>       queue_for_each_hw_ctx(q, hctx_array, cnt, &tmp);
> @@ -4796,6 +4818,8 @@ void diskio_init(void)
>                       "request_queue", "queue_hw_ctx");
>               MEMBER_OFFSET_INIT(request_queue_nr_hw_queues,
>                       "request_queue", "nr_hw_queues");
> +             MEMBER_OFFSET_INIT(request_queue_hctx_table,
> +                     "request_queue", "hctx_table");
>               MEMBER_OFFSET_INIT(blk_mq_ctx_rq_dispatched, "blk_mq_ctx",
>                       "rq_dispatched");
>               MEMBER_OFFSET_INIT(blk_mq_ctx_rq_completed, "blk_mq_ctx",
> diff --git a/symbols.c b/symbols.c
> index c432469671a4..cc439e8eb636 100644
> --- a/symbols.c
> +++ b/symbols.c
> @@ -10401,6 +10401,8 @@ dump_offset_table(char *spec, ulong makestruct)
>               OFFSET(request_queue_queue_hw_ctx));
>       fprintf(fp, "       request_queue_nr_hw_queues: %ld\n",
>               OFFSET(request_queue_nr_hw_queues));
> +     fprintf(fp, "       request_queue_hctx_table: %ld\n",
> +             OFFSET(request_queue_hctx_table));
>       fprintf(fp, "      blk_mq_ctx_rq_dispatched: %ld\n",
>               OFFSET(blk_mq_ctx_rq_dispatched));
>       fprintf(fp, "       blk_mq_ctx_rq_completed: %ld\n",