Slide 1

Slide 1 text

device mapperによる ディスクI/O障害のエミュレーション ~ 既存ターゲット編 ~ Dec, 10th, 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

ディスクは色々な理由で壊れる ● I/Oが遅延 ● 特定セクタが壊れる ● ディスクが応答しない 3

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

エラー処理はテストが大変 ● 課題 ○ ディスクはテスト中に気を使って障害を起こしてくれたりしない ○ うまくテストできなくてバグの温床になりがち ● 解決策(の一つ) ○ Linuxカーネルのdevice mapper 5

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

dmsetupのつかいかた ● dmデバイスとマップ先デバイスを対応付けるテーブルを作る ● dmデバイスを作る ● dmデバイスの挙動を動的に変更する 7 $ cat table.txt <開始セクタ> <長さ> <ターゲット名> <マップ先デバイス> [<パラメタ>...] ... $ sudo dmsetup create <テーブルファイル> $ ls /dev/mapper/ … … 1セクタ=512バイト $ sudo dmsetup message 0 <コマンド> [<パラメタ>...]

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

使用例 11 $ 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 12

Slide 12 text

使用例 12 $ 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 13

Slide 13 text

使用例 13 $ 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 14

Slide 14 text

使用例 14 $ 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 15

Slide 15 text

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

Slide 16

Slide 16 text

dm-flakey ● I/Oエラーを一定間隔で発生させる ● テーブルの形式 16 <開始セクタ> <長さ> flakey <マップ対象デバイス> <マップ先開始セクタ> <成功期間> <失敗期間> dm-delay disk write write(たまに失敗) read read(たまに失敗)

Slide 17

Slide 17 text

使用例 17 $ 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 18

Slide 18 text

使用例 18 $ 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 19

Slide 19 text

使用例 19 $ 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 20

Slide 20 text

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

Slide 21

Slide 21 text

dm-flakey上でファイルシステムを作ると… 21 $ 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 22

Slide 22 text

dm-flakey上でファイルシステムを作ると… 22 $ 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 23

Slide 23 text

カーネルログを見ると… 23 $ 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 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

dm-dustの主なメッセージ ● 機能の有効化/無効化(デフォルトは無効) ● 指定したセクタを疑似不良ブロックにする ● 指定したブロックを疑似不良ブロックではなくする ● 疑似不良ブロックのリスト ○ 26 $ sudo dmsetup message 0 addbadblock <ブロック番号> [修復前にI/Oが失敗する回数] $ sudo dmsetup message 0 removebadblock <ブロック番号> $ sudo dmsetup message 0 {enable,disable} $ sudo dmsetup message 0 listbadblocks <ブロック番号>

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

使用例 28 $ 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 29

Slide 29 text

使用例 29 $ 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 30

Slide 30 text

使用例 30 $ 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 31

Slide 31 text

使用例 31 $ 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 32

Slide 32 text

使用例 32 $ 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 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

使用例 35 $ 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 36

Slide 36 text

使用例 36 $ 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 37

Slide 37 text

使用例 37 $ 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 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

まとめ ● device mapperを使えばディスクI/O障害をエミュレーションできる ● device mapperターゲットのドキュメント ○ https://docs.kernel.org/admin-guide/device-mapper 43