Наблюдение за записью жесткого диска в пространстве ядра (с драйверами / модулями)

Извиняюсь заранее, если этот пост немного плотный / беспорядочный, но мне сложно сформулировать его лучше … В принципе, я хотел бы изучить, что происходит на жестком диске, и я хотел бы знать:

  • Правильно ли я понимаю это, а если нет, то где я ошибаюсь?
  • Есть ли лучший инструмент для «захвата» данных журнала, обо всех аспектах, происходящих на ПК, во время записи диска?

Более подробно – во-первых, используемая ОС:

$ 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 

Итак, у меня есть следующие простые (например, обычные проверки на отказ от операций пропущены) user-space C program, 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 (и я использую другие разделы как «автономные» диски / mounts). Чтобы найти драйвер для этого устройства, я использую 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_piixsd ).

 $ 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_piixsd ) ata_piix впервые.

Моя первая путаница в том, что я не могу иначе наблюдать ata_piix или sd :

 $ 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_piixsd ) построены как встроенные драйверы в (монолитном) ядре, а не в качестве (загружаемых) .ko модулей ядра?

Итак, теперь я пытаюсь наблюдать, что происходит при запуске программы с ftrace встроенного функции ftrace Linux.

 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 |  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 |  common_file_perm ();
  4604,352696 |  0) wtest-31632 |  2.198 |  }
  4604.352697 |  0) wtest-31632 |  3.573 |  }
  4604.352697 |  0) wtest-31632 |  4.979 |  }
  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 |  _cond_resched ();
  4604.352703 |  0) wtest-31632 |  1.994 |  }
  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 |  _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 |  }
  4604.352823 |  0) wtest-31632 |  |  generic_file_buffered_write () {
  4604,352824 |  0) wtest-31632 |  0.654 |  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 |  }
  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 |  generic_write_sync ();
  4604.352912 |  0) wtest-31632 |  !  212.259 us |  }
  4604.352913 |  0) wtest-31632 |  !  213.845 |  }
  4604.352914 |  0) wtest-31632 |  !  215.286 |  }
  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 |  }
  4604.352920 |  0) wtest-31632 |  !  228.409 us |  }
  4604.352921 |  0) wtest-31632 |  !  231.334 |  }

Это мой второй момент путаницы – я могу наблюдать за пользователем- write() с ядром-пространством sys_write() , как и ожидалось; и в sys_write() я наблюдаю функции, связанные с безопасностью (например, apparmor_file_permission() ), «общие» функции записи (например, generic_file_aio_write() ), связанные с файловой системой ext4 (например, ext4_journal_start_sb() ) – но я не вижу ничего связанного к ata_piix (или sd )?!

Трассировка страницы и профилирование – проект Yocto предлагает использовать трассировку blk в ftrace для получения дополнительной информации об операции с блочным устройством, но в этом примере он ничего не сообщает. Кроме того, Linux Filesystem Drivers – Annon Inglorion (tutorfs) предполагает, что файловые системы (могут?) Также реализованы как модули ядра / драйверы, и я предполагаю, что это относится и к ext4 .

Наконец, я мог бы поклясться, что ранее я заметил имя драйвера в квадратных скобках рядом с функцией, показанной function_graph tracer, но я предполагаю, что у меня были смешанные вещи – возможно, это может быть похоже на следы стека (назад), но а не в графе функций. Кроме того, я могу проверить /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 ядра .ko , сохраняют эту информацию (например, [psmouse] показанная выше в квадратных скобках). Таким образом, ftrace может отображать только информацию «исходящего модуля», только для тех функций, которые поступают из загружаемых модулей ядра. Это верно?

Принятое во внимание, это понимание того, что у меня есть процесс в настоящее время:

  • Во время ata_piix драйвер ata_piix устанавливает сопоставление памяти DMA (?) Между /dev/sda и жестким диском
    • из-за этого все будущие обращения к /dev/sda через ata_piix будут прозрачными для ядра (т. е. не отслеживаются) – поскольку все ядро ​​увидит, просто читают / записывают в ячейки памяти (необязательно вызовы для определенных прослеживаемых функции ядра), которые не сообщаются function_graph tracer
  • Во время загрузки драйвер sd , кроме того, «разбирает» разделы /dev/sda , делает их доступными и, возможно, обрабатывает сопоставления памяти между разделами <-> дискового устройства
    • опять же, это должно сделать операции доступа через sd прозрачными для ядра
  • Поскольку ata_piix и sd скомпилированы в ядре, даже если некоторые из их функций в конечном итоге захватываются ftrace , мы не можем получить информацию о том, из какого модуля будут поступать эти функции (помимо «ручной» корреляции с исходными файлами)
  • Позже mount устанавливает связь / привязку между разделом и соответствующим драйвером файловой системы (в данном случае ext4 )
    • с этого момента все обращения к смонтированной файловой системе будут обрабатываться функциями ext4 которые отслеживаются ядром; но поскольку ext4 скомпилирован в ядре, трассировщик не может предоставить нам исходную информацию модуля
  • Таким образом, наблюдаемые «общие» записи, вызванные через функции ext4 , в конечном счете будут иметь доступ к ata_piix памяти, отображение которых установлено ata_piix но кроме этого ata_piix не вмешивается непосредственно в передачу данных (возможно, это ata_piix с DMA (вне процессора (ов) и, таким образом, прозрачны для него).

Правильно ли это понимание?

Некоторые связанные с этим подтексты:

  • В моей установке выше я могу определить драйвер устройства PCI ( ata_piix ) и драйвер файловой системы ( ext4 ); но существуют ли драйверы символов или блоков где-то на пути выполнения «write», и если да, то каковы они?
  • Какой из этих драйверов будет обрабатывать кеширование (поэтому ненужные дисковые операции пропускаются или оптимизируются?)
  • Я знаю, что до этого /dev/shm является файловой системой в ОЗУ; mount | grep shm mount | grep shm для меня отчеты: none on /dev/shm type tmpfs (rw,nosuid,nodev) . Означает ли это, что – в отличие от /dev/sda – файловая система shm просто лишена (DMA) отображения от «своих» адресов до адресов шины к устройству; и, следовательно, все обращения через драйвер файловой системы tmpfs приводятся в фактической ОЗУ?

2 Solutions collect form web for “Наблюдение за записью жесткого диска в пространстве ядра (с драйверами / модулями)”

Вы задали слишком много вопросов в одном вопросе – ну, технически нет, поскольку я думаю, что «это понимание правильное» можно быстро ответить: нет. Но это не очень полезный ответ.

Во-первых, вы правы в ata_piix и sd_mod видимому, скомпилирован в ваше ядро. Это выбор, который вы настраиваете для ядра – вы можете его опустить, включить или включить в качестве модуля. (То же самое с ext4).

Во-вторых, вы предположили, что записи намного проще, чем они есть на самом деле. Основной контур того, как работает запись, заключается в том, что код файловой системы помещает данные в память, как часть кеша буфера, и маркирует их как написанные для нужд («грязные»). (Если в ОЗУ уже слишком много, в этом случае на самом деле это вынуждено делать запись …)

Позже различные вещи (например, bdflush ядра bdflush ) фактически bdflush грязные страницы до диска. Это когда вы увидите вызовы через sd, scsi, libata, ata_piix, io schedulers, PCI и т. Д. Хотя в этой записи очень вероятен DMA, это данные передаются и, возможно, команда. Но записи на диске, по крайней мере в SATA, обрабатываются путем отправки команд, которые в основном означают «запись сектора X с данными Y». Но это определенно не связано с отображением памяти на весь диск (учтите: вы можете использовать диски, размер которых намного больше, чем 4GiB на 32-битных машинах).

Кэширование обрабатывается подсистемой управления памятью (а не драйвером) в сочетании с файловой системой, блочным слоем и т. Д.

tmpfs является особенным, в основном это кеш. Его просто специальный кеш, который никогда не отбрасывается или не записывается (хотя его можно поменять). Вы можете найти код в mm/shmem.c и в нескольких других местах (попробуйте ack-grep --cc CONFIG_TMPFS чтобы найти их).

В принципе, запись на диск проходит через значительную часть подсистем ядра; сетевое взаимодействие – единственное, что я могу придумать, что не участвует в вашем примере. Правильное объяснение этого требует усилий, связанных с книгой; Я рекомендую его искать.

Поэтому мой первый вопрос: почему я не могу наблюдать модуль ata_piix здесь, только в журналах загрузки? Это потому, что ata_piix (и sd) построены как встроенные драйверы в (монолитном) ядре, а не в качестве (загружаемых) .ko модулей ядра?

Вам не нужно угадывать, что такое ваша конфигурация. На моей машине у меня есть

 $ 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 

По крайней мере, в моем ядре это модуль.

  • Сколько времени занимает пользователь => переход в режим ядра?
  • IPsec не считывает конфигурацию при удалении туннеля
  • Linux Kernel 3.x новая схема управления версиями
  • Является ли отключенная опция ядра эквивалентной, не загружая соответствующий модуль?
  • Ошибка малины Pi RT.
  • Путаница относительно конфигурации # прерываний на расширителе PCA9555
  • Почему существует AF_NETLINK? Недостаточно AF_UNIX?
  • Virtualbox жалуется, что у меня нет заголовков
  • Как установить «установить USB» с пользовательским Linux?
  • Как хорошо работать?
  • Qemu - отладка нового syscall
  • Linux и Unix - лучшая ОС в мире.