LeavaTailの日記

LeavaTailの日記

Linuxエンジニアを目指した技術者の備忘録

Linuxカーネルのファイルアクセスの処理を追いかける (1)

はじめに

一般的なOSはファイルという形式を通して、ハードディスクやフラッシュメモリといった記憶装置にデータを保存している。
この処理を担うのがファイルシステムと呼ばれる機構である。
一般的な利用者はこのことを意識せずに利用することができるが、ソフトウェアエンジニアは処理を理解していないとディスクIOパフォーマンスが悪化し、システム全体のパフォーマンスに大きく影響を及ぼす恐れがある。
そこで、アプリケーションがファイルを書き込んだ際にLinuxカーネルがどのような処理で記憶装置に読み書きされるかを順を追って説明する。

f:id:LeavaTail:20201122225232p:plain
調査範囲

本記事では、SYSCALL_DEFINE(write)からデバイスドライバまでの処理を対象とする。

変更履歴

背景

一般的なOSでは、さまざまなコンポーネントから成り立っている。ファイルシステムもその一つである。 ファイルの書き込み処理一つとっても、多数のコンポーネントとの関係を持つ。

下記の図は、他サイトで掲載されているLinuxカーネルv4.10の構成図である。(2020年12月現在、Linuxカーネルv5.10.1がリリースされている)

https://www.thomas-krenn.com/de/wikiDE/images/e/e0/Linux-storage-stack-diagram_v4.10.png

Reference: Linux Storage Stack Diagram

このように、Linuxカーネルv4.10の時点でもたくさんのフローからファイルアクセスが成り立っている。(大まかな処理は最新カーネルでも変わらないのでこの図を基に説明を続ける)
ここでは、read(2)とwrite(2)について説明する。
read(2)

  1. VFSは、ファイルに対応するファイルシステムのread処理を呼び出す。
  2. ファイルシステムは、ファイルがキャッシュに載っているか確認する。(あればそれをApplicationに渡して終了する)
  3. ファイルシステムは、Block LayerにBIOを挿入する。
  4. Block Layerは、スケジューラによりBIOを並び替る。
  5. Block Layerは、Device DriverにRequestを発行する。
  6. Device Driverは、Physical devicesにIOを要求する。
  7. Physical devicesは、デバイスファームウェアに則りデータの読み込みをする。
  8. Physical devicesは、カーネルにIO完了通知をする。
  9. (Direct_IOでなければ)カーネルは、読み込みしたデータをPage cacheとしてキャッシュする。
  10. カーネルは、Applicationにデータを渡して終了する。

write(2)

  1. VFSは、ファイルに対応するファイルシステムのwrite処理を呼び出す。
  2. (Direct_IOでなければ)ファイルシステムは、ファイルをキャッシュにしてApplicationに完了を通知する。
  3. ファイルシステムは、Block LayerにBIOを挿入する。
  4. Block Layerは、スケジューラによりBIOを並び替る。
  5. Block Layerは、Device DriverにRequestを発行する。
  6. Device Driverは、Physical devicesにIOを要求する。
  7. Physical devicesは、デバイスファームウェアに則りデータの書き込みをする。
  8. Physical devicesは、カーネルにIO完了通知をする。

このように、概要だけ記載してただけでもこれらを一から追うとなると多大な労力を要する。

一方でLinuxでは、各レイヤにおけるトレース機構が充実している。 本記事では、これらのトレースツールをうまく活用して、Linuxカーネルのファイルアクセスの処理(read/writeを対象とする)を追いかけることにする。

環境構成

本稿では、QEMUを用いて観測対象のLinuxカーネルを起動させる。 QEMUを利用することで、下記のような利点が得られる。

  • 実行環境による違いを緩和することができる
  • ホスト側から任意のタイミングでGDBでアタッチすることができる

ユーザランドの構築にはBuildrootを利用する。
BuildrootはツールチェインやルートファイルシステムLinuxカーネルなどを構築するツールであり、本稿でもこれを利用する。 Buildrootの使い方については、過去の記事に記載しているのでそちらを参考にしてほしい。

leavatail.hatenablog.com

以上を踏まえて、本稿では下記のソフトウェアを用いて処理を確認していく。

QEMUでは、Versatile Express motherboardとCoreTile Express A9x4 daughterboardの組み合わせをvexpress-a9というボードでサポートしている。 それぞれの機器のデータシートはArm Developerに記載されている。

下記は、Arm Developerで記載されている機器のレイアウト図を引用している。
こちらは、Versatile Express motherboardのレイアウト図である。

https://documentation-service.arm.com/static/5e9074b78259fe2368e2acd9?token=

こちらは、CoreTile Express A9x4 daughterboardのレイアウト図である。

https://documentation-service.arm.com/static/5e9db8569931941038de23df?token=

Reference: Documentation – Arm Developer

これらの情報とQEMUの公式サイトに書かれている情報を基に、vexpress-a9の概略図を示す。

f:id:LeavaTail:20210203234353p:plain
vexpress-a9のレイアウト イメージ図

また、Arm Developerなどに記載されているドキュメントを基にこのボードのメモリレイアウトを記す。

f:id:LeavaTail:20210221120656p:plain
ARM Memory Layout

上記の概略図はあくまで著者の理解であり、正確なものではないので注意していただきたい。
ここでは、SDRAMにロードされたinitramfsとSDに接続されているデバイス(調査対象のファイルシステムでフォーマットしておく)を使用して調査を進めていく。

作成手順

開発環境の構築にはBuildrootを用いる。 Buildrootの実行環境として下記のDocker Imageを使用した。 github.com

  1. Buildrootを入手する。

     leava@kbuild:/work$ wget https://git.busybox.net/buildroot/snapshot/buildroot-2020.08.tar.gz
     leava@kbuild:/work$ tar xf buildroot-2020.11.tar.gz
     leava@kbuild:/work$ cd buildroot-2020.11
    
  2. Buildrootのデフォルトの設定を使用する。

     leava@kbuild:/work/buildroot-2020.11$ make qemu_arm_vexpress_defconfig
    
  3. Buildrootの設定を適宜修正する。

     toolchain  --->
       (glibc) C library
       Kernel Headers (Same as kernel being built)  --->
       Custom kernel headers series (5.9.x or later)  --->
       [*] Enable C++ support
       [*] Build cross gdb for the host
         [*]   TUI support
    
     System configuration  --->  
       (root) Root password 
    
     Kernel   --->
       Kernel version (Custom version)  --->
       (5.10) Kernel version
    
     Target packages  --->
       Debugging, profiling and benchmark  --->
         [*] blktrace
         [*] ltrace  
         [*] strace   
         [*] trace-cmd  
       Development tools  --->
         [*] git  
       Filesystem and flash utilities  ---> 
         [*] cpio 
         [*] dosfstools 
           [ ]   fatlabel (NEW)
           [*]   fsck.fat
           [*]   mkfs.fat   
       Hardware handling  --->
          [*] hwloc  
          [*] iostat 
          [*] lshw    
          [*] lsscsi         
          [*] parted   
       Networking applications  --->   
         [*] dropbear 
       Interpreter languages and scripting  --->       
         [*] python3      
    
     Filesystem images  ---> 
       [*] cpio the root filesystem (for use as an initial RAM filesystem)    
    
     Host utilities  ---> 
       [*] host qemu 
          *** Emulators selection ***
         [*]   Enable system emulation
         [*]   Enable Linux user-land emulation
    
  4. Buildrootの設定からユーザランドを構築する。

     leava@kbuild:/work/buildroot-2020.11$ make
    
  5. QEMU用のスクリプトの末尾の行を下記のように修正する。 (-s-gdb tcp::1234と等価)

     exec   qemu-system-arm -M vexpress-a9 -smp 1 -m 256 -kernel ${IMAGE_DIR}/zImage -dtb ${IMAGE_DIR}/vexpress-v2p-ca9.dtb -initrd ${IMAGE_DIR}/rootfs.cpio -drive file=${IMAGE_DIR}/rootfs.ext2,if=sd,format=raw -append "console=ttyAMA0,115200 rootwait root=/dev/ram"  -net nic,model=lan9118 -net user -s ${EXTRA_ARGS}
    
  6. QEMU上でLinuxカーネルを起動する。

     leava@leava-host:/srv$ ./output/images/start-qemu.sh serial-only
    
  7. 別ウインドウからGDBで接続できるか確認する。

     leava2@leava-host:/srv/buildroot-2020.11/output/build/linux-5.10$ sudo ./output/host/bin/arm-buildroot-linux-gnueabihf-gdb ./output/build/linux-5.10.1/vmlinux 
     GNU gdb (GDB) 8.3.1
     Copyright (C) 2019 Free Software Foundation, Inc.
     License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
     This is free software: you are free to change and redistribute it.
     There is NO WARRANTY, to the extent permitted by law.
     Type "show copying" and "show warranty" for details.
     This GDB was configured as "--host=x86_64-pc-linux-gnu --target=arm-buildroot-linux-gnueabihf".
     Type "show configuration" for configuration details.
     For bug reporting instructions, please see:
     <http://www.gnu.org/software/gdb/bugs/>.
     Find the GDB manual and other documentation resources online at:
         <http://www.gnu.org/software/gdb/documentation/>.
    
     For help, type "help".
     Type "apropos word" to search for commands related to "word"...
     Reading symbols from vmlinux...
     (gdb) target remote :1234
     Remote debugging using :1234
     cpu_v7_do_idle () at arch/arm/mm/proc-v7.S:78
     78              ret     lr
     (gdb)         
    

調査方法

本記事では、上記の環境で下記のコマンドを実行した場合のファイルアクセスの処理を調査する。

# echo "DIRTY" >> /mnt/root/.ash_history 

この時、/mntmount -t ext2 /dev/mmcblk0 /mntによりマウントされているものとする。

まとめ

本記事では、これからLinuxカーネルのファイルアクセスの処理を追いかけるための環境構築をした。
次回の記事では、作成した環境を用いて「writeシステムコールの実態からVFSレイヤまで」の処理を追いかける。

参考