Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

使用例 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 通常時のスループットを確認

Slide 18

Slide 18 text

使用例 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デバイスの作成

Slide 19

Slide 19 text

使用例 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

Slide 20

Slide 20 text

使用例 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 すごく遅くなった

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

使用例 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エラーを出す

Slide 24

Slide 24 text

使用例 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

Slide 25

Slide 25 text

使用例 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 仕様通りに動作

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

カーネルログを見ると… 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エラーのエミュレーションに使うのは面倒 ジャーナル処理も失敗

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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 <ブロック番号>

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

使用例 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で不良セクタが消える

Slide 35

Slide 35 text

使用例 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

Slide 36

Slide 36 text

使用例 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で不良セクタが消える

Slide 37

Slide 37 text

使用例 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で不良セクタが消える

Slide 38

Slide 38 text

使用例 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で不良セクタが消える

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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に存在する

Slide 41

Slide 41 text

使用例 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

Slide 42

Slide 42 text

使用例 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

Slide 43

Slide 43 text

使用例 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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

ものすごく簡単な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

Slide 53

Slide 53 text

ターゲットをあらわす構造体を作る 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を下のデバイスに渡す

Slide 54

Slide 54 text

マップ処理 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; }

Slide 55

Slide 55 text

マップ処理 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対象デバイス

Slide 56

Slide 56 text

マップ処理 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対象デバイスを マップ先デバイスに書き換え

Slide 57

Slide 57 text

マップ処理 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をマップ先デバイスに リマップしたことを呼び出し元に伝える

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

使用例 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

Slide 60

Slide 60 text

使用例 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 …

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

マップ処理 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; }

Slide 63

Slide 63 text

マップ処理 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内の全領域(データの断片)を走査

Slide 64

Slide 64 text

マップ処理 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!”という文字列を書き込む

Slide 65

Slide 65 text

マップ処理 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; } 書き終わったら走査終了 先頭領域以外は触らない

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

使用例 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

Slide 68

Slide 68 text

使用例 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 データが書き換わった

Slide 69

Slide 69 text

参考になるコード ● ターゲット作成時にパラメタを渡して挙動を変更 ○ 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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

役立ちそうなドキュメント ● 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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

その他カーネルのディスク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

Slide 75

Slide 75 text

おわり 75 disk あばよ