crashコマンドの使い方(file_systems編)

以前super_blockからNFS情報を取得する方法を書きました。
Linuxではさまざまな種類のファイルシステムを扱うことができ、それぞれのオブジェクトが必要となります。このオブジェクトがfile_system_typeという構造体であり、file_systemsというグローバル変数です。
そこで今回は、file_systemsからどんな情報が取れるかcrashコマンドを使って説明したいと思います。

初めに、file_systemsから、file_system_typeの一覧を表示してみます。手順は、listコマンドを使ってfile_system_type.nextを順番に辿っていきます。

crash> p file_systems
file_systems = $1 = (struct file_system_type *) 0xffffffff819f95c0 <sysfs_fs_type>
crash> struct -o file_system_type
struct file_system_type {
   [0x0] const char *name;
   [0x8] int fs_flags;
         struct dentry *(*mount)(struct file_system_type *, int, const char *, void *);
  [0x18] void (*kill_sb)(struct super_block *);
  [0x20] struct module *owner;
  [0x28] struct file_system_type *next;
...
crash> list file_system_type.next 0xffffffff819f95c0 -s file_system_type.name
ffffffff819f95c0
  name = 0xffffffff818b3596 "sysfs"
ffffffff819fa000
  name = 0xffffffff81897bf5 "rootfs"
...
  name = 0xffffffffa026a1c4 "xfs"
ffffffffa0331b80
  name = 0xffffffffa0328be0 "rpc_pipefs"
ffffffffa03839c0
  name = 0xffffffffa037fae0 "nfsd"
ffffffffa05ea1e0
  name = 0xffffffffa05e4e47 "nfs"
ffffffffa05ea160
  name = 0xffffffffa05e4e42 "nfs4"
crash> 

ここでは、nfs4を例にして、file_system_typeの値を表示してみます。

crash> file_system_type 0xffffffffa05ea160
struct file_system_type {
  name = 0xffffffffa05e4e42 "nfs4", 
  fs_flags = 0x8002, 
  mount = 0xffffffffa05ce030 <nfs_fs_mount>, 
  kill_sb = 0xffffffffa05cd870 <nfs_kill_super>, 
  owner = 0xffffffffa05edbe0 <__this_module>, 
  next = 0x0, 
  fs_supers = {
    first = 0xffff880035a83138
  }, 
 ...
}

file_system_typeの構造体を確認すると、fs_supersは次のように定義されています。

include/linux/fs.h:
...
struct file_system_type {
        const char *name;
        int fs_flags;
...
        struct dentry *(*mount) (struct file_system_type *, int,
                       const char *, void *);
        void (*kill_sb) (struct super_block *);
        struct module *owner;
        struct file_system_type * next;
        struct hlist_head fs_supers;

また、hlist_headが何かを確認し、hlist_nodeの値も取得してみます。

crash> whatis hlist_head
struct hlist_head {
    struct hlist_node *first;
}
SIZE: 0x8
crash> whatis hlist_node
struct hlist_node {
    struct hlist_node *next;
    struct hlist_node **pprev;
}
SIZE: 0x10
crash> hlist_node 0xffff880035a83138
struct hlist_node {
  next = 0x0, 
  pprev = 0xffffffffa05ea190 <nfs4_fs_type+48>
}

このfs_supersは、super_blockのs_instancesに登録されているので、super_blockを参照しても確認できます。

fs/super.c:
...
struct super_block *sget(struct file_system_type *type,
                        int (*test)(struct super_block *,void *),
                        int (*set)(struct super_block *,void *),
                        int flags,
                        void *data)
{
        struct super_block *s = NULL;
...
        s->s_type = type;
        strlcpy(s->s_id, type->name, sizeof(s->s_id));
        list_add_tail(&s->s_list, &super_blocks);
        hlist_add_head(&s->s_instances, &type->fs_supers);

では、マウントされている状況で確認してみます。

crash>  mount
     MOUNT           SUPERBLK     TYPE   DEVNAME   DIRNAME
ffff88007d12e100 ffff88007c771000 rootfs rootfs    /         
ffff88007ac57700 ffff88007c220800 sysfs  sysfs     /sys      
...
ffff88007b817200 ffff880035a83000 nfs4   192.168.122.135:/tmp /mnt      
crash> 

crash> super_block ffff880035a83000
struct super_block {
  s_list = {
    next = 0xffffffff819ea610 <super_blocks>, 
    prev = 0xffff8800799d1000
  }, 
...
  s_mtd = 0x0, 
  s_instances = {
    next = 0x0, 
    pprev = 0xffffffffa05ea190
  }, 

file_system_typeのfs_supersでもsuper_blockのs_instancesでも「0xffffffffa05ea190」が確認できたので、繋がりがあることがわかります。
図にすると、このような関係性になります。
f:id:shinji629:20181213143352p:plain