Hi, Kazu
Thank you for the fix.
On Wed, Jun 15, 2022 at 8:00 PM <crash-utility-request(a)redhat.com> wrote:
 Date: Wed, 15 Jun 2022 01:50:13 +0000
 From: HAGIO KAZUHITO(?????)  <k-hagio-ab(a)nec.com>
 To: "lijiang(a)redhat.com" <lijiang(a)redhat.com>,
         "crash-utility(a)redhat.com" <crash-utility(a)redhat.com>
 Subject: [Crash-utility] [PATCH] Fix for "dev" command on Linux 5.11
         and later
 Message-ID: <1655257808-3245-1-git-send-email-k-hagio-ab(a)nec.com>
 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 <k-hagio-ab(a)nec.com>
 ---
  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