Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Kernel fcache-bug

5,234 views

Published on

how to find a bug in kernel/fs about wrong page cache flush in resizing MD device.

Published in: Technology
  • Be the first to comment

Kernel fcache-bug

  1. 1. ファイルキャッシュクリアの謎 技術Bar#9 2012/12/4 光成滋生
  2. 2. cybozu.comで障害発生 ストレージ容量拡張操作の結果、Officeが動 いているLinuxマシンのページキャッシュが約 15分おきに破棄されるという未知の現象が発 生したためです 2 / 20
  3. 3. 現象の詳細mdadmでLVMのパーティションを拡大する と15分毎にpage cacheがクリアされる メモリにキャッシュ MySQLなどのアプリ これがクリアされて 激遅に ext3 ファイルシステム mdadm ソフトウェアRAID LVM パーティション管理 kernel/device driver 犯人はだれか? hard disk 3 / 20
  4. 4. 調査のやりかた現象の再現方法の構築 頻度が低かったり環境によって起こらないと面倒原因を推測して絞り込み トライアンドエラー さまざまなツールを使う特定したら修正して確認 はずれていたらまた別の原因を推測 4 / 20
  5. 5. 現象の確認hazamaでの容量の変更は500GB→1TB バックグラウンドリサイズが長時間 数十MB程度では17分以内に終わってしまう手元の環境でディスクを用意して… 1時間待ったが発現しなかった 私の勘違い  キャッシュがクリアされるのはそのディスクに構築し たファイルシステム上のもののみ 再度テスト クリアされることを確認 約17分=>概ね1000秒であることも判明 5 / 20
  6. 6. 犯人は誰か全然見当がつかない 普通ユーザラウンドで明示的に破棄なんてしない page cacheを破棄しそうなkernelの関数を列挙 flush_disk, invalidate_disk, invalidate_parition, ... これらの関数を呼び出すやつを探そうftraceを使って探す ubuntuでは標準搭載 呼ばれた関数,stacktrace,eventなどがわかる /sys/kernel/debug/tracingに様々な値を書き込 むことでパラメータを設定する 結構複雑で慣れるまで難しかった 6 / 20
  7. 7. ftraceの例ext4系関数が呼ばれたときのcall treeを表示// debugfsをmountmount -t debugfs debugfs /sys/kernel/debug// stack tracerを有効echo 1 > /proc/sys/kernel/stack_tracer_enabledcd /sys/kernel/debug/tracing// ext4で始まる関数名をターゲットにecho "ext4*" > set_ftrace_filter// 関数トレーサーをセットecho function > current_tracerecho 0 > trace cat trace_pipeext4のファイルシステムをmoutすると関連関 数のlogが表示される 7 / 20
  8. 8. あたりをつけるディスクを交換したり,resize開始直後に呼ば れる関数をセットして17分待つ 呼ばれない… 別の関数を試すことの繰り返し このあたりが結構辛い 8 / 20
  9. 9. 漸くヒット__invalidate_deviceが網にかかった!mdadm-900 [001] .... 75491.384221: __invalidate_device <-invalidate_partitionmdadm-900 [001] .... 75491.384235: <stack trace>=> ftrace_call=> invalidate_partition=> rescan_partitions=> __blkdev_get 下の関数が上の関数=> blkdev_get=> blkdev_open を呼び出している=> do_dentry_open=> nameidata_to_filp=> do_last=> path_openat=> do_filp_open=> do_sys_open=> sys_open ここから下はユーザ空間=> system_call_fastpathここには重要な情報が… 9 / 20
  10. 10. 犯人はmdadmのdaemon? __invalidate_deviceが網にかかった! mdadm-900 [001] .... 75491.384221: __invalidate_device <-invalidate_partition mdadm-900 [001] .... 75491.384235: <stack trace> => ftrace_call ...ユーザ空間側なのでgdbでひっかけられるsudo gdb –p <processId>でatach backtraceしてみる gdb) bt #0 0x00007f85b1ebf103 in __select_nocancel () at ../sysdeps/unix/syscall-template.S:82 #1 0x000000000040de66 in mdstat_wait (seconds=1000) at mdstat.c:317 #2 0x000000000042dea1 in Monitor (devlist=0x0, mailaddr=0x1a7b020 "root",時間の間隔も正確に1000秒なのがわかる 10 / 20
  11. 11. 位置関係md daemon monitor daemon use space kernel ? md driver disk driver invalidate_partition hard disk clear page cache 11 / 20
  12. 12. mdadmのソースをで追いかけるまずこれで1000秒を30秒に短縮できる 調査効率が大幅に改善されるしかしやや戸惑いが monitorコマンドがクリアするとも思えない ファイルキャッシュがクリアされる関数が何か確認 しながらgdbでstep実行 daemon内部で/dev/mdをopenするだけでクリ アされることが判明 fd = open("dev/md/test..", O_RDONLY); mdのdevice driverの問題? 12 / 20
  13. 13. 位置関係md daemon monitor daemon use space kernel md driver md_open ? disk driver invalidate_partition hard disk clear page cache 13 / 20
  14. 14. md_openを追いかけるcheck_disk_changeが呼ばれている これが怪しい?しかしこいつは犯人ではなかったもう一度call graphをみる __invalidate_deviceが網にかかった! mdadm-900 [001] .... 75491.384221: __invalidate_device <-invalidate_partition mdadm-900 [001] .... 75491.384235: <stack trace> => ftrace_call => invalidate_partition => rescan_partitions => __blkdev_get => blkdev_get => blkdev_openblkdev_getのあたりから分岐してそう 14 / 20
  15. 15. blk_devの中身このあたり // こいつでmd_openが呼ばれる ret = disk->fops->open(bdev, mode); .. if (bdev->bd_invalidated) { if (!ret) rescan_partitions(disk, bdev); else if (ret == -ENOMEDIUM) // この中で__invalidate_paritionが呼ばれる invalidate_partitions(disk, bdev);bd_invalidatedフラグが怪しい 15 / 20
  16. 16. 位置関係md daemon monitor daemon use space kernel blk_dev md driver bd_invalidated md_open disk driver invalidate_partition hard disk clear page cache 16 / 20
  17. 17. bd_invalidatedフラグを探すクリアしているのは初期化と二カ所rescan_partitions() { .... disk->fops->revalidate_disk(disk); check_disk_size_change(disk, bdev); bdev->bd_invalidated = 0;invalidate_partitions() { ... set_capacity(disk, 0); check_disk_size_change(disk, bdev); bdev->bd_invalidated = 0; どちらもcheck_disk_size_change()を呼んで からbd_invalidatedを0クリア 17 / 20
  18. 18. クリアし忘れ?しかし,revalidate_disk()の中では check_disk_size_change()を呼んだあとクリ アしていない revalidate_disk() { ... mutex_lock(&bdev->bd_mutex); check_disk_size_change(disk, bdev); // bdev->bd_invalidated = 0; がない mutex_unlock(&bdev->bd_mutex); このせいでopenするたびに毎回キャッシュクリア 結局LVMでもmdadmでもなくkernel/fsが原因 18 / 20
  19. 19. 動作確認クリアするようにしてkernelをビルド キャッシュクリア問題は起こらないてか,そもそもcheck_disk_size_change()の 中でクリアすればええんとちゃうか? 19 / 20
  20. 20. その後LinuxのMLに投げる 作法がいろいろある patchの作り方 scripts/checkpatch.plでパッチフォーマットの検証 patchのMLへの投げかた  git send-emailを使う 題名のつけかたと投げる場所が不適切だったかも MLに投げたが黙殺 再度別のMLに挑戦 山本さんによる英語メールの推敲(という名の書き直し)  結局パッチを手動で張り付けたものがaccept...  http://git.kernel.org/?p=linux/kernel/git/next/lin ux-next.git;a=commit;h=9b4b0d9f9f9ad2 20 / 20

×