カーネル空間でのハードディスク書き込みの観察(ドライバー/モジュールを使用)


13

この投稿が少々密集している場合は事前におApび申し上げますが、それをより適切に定式化するのに苦労しています...

  • 以下の私の理解は正しいですか?そうでない場合、どこが間違っていますか?
  • ディスク書き込み中にPCで発生するすべての側面について、ログデータを「キャプチャ」するためのより良いツールはありますか?

より詳細に-まず、私が使用しているOSは次のとおりです。

$ uname -a
Linux mypc 2.6.38-16-generic #67-Ubuntu SMP Thu Sep 6 18:00:43 UTC 2012 i686 i686 i386 GNU/Linux

だから、私は次の簡単な(たとえば、操作の失敗の通常のチェックがスキップされる)ユーザースペースCプログラムを持っていますwtest.c

#include <stdio.h>
#include <fcntl.h>  // O_CREAT, O_WRONLY, S_IRUSR

int main(void) {
  char filename[] = "/tmp/wtest.txt";
  char buffer[] = "abcd";
  int fd;
  mode_t perms = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;

  fd = open(filename, O_RDWR|O_CREAT, perms);
  write(fd,buffer,4);
  close(fd);

  return 0;
}

私はこれをビルドしgcc -g -O0 -o wtest wtest.cます。今、私はに書き込もうとしているので/tmp、それはルートの下のディレクトリであることに注意して/ください-私はチェックしmountます:

$ mount
/dev/sda5 on / type ext4 (rw,errors=remount-ro,commit=0)
...
/dev/sda6 on /media/disk1 type ext4 (rw,uhelper=hal,commit=0)
/dev/sda7 on /media/disk2 type ext3 (rw,nosuid,nodev,uhelper=udisks,commit=0,commit=0,commit=0,commit=0,commit=0,commit=0)
...

したがって、私のルートファイルシステム//dev/sdaデバイスの1つのパーティションです(そして、他のパーティションも「スタンドアロン」ディスク/マウントとして使用しています)。このデバイスのドライバーを見つけるには、次を使用しますhwinfo

$ hwinfo --disk
...
19: IDE 00.0: 10600 Disk
...
  SysFS ID: /class/block/sda
  SysFS BusID: 0:0:0:0
...
  Hardware Class: disk
  Model: "FUJITSU MHY225RB"
...
  Driver: "ata_piix", "sd"
  Driver Modules: "ata_piix"
  Device File: /dev/sda
...
  Device Number: block 8:0-8:15
...

したがって、/dev/sdaハードディスクは明らかにata_piix(およびsd)ドライバーによって処理されます。

$ grep 'ata_piix\| sd' <(gunzip </var/log/syslog.2.gz)
Jan 20 09:28:31 mypc kernel: [    1.963846] ata_piix 0000:00:1f.2: version 2.13
Jan 20 09:28:31 mypc kernel: [    1.963901] ata_piix 0000:00:1f.2: PCI INT B -> GSI 19 (level, low) -> IRQ 19
Jan 20 09:28:31 mypc kernel: [    1.963912] ata_piix 0000:00:1f.2: MAP [ P0 P2 P1 P3 ]
Jan 20 09:28:31 mypc kernel: [    2.116038] ata_piix 0000:00:1f.2: setting latency timer to 64
Jan 20 09:28:31 mypc kernel: [    2.116817] scsi0 : ata_piix
Jan 20 09:28:31 mypc kernel: [    2.117068] scsi1 : ata_piix
Jan 20 09:28:31 mypc kernel: [    2.529065] sd 0:0:0:0: [sda] 488397168 512-byte logical blocks: (250 GB/232 GiB)
Jan 20 09:28:31 mypc kernel: [    2.529104] sd 0:0:0:0: Attached scsi generic sg0 type 0
Jan 20 09:28:31 mypc kernel: [    2.529309] sd 0:0:0:0: [sda] Write Protect is off
Jan 20 09:28:31 mypc kernel: [    2.529319] sd 0:0:0:0: [sda] Mode Sense: 00 3a 00 00
Jan 20 09:28:31 mypc kernel: [    2.529423] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
Jan 20 09:28:31 mypc kernel: [    2.674783]  sda: sda1 sda2 < sda5 sda6 sda7 sda8 sda9 sda10 >
Jan 20 09:28:31 mypc kernel: [    2.676075] sd 0:0:0:0: [sda] Attached SCSI disk
Jan 20 09:28:31 mypc kernel: [    4.145312] sd 2:0:0:0: Attached scsi generic sg1 type 0
Jan 20 09:28:31 mypc kernel: [    4.150596] sd 2:0:0:0: [sdb] Attached SCSI removable disk

私は多くのことを中断として古いのsyslogからプルする必要がありますが、上記のブート時のsyslogから適切なスニペット、のように思えるata_piix(とsd初めて中)ドライバキック。

混乱の私の最初のポイントは、私はそう観察することができないということですata_piixsdドライバを:

$ lsmod | grep 'ata_piix\| sd'
$
$ modinfo sd
ERROR: modinfo: could not find module sd
$ modinfo ata_piix
ERROR: modinfo: could not find module ata_piix

だから私の最初の質問は- ata_piixブート時のログでのみここでモジュールを観察できないのはなぜですか?ので、それはata_piix(とがsd)として構築されているビルトイン(モノリシック)カーネル内のドライバ(ロード可能)として構築されるのとは対照的に.ko、カーネルモジュール?

そうです-だから今、ftraceLinuxの組み込み関数トレーサーでプログラムを実行すると何が起こるかを観察しようとしています。

sudo bash -c '
KDBGPATH="/sys/kernel/debug/tracing"
echo function_graph > $KDBGPATH/current_tracer
echo funcgraph-abstime > $KDBGPATH/trace_options
echo funcgraph-proc > $KDBGPATH/trace_options
echo 0 > $KDBGPATH/tracing_on
echo > $KDBGPATH/trace
echo 1 > $KDBGPATH/tracing_on ; ./wtest ; echo 0 > $KDBGPATH/tracing_on
cat $KDBGPATH/trace > wtest.ftrace
'

...そして、これは以下ftraceに関するログの断片ですwrite

4604.352690 | 0)wtest-31632 | | sys_write(){
 4604.352690 | 0)wtest-31632 | 0.750 us | fget_light();
 4604.352692 | 0)wtest-31632 | | vfs_write(){
 4604.352693 | 0)wtest-31632 | | rw_verify_area(){
 4604.352693 | 0)wtest-31632 | | security_file_permission(){
 4604.352694 | 0)wtest-31632 | | apparmor_file_permission(){
 4604.352695 | 0)wtest-31632 | 0.811 us | common_file_perm();
 4604.352696 | 0)wtest-31632 | 2.198 us | }
 4604.352697 | 0)wtest-31632 | 3.573 us | }
 4604.352697 | 0)wtest-31632 | 4.979 us | }
 4604.352698 | 0)wtest-31632 | | do_sync_write(){
 4604.352699 | 0)wtest-31632 | | ext4_file_write(){
 4604.352700 | 0)wtest-31632 | | generic_file_aio_write(){
 4604.352701 | 0)wtest-31632 | | mutex_lock(){
 4604.352701 | 0)wtest-31632 | 0.666 us | _cond_resched();
 4604.352703 | 0)wtest-31632 | 1.994 us | }
 4604.352704 | 0)wtest-31632 | | __generic_file_aio_write(){
...
 4604.352728 | 0)wtest-31632 | | file_update_time(){
...
 4604.352732 | 0)wtest-31632 | 0.756 us | mnt_want_write_file();
 4604.352734 | 0)wtest-31632 | | __mark_inode_dirty(){
...
 4604.352750 | 0)wtest-31632 | | ext4_mark_inode_dirty(){
 4604.352750 | 0)wtest-31632 | 0.679 us | _cond_resched();
 4604.352752 | 0)wtest-31632 | | ext4_reserve_inode_write(){
...
 4604.352777 | 0)wtest-31632 | | __ext4_journal_get_write_access(){
...
 4604.352795 | 0)wtest-31632 | | ext4_mark_iloc_dirty(){
...
 4604.352806 | 0)wtest-31632 | | __ext4_journal_stop(){
...
 4604.352821 | 0)wtest-31632 | 0.684 us | mnt_drop_write();
 4604.352822 | 0)wtest-31632 | + 93.541 us | }
 4604.352823 | 0)wtest-31632 | | generic_file_buffered_write(){
 4604.352824 | 0)wtest-31632 | 0.654 us | iov_iter_advance();
 4604.352825 | 0)wtest-31632 | | generic_perform_write(){
 4604.352826 | 0)wtest-31632 | 0.709 us | iov_iter_fault_in_readable();
 4604.352828 | 0)wtest-31632 | | ext4_da_write_begin(){
 4604.352829 | 0)wtest-31632 | | ext4_journal_start_sb(){
...
 4604.352847 | 0)wtest-31632 | 1.453 us | __block_write_begin();
 4604.352849 | 0)wtest-31632 | + 21.128 us | }
 4604.352849 | 0)wtest-31632 | | iov_iter_copy_from_user_atomic(){
 4604.352850 | 0)wtest-31632 | | __kmap_atomic(){
...
 4604.352863 | 0)wtest-31632 | 0.672 us | mark_page_accessed();
 4604.352864 | 0)wtest-31632 | | ext4_da_write_end(){
 4604.352865 | 0)wtest-31632 | | generic_write_end(){
 4604.352866 | 0)wtest-31632 | | block_write_end(){
...
 4604.352893 | 0)wtest-31632 | | __ext4_journal_stop(){
...
 4604.352909 | 0)wtest-31632 | 0.655 us | mutex_unlock();
 4604.352911 | 0)wtest-31632 | 0.727 us | generic_write_sync();
 4604.352912 | 0)wtest-31632 | !212.259 us | }
 4604.352913 | 0)wtest-31632 | !213.845 us | }
 4604.352914 | 0)wtest-31632 | !215.286 us | }
 4604.352914 | 0)wtest-31632 | 0.685 us | __fsnotify_parent();
 4604.352916 | 0)wtest-31632 | | fsnotify(){
 4604.352916 | 0)wtest-31632 | 0.907 us | __srcu_read_lock();
 4604.352918 | 0)wtest-31632 | 0.685 us | __srcu_read_unlock();
 4604.352920 | 0)wtest-31632 | 3.958 us | }
 4604.352920 | 0)wtest-31632 | !228.409 us | }
 4604.352921 | 0)wtest-31632 | !231.334 us | }

これが混乱の2番目のポイントです- 予想どおりwrite()、kernel-space sys_write()で生じたユーザー空間を観察できます。内でsys_write()、セキュリティ関連の機能(例apparmor_file_permission())、「汎用」書き込み機能(例generic_file_aio_write())、ext4ファイルシステム関連の機能(例ext4_journal_start_sb())を観察しますが、ドライバー(または)に関連するもの観察しませんか?!ata_piixsd

トレースとプロファイリング-Yocto Projectページでは、blkトレーサーを使用してftraceブロックデバイスの操作に関する詳細情報を取得することを推奨していますが、この例では何も報告されません。また、Linux Filesystem Drivers-Annon Inglorion(tutorfs)は、ファイルシステムをカーネルモジュール/ドライバーとして実装(できる?)する(提案することを提案していますが、それも当てはまると思いext4ます。

最後に、function_graphトレーサーによって示された関数の隣にある角括弧でドライバー名を以前に観察したことを誓うことができましたが、私は物事を混同していたと思います-それはおそらくスタック(バック)トレースでそのように見えるかもしれませんが、関数グラフで。さらに、私は検査することができます/proc/kallsyms

$ grep 'piix\| sd\|psmouse' /proc/kallsyms
...
00000000 d sd_ctl_dir
00000000 d sd_ctl_root
00000000 d sdev_class
00000000 d sdev_attr_queue_depth_rw
00000000 d sdev_attr_queue_ramp_up_period
00000000 d sdev_attr_queue_type_rw
00000000 d sd_disk_class
...
00000000 t piix_init_sata_map
00000000 t piix_init_sidpr
00000000 t piix_init_one
00000000 t pci_fixup_piix4_acpi
...
00000000 t psmouse_show_int_attr        [psmouse]
00000000 t psmouse_protocol_by_type     [psmouse]
00000000 r psmouse_protocols    [psmouse]
00000000 t psmouse_get_maxproto [psmouse]
...

...そして、ソースLinux / drivers / ata / ata_piix.cで確認し、例えばpiix_init_sata_mapが実際にの関数であることを確認しata_piixます。それはおそらく私に言う必要があります:カーネルでコンパイルされるモジュール(したがって、モノリシックカーネルの一部になります)は、どのモジュールからの情報を「失う」。ただし、個別の.koカーネルオブジェクトとして構築されたロード可能モジュールは、その情報を保持します(たとえば、[psmouse]上記の角括弧内)。したがって、ftraceロード可能なカーネルモジュールからの機能についてのみ、「発信元モジュール」情報のみを表示することもできます。これは正しいです?

上記を考慮して、これは私が現在プロセスについて持っている理解です:

  • 起動時に、ata_piixドライバー/dev/sdaは、ハードディスクとの 間にDMA(?)メモリマッピングを確立します
    • このため、今後の/dev/sdavia へのすべてのアクセスata_piixはカーネルに対して透過的です(つまり、追跡可能ではありません)-すべてのカーネルが参照するため、メモリ位置への読み取り/書き込みのみです(特定の追跡可能なカーネル関数の呼び出しとは限りません)。function_graphトレーサーによって報告されません
  • ブート時に、sdドライバーはさらにのパーティションを「解析」し、/dev/sdaそれらを利用可能にし、パーティション間のメモリマッピングを処理します<->ディスクデバイス
    • 繰り返しますが、これsdにより、カーネルに対して透過的なアクセス操作が可能になります。
  • 両方以来ata_piixsd終わるん、その機能の一部はによって捕獲された場合でも、カーネル内にコンパイルされているftrace、我々はから来るこれらの機能をどのモジュールの情報を得ることができない(離れてからソースファイルと「マニュアル」の相関関係)
  • 後でmount、パーティションと対応するファイルシステムドライバー(この場合ext4)の 間の関係/バインディングを確立します
    • この時点から、マウントされたファイルシステムへのアクセスはすべてext4、カーネルによって追跡可能な関数によって処理されます。しかし、ext4カーネル内でコンパイルされているように、トレーサーは元のモジュール情報を提供できません
  • したがって、ext4関数を介して呼び出される観察された「汎用」書き込みは、最終的にマッピングが確立されたメモリ位置にアクセスしますata_piixが、それ以外は、ata_piixデータ転送に直接干渉しません(おそらくDMA(プロセッサの外部で処理されます(s)、したがって透過的です)。

この理解は正しいですか?

関連するサブ質問:

  • 上記のセットアップでは、PCIデバイスドライバー(ata_piix)とファイルシステムドライバー(ext4)を識別できます。しかし、「書き込み」実行パスのどこかで使用されるキャラクターまたはブロックドライバーはありますか?
  • これらのドライバーのどれがキャッシングを処理します(したがって、不必要なディスク操作はスキップまたは最適化されますか?)
  • 私は以前から/dev/shmRAMのファイルシステムであることを知っています。mount | grep shm私のレポート:none on /dev/shm type tmpfs (rw,nosuid,nodev)。それとは対照的に/dev/sdashmファイルシステムには単に「独自の」アドレスからデバイスへのバスアドレスへの(DMA)マッピングがありません。したがって、tmpfsファイルシステムドライバを介したすべてのアクセスは、実際のRAMで行われますか?

4
こんにちはsdaau。これは良い質問ですが、この投稿の長さは過度であり、いくつかの質問があります。ヘルプデスクに質問するだけでなく、物事を理解しようとしていることは称賛に値します。これらの質問はそれぞれ、単独で長い答えに値します。少なくとも、投稿を明確に定義されたピースに分割し、各ピースを個別の質問に入れて、一連の質問を作成することをお勧めします。
ファヒムミタ

その後、これらの質問をまとめて、または順番に投稿できます。質問内の別の質問(または複数の質問)を参照する場合は、OKです。
ファヒムミタ

1
質問を整理するためのヒントが必要な場合は、チャットルームに飛び込んで、そこでチャットをすることをお勧めします。私たちはすでにここでそれについて話していました。:-)
ファヒームミタ14

コメント、@ FaheemMithaに感謝します-同様の疑いもありましたが、質問をどのように切り分けるかが本当にわかりませんでした-そして今までチャットを使用できることに気づいていませんでした(そして、私は熱心ではありませんでした)そのようなアドバイスについて尋ねるためにメタを使用します); 次回は間違いなくチャットをお試しください。ありがたいことに、今回は非常に受け入れられる答えでうまくいきました...乾杯!
sdaau 14年

@sdaau、ディスクアクセスを監視する方法を見つけましたか?
ランシュ

回答:


10

1つの質問であまりにも多くの質問をしましたが、技術的にはそうではありません。「この理解は正しいか」とすぐに答えられると思います。しかし、それは有用な答えではありません。

まず、あなたは右の程度だata_piixsd_modコンパイル時にされているカーネルに明らかに。これは、カーネルを構成する際の選択です。カーネルを省略するか、含めるか、モジュールとして含めることができます。(ext4と同じ)。

第二に、書き込みは実際よりもはるかに単純であると想定しています。書き込みがどのように機能するかの基本的な概要は、ファイルシステムのコードが、書き込まれるデータをバッファーキャッシュの一部としてメモリに入れ、書き込みの必要性(「ダーティ」)としてマークすることです。(RAMにすでに多すぎる場合を除き、実際には書き込みを強制されます...)

後で、さまざまなもの(bdflushカーネルスレッドなど)が実際にダーティページをディスクにフラッシュします。これは、sd、scsi、libata、ata_piix、ioスケジューラ、PCIなどを介した呼び出しを確認するときです。その書き込みにはDMAが関与する可能性が非常に高いですが、転送されるデータとコマンドの可能性があります。ただし、少なくともSATAでのディスク書き込みは、基本的に「セクターXにデータYを書き込む」ことを意味するコマンドを送信することで処理されます。ただし、ディスク全体のメモリマッピングでは処理されません(32ビットマシンでは4GiBよりもはるかに大きいディスクを使用できます)。

キャッシュは、ファイルシステム、ブロックレイヤーなどと連動して、メモリ管理サブシステム(ドライバーではない)によって処理されます。

tmpfs特別であり、基本的に完全にキャッシュです。破棄も書き戻しもされない特別なキャッシュ(スワップアウトは可能)。コードはmm/shmem.c他のいくつかの場所で見つけることができます(ack-grep --cc CONFIG_TMPFS見つけてみてください)。

基本的に、ディスクへの書き込みはカーネルのサブシステムのかなりの部分を通過します。ネットワークは私が考えることができる唯一の主要なものであり、それはあなたの例には関係していません。それを適切に説明するには、本の長さの努力が必要です。探してみることをお勧めします。


こんにちは、@ derobert-ご回答ありがとうございます。それは私が行方不明だった正確な種類の情報を含んでいます!私はもともとユーザー対カーネルスペースのシンプルなイラストを探し始めましたが、すぐにハードディスクの書き込みは完全に理解できるものではなく、それほど簡単ではないことに気付きました-それが実際に本であることを確認してくれてありがとう-長い努力!乾杯!
sdaau 14年

ちょっとした注意:sudo bash...OP のスクリプト内でftraceメモリが増加している場合(echo 8192 > $KDBGPATH/buffer_size_kb)、この回答の説明の一部(ダーティページのフラッシュなど)は観察可能です。そしてsync ;後に追加される./wtest ;コール。次にflush-8kworker(の下kthreaddにあるps axf)と、syncそれ自体を、ftraceたとえばata_bmdma_setup()(の一部でありlibata、上にata_piix構築される)またはのような関数を呼び出すプロセスとして見ることができますget_nr_dirty_inodes()
sdaau 14年

4

だから私の最初の質問は-なぜブート時ログでのみata_piixモジュールを観察できないのですか?これは、(ロード可能な).koカーネルモジュールとして構築されるのではなく、ata_piix(およびsd)が(モノリシック)カーネルの組み込みドライバーとして構築されるためですか?

構成を推測する必要はありません。私のマシンには

$ uname -a
Linux orwell 3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64 GNU/Linux

このカーネルの設定ファイルはにあります/boot/config-3.2.0-4-amd64

について尋ねましたata_piix。上記の.configファイルを検索すると、が表示され CONFIG_ATA_PIIX=mます。これを確認することができます

dlocate ata_piix.ko   

代わりに

dpkg -S ata_piix.ko

linux-image-3.2.0-4-amd64: /lib/modules/3.2.0-4-amd64/kernel/drivers/ata/ata_piix.ko

少なくとも私のカーネルでは、それはモジュールです。


@FaheemMithaに感謝します-以前に設定ファイルを聞いた(そして使用した)が、何らかの理由でこの例ではそれを完全に忘れてしまいました。きれいに発見!:)私のシステムでgrep ATA_PIIX /boot/config-2.6.38-16-genericCONFIG_ATA_PIIX=y、おそらくこのカーネルでata_piixはおそらく「カーネル内」でビルドされるのであって、モジュールとしてではない、と言う。乾杯!
sdaau 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.