Upgrade to Pro — share decks privately, control downloads, hide ads and more …

device mapperによるディスクI/O障害のエミュレーション

device mapperによるディスクI/O障害のエミュレーション

Linuxカーネルのdevice mapper機能を使ってブロックデバイスレベルでディスクI/O障害をエミュレーションをする方法について紹介しました。kernel/vm 北陸 part6で発表しました。
https://kernelvm.connpass.com/event/297033/?utm_campaign=event_participate_to_follower&utm_source=notifications&utm_medium=twitter

Satoru Takeuchi

December 02, 2023
Tweet

More Decks by Satoru Takeuchi

Other Decks in Technology

Transcript

  1. device mapperによる
    ディスクI/O障害のエミュレーション
    Kernel/VM探検隊@北陸 Part 6
    Dec, 2nd, 2023
    Satoru Takeuchi
    X: satoru_takeuchi
    1

    View full-size slide

  2. はじめに
    ● はなすこと
    ○ LinuxでディスクI/O障害をエミュレーションする方法を紹介
    ○ 自分で機能追加する方法も紹介
    ● 補足
    ○ ブロックデバイスレベルの障害にフォーカス
    ○ Ubuntu 22.04.3のカーネル(kernel 5.15.0-89-generic)を使って動作確認
    2

    View full-size slide

  3. もくじ
    ● ディスク障害について
    ● device mapper
    ● ディスク障害エミュレーション
    ● そして自作へ
    ● まとめ
    3

    View full-size slide

  4. もくじ
    ● ディスク障害について
    ● device mapper
    ● ディスク障害エミュレーション
    ● そして自作へ
    ● まとめ
    4

    View full-size slide

  5. ディスクは壊れる
    ● I/Oが遅延
    ● 特定セクタが壊れる
    ● ディスクが全く応答しない
    ● 書けたと言ったがそれは嘘だ
    ● 読めたと言ったがそれは嘘だ
    5
    disk
    俺をあまり信用しないほうがいい

    View full-size slide

  6. 壊れたときのためにエラー処理がある
    ● I/Oのリトライ
    ○ 一時的に起きてすぐ解消することもある
    ● データの冗長化
    ○ RAID、レプリケーション、erasure coding
    ● データの破壊検知、修復
    ● ユーザに対処を任せる
    6
    disk
    ソフトウェア
    何らかの異常
    対処
    理想
    ● I/Oが最終的に成功する
    ● I/Oが失敗を返して対処がゆだねられる

    View full-size slide

  7. エラー処理のテストは大変
    ● ディスクはテスト中に気を使って障害を起こしてくれたりしない
    ● うまくテストできなくてバグの温床になりがち
    7
    disk
    いつ壊れるかわからないぜ

    View full-size slide

  8. エラー処理のテストは大変
    ● ディスクはテスト中に気を使って障害を起こしてくれたりしない
    ● うまくテストできなくてバグの温床になりがち
    8
    disk
    ええっ、本当なのかい ?
    device mapperを作れば
    I/O障害をエミュレーションできるよ !

    View full-size slide

  9. もくじ
    ● ディスク障害について
    ● device mapper
    ● ディスク障害エミュレーション
    ● そして自作へ
    ● まとめ
    9

    View full-size slide

  10. device mapper
    ● ブロックデバイスに機能追加するためのLinuxカーネルの仕組み
    ○ ターゲット: device mapperの個々の機能
    ■ 暗号化、マルチパス化、ディスク障害エミュレーションなど
    ○ dmデバイス: device mapperによって作るブロックデバイス
    ● 基本はdmsetupコマンドで制御
    10
    /dev/sda
    /dev/mapper/
    書き込み
    書き込み+α 読み出し
    読み出し+α

    View full-size slide

  11. dmsetupのつかいかた(1/2)
    ● dmデバイスとマップ先デバイスを対応付けるテーブルを作る
    ● dmデバイスを作る
    11
    $ cat table.txt
    <開始セクタ> <終了セクタ> <ターゲット名> <マップ先デバイス> [<パラメタ
    >...]
    ...
    $ sudo dmsetup create <テーブルファイル>
    $ ls /dev/mapper/
    … …
    1セクタ=512バイト

    View full-size slide

  12. dmsetupのつかいかた(2/2)
    ● dmデバイスの挙動を動的に変更する
    ● dmデバイスを削除する
    12
    $ sudo dmsetup message 0 <コマンド> [<パラメタ>...]
    $ sudo dmsetup remove

    View full-size slide

  13. もくじ
    ● ディスク障害について
    ● device mapper
    ● ディスク障害エミュレーション
    ● そして自作へ
    ● まとめ
    13

    View full-size slide

  14. ディスク障害エミュレーション用ターゲット
    ● dm-delay: I/Oの遅延をエミュレーション
    ● dm-flakey: I/Oエラーをエミュレーション
    ● dm-dust: ディスクのブロック障害をエミュレーション
    14

    View full-size slide

  15. ディスク障害エミュレーション用ターゲット
    ● dm-delay: I/Oの遅延をエミュレーション
    ● dm-flakey: I/Oエラーをエミュレーション
    ● dm-dust: ディスクのブロック障害をエミュレーション
    15

    View full-size slide

  16. dm-delay
    ● I/Oを遅延させる
    ● テーブルの形式
    16
    <開始セクタ> <終了セクタ> delay <マップ先デバイス> <マップ先開始セクタ > <遅延[ms]>
    dm-delay
    disk
    write
    遅延を入れてからwrite read
    遅延を入れてからread

    View full-size slide

  17. 使用例
    17
    $ sudo dd if=/dev/zero of=/dev/loop0 bs=1M count=1024 oflag=direct

    1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.615917 s, 1.7 GB/s
    通常時のスループットを確認

    View full-size slide

  18. 使用例
    18
    $ sudo dd if=/dev/zero of=/dev/loop0 bs=1M count=1024 oflag=direct

    1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.615917 s, 1.7 GB/s
    通常時のスループットを確認
    $ cat test-delay.txt
    0 2097152 delay /dev/loop0 0 10
    $ sudo dmsetup create test-delay test-delay.txt
    dmデバイスの作成

    View full-size slide

  19. 使用例
    19
    $ sudo dd if=/dev/zero of=/dev/mapper/test-delay bs=1M count=1024 oflag=direct
    $ sudo dd if=/dev/zero of=/dev/loop0 bs=1M count=1024 oflag=direct

    1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.615917 s, 1.7 GB/s
    通常時のスループットを確認
    $ cat test-delay.txt
    0 2097152 delay /dev/loop0 0 10
    $ sudo dmsetup create test-delay test-delay.txt
    dmデバイスの作成
    dmデバイスにwrite

    View full-size slide

  20. 使用例
    20
    $ sudo dd if=/dev/zero of=/dev/mapper/test-delay bs=1M count=1024 oflag=direct

    1073741824 bytes (1.1 GB, 1.0 GiB) copied, 16.4044 s, 65.5 MB/s
    $ sudo dd if=/dev/zero of=/dev/loop0 bs=1M count=1024 oflag=direct

    1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.615917 s, 1.7 GB/s
    通常時のスループットを確認
    $ cat test-delay.txt
    0 2097152 delay /dev/loop0 0 10
    $ sudo dmsetup create test-delay test-delay.txt
    dmデバイスの作成
    dmデバイスにwrite
    すごく遅くなった

    View full-size slide

  21. ディスク障害エミュレーション用ターゲット
    ● dm-delay: I/Oの遅延をエミュレーション
    ● dm-flakey: I/Oエラーをエミュレーション
    ● dm-dust: ディスクのブロック障害をエミュレーション
    21

    View full-size slide

  22. dm-flakey
    ● I/Oが成功する期間と失敗する期間を設定
    ● テーブルの形式
    22
    <開始セクタ> <終了セクタ> flakey <マップ対象デバイス> <マップ先開始セクタ> <成功期間> <失敗期間>
    dm-delay
    disk
    write
    write(たまに失敗) read
    read(たまに失敗)

    View full-size slide

  23. 使用例
    23
    $ cat test-flakey.txt
    0 2097152 flakey /dev/loop0 0 2 2
    $ sudo dmsetup create test-flakey test-flakey.txt
    dmデバイスの作成
    2秒間の正常動作後
    2秒間I/Oエラーを出す

    View full-size slide

  24. 使用例
    24
    $ cat test-flakey.txt
    0 2097152 flakey /dev/loop0 0 2 2
    $ sudo dmsetup create test-flakey test-flakey.txt
    $ sudo bash -c 'for ((i=0;i<10;i++)) ; do
    dd if=/dev/mapper/test-flakey of=/dev/null bs=128 count=1
    sleep 1
    done'
    dmデバイスの作成
    dmデバイスから1秒に1回read

    View full-size slide

  25. 使用例
    25
    $ cat test-flakey.txt
    0 2097152 flakey /dev/loop0 0 2 2
    $ sudo dmsetup create test-flakey test-flakey.txt
    $ sudo bash -c 'for ((i=0;i<10;i++)) ; do
    dd if=/dev/mapper/test-flakey of=/dev/null bs=128 count=1
    sleep 1
    done'
    ...
    128 bytes copied, 0.000198435 s, 645 kB/s
    dd: error reading '/dev/mapper/test-flakey': Input/output error
    ...
    dd: error reading '/dev/mapper/test-flakey': Input/output error
    ...
    128 bytes copied, 0.000169802 s, 754 kB/s
    ...
    128 bytes copied, 0.000224296 s, 571 kB/s
    dd: error reading '/dev/mapper/test-flakey': Input/output error
    ...
    dmデバイスの作成
    dmデバイスから1秒に1回read
    仕様通りに動作

    View full-size slide

  26. dm-flakey上でファイルシステムを作ると…
    26
    $ sudo mkfs.ext4 -F /dev/loop0
    $ sudo dmsetup create test-flakey test-flakey.txt
    $ mount /dev/mapper/test-flakey mnt
    ファイルシステムが存在するデバイス上にdmデバイスを作成

    View full-size slide

  27. dm-flakey上でファイルシステムを作ると…
    27
    $ for ((i=0;i<10;i++)) ; do
    sudo dd if=/dev/zero of=mnt/test.txt bs=1 count=1 oflag=direct
    sleep 1
    done
    $ sudo mkfs.ext4 -F /dev/loop0
    $ sudo dmsetup create test-flakey test-flakey.txt
    $ mount /dev/mapper/test-flakey mnt
    ファイルシステムが存在するデバイス上にdmデバイスを作成
    ファイルシステム上のファイルに1秒に1回write

    View full-size slide

  28. dm-flakey上でファイルシステムを作ると…
    28
    $ for ((i=0;i<10;i++)) ; do
    sudo dd if=/dev/zero of=mnt/test.txt bs=1 count=1 oflag=direct
    sleep 1
    done
    dd: failed to open 'mnt/test.txt': Input/output error
    dd: failed to open 'mnt/test.txt': Input/output error
    dd: failed to open 'mnt/test.txt': Read-only file system

    ファイルシステムが存在するデバイス上にdmデバイスを作成
    ファイルシステム上のファイルに1秒に1回write
    すぐにread onlyに
    $ sudo mkfs.ext4 -F /dev/loop0
    $ sudo dmsetup create test-flakey test-flakey.txt
    $ mount /dev/mapper/test-flakey mnt

    View full-size slide

  29. カーネルログを見ると…
    29
    $ sudo dmesg

    [10912.976026] EXT4-fs error (device dm-0): ext4_journal_check_start:83: comm dd: Detected aborted journal
    [10912.991408] EXT4-fs (dm-0): Remounting filesystem read-only
    ● ext4はデータが存在するデバイスの挙動が怪しいとreadonlyでremountする
    ○ 他のファイルシステムもこのようなフェイルセーフのしくみがある
    ● 📝 dm-flakeyをファイルシステム上のI/Oエラーのエミュレーションに使うのは面倒
    ジャーナル処理も失敗

    View full-size slide

  30. ディスク障害エミュレーション用ターゲット
    ● dm-delay: I/Oの遅延をエミュレーション
    ● dm-flakey: I/Oエラーをエミュレーション
    ● dm-dust: ディスクのブロック障害をエミュレーション
    30

    View full-size slide

  31. dm-dust
    ● 特定ブロックの故障をエミュレーション
    ● テーブル形式
    31
    <開始セクタ> <終了セクタ> dust <マップ先デバイス> <マップ先開始セクタ> <ブロックサイズ>
    旧データ
    不良ブロック
    dm-dust
    disk

    View full-size slide

  32. dm-dustの主なメッセージ
    ● 機能の有効化/無効化
    ● 指定したセクタを疑似不良ブロックにする
    ● 指定したブロックを疑似不良ブロックではなくする
    ● 疑似不良ブロックのリスト

    32
    $ sudo dmsetup message 0 addbadblock <ブロック番号> [修復前にI/Oが失敗する回数]
    $ sudo dmsetup message 0 removebadblock <ブロック番号>
    $ sudo dmsetup message 0 {enable,disable}
    $ sudo dmsetup message 0 listbadblocks <ブロック番号>

    View full-size slide

  33. dm-dustを使う前の準備
    ● kernel 5.15.0-89-genericではdm-dustは無効化されている
    ● 自前ビルドすれば使える
    33
    $ git clone https://github.com/satoru-takeuchi/kernelvm-hokuriku-part6
    $ cd kernelvm-hokuriku-part6
    $ make -C kernel-modules
    $ sudo insmod kernel-modules/dm-dust.ko

    View full-size slide

  34. 使用例
    34
    $ cat test-dust.txt
    0 2097152 dust /dev/loop0 0 512
    $ sudo dmsetup create test-dust test-dust.txt
    $ sudo dmsetup message test-dust 0 enable
    $ sudo dmsetup message test-dust 0 addbadblock 0 1
    dmデバイスの作成&設定
    セクタ0にアクセスすると
    ● readは失敗する
    ● 1回目のwriteは失敗する
    ● 2回目のwriteで不良セクタが消える

    View full-size slide

  35. 使用例
    35
    $ cat test-dust.txt
    0 2097152 dust /dev/loop0 0 512
    $ sudo dmsetup create test-dust test-dust.txt
    $ sudo dmsetup message test-dust 0 enable
    $ sudo dmsetup message test-dust 0 addbadblock 0 1
    dmデバイスの作成&設定
    セクタ0にアクセスすると
    ● readは失敗する
    ● 1回目のwriteは失敗する
    ● 2回目のwriteで不良セクタが消える
    $ sudo dd if=/dev/mapper/test-dust of=/dev/null bs=512 count=1
    不良ブロックからread

    View full-size slide

  36. 使用例
    36
    $ cat test-dust.txt
    0 2097152 dust /dev/loop0 0 512
    $ sudo dmsetup create test-dust test-dust.txt
    $ sudo dmsetup message test-dust 0 enable
    $ sudo dmsetup message test-dust 0 addbadblock 0 1
    $ sudo dd if=/dev/mapper/test-dust of=/dev/null bs=512 count=1
    dd: error reading '/dev/mapper/test-dust': Input/output error

    dmデバイスの作成&設定 不良blockからのread
    セクタ0にアクセスすると
    ● readは失敗する
    ● 1回目のwriteは失敗する
    ● 2回目のwriteで不良セクタが消える

    View full-size slide

  37. 使用例
    37
    $ cat test-dust.txt
    0 2097152 dust /dev/loop0 0 512
    $ sudo dmsetup create test-dust test-dust.txt
    $ sudo dmsetup message test-dust 0 enable
    $ sudo dmsetup message test-dust 0 addbadblock 0 1
    $ sudo dd if=/dev/mapper/test-dust of=/dev/null bs=512 count=1
    dd: error reading '/dev/mapper/test-dust': Input/output error

    $ sudo dd if=/dev/zero of=/dev/mapper/test-dust bs=512 count=1
    oflag=direct,dsync
    dd: error writing '/dev/mapper/test-dust': Input/output error

    dmデバイスの作成&設定 不良blockへのwrite
    セクタ0にアクセスすると
    ● readは失敗する
    ● 1回目のwriteは失敗する
    ● 2回目のwriteで不良セクタが消える

    View full-size slide

  38. 使用例
    38
    $ cat test-dust.txt
    0 2097152 dust /dev/loop0 0 512
    $ sudo dmsetup create test-dust test-dust.txt
    $ sudo dmsetup message test-dust 0 enable
    $ sudo dmsetup message test-dust 0 addbadblock 0 1
    $ sudo dd if=/dev/mapper/test-dust of=/dev/null bs=512 count=1
    dd: error reading '/dev/mapper/test-dust': Input/output error

    $ sudo dd if=/dev/zero of=/dev/mapper/test-dust bs=512 count=1
    oflag=direct,dsync
    dd: error writing '/dev/mapper/test-dust': Input/output error

    $ sudo dd if=/dev/zero of=/dev/mapper/test-dust bs=512 count=1
    oflag=direct,dsync

    512 bytes copied, 0.0134639 s, 38.0 kB/s
    dmデバイスの作成&設定 不良ブロックへの2度目のwrite
    セクタ0にアクセスすると
    ● readは失敗する
    ● 1回目のwriteは失敗する
    ● 2回目のwriteで不良セクタが消える

    View full-size slide

  39. ファイルとセクタの関係
    ● 一般的にユーザはブロックデバイスを直接使わず、その上にファイルシステムを置
    いて使う
    ● あるファイルの、あるオフセットへのアクセス時に障害を起こしたい
    ● それはどこのセクタにあるの?
    39
    disk
    ファイル
    ? ? ?

    View full-size slide

  40. ioctl(FS_IOC_FIEMAP)を使えばわかる
    ● ファイルとextent、extentとブロックの対応が得るためのioctl()
    ● xfs_io -c fiemapコマンドを介して手軽に使える
    40
    $ xfs_io -c fiemap test.txt
    test.txt:
    0: [0..7]: 266240..266247
    test.txtの先頭領域を含むextentは
    ファイルシステムの下にあるブロックデバイスの
    セクタ266240~266247に存在する

    View full-size slide

  41. 使用例
    41
    $ sudo dmsetup message test-dust 0 enable
    $ sudo xfs_io -c fiemap mnt/test.txt
    mnt/test.txt:
    0: [0..7]: 266240..266247
    $ sudo dmsetup message test-dust 0 addbadblock 266240
    dmデバイス上の作成&設定
    test.txtファイル先頭のデータに対応
    するセクタを不良セクタにする
    /dev/loop0
    /dev/mapper/test-dust
    filesystem
    test.txt

    View full-size slide

  42. 使用例
    42
    $ sudo dmsetup message test-dust 0 enable
    $ sudo xfs_io -c fiemap mnt/test.txt
    mnt/test.txt:
    0: [0..7]: 266240..266247
    $ sudo dmsetup message test-dust 0 addbadblock 266240
    $ sudo dd if=mnt/test.txt of=/dev/null bs=512 count=1 iflag=direct
    dmデバイス上の作成&設定
    dmデバイス上のファイルからread
    /dev/loop0
    /dev/mapper/test-dust
    filesystem
    test.txt

    View full-size slide

  43. 使用例
    43
    $ sudo dmsetup message test-dust 0 enable
    $ sudo xfs_io -c fiemap mnt/test.txt
    mnt/test.txt:
    0: [0..7]: 266240..266247
    $ sudo dmsetup message test-dust 0 addbadblock 266240
    $ sudo dd if=mnt/test.txt of=/dev/null bs=512 count=1 iflag=direct
    dd: error reading 'mnt/test-dust.txt': Input/output error

    dmデバイス上の作成&設定
    dmデバイス上のファイルからread
    /dev/loop0
    /dev/mapper/test-dust
    filesystem
    test.txt

    View full-size slide

  44. ● CoW型、ログ構造型のファイルシステムではうまく機能しない
    ○ 例: Btrfs, NILFS
    ○ writeするたびにextentとblockの対応関係が変化
    dm-dustと相性の悪いファイルシステム
    44
    Btrfs
    旧データ
    不良ブロック
    dm-dust
    disk

    View full-size slide

  45. ● CoW型、ログ構造型のファイルシステムではうまく機能しない
    ○ 例: Btrfs, NILFS
    ○ writeするたびにextentとblockの対応関係が変化
    dm-dustと相性の悪いファイルシステム
    45
    Btrfs
    旧データ
    不良ブロック
    新データ
    writeするとデータの場所が変わる
    dm-dust
    disk

    View full-size slide

  46. ● CoW型、ログ構造型のファイルシステムではうまく機能しない
    ○ 例: Btrfs, NILFS
    ○ writeするたびにextentとblockの対応関係が変化
    dm-dustと相性の悪いファイルシステム
    46
    Btrfs
    旧データ
    不良ブロック
    新データ
    writeするとデータの場所が変わる
    dm-dust
    disk
    📝 ファイルシステムはなんでもいいなら ext4などのin-placeな更新をするものを使う

    View full-size slide

  47. デバイスに全くアクセスできない状況も作れる
    ● ターゲットへのI/Oを受け付けない状態にする
    ● 上記の状態の解除
    ● 📝 どんなターゲットでも使える技
    47
    dmsetup suspend
    dmsetup resume

    View full-size slide

  48. ターゲットを重ねるとさらに高機能化
    48
    disk
    dm-flakey
    dm-delay
    dm-dust
    元気です
    I/O失敗させます
    I/O遅延させます
    セクタ壊します
    やったね!

    View full-size slide

  49. もくじ
    ● ディスク障害について
    ● device mapper
    ● ディスク障害エミュレーション用ターゲット
    ● そして自作へ
    ● まとめ
    49

    View full-size slide

  50. 本日紹介したターゲットでは再現できないI/O障害
    ● I/O遅延の長さが動的に変動
    ● 特定セクタへのI/Oがランダムに失敗
    ● だんだん症状が重くなっていく
    50
    disk
    可能性は無限大!

    View full-size slide

  51. 本日紹介したターゲットでは再現できないI/O障害
    ● I/O遅延の長さが動的に変動
    ● 特定セクタへのI/Oがランダムに失敗
    ● だんだん症状が重くなっていく
    51
    disk
    可能性は無限大!
    ないならつくればいい
    💡

    View full-size slide

  52. ものすごく簡単なdevice mapperの自作
    ● dm-simple
    ○ dm-linearのコードから必要最小限の部分以外を削って
    100行強にしたもの
    ○ マップ先にあるデバイスに
    I/Oをそのまま受け渡すだけ
    ● テーブルの形式
    ● ソース
    ○ https://github.com/satoru-takeuchi/kernelvm-hokuriku-part6/blob/main/kernel-modules/dm-simple.c
    52
    <開始セクタ> <終了セクタ> simple <マップ先デバイス>
    write
    dm-simple
    disk
    write
    read
    read

    View full-size slide

  53. ターゲットをあらわす構造体を作る
    53
    static struct target_type simple_target = {
    .name = "simple",
    .version = {0, 0, 1},
    .features = DM_TARGET_NOWAIT | DM_TARGET_PASSES_CRYPTO,
    .module = THIS_MODULE,
    .ctr = simple_ctr,
    .dtr = simple_dtr,
    .map = simple_map,
    .iterate_devices = simple_iterate_devices,
    };
    dmデバイスのI/Oを下のデバイスに渡す

    View full-size slide

  54. マップ処理
    54
    static int simple_map(struct dm_target *ti, struct bio *bio)
    {
    struct simple_c *sc = ti->private;
    bio_set_dev(bio, sc->dev->bdev);
    return DM_MAPIO_REMAPPED;
    }

    View full-size slide

  55. マップ処理
    55
    static int simple_map(struct dm_target *ti, struct bio *bio)
    {
    struct simple_c *sc = ti->private;
    bio_set_dev(bio, sc->dev->bdev);
    return DM_MAPIO_REMAPPED;
    }
    個々のI/Oを管理するデータ
    ● I/Oに使うメモリ領域
    ● I/O対象デバイス

    View full-size slide

  56. マップ処理
    56
    static int simple_map(struct dm_target *ti, struct bio *bio)
    {
    struct simple_c *sc = ti->private;
    bio_set_dev(bio, sc->dev->bdev);
    return DM_MAPIO_REMAPPED;
    }
    I/O対象デバイスを
    マップ先デバイスに書き換え

    View full-size slide

  57. マップ処理
    57
    static int simple_map(struct dm_target *ti, struct bio *bio)
    {
    struct simple_c *sc = ti->private;
    bio_set_dev(bio, sc->dev->bdev);
    return DM_MAPIO_REMAPPED;
    }
    I/Oをマップ先デバイスに
    リマップしたことを呼び出し元に伝える

    View full-size slide

  58. 使用例
    58
    $ cat test-simple.txt
    0 2097152 simple /dev/loop0
    $ sudo dmsetup create test-simple test-simple.txt
    dmデバイスの作成

    View full-size slide

  59. 使用例
    59
    $ cat test-simple.txt
    0 2097152 simple /dev/loop0
    $ sudo dmsetup create test-simple test-simple.txt
    dmデバイスの作成
    $ sudo dd if=test-simple.txt of=/dev/mapper/test-simple
    dmデバイスにwrite

    View full-size slide

  60. 使用例
    60
    $ cat test-simple.txt
    0 2097152 simple /dev/loop0
    $ sudo dmsetup create test-simple test-simple.txt
    dmデバイスの作成
    dmデバイスにwrite
    $ sudo dd if=test-simple.txt of=/dev/mapper/test-simple

    $ sudo dmsetup remove test-simple
    $ sudo hexdump -c -n 128 /dev/loop0
    0000000 0 2 0 9 7 1 5 2 s i m p l e
    0000010 / d e v / l o o p 0 0 \n \0 \0

    View full-size slide

  61. dm-hello
    ● writeしてくれた人にあいさつをする
    ○ 📝 あいさつは社会人の基本
    ● テーブルの形式
    ● ソース
    ○ https://github.com/satoru-takeuchi/kernelvm-hokuriku-part6/blob/main/kernel-modules/dm-shello.c
    61
    <開始セクタ> <終了セクタ> hello <マップ対象デバイス>

    View full-size slide

  62. マップ処理
    62
    static int hello_map(struct dm_target *ti, struct bio *bio)
    {
      ...
    bio_for_each_segment(bvec, bio, iter) {
    char *segment;
    struct page *page = bio_iter_page(bio, iter);
    if (unlikely(page == ZERO_PAGE(0)))
    break;
    segment = bvec_kmap_local(&bvec);
    memcpy(segment, hello, sizeof(hello));
    kunmap_local(segment);
    break;
    }
    bio_set_dev(bio, hc->dev->bdev);
    return DM_MAPIO_REMAPPED;
    }

    View full-size slide

  63. マップ処理
    63
    static int hello_map(struct dm_target *ti, struct bio *bio)
    {
      ...
    bio_for_each_segment(bvec, bio, iter) {
    char *segment;
    struct page *page = bio_iter_page(bio, iter);
    if (unlikely(page == ZERO_PAGE(0)))
    break;
    segment = bvec_kmap_local(&bvec);
    memcpy(segment, hello, sizeof(hello));
    kunmap_local(segment);
    break;
    }
    bio_set_dev(bio, hc->dev->bdev);
    return DM_MAPIO_REMAPPED;
    }
    bio内の全領域(データの断片)を走査

    View full-size slide

  64. マップ処理
    64
    static int hello_map(struct dm_target *ti, struct bio *bio)
    {
      ...
    bio_for_each_segment(bvec, bio, iter) {
    char *segment;
    struct page *page = bio_iter_page(bio, iter);
    if (unlikely(page == ZERO_PAGE(0)))
    break;
    segment = bvec_kmap_local(&bvec);
    memcpy(segment, hello, sizeof(hello));
    kunmap_local(segment);
    break;
    }
    bio_set_dev(bio, hc->dev->bdev);
    return DM_MAPIO_REMAPPED;
    }
    先頭領域に”Hello!”という文字列を書き込む

    View full-size slide

  65. マップ処理
    65
    static int hello_map(struct dm_target *ti, struct bio *bio)
    {
      ...
    bio_for_each_segment(bvec, bio, iter) {
    char *segment;
    struct page *page = bio_iter_page(bio, iter);
    if (unlikely(page == ZERO_PAGE(0)))
    break;
    segment = bvec_kmap_local(&bvec);
    memcpy(segment, hello, sizeof(hello));
    kunmap_local(segment);
    break;
    }
    bio_set_dev(bio, hc->dev->bdev);
    return DM_MAPIO_REMAPPED;
    }
    書き終わったら走査終了
    先頭領域以外は触らない

    View full-size slide

  66. 使用例
    66
    $ cat test-hello.txt
    0 2097152 hello /dev/loop0
    $ sudo dmsetup create test-hello test-hello.txt
    dmデバイスの作成

    View full-size slide

  67. 使用例
    67
    $ cat test-hello.txt
    0 2097152 hello /dev/loop0
    $ sudo dmsetup create test-hello test-hello.txt
    $ sudo dd if=test-hello.txt of=/dev/mapper/test-hello

    $ sudo hexdump -c -n 128 /dev/mapper/test-hello
    dmデバイスの作成
    dmデバイスにwrite

    View full-size slide

  68. 使用例
    68
    $ cat test-hello.txt
    0 2097152 hello /dev/loop0
    $ sudo dmsetup create test-hello test-hello.txt
    元気にあいさつができて
    えらいね!
    $ sudo dd if=test-hello.txt of=/dev/mapper/test-hello

    $ sudo hexdump -c -n 128 /dev/mapper/test-hello
    0000000 H e l l o ! \n \0 2 h e l l o
    0000010 / d e v / l o o p 0 0 \n \0 \0 \0

    dmデバイスの作成
    dmデバイスにwrite データが書き換わった

    View full-size slide

  69. 参考になるコード
    ● ターゲット作成時にパラメタを渡して挙動を変更
    ○ https://github.com/torvalds/linux/blob/v5.15/drivers/md/dm-flakey.c#L184-L261
    ● ターゲット作成後にmessageを送って挙動を変更
    ○ https://github.com/torvalds/linux/blob/master/drivers/md/dm-dust.c#L414-L511
    ● 障害を一定確率で発生させる
    ○ https://github.com/torvalds/linux/blob/master/drivers/md/dm-flakey.c#L529-L532
    69

    View full-size slide

  70. もくじ
    ● ディスク障害について
    ● device mapper
    ● ディスク障害エミュレーション用ターゲット
    ● そして自作へ
    ● まとめ
    70

    View full-size slide

  71. 何を学んだか
    ● device mapperを使えばディスクI/O障害をエミュレーションできる
    ● その気になれば自作もできる
    71

    View full-size slide

  72. 役立ちそうなドキュメント
    ● device mapperターゲットのマニュアル
    ○ https://docs.kernel.org/admin-guide/device-mapper
    ● カーネルモジュールの作り方
    ○ https://github.com/torvalds/linux/blob/master/Documentation/kbuild/modules.rst
    ● device mapperのコード
    ○ https://github.com/torvalds/linux/blob/master/drivers/md/
    72

    View full-size slide

  73. Rustでターゲットを書けるようにする試みも
    ● Rust device mapper abstractions
    ○ https://lore.kernel.org/lkml/ZJm%2FJfIPMrgXkYpp@boqun-archlinux/T/
    ○ まだマージはされていない &今度されるかどうかも不明
    ● 興味のある人はさわってみるといいかも
    73
    ナウいよ!

    View full-size slide

  74. その他カーネルのディスクI/O障害エミュレーション機能
    ● fault injection
    ○ カーネルの様々なコンポーネントに対応する汎用的な障害エミュレーション機能
    ○ 任意のブロックデバイスへの fault injection、NVMe SSDへのfault injectionなどもある
    ○ kernel 5.15.0-89-genericでは無効化されている
    ○ https://docs.kernel.org/fault-injection/index.html
    ● scsi_debug
    ○ SCSIコマンドの失敗をエミュレーション
    ○ kernel 5.15.0-89-genericではモジュールとして提供されている
    ○ https://sg.danny.cz/sg/scsi_debug.html
    ● multiple devices(device mapperと似たような機能)
    ○ md-faultというI/O障害エミュレーション用のサブ機能がある
    ○ 色々できそうだが使ったことがない
    ○ man mdadmに使い方が書いている
    74

    View full-size slide

  75. おわり
    75
    disk
    あばよ

    View full-size slide