Hi, Kazu
Thank you for the fix.
On Wed, Jun 15, 2022 at 8:00 PM <[email protected]> wrote:

> Date: Wed, 15 Jun 2022 01:50:13 +0000
> From: HAGIO KAZUHITO(?????)  <[email protected]>
> To: "[email protected]" <[email protected]>,
>         "[email protected]" <[email protected]>
> Subject: [Crash-utility] [PATCH] Fix for "dev" command on Linux 5.11
>         and later
> Message-ID: <[email protected]>
> Content-Type: text/plain; charset="iso-2022-jp"
>
> The following kernel commits eventually removed the bdev_map array in
> Linux v5.11 kernel:
>
>   e418de3abcda ("block: switch gendisk lookup to a simple xarray")
>   22ae8ce8b892 ("block: simplify bdev/disk lookup in blkdev_get")
>
> Without the patch, the "dev" command fails to dump block device data
> with the following error:
>
>   crash> dev
>   ...
>   dev: blkdevs or all_bdevs: symbols do not exist
>
> To get block device's gendisk, search blockdev_superblock.s_inodes
> instead of bdev_map.
>
> Signed-off-by: Kazuhito Hagio <[email protected]>
> ---
>  dev.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 71 insertions(+), 5 deletions(-)
>
> diff --git a/dev.c b/dev.c
> index db97f8aebdc2..238dfe0fbe3c 100644
> --- a/dev.c
> +++ b/dev.c
> @@ -24,6 +24,7 @@ static void dump_blkdevs_v2(ulong);
>  static void dump_blkdevs_v3(ulong);
>  static ulong search_cdev_map_probes(char *, int, int, ulong *);
>  static ulong search_bdev_map_probes(char *, int, int, ulong *);
> +static ulong search_blockdev_inodes(int, ulong *);
>

It could be good to be consistent with the above function name, I would
suggest renaming
the "search_blockdev_inodes()" to "search_sb_inodes()".

 static void do_pci(void);
>  static void do_pci2(void);
>  static void do_io(void);
> @@ -493,9 +494,10 @@ dump_blkdevs(ulong flags)
>                  ulong ops;
>          } blkdevs[MAX_DEV], *bp;
>
> -       if (kernel_symbol_exists("major_names") &&
> -           kernel_symbol_exists("bdev_map")) {
> -                dump_blkdevs_v3(flags);
> +       if (kernel_symbol_exists("major_names") &&
> +           (kernel_symbol_exists("bdev_map") ||
> +            kernel_symbol_exists("blockdev_superblock"))) {
> +               dump_blkdevs_v3(flags);
>                 return;
>         }
>
> @@ -717,6 +719,7 @@ dump_blkdevs_v3(ulong flags)
>         char buf[BUFSIZE];
>         uint major;
>         ulong gendisk, addr, fops;
> +       int use_bdev_map = kernel_symbol_exists("bdev_map");
>
>         if (!(len = get_array_length("major_names", NULL, 0)))
>                 len = MAX_DEV;
> @@ -745,8 +748,11 @@ dump_blkdevs_v3(ulong flags)
>                 strncpy(buf, blk_major_name_buf +
>                         OFFSET(blk_major_name_name), 16);
>
> -               fops = search_bdev_map_probes(buf, major == i ? major : i,
> -                       UNUSED, &gendisk);
> +               if (use_bdev_map)
> +                       fops = search_bdev_map_probes(buf, major == i ?
> major : i,
> +                               UNUSED, &gendisk);
> +               else /* v5.11 and later */
> +                       fops = search_blockdev_inodes(major, &gendisk);
>
>                 if (CRASHDEBUG(1))
>                         fprintf(fp, "blk_major_name: %lx block major: %d
> name: %s gendisk: %lx fops: %lx\n",
> @@ -829,6 +835,66 @@ search_bdev_map_probes(char *name, int major, int
> minor, ulong *gendisk)
>         return fops;
>  }
>
> +/* For bdev_inode.  See block/bdev.c */
> +#define I_BDEV(inode) (inode - SIZE(block_device))
> +
>

Good understanding, this is equivalent to the contain_of().

+static ulong
> +search_blockdev_inodes(int major, ulong *gendisk)
> +{
> +       struct list_data list_data, *ld;
> +       ulong addr, bd_sb, disk, fops = 0;
> +       int i, inode_count, gendisk_major;
> +       char *gendisk_buf;
> +
> +       ld = &list_data;
> +       BZERO(ld, sizeof(struct list_data));
> +
> +       get_symbol_data("blockdev_superblock", sizeof(void *), &bd_sb);
> +
> +       addr = bd_sb + OFFSET(super_block_s_inodes);
> +       if (!readmem(addr, KVADDR, &ld->start, sizeof(ulong),
> +           "blockdev_superblock.s_inodes", QUIET|RETURN_ON_ERROR))
> +               return 0;
> +
> +       if (empty_list(ld->start))
> +               return 0;
> +
> +       ld->flags |= LIST_ALLOCATE;
> +       ld->end = bd_sb + OFFSET(super_block_s_inodes);
> +       ld->list_head_offset = OFFSET(inode_i_sb_list);
> +
> +       inode_count = do_list(ld);
> +
> +       gendisk_buf = GETBUF(SIZE(gendisk));
> +
> +       for (i = 0; i < inode_count; i++) {
> +               addr = I_BDEV(ld->list_ptr[i]) +
> OFFSET(block_device_bd_disk);
> +               if (!readmem(addr, KVADDR, &disk, sizeof(ulong),
> +                   "block_device.bd_disk", QUIET|RETURN_ON_ERROR))
> +                       continue;
> +
> +               if (!disk)
> +                       continue;
> +
> +               if (!readmem(disk, KVADDR, gendisk_buf, SIZE(gendisk),
> +                   "gendisk buffer", QUIET|RETURN_ON_ERROR))
> +                       continue;
> +
> +               gendisk_major = INT(gendisk_buf + OFFSET(gendisk_major));
> +               if (gendisk_major != major)
> +                       continue;
> +
> +               fops = ULONG(gendisk_buf + OFFSET(gendisk_fops));
> +               if (fops) {
> +                       *gendisk = disk;
> +                       break;
> +               }
> +       }
> +
>

Because the ld->flags is set to LIST_ALLOCATE,  here need to free it as
below:
FREEBUF(ld->list_ptr);

Thanks.
Lianbo

+       FREEBUF(gendisk_buf);
> +       return fops;
> +}
> +
>  void
>  dump_dev_table(void)
>  {
> --
> 2.31.1
>
--
Crash-utility mailing list
[email protected]
https://listman.redhat.com/mailman/listinfo/crash-utility
Contribution Guidelines: https://github.com/crash-utility/crash/wiki

Reply via email to